import { FilterActionType } from "./types";

export class FilterStateManager {
    constructor(table, engine) {
        this.listeners = [], this.state = {
            filters: new Map
        }, this.engine = engine, this.table = table;
    }
    getFilterState(fieldId) {
        return this.state.filters.get(fieldId);
    }
    getActiveFilterFields() {
        const activeFields = [];
        return this.state.filters.forEach(((config, field) => {
            config.enable && activeFields.push(field);
        })), activeFields;
    }
    getAllFilterStates() {
        return this.state;
    }
    getSnapshot() {
        const filters = [];
        return this.state.filters.forEach((v => {
            const next = Object.assign({}, v);
            next && "byValue" === next.type && Array.isArray(next.values) && (next.values = next.values.slice().sort(((a, b) => String(a).localeCompare(String(b))))), 
            next && Array.isArray(next.condition) && next.condition.length > 2 && (next.condition = next.condition.slice()), 
            filters.push(next);
        })), filters.sort(((a, b) => String(a.field).localeCompare(String(b.field)))), {
            filters: filters
        };
    }
    applySnapshot(snapshot, actionType = FilterActionType.APPLY_FILTERS) {
        var _a;
        const next = new Map;
        (null !== (_a = null == snapshot ? void 0 : snapshot.filters) && void 0 !== _a ? _a : []).forEach((cfg => {
            if (!cfg) return;
            const cloned = Object.assign({}, cfg);
            cloned && "byValue" === cloned.type && Array.isArray(cloned.values) && (cloned.values = cloned.values.slice()), 
            cloned && Array.isArray(cloned.condition) && (cloned.condition = cloned.condition.slice()), 
            next.set(cloned.field, cloned);
        })), this.state = Object.assign(Object.assign({}, this.state), {
            filters: next
        }), this.applyFilters(), this.notifyListeners({
            type: actionType,
            payload: {
                fromSnapshot: !0
            }
        });
    }
    shiftFieldsOnAddColumns(columnIndex, columnCount) {
        if (!Number.isFinite(columnIndex) || !Number.isFinite(columnCount) || columnCount <= 0) return;
        const next = new Map;
        this.state.filters.forEach(((cfg, key) => {
            let newKey = key;
            const cloned = Object.assign({}, cfg);
            "number" == typeof newKey && newKey >= columnIndex && (newKey += columnCount), "number" == typeof cloned.field && cloned.field >= columnIndex && (cloned.field = cloned.field + columnCount), 
            cloned && "byValue" === cloned.type && Array.isArray(cloned.values) && (cloned.values = cloned.values.slice()), 
            cloned && Array.isArray(cloned.condition) && (cloned.condition = cloned.condition.slice()), 
            next.set(newKey, cloned);
        })), this.state = Object.assign(Object.assign({}, this.state), {
            filters: next
        });
    }
    shiftFieldsOnDeleteColumns(deleteColIndexs) {
        if (!Array.isArray(deleteColIndexs) || 0 === deleteColIndexs.length) return;
        const deleteIndexNums = deleteColIndexs.slice().filter((n => Number.isFinite(n))).sort(((a, b) => a - b)).map(((idx, i) => idx - i)), next = new Map;
        this.state.filters.forEach(((cfg, key) => {
            let newKey = key;
            const cloned = Object.assign({}, cfg);
            let removed = !1;
            if ("number" == typeof newKey) {
                let k = newKey;
                for (let i = 0; i < deleteIndexNums.length; i++) {
                    const d = deleteIndexNums[i];
                    if (k === d) {
                        removed = !0;
                        break;
                    }
                    k > d && (k -= 1);
                }
                newKey = k;
            }
            if ("number" == typeof cloned.field) {
                let f = cloned.field;
                for (let i = 0; i < deleteIndexNums.length; i++) {
                    const d = deleteIndexNums[i];
                    if (f === d) {
                        removed = !0;
                        break;
                    }
                    f > d && (f -= 1);
                }
                cloned.field = f;
            }
            removed || (cloned && "byValue" === cloned.type && Array.isArray(cloned.values) && (cloned.values = cloned.values.slice()), 
            cloned && Array.isArray(cloned.condition) && (cloned.condition = cloned.condition.slice()), 
            next.set(newKey, cloned));
        })), this.state = Object.assign(Object.assign({}, this.state), {
            filters: next
        });
    }
    reapplyCurrentFilters() {
        this.getActiveFilterFields().length > 0 && this.applyFilters();
    }
    dispatch(action) {
        this.state = this.reduce(this.state, action), this.shouldApplyFilter(action) && this.applyFilters(), 
        this.notifyListeners(action);
    }
    subscribe(listener) {
        return this.listeners.push(listener), () => {
            this.listeners = this.listeners.filter((l => l !== listener));
        };
    }
    notifyListeners(action) {
        this.listeners.forEach((listener => listener(this.state, action)));
    }
    reduce(state, action) {
        const {type: type, payload: payload} = action, newFilter = new Map(state.filters);
        switch (type) {
          case FilterActionType.ADD_FILTER:
            payload.shouldKeepUnrelatedState ? newFilter.set(payload.field, Object.assign(Object.assign({}, newFilter.get(payload.field)), payload)) : newFilter.set(payload.field, payload);
            break;

          case FilterActionType.REMOVE_FILTER:
            payload.shouldKeepUnrelatedState && "byValue" === payload.type ? (delete newFilter.get(payload.field).values, 
            newFilter.set(payload.field, Object.assign(Object.assign({}, newFilter.get(payload.field)), {
                enable: !1
            }))) : payload.shouldKeepUnrelatedState && "byCondition" === payload.type ? (delete newFilter.get(payload.field).condition, 
            delete newFilter.get(payload.field).operator, newFilter.set(payload.field, Object.assign(Object.assign({}, newFilter.get(payload.field)), {
                enable: !1
            }))) : newFilter.delete(payload.field);
            break;

          case FilterActionType.UPDATE_FILTER:
            newFilter.set(payload.field, Object.assign(Object.assign({}, newFilter.get(payload.field)), payload));
            break;

          case FilterActionType.ENABLE_FILTER:
            newFilter.set(payload.field, Object.assign(Object.assign({}, newFilter.get(payload.field)), {
                enable: !0
            }));
            break;

          case FilterActionType.DISABLE_FILTER:
            newFilter.set(payload.field, Object.assign(Object.assign({}, newFilter.get(payload.field)), {
                enable: !1
            }));
            break;

          case FilterActionType.CLEAR_ALL_FILTERS:
            newFilter.clear();
            break;

          case FilterActionType.APPLY_FILTERS:
            newFilter.set(payload.field, Object.assign(Object.assign(Object.assign({}, newFilter.get(payload.field)), payload), {
                enable: !0
            }));
        }
        return Object.assign(Object.assign({}, state), {
            filters: newFilter
        });
    }
    applyFilters() {
        this.engine.applyFilter(this.state, this.table);
    }
    shouldApplyFilter(action) {
        return [ FilterActionType.REMOVE_FILTER, FilterActionType.ENABLE_FILTER, FilterActionType.DISABLE_FILTER, FilterActionType.CLEAR_ALL_FILTERS, FilterActionType.APPLY_FILTERS ].includes(action.type);
    }
}
//# sourceMappingURL=filter-state-manager.js.map