"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.mapStateReducer = exports.MAP_STATE_INITIAL_SUB_STATE = exports.MG_INITIAL_SUB_STATE = exports.MAP_STATE_INITIAL_STATE = void 0;
var tslib_1 = require("tslib");
var type_guards_1 = require("../utils/type-guards");
var array_1 = require("../utils/array");
var actions_1 = require("../constants/actions");
var defs_1 = require("../actions/defs");
var logger_1 = require("../utils/logger");
var ol_style_contracts_1 = require("../api/ol-style-contracts");
var units_1 = require("../utils/units");
exports.MAP_STATE_INITIAL_STATE = {};
exports.MG_INITIAL_SUB_STATE = {
    selectionSet: undefined,
    layerTransparency: {},
    selectableLayers: {},
    expandedGroups: {},
    runtimeMap: undefined,
    isArbitraryCs: false,
    showLayers: [],
    showGroups: [],
    hideLayers: [],
    hideGroups: [],
    activeSelectedFeature: undefined,
};
exports.MAP_STATE_INITIAL_SUB_STATE = {
    currentView: undefined,
    initialView: undefined,
    history: [],
    historyIndex: -1,
    externalBaseLayers: [],
    initialExternalLayers: [],
    layers: undefined,
    mapguide: undefined,
    generic: undefined,
    clientSelection: undefined
};
function applyMapGuideSubState(state, mapName, applyFn) {
    var subState = state[mapName];
    if (subState) {
        var mgSubState = subState.mapguide;
        if (mgSubState) {
            var toApply = applyFn(mgSubState);
            var mgSubState1 = tslib_1.__assign(tslib_1.__assign({}, mgSubState), toApply);
            return mergeSubState(state, mapName, tslib_1.__assign(tslib_1.__assign({}, subState), { mapguide: mgSubState1 }));
        }
    }
    return state;
}
function setLayerAction(state, mapName, layerName, selector) {
    var subState = state[mapName];
    if (subState && subState.layers) {
        var layers = subState.layers.map(function (l) {
            if (l.name == layerName) {
                return tslib_1.__assign(tslib_1.__assign({}, l), (selector(l)));
            }
            else {
                return l;
            }
        });
        var state1 = {
            layers: layers
        };
        return mergeSubState(state, mapName, tslib_1.__assign(tslib_1.__assign({}, subState), state1));
    }
    return state;
}
function mergeSubState(state, mapName, subState) {
    var state1 = {};
    state1[mapName] = tslib_1.__assign(tslib_1.__assign({}, state[mapName]), subState);
    return tslib_1.__assign(tslib_1.__assign({}, state), state1);
}
function mapStateReducer(state, action) {
    var _a, _b, _c, _d, _e, _f, _g, _h;
    if (state === void 0) { state = exports.MAP_STATE_INITIAL_STATE; }
    switch (action.type) {
        case actions_1.ActionType.MAP_REFRESH:
            {
                var payload_1 = action.payload;
                return applyMapGuideSubState(state, payload_1.mapName, function (_) { return ({
                    runtimeMap: payload_1.map,
                    isArbitraryCs: (0, units_1.tryParseArbitraryCs)(payload_1.map.CoordinateSystem.MentorCode) != null
                }); });
            }
        case actions_1.ActionType.INIT_APP:
            {
                var payload = action.payload;
                var maps = payload.maps;
                var mapKeys = Object.keys(maps);
                var newState = {};
                var mapNameToApplyInitialState = payload.activeMapName;
                if (!mapNameToApplyInitialState && mapKeys.length == 1) {
                    mapNameToApplyInitialState = mapKeys[0];
                }
                for (var _i = 0, mapKeys_1 = mapKeys; _i < mapKeys_1.length; _i++) {
                    var mapName = mapKeys_1[_i];
                    var cv = void 0;
                    if (payload.initialView && mapName == mapNameToApplyInitialState) {
                        cv = {
                            currentView: tslib_1.__assign({}, payload.initialView)
                        };
                    }
                    var isel = void 0;
                    if (payload.initialSelections && payload.initialSelections[mapName]) {
                        isel = {
                            selectionSet: payload.initialSelections[mapName]
                        };
                        (0, logger_1.debug)("Restoring client-side selection set for: ".concat(mapName));
                    }
                    var sl = [];
                    var sg = [];
                    var hl = [];
                    var hg = [];
                    var mrtm = void 0;
                    var mgeneric = void 0;
                    var rtm = maps[mapName].map;
                    if (rtm) {
                        if (!(0, defs_1.isGenericSubjectMapLayer)(rtm)) {
                            var arbCs = (0, units_1.tryParseArbitraryCs)(rtm.CoordinateSystem.MentorCode);
                            mrtm = { runtimeMap: rtm, isArbitraryCs: arbCs != null };
                        }
                        else {
                            mgeneric = { subject: tslib_1.__assign({}, rtm) };
                        }
                    }
                    if (mapName == mapNameToApplyInitialState) {
                        if (rtm && !(0, defs_1.isGenericSubjectMapLayer)(rtm)) {
                            var isl = (_a = payload.initialShowLayers) !== null && _a !== void 0 ? _a : [];
                            var isg = (_b = payload.initialShowGroups) !== null && _b !== void 0 ? _b : [];
                            var ihl = (_c = payload.initialHideLayers) !== null && _c !== void 0 ? _c : [];
                            var ihg = (_d = payload.initialHideGroups) !== null && _d !== void 0 ? _d : [];
                            //Only initally show what is initially hidden and vice versa
                            //NOTE: A map could have duplicate group/layer names, we make no attempt
                            //to pick out the "correct" one. It's first come first serve.
                            if (rtm.Layer) {
                                for (var _j = 0, _k = rtm.Layer; _j < _k.length; _j++) {
                                    var l = _k[_j];
                                    if (isl.indexOf(l.Name) >= 0 && !l.Visible) {
                                        sl.push(l.ObjectId);
                                    }
                                    else if (ihl.indexOf(l.Name) >= 0 && l.Visible) {
                                        hl.push(l.ObjectId);
                                    }
                                }
                            }
                            if (rtm.Group) {
                                for (var _l = 0, _m = rtm.Group; _l < _m.length; _l++) {
                                    var g = _m[_l];
                                    if (isg.indexOf(g.Name) >= 0 && !g.Visible) {
                                        sg.push(g.ObjectId);
                                    }
                                    else if (ihg.indexOf(g.Name) >= 0 && g.Visible) {
                                        hg.push(g.ObjectId);
                                    }
                                }
                            }
                            (0, logger_1.debug)("Initially showing layers: ".concat(isl.join("|")));
                            (0, logger_1.debug)("Initially showing groups: ".concat(isg.join("|")));
                            (0, logger_1.debug)("Initially hiding layers: ".concat(ihl.join("|")));
                            (0, logger_1.debug)("Initially hiding groups: ".concat(ihg.join("|")));
                            (0, logger_1.debug)("Initially showing layer ids: ".concat(sl.join("|")));
                            (0, logger_1.debug)("Initially showing group ids: ".concat(sg.join("|")));
                            (0, logger_1.debug)("Initially hiding layer ids: ".concat(hl.join("|")));
                            (0, logger_1.debug)("Initially hiding group ids: ".concat(hg.join("|")));
                        }
                    }
                    var newMgSubState = tslib_1.__assign(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, exports.MG_INITIAL_SUB_STATE), mrtm), (isel || {})), (sl.length > 0 ? { showLayers: tslib_1.__spreadArray([], sl, true) } : {})), (sg.length > 0 ? { showGroups: tslib_1.__spreadArray([], sg, true) } : {})), (hl.length > 0 ? { hideLayers: tslib_1.__spreadArray([], hl, true) } : {})), (hg.length > 0 ? { hideGroups: tslib_1.__spreadArray([], hg, true) } : {}));
                    var newMapState = tslib_1.__assign(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, exports.MAP_STATE_INITIAL_SUB_STATE), { generic: mgeneric }), { externalBaseLayers: maps[mapName].externalBaseLayers }), { initialExternalLayers: maps[mapName].initialExternalLayers }), { initialView: maps[mapName].initialView }), (cv || {})), { mapguide: newMgSubState });
                    // As INIT_APP does not establish a currentView, if a currentView was
                    // somehow established as part of the initial app state, we will keep
                    // it instead of it being discarded
                    if ((_e = state === null || state === void 0 ? void 0 : state[mapName]) === null || _e === void 0 ? void 0 : _e.currentView) {
                        newMapState.currentView = state[mapName].currentView;
                    }
                    newState[mapName] = newMapState;
                }
                return tslib_1.__assign(tslib_1.__assign({}, state), newState);
            }
        case actions_1.ActionType.MAP_PREVIOUS_VIEW:
            {
                var payload = action.payload;
                var subState = state[payload.mapName];
                var rs = state;
                if (subState) {
                    var index = subState.historyIndex - 1;
                    if (index >= 0) {
                        var state1 = {
                            historyIndex: index,
                            currentView: subState.history[index]
                        };
                        rs = mergeSubState(state, payload.mapName, tslib_1.__assign(tslib_1.__assign({}, subState), state1));
                    }
                }
                (0, logger_1.debug)("Next navigation stack:", rs[payload.mapName].historyIndex, rs[payload.mapName].history);
                return rs;
            }
        case actions_1.ActionType.MAP_NEXT_VIEW:
            {
                var payload = action.payload;
                var subState = state[payload.mapName];
                var rs = state;
                if (subState) {
                    var index = subState.historyIndex + 1;
                    if (index < subState.history.length) {
                        var state1 = {
                            historyIndex: index,
                            currentView: subState.history[index]
                        };
                        rs = mergeSubState(state, payload.mapName, tslib_1.__assign(tslib_1.__assign({}, subState), state1));
                    }
                }
                (0, logger_1.debug)("Next navigation stack:", rs[payload.mapName].historyIndex, rs[payload.mapName].history);
                return rs;
            }
        case actions_1.ActionType.MAP_SET_SCALE:
            {
                var payload = action.payload;
                var subState = state[payload.mapName];
                if (subState) {
                    var view = subState.currentView;
                    var scale = payload.scale;
                    if (typeof view === 'object' && typeof scale === 'number') {
                        var view1 = { scale: scale, resolution: payload.resolution };
                        view = tslib_1.__assign(tslib_1.__assign({}, view), view1);
                    }
                    var state1 = {
                        currentView: view
                    };
                    var newSubState = tslib_1.__assign(tslib_1.__assign({}, state1), { historyIndex: subState.historyIndex });
                    newSubState.history = tslib_1.__spreadArray([], subState.history, true);
                    if (view && newSubState.history && newSubState.historyIndex != null) {
                        newSubState.historyIndex++;
                        newSubState.history[newSubState.historyIndex] = view;
                        //If we slotted at a position that is not the end of the array
                        //remove everything after it
                        if (newSubState.history.length > newSubState.historyIndex + 1) {
                            newSubState.history.splice(newSubState.historyIndex + 1);
                        }
                    }
                    return mergeSubState(state, payload.mapName, newSubState);
                }
                return state;
            }
        case actions_1.ActionType.MAP_SET_VIEW:
            {
                var payload = action.payload;
                var subState = state[payload.mapName];
                var rs = state;
                if (subState) {
                    var data = payload.view;
                    if ((0, type_guards_1.isMapView)(data)) {
                        var state1 = {
                            currentView: data
                        };
                        var newSubState = tslib_1.__assign(tslib_1.__assign({}, state1), { historyIndex: subState.historyIndex });
                        newSubState.history = tslib_1.__spreadArray([], subState.history, true);
                        if (newSubState.history && newSubState.historyIndex != null) {
                            newSubState.historyIndex++;
                            newSubState.history[newSubState.historyIndex] = data;
                            //If we slotted at a position that is not the end of the array
                            //remove everything after it
                            if (newSubState.history.length > newSubState.historyIndex + 1) {
                                newSubState.history.splice(newSubState.historyIndex + 1);
                            }
                        }
                        rs = mergeSubState(state, payload.mapName, newSubState);
                    }
                }
                (0, logger_1.debug)("Next navigation stack:", rs[payload.mapName].historyIndex, rs[payload.mapName].history);
                return rs;
            }
        case actions_1.ActionType.MAP_SET_LAYER_TRANSPARENCY:
            {
                //TODO: Move state to non-MG branch for next major release
                var payload_2 = action.payload;
                return applyMapGuideSubState(state, payload_2.mapName, function (mgSubState) {
                    var trans = tslib_1.__assign({}, mgSubState.layerTransparency);
                    trans[payload_2.layerName] = payload_2.opacity;
                    return {
                        layerTransparency: trans
                    };
                });
            }
        case actions_1.ActionType.LEGEND_SET_LAYER_SELECTABLE:
            {
                var payload_3 = action.payload;
                return applyMapGuideSubState(state, payload_3.mapName, function (mgSubState) {
                    var layers = tslib_1.__assign({}, mgSubState.selectableLayers);
                    layers[payload_3.id] = payload_3.value;
                    return {
                        selectableLayers: layers
                    };
                });
            }
        case actions_1.ActionType.LEGEND_SET_GROUP_EXPANDABLE:
            {
                var payload_4 = action.payload;
                return applyMapGuideSubState(state, payload_4.mapName, function (mgSubState) {
                    var groups = tslib_1.__assign({}, mgSubState.expandedGroups);
                    groups[payload_4.id] = payload_4.value;
                    return {
                        expandedGroups: groups
                    };
                });
            }
        case actions_1.ActionType.LEGEND_SET_GROUP_VISIBILITY:
            {
                var payload_5 = action.payload;
                return applyMapGuideSubState(state, payload_5.mapName, function (mgSubState) {
                    var showGroups = tslib_1.__spreadArray([], mgSubState.showGroups, true);
                    var hideGroups = tslib_1.__spreadArray([], mgSubState.hideGroups, true);
                    if (payload_5.value === true) { //Show it
                        showGroups.push(payload_5.id);
                        showGroups = (0, array_1.makeUnique)(showGroups);
                        hideGroups = hideGroups.filter(function (g) { return g != payload_5.id; });
                    }
                    else { //Hide it
                        hideGroups.push(payload_5.id);
                        hideGroups = (0, array_1.makeUnique)(hideGroups);
                        showGroups = showGroups.filter(function (g) { return g != payload_5.id; });
                    }
                    return {
                        showLayers: mgSubState.showLayers,
                        showGroups: showGroups,
                        hideLayers: mgSubState.hideLayers,
                        hideGroups: hideGroups
                    };
                });
            }
        case actions_1.ActionType.LEGEND_SET_LAYER_VISIBILITY:
            {
                var payload_6 = action.payload;
                return applyMapGuideSubState(state, payload_6.mapName, function (mgSubState) {
                    var showLayers = tslib_1.__spreadArray([], mgSubState.showLayers, true);
                    var hideLayers = tslib_1.__spreadArray([], mgSubState.hideLayers, true);
                    if (payload_6.value === true) { //Show it
                        showLayers.push(payload_6.id);
                        showLayers = (0, array_1.makeUnique)(showLayers);
                        hideLayers = hideLayers.filter(function (g) { return g != payload_6.id; });
                    }
                    else { //Hide it
                        hideLayers.push(payload_6.id);
                        hideLayers = (0, array_1.makeUnique)(hideLayers);
                        showLayers = showLayers.filter(function (g) { return g != payload_6.id; });
                    }
                    return {
                        showLayers: showLayers,
                        showGroups: mgSubState.showGroups,
                        hideLayers: hideLayers,
                        hideGroups: mgSubState.hideGroups
                    };
                });
            }
        case actions_1.ActionType.MAP_SET_SELECTION:
            {
                var payload_7 = action.payload;
                return applyMapGuideSubState(state, payload_7.mapName, function (_) { return ({
                    selectionSet: payload_7.selection,
                    layerIndex: -1,
                    featureIndex: -1,
                    activeSelectedFeature: undefined
                }); });
            }
        case actions_1.ActionType.MAP_ADD_CLIENT_SELECTED_FEATURE:
            {
                var payload_8 = action.payload;
                var subState = state[payload_8.mapName];
                if (subState) {
                    var cs = (_f = subState.clientSelection) !== null && _f !== void 0 ? _f : {
                        layers: []
                    };
                    var lyr = cs.layers.find(function (l) { return l.name == payload_8.layerName; });
                    if (!lyr) {
                        lyr = {
                            name: payload_8.layerName,
                            features: []
                        };
                        cs.layers.push(lyr);
                    }
                    lyr.features.push(payload_8.feature);
                    return mergeSubState(state, payload_8.mapName, tslib_1.__assign(tslib_1.__assign({}, subState), { clientSelection: cs }));
                }
                return state;
            }
        case actions_1.ActionType.MAP_CLEAR_CLIENT_SELECTION:
            {
                var payload = action.payload;
                var subState = state[payload.mapName];
                if (subState) {
                    return mergeSubState(state, payload.mapName, tslib_1.__assign(tslib_1.__assign({}, subState), { clientSelection: undefined }));
                }
                return state;
            }
        case actions_1.ActionType.MAP_SHOW_SELECTED_FEATURE:
            {
                var payload_9 = action.payload;
                return applyMapGuideSubState(state, payload_9.mapName, function (_) { return ({
                    activeSelectedFeature: {
                        layerId: payload_9.layerId,
                        selectionKey: payload_9.selectionKey
                    }
                }); });
            }
        case actions_1.ActionType.MAP_SET_BASE_LAYER:
            {
                var payload_10 = action.payload;
                var subState = state[payload_10.mapName];
                if (subState) {
                    var layers = (subState.externalBaseLayers || []);
                    var baseLayers = layers.map(function (layer) {
                        // Non-visual base layers like UTFGrid will always stay visible
                        if (layer.kind != "UTFGrid") {
                            layer.visible = false;
                        }
                        if (layer.name == payload_10.layerName) {
                            layer.visible = true;
                        }
                        return layer;
                    });
                    var state1 = {
                        externalBaseLayers: baseLayers
                    };
                    return mergeSubState(state, payload_10.mapName, tslib_1.__assign(tslib_1.__assign({}, subState), state1));
                }
                return state;
            }
        case actions_1.ActionType.EXTERNAL_LAYERS_READY:
            {
                var payload = action.payload;
                var subState = state[payload.mapName];
                if (subState) {
                    var layers = (_g = subState.layers) !== null && _g !== void 0 ? _g : [];
                    var state1 = {
                        layers: layers
                    };
                    return mergeSubState(state, payload.mapName, tslib_1.__assign(tslib_1.__assign({}, subState), state1));
                }
                return state;
            }
        case actions_1.ActionType.LAYER_ADDED:
            {
                var payload_11 = action.payload;
                var subState = state[payload_11.mapName];
                if (subState) {
                    var layers = tslib_1.__spreadArray([payload_11.layer], ((_h = subState.layers) !== null && _h !== void 0 ? _h : []), true);
                    var state1 = {
                        layers: layers
                    };
                    var ss = mergeSubState(state, payload_11.mapName, tslib_1.__assign(tslib_1.__assign({}, subState), state1));
                    if (payload_11.defaultStyle) {
                        var ss1 = setLayerAction(ss, payload_11.mapName, payload_11.layer.name, function () { return ({ vectorStyle: payload_11.defaultStyle }); });
                        return ss1;
                    }
                    return ss;
                }
                return state;
            }
        case actions_1.ActionType.REMOVE_LAYER:
            {
                var payload = action.payload;
                var subState = state[payload.mapName];
                if (subState && subState.layers) {
                    var layers = subState.layers.filter(function (l) { return l.name != action.payload.layerName; });
                    var state1 = {
                        layers: layers
                    };
                    return mergeSubState(state, payload.mapName, tslib_1.__assign(tslib_1.__assign({}, subState), state1));
                }
                return state;
            }
        case actions_1.ActionType.SET_LAYER_VISIBILITY:
            {
                var _o = action.payload, mapName = _o.mapName, layerName = _o.layerName, visible_1 = _o.visible;
                var state1 = setLayerAction(state, mapName, layerName, function () { return ({ visible: visible_1 }); });
                return state1;
            }
        case actions_1.ActionType.SET_LAYER_OPACITY:
            {
                var _p = action.payload, mapName = _p.mapName, layerName = _p.layerName, opacity_1 = _p.opacity;
                var state1 = setLayerAction(state, mapName, layerName, function () { return ({ opacity: opacity_1 }); });
                return state1;
            }
        case actions_1.ActionType.SET_HEATMAP_LAYER_BLUR:
            {
                var _q = action.payload, mapName = _q.mapName, layerName = _q.layerName, blur_1 = _q.blur;
                var state1 = setLayerAction(state, mapName, layerName, function (layer) {
                    var _a;
                    return ({
                        heatmap: tslib_1.__assign(tslib_1.__assign({}, ((_a = layer.heatmap) !== null && _a !== void 0 ? _a : { blur: 15, radius: 5 })), { blur: blur_1 })
                    });
                });
                return state1;
            }
        case actions_1.ActionType.SET_HEATMAP_LAYER_RADIUS:
            {
                var _r = action.payload, mapName = _r.mapName, layerName = _r.layerName, radius_1 = _r.radius;
                var state1 = setLayerAction(state, mapName, layerName, function (layer) {
                    var _a;
                    return ({
                        heatmap: tslib_1.__assign(tslib_1.__assign({}, ((_a = layer.heatmap) !== null && _a !== void 0 ? _a : { blur: 15, radius: 5 })), { radius: radius_1 })
                    });
                });
                return state1;
            }
        case actions_1.ActionType.SET_LAYER_INDEX:
            {
                var _s = action.payload, mapName = _s.mapName, index = _s.index, layerName = _s.layerName;
                var subState = state[mapName];
                if (subState && subState.layers) {
                    var layers = tslib_1.__spreadArray([], subState.layers, true);
                    var currentIdx = -1;
                    for (var i = 0; i < layers.length; i++) {
                        if (layers[i].name == layerName) {
                            currentIdx = i;
                            break;
                        }
                    }
                    if (currentIdx >= 0 && currentIdx != index && index < layers.length && index >= 0) {
                        var theLayer = layers[currentIdx];
                        layers.splice(currentIdx, 1);
                        layers.splice(index, 0, theLayer);
                        var state1 = {
                            layers: layers
                        };
                        return mergeSubState(state, mapName, tslib_1.__assign(tslib_1.__assign({}, subState), state1));
                    }
                }
                return state;
            }
        case actions_1.ActionType.SET_LAYER_VECTOR_STYLE:
            {
                var _t = action.payload, mapName = _t.mapName, layerName = _t.layerName, style_1 = _t.style, which_1 = _t.which;
                var state1 = setLayerAction(state, mapName, layerName, function (current) {
                    if (which_1 == ol_style_contracts_1.VectorStyleSource.Base) {
                        return { vectorStyle: style_1 };
                    }
                    else if (which_1 == ol_style_contracts_1.VectorStyleSource.Cluster) {
                        return {
                            cluster: tslib_1.__assign(tslib_1.__assign({}, current.cluster), { style: tslib_1.__assign({}, style_1) })
                        };
                    }
                    else {
                        return {};
                    }
                });
                return state1;
            }
        case actions_1.ActionType.ADD_LAYER_BUSY_WORKER:
            {
                var _u = action.payload, mapName = _u.mapName, layerName = _u.layerName;
                var state1 = setLayerAction(state, mapName, layerName, function (l) { return ({ busyWorkerCount: l.busyWorkerCount + 1 }); });
                return state1;
            }
        case actions_1.ActionType.REMOVE_LAYER_BUSY_WORKER:
            {
                var _v = action.payload, mapName = _v.mapName, layerName = _v.layerName;
                var state1 = setLayerAction(state, mapName, layerName, function (l) { return ({ busyWorkerCount: l.busyWorkerCount - 1 }); });
                return state1;
            }
    }
    return state;
}
exports.mapStateReducer = mapStateReducer;
//# sourceMappingURL=map-state.js.map