Source: map/filters/FilterBuilder.js

import { TimeDimension } from "./builders/TimeDimension.js";
import { CQLEsri } from "./builders/CQLEsri.js";
import { CQLGeoserver } from "./builders/CQLGeoserver.js";
import { OGCGeoserver } from "./builders/OGCGeoserver.js";
import { SQLEsri } from "./builders/SQLEsri.js";

export { FilterBuilder };

/**
 * Helper class for creating filter query strings for different software and service types.
 * @memberof vef.map.filters
 */
class FilterBuilder {

    static FILTER_CASES = {
        "geoserver": {
            "wms": {
                "dimension": TimeDimension,
                "cql": CQLGeoserver,
                "ogc": OGCGeoserver
            },
            "wfs": {
                "cql": CQLGeoserver,
                "ogc": OGCGeoserver
            }
        },
        "esri": {
            "wms": {
                "dimension": TimeDimension,
                "cql_imageserver": SQLEsri,
                "sql": SQLEsri,
                "cql": CQLEsri
            }
        },
        "thredds": {
            "wms": {
                "dimension": TimeDimension
            }
        },
        "rasdaman": {
            "wms": {
                "dimension": TimeDimension
            }
        }
    }

    /**
     * Get the filter query for a service based on the filter config for a specific layer
     * 
     * @param {Layer} layer 
     * @param {object[]} filters 
     * 
     * @returns {string}
     */
    static getFilterParams(filters, software, service, type, layerName) {
        const filterCase = this.FILTER_CASES?.[software.toLowerCase()]?.[service.toLowerCase()]?.[type.toLowerCase()] || undefined;
        return (filterCase) ? filterCase.getFilterParams(this.harmonizeFilter(filters), layerName) : {};
    }

    /**
     * Group all columns by attribute in an object
     * 
     * @param {object[]} filters 
     * @returns {object} mapped filters to an object grouped by column
     */
    static harmonizeFilter(filters) {
        const harmonizedFilter = {};

        const add = (column, values) => {
            if (!column) return;
            if (!(column in harmonizedFilter)) harmonizedFilter[column] = [];
            harmonizedFilter[column].push(values)
        };

        for (let i = 0; i < filters.length; ++i) {
            const filter = filters[i];

            if (Array.isArray(filter.values)) for (let j = 0; j < filter.values.length; ++j) {
                const value = filter.values[j];
                const operator = value[0].toLowerCase();

                switch (operator) {
                    case "bt":
                        if (value.length == 4) {
                            add(value[1], [operator, value[2], value[3]]);
                        } else if (value.length == 3) {
                            add(filter.column, [operator, value[1], value[2]]);
                        }
                        break;
                    case "null":
                        if (value.length == 2) {
                            add(value[1], [operator]);
                        } else if (value.length == 1) {
                            add(filter.column, [operator]);
                        }
                        break;
                    case "eq":
                    case "like":
                    case "gt":
                    case "gteq":
                    case "lt":
                    case "lteq":
                        if (value.length == 3) {
                            add(value[1], [operator, value[2]]);
                        } else if (value.length == 2) {
                            add(filter.column, [operator, value[1]]);
                        }
                        break;
                    case "bbox":
                        if (value.length == 6) {
                            add(value[1], [operator, value[2], value[3], value[4], value[5]]);
                        } else if (value.length == 5) {
                            add(filter.column, [operator, value[1], value[2], value[3], value[4]]);
                        }
                }
            }
        }

        return harmonizedFilter;
    }

}