"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getCommand = exports.registerCommand = exports.openUrlInTarget = exports.isSupportedCommandInStatelessMode = exports.DefaultCommands = exports.CommandConditions = exports.reduceAppToToolbarState = exports.mapToolbarReference = exports.mergeInvokeUrlParameters = void 0;
var common_1 = require("../../api/common");
var runtime_1 = require("../../api/runtime");
var i18n_1 = require("../i18n");
var asset_1 = require("../../utils/asset");
var assets_1 = require("../../constants/assets");
var never_1 = require("../../utils/never");
var url_1 = require("../../utils/url");
var actions_1 = require("../../constants/actions");
var modal_1 = require("../../actions/modal");
var logger_1 = require("../../utils/logger");
var FUSION_ICON_REGEX = /images\/icons\/[a-zA-Z\-]*.png/;
function fixIconPath(path) {
    if (FUSION_ICON_REGEX.test(path)) {
        return "".concat((0, asset_1.getAssetRoot)(), "/").concat(path).replace(/\/\//g, "/");
    }
    return path;
}
function fusionFixSpriteClass(tb, cmd) {
    if (tb.spriteClass) {
        return tb.spriteClass;
    }
    if (cmd && cmd.iconClass) {
        return cmd.iconClass;
    }
    return undefined;
}
/**
 * @hidden
 */
function mergeInvokeUrlParameters(currentParameters, extraParameters) {
    var currentP = currentParameters.reduce(function (prev, current, i, arr) {
        prev[current.name] = current.value;
        return prev;
    }, {});
    if (extraParameters) {
        var keys = Object.keys(extraParameters);
        for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
            var k = keys_1[_i];
            currentP[k] = extraParameters[k];
        }
    }
    var merged = [];
    var mkeys = Object.keys(currentP);
    for (var _a = 0, mkeys_1 = mkeys; _a < mkeys_1.length; _a++) {
        var k = mkeys_1[_a];
        merged.push({ name: k, value: currentP[k] });
    }
    return merged;
}
exports.mergeInvokeUrlParameters = mergeInvokeUrlParameters;
function fixChildItems(childItems, state, commandInvoker) {
    return childItems
        .map(function (tb) { return mapToolbarReference(tb, state, commandInvoker); })
        .filter(function (tb) { return tb != null; });
}
//TODO: This function should be its own react hook that layers on top of the
//useDispatch() and useSelector() hooks provided by react-redux
/**
 * @hidden
 */
function mapToolbarReference(tb, state, commandInvoker) {
    if (tb.error) {
        var cmdItem = {
            iconClass: assets_1.SPRITE_ICON_ERROR,
            tooltip: tb.error,
            label: (0, i18n_1.tr)("ERROR"),
            selected: common_1.ALWAYS_FALSE,
            enabled: common_1.ALWAYS_FALSE,
            invoke: common_1.NOOP
        };
        return cmdItem;
    }
    else if (tb.componentName) {
        return {
            icon: tb.icon,
            iconClass: fusionFixSpriteClass(tb),
            flyoutId: tb.flyoutId,
            tooltip: tb.tooltip,
            label: tb.label,
            componentName: tb.componentName,
            componentProps: tb.componentProps
        };
    }
    else if (tb.isSeparator === true) {
        return { isSeparator: true };
    }
    else if (tb.command) {
        var cmd_1 = getCommand(tb.command);
        if (cmd_1 != null) {
            var cmdItem = {
                icon: fixIconPath(tb.icon || cmd_1.icon),
                iconClass: fusionFixSpriteClass(tb, cmd_1),
                tooltip: tb.tooltip,
                label: tb.label,
                selected: function () { return cmd_1.selected(state); },
                enabled: function () { return cmd_1.enabled(state, tb.parameters); },
                invoke: function () { return commandInvoker(cmd_1, tb.parameters); }
            };
            return cmdItem;
        }
    }
    else if (tb.children) {
        var childItems = tb.children;
        return {
            icon: fixIconPath(tb.icon),
            iconClass: fusionFixSpriteClass(tb),
            label: tb.label,
            tooltip: tb.tooltip,
            childItems: fixChildItems(childItems, state, commandInvoker)
        };
    }
    else if (tb.label && tb.flyoutId) {
        return {
            icon: fixIconPath(tb.icon),
            iconClass: fusionFixSpriteClass(tb),
            label: tb.label,
            tooltip: tb.tooltip,
            flyoutId: tb.flyoutId
        };
    }
    return null;
}
exports.mapToolbarReference = mapToolbarReference;
/**
 * Helper function to reduce full application state to state relevant for toolbar items
 *
 * @param state The full application state
 * @since 0.13
 */
function reduceAppToToolbarState(state) {
    var _a;
    var hasSelection = false;
    var hasClientSelection = false;
    var hasPreviousView = false;
    var hasNextView = false;
    var visibleWmsLayerCount = 0;
    var selection = (0, common_1.getSelectionSet)(state);
    hasSelection = (selection != null && selection.SelectedFeatures != null);
    if (state.config.activeMapName) {
        hasClientSelection = state.mapState[state.config.activeMapName].clientSelection != null;
        hasPreviousView = state.mapState[state.config.activeMapName].historyIndex > 0;
        hasNextView = state.mapState[state.config.activeMapName].historyIndex < state.mapState[state.config.activeMapName].history.length - 1;
        visibleWmsLayerCount = ((_a = state.mapState[state.config.activeMapName].layers) !== null && _a !== void 0 ? _a : []).filter(function (l) { return l.visible && l.selectable && l.type == "WMS"; }).length;
    }
    return {
        stateless: state.config.viewer.isStateless,
        visibleAndSelectableWmsLayerCount: visibleWmsLayerCount,
        busyWorkerCount: state.viewer.busyCount,
        hasSelection: hasSelection,
        hasClientSelection: hasClientSelection,
        hasPreviousView: hasPreviousView,
        hasNextView: hasNextView,
        activeTool: state.viewer.tool,
        featureTooltipsEnabled: state.viewer.featureTooltipsEnabled
    };
}
exports.reduceAppToToolbarState = reduceAppToToolbarState;
/**
 * Common command condition evaluators
 *
 * @export
 * @class CommandConditions
 */
var CommandConditions = /** @class */ (function () {
    function CommandConditions() {
    }
    /**
     * The viewer is not busy
     *
     * @static
     * @param {Readonly<IToolbarAppState>} state
     * @returns {boolean}
     *
     * @memberof CommandConditions
     */
    CommandConditions.isNotBusy = function (state) {
        return state.busyWorkerCount == 0;
    };
    /**
     * The viewer has a MapGuide selection set
     *
     * @static
     * @param {Readonly<IToolbarAppState>} state
     * @returns {boolean}
     *
     * @memberof CommandConditions
     */
    CommandConditions.hasSelection = function (state) {
        return state.hasSelection;
    };
    /**
     * The viewer has a client-side selection set
     *
     * @static
     * @param state
     * @returns
     *
     * @since 0.14
     */
    CommandConditions.hasClientSelection = function (state) {
        return state.hasClientSelection;
    };
    /**
     * The command is set to be disabled if selection is empty
     *
     * @static
     * @param {*} [parameters]
     * @returns {boolean}
     *
     * @memberof CommandConditions
     */
    CommandConditions.disabledIfEmptySelection = function (state, parameters) {
        if (!state.hasSelection) {
            return (parameters != null && (parameters.DisableIfSelectionEmpty == "true" || parameters.DisableIfSelectionEmpty == true));
        }
        else
            return false;
    };
    /**
     * The viewer has a previous view in the view navigation stack
     *
     * @static
     * @param {Readonly<IToolbarAppState>} state
     * @returns {boolean}
     *
     * @memberof CommandConditions
     */
    CommandConditions.hasPreviousView = function (state) {
        return state.hasPreviousView;
    };
    /**
     * The viewer has a next view in the view navigation stack
     *
     * @static
     * @param {Readonly<IToolbarAppState>} state
     * @returns {boolean}
     *
     * @memberof CommandConditions
     */
    CommandConditions.hasNextView = function (state) {
        return state.hasNextView;
    };
    return CommandConditions;
}());
exports.CommandConditions = CommandConditions;
/**
 * The set of default command names
 *
 * @export
 * @class DefaultCommands
 */
var DefaultCommands;
(function (DefaultCommands) {
    DefaultCommands["Select"] = "Select";
    DefaultCommands["Pan"] = "Pan";
    DefaultCommands["Zoom"] = "Zoom";
    DefaultCommands["MapTip"] = "MapTip";
    DefaultCommands["ZoomIn"] = "ZoomIn";
    DefaultCommands["ZoomOut"] = "ZoomOut";
    DefaultCommands["RestoreView"] = "RestoreView";
    DefaultCommands["ZoomExtents"] = "ZoomExtents";
    DefaultCommands["SelectRadius"] = "SelectRadius";
    DefaultCommands["SelectPolygon"] = "SelectPolygon";
    DefaultCommands["ClearSelection"] = "ClearSelection";
    DefaultCommands["ZoomToSelection"] = "ZoomToSelection";
    DefaultCommands["PanLeft"] = "PanLeft";
    DefaultCommands["PanRight"] = "PanRight";
    DefaultCommands["PanUp"] = "PanUp";
    DefaultCommands["PanDown"] = "PanDown";
    DefaultCommands["RefreshMap"] = "RefreshMap";
    DefaultCommands["PreviousView"] = "PreviousView";
    DefaultCommands["NextView"] = "NextView";
    DefaultCommands["About"] = "About";
    DefaultCommands["Help"] = "Help";
    DefaultCommands["Measure"] = "Measure";
    DefaultCommands["ViewerOptions"] = "ViewerOptions";
    DefaultCommands["Buffer"] = "Buffer";
    DefaultCommands["SelectWithin"] = "SelectWithin";
    DefaultCommands["QuickPlot"] = "QuickPlot";
    DefaultCommands["Redline"] = "Redline";
    DefaultCommands["FeatureInfo"] = "FeatureInfo";
    DefaultCommands["Theme"] = "Theme";
    DefaultCommands["Query"] = "Query";
    DefaultCommands["Geolocation"] = "Geolocation";
    DefaultCommands["CoordinateTracker"] = "CoordinateTracker";
    /**
     * @since 0.11
     */
    DefaultCommands["AddManageLayers"] = "AddManageLayers";
    /**
     * @since 0.11
     */
    DefaultCommands["CenterSelection"] = "CenterSelection";
    /**
     * @since 0.14
     */
    DefaultCommands["Print"] = "Print";
})(DefaultCommands = exports.DefaultCommands || (exports.DefaultCommands = {}));
var commands = {};
function isInvokeUrlCommand(cmdDef) {
    return typeof cmdDef.url !== 'undefined';
}
function isSearchCommand(cmdDef) {
    return typeof cmdDef.layer !== 'undefined';
}
function openModalUrl(name, dispatch, url, modalTitle) {
    dispatch((0, modal_1.showModalUrl)({
        modal: {
            title: modalTitle || (0, i18n_1.tr)(name),
            backdrop: false,
            overflowYScroll: true
        },
        name: name,
        url: url
    }));
}
function isSupportedCommandInStatelessMode(name) {
    switch (name) {
        case DefaultCommands.MapTip:
        case DefaultCommands.QuickPlot:
        case DefaultCommands.SelectRadius:
        case DefaultCommands.SelectPolygon:
        case DefaultCommands.Buffer:
        case DefaultCommands.SelectWithin:
        case DefaultCommands.Redline:
        case DefaultCommands.FeatureInfo:
        case DefaultCommands.Query:
        case DefaultCommands.Theme:
        case DefaultCommands.CenterSelection:
            return false;
    }
    return true;
}
exports.isSupportedCommandInStatelessMode = isSupportedCommandInStatelessMode;
/**
 * Opens the given URL in the specified target
 *
 * @hidden
 * @param name
 * @param cmdDef
 * @param dispatch
 * @param url
 */
function openUrlInTarget(name, cmdDef, hasTaskPane, dispatch, url, modalTitle) {
    var target = cmdDef.target;
    if (target == "TaskPane") {
        //If there's no actual task pane, fallback to modal dialog
        if (!hasTaskPane) {
            openModalUrl(name, dispatch, url, modalTitle);
        }
        else {
            dispatch({
                type: actions_1.ActionType.TASK_INVOKE_URL,
                payload: {
                    url: url
                }
            });
        }
    }
    else if (target == "NewWindow") {
        openModalUrl(name, dispatch, url, modalTitle);
    }
    else if (target == "SpecifiedFrame") {
        if (cmdDef.targetFrame) {
            var frames_1 = window.frames;
            var bInvoked = false;
            for (var i = 0; i < frames_1.length; i++) {
                if (frames_1[i].name == cmdDef.targetFrame) {
                    frames_1[i].location = url;
                    bInvoked = true;
                    break;
                }
            }
            if (!bInvoked) {
                (0, logger_1.error)("Frame not found: ".concat(cmdDef.targetFrame));
            }
        }
        else {
            (0, logger_1.error)("Command ".concat(name, " has a target of \"SpecifiedFrame\", but does not specify a target frame"));
        }
    }
    else {
        (0, never_1.assertNever)(target);
    }
}
exports.openUrlInTarget = openUrlInTarget;
/**
 * Registers a viewer command
 *
 * @export
 * @param {string} name
 * @param {(ICommand | IInvokeUrlCommand | ISearchCommand)} cmdDef
 */
function registerCommand(name, cmdDef) {
    var cmd;
    if (isInvokeUrlCommand(cmdDef)) {
        cmd = {
            icon: cmdDef.icon,
            iconClass: cmdDef.iconClass,
            title: cmdDef.title,
            enabled: function (state) {
                if (cmdDef.disableIfSelectionEmpty === true) {
                    return CommandConditions.hasSelection(state);
                }
                return true;
            },
            selected: function () { return false; },
            invoke: function (dispatch, getState, viewer, parameters) {
                var state = getState();
                var config = state.config;
                var map = (0, common_1.getRuntimeMap)(state);
                var params = mergeInvokeUrlParameters(cmdDef.parameters, parameters);
                var url = (0, url_1.ensureParameters)(cmdDef.url, map === null || map === void 0 ? void 0 : map.Name, map === null || map === void 0 ? void 0 : map.SessionId, config.locale, true, params);
                openUrlInTarget(name, cmdDef, config.capabilities.hasTaskPane, dispatch, url, cmd.title);
            }
        };
    }
    else if (isSearchCommand(cmdDef)) {
        cmd = {
            icon: cmdDef.icon,
            iconClass: cmdDef.iconClass,
            title: cmdDef.title,
            enabled: function (state) { return !state.stateless; },
            selected: function () { return false; },
            invoke: function (dispatch, getState, viewer, parameters) {
                var state = getState();
                var config = state.config;
                var map = (0, common_1.getRuntimeMap)(state);
                if (map) {
                    var url = (0, url_1.ensureParameters)("".concat((0, runtime_1.getFusionRoot)(), "/widgets/Search/SearchPrompt.php"), map.Name, map.SessionId, config.locale, false)
                        + "&popup=0"
                        + "&target=TaskPane"
                        + "&title=".concat(encodeURIComponent(cmdDef.title))
                        + "&prompt=".concat(encodeURIComponent(cmdDef.prompt))
                        + "&layer=".concat(encodeURIComponent(cmdDef.layer))
                        + "&pointZoomLevel=".concat(parameters.PointZoomLevel)
                        + (cmdDef.filter ? "&filter=".concat(encodeURIComponent(cmdDef.filter)) : '')
                        + "&limit=".concat(cmdDef.matchLimit)
                        + "&properties=".concat((cmdDef.resultColumns.Column || []).map(function (col) { return col.Property; }).join(","))
                        + "&propNames=".concat((cmdDef.resultColumns.Column || []).map(function (col) { return col.Name; }).join(","));
                    openUrlInTarget(name, cmdDef, config.capabilities.hasTaskPane, dispatch, url, cmd.title);
                }
            }
        };
    }
    else {
        cmd = cmdDef;
    }
    commands[name] = cmd;
}
exports.registerCommand = registerCommand;
/**
 * Gets a registered viewer command by its name
 *
 * @export
 * @param {string} name
 * @returns {(ICommand | undefined)}
 */
function getCommand(name) {
    return commands[name];
}
exports.getCommand = getCommand;
//# sourceMappingURL=command.js.map