Source: map/filters/Filters.js

import { FilterUi } from './ui/FilterUi.js';
import { TimeFilter } from './ui/TimeFilter.js';
import { CheckboxFilter } from './ui/CheckboxFilter.js'
import { KeyValueFilter } from './ui/KeyValueFilter.js'
import { BoundingBox } from './ui/BoundingBoxFilter.js';
import { DropdownFilter } from './ui/DropdownFilter.js'
import { RangeFilter } from './ui/RangeFilter.js'
import { EventObject } from "../../events/EventObject.js";
import { Window } from '../../ui/Window.js';
import { TextFilter } from './ui/TextFilter.js';
import { MagnituteFilter } from './ui/MagnituteFilter.js';
import "./Filters.css";

export { Filters };

/**
 * A class that inititates the DateTime and Attribute Filters based on the config
 * Also contains methods for the active filters
 * 
 * @author sjaswal <shahzeib.jaswal@awi.de>
 * @author rhess <robin.hess@awi.de>
 * 
 * @memberof vef.map.filters
 */
class Filters extends EventObject {

    filterClasses = {
        "time": TimeFilter,
        "checkbox": CheckboxFilter,
        "dropdown": DropdownFilter,
        "range": RangeFilter,
        "keyvalue": KeyValueFilter,
        "boundingbox": BoundingBox,
        "text": TextFilter,
        "mags": MagnituteFilter
    };

    constructor(cache, map) {
        super({
            "change": [],
            "add": [],
            "remove": []
        });

        this.cache = cache;
        this.map = map;
        this.filters = {};

        this.cache.on("layermanager_filterlayer_change", () => this.fire("change", this))
    }

    /**
    * Returns the Active Filters i.e. DateTime and Attribute Filters
    */
    getActiveFilters() {
        let activeFilters = [];

        const addFilter = filter => {
            const required = !!(filter?.options_?.required);
            let filters = filter.getActiveFilter();
            if (!Array.isArray(filters)) filters = [filters];

            for (let i = 0; i < filters.length; ++i) {
                if (filters[i].hasOwnProperty('values')) {
                    filters[i].required = required;
                    activeFilters.push(filters[i]);
                }
            }
        }

        for (let key in this.filters) {
            if (this.filters[key] instanceof FilterUi) {
                if (!this.filters[key].isActive()) continue;
                addFilter(this.filters[key]);
            }
        }

        addFilter(this.cache);

        return activeFilters;
    }

    setMap(map) {
        this.map = map;
        for (let key in this.filters) {
            this.filters[key].setMap(map);
        }
    }

    /**
     * Add a filter based on the json config
     * @param {object} config filter config
     */
    addFilter(config) {
        const type = config.type.toLowerCase();
        const filterClass = this.filterClasses[type];

        if (filterClass) {
            const id = config.id || (type + "_" + new Date().getTime().toString() + Math.floor(Math.random() * 1000000).toString());

            const filter = new filterClass(null, config, this.cache, this.map);
            this.filters[id] = filter;

            filter.on("change", () => this.fire("change", this));
            filter.on("remove", () => this.removeFilter(id));
            filter.on("copy", () => {
                const options = filter.getOptions();
                options.type = type;
                if (options.id) delete options.id;
                this.addFilter(options);
            });

            this.fire("add", { id: id, filter: filter });

            return filter;
        }
    }

    /**
     * @param {object[]} configs array of configurations
     */
    addFilters(configs) {
        for (let i = 0; i < configs.length; ++i) {
            this.addFilter(configs[i]);
        }
    }

    /**
     * @param {string} id 
     */
    removeFilter(id) {
        if (id in this.filters) {
            this.filters[id].dispose();
            delete this.filters[id];
            this.fire("remove", { id: id, filter: this.filters[id] });
        }
    }

    /**
     * Helper function to create an add button to create new filters
     */
    createAddButton() {
        let selectionWindow = null;

        const div = document.createElement("div");
        div.classList.add("btn-add-filter");
        div.innerHTML = '<a href="#"><i class="fas fa-plus"></i> Add Filter</a>';
        div.querySelector("a").addEventListener("click", e => {
            e.preventDefault();

            if (!selectionWindow) selectionWindow = this.createSelectionWindow_();
            selectionWindow.setOptions({ pointerEvent: e, open: true });
        });

        return div;
    }

    /**
     * Helper function to create a simple filter selection window with a dropdown
     * @private
     */
    createSelectionWindow_() {
        const content = `
            <div class="filter-selection-dropdown-wrapper">
                <select class="filter-selection-dropdown">
                    <option value="time">Time Filter</option>
                    <option value="range">Range Filter</option>
                    <option value="keyvalue">Key Value Filter</option>
                    <option value="checkbox">Checkbox Filter</option>
                    <option value="dropdown">Dropdown Filter</option>
                    <option value="boundingbox">Bounding Box Filter</option>
                </select>
                <button class="btn-add"><i class="fas fa-plus"></i></button>
            </div>
        `;

        const options = {
            width: "350px",
            responsive: true,
            content: content,
            draggable: true,
            title: "Add Filter",
            open: false
        };

        const selectionWindow = new Window(null, options);

        selectionWindow.query(".btn-add").addEventListener("click", e => {
            const value = selectionWindow.query(".filter-selection-dropdown").value;
            const filter = this.addFilter({ type: value });
            selectionWindow.close();
            if (filter) {
                const style = selectionWindow.getElement().style;
                filter.openSettings({ top: style.top, left: style.left });
            }
        });

        return selectionWindow;
    }

}