"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.getActiveAxes = exports.testIsOverAxes = exports.ChartModifierBase2D = void 0;
var ModifierType_1 = require("../../types/ModifierType");
var XyDirection_1 = require("../../types/XyDirection");
var pointUtil_1 = require("../../utils/pointUtil");
var ChartModifierBase_1 = require("./ChartModifierBase");
var constants_1 = require("./constants");
var IncludedItems_1 = require("../../Core/IncludedItems");
var IWithXYAxes_1 = require("../../Core/IWithXYAxes");
/**
 * Defines a base class to a ChartModifier2D - a class which provides Zoom, Pan, Tooltip or interaction behavior
 * to SciChart - High Performance Realtime {@link https://www.scichart.com/javascript-chart-features | 2D JavaScript Charts}
 */
var ChartModifierBase2D = /** @class */ (function (_super) {
    __extends(ChartModifierBase2D, _super);
    /**
     * Creates an instance of the {@link ChartModifierBase2D}
     * @param options optional parameters via {@link IChartModifierBaseOptions} which can be passed to configure the modifier
     */
    function ChartModifierBase2D(options) {
        var _this = this;
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
        _this = _super.call(this, options) || this;
        /**
         * Direction to which the modifier can be applied
         */
        _this.xyDirection = XyDirection_1.EXyDirection.XyDirection;
        /**
         * The helper property to get and set the list of included renderable series
         */
        _this.includedSeries = new IncludedItems_1.IncludedItems();
        /**
         * The helper property to get and set the list of included X axes
         */
        _this.includedXAxes = new IncludedItems_1.IncludedItems();
        /**
         * The helper property to get and set the list of included Y axes
         */
        _this.includedYAxes = new IncludedItems_1.IncludedItems();
        _this.changedPropertiesList = [];
        // used to track if registered types were used for function properties, so they can be serialized
        _this.typeMap = new Map();
        _this.xyDirection = (_a = options === null || options === void 0 ? void 0 : options.xyDirection) !== null && _a !== void 0 ? _a : _this.xyDirection;
        _this.modifierGroup = (_b = options === null || options === void 0 ? void 0 : options.modifierGroup) !== null && _b !== void 0 ? _b : _this.modifierGroup;
        _this.xAxisIdProperty = (_c = options === null || options === void 0 ? void 0 : options.xAxisId) !== null && _c !== void 0 ? _c : _this.xAxisIdProperty;
        _this.yAxisIdProperty = (_d = options === null || options === void 0 ? void 0 : options.yAxisId) !== null && _d !== void 0 ? _d : _this.yAxisIdProperty;
        if (((_e = options === null || options === void 0 ? void 0 : options.includedSeriesIds) === null || _e === void 0 ? void 0 : _e.length) > 0 && ((_f = options === null || options === void 0 ? void 0 : options.excludedSeriesIds) === null || _f === void 0 ? void 0 : _f.length) > 0) {
            throw new Error("You should either use `includedSeriesIds` or `excludedSeriesIds`, not both.");
        }
        if (((_g = options === null || options === void 0 ? void 0 : options.includedXAxisIds) === null || _g === void 0 ? void 0 : _g.length) > 0 && ((_h = options === null || options === void 0 ? void 0 : options.excludedXAxisIds) === null || _h === void 0 ? void 0 : _h.length) > 0) {
            throw new Error("You should either use `includedXAxisIds` or `excludedXAxisIds`, not both.");
        }
        if (((_j = options === null || options === void 0 ? void 0 : options.includedYAxisIds) === null || _j === void 0 ? void 0 : _j.length) > 0 && ((_k = options === null || options === void 0 ? void 0 : options.excludedYAxisIds) === null || _k === void 0 ? void 0 : _k.length) > 0) {
            throw new Error("You should either use `includedYAxisIds` or `excludedYAxisIds`, not both.");
        }
        if (((_l = options === null || options === void 0 ? void 0 : options.includedSeriesIds) === null || _l === void 0 ? void 0 : _l.length) > 0)
            _this.includedSeries.includeList(options.includedSeriesIds);
        if (((_m = options === null || options === void 0 ? void 0 : options.excludedSeriesIds) === null || _m === void 0 ? void 0 : _m.length) > 0)
            _this.includedSeries.excludeList(options.excludedSeriesIds);
        if (((_o = options === null || options === void 0 ? void 0 : options.includedXAxisIds) === null || _o === void 0 ? void 0 : _o.length) > 0)
            _this.includedXAxes.includeList(options.includedXAxisIds);
        if (((_p = options === null || options === void 0 ? void 0 : options.excludedXAxisIds) === null || _p === void 0 ? void 0 : _p.length) > 0)
            _this.includedXAxes.excludeList(options.excludedXAxisIds);
        if (((_q = options === null || options === void 0 ? void 0 : options.includedYAxisIds) === null || _q === void 0 ? void 0 : _q.length) > 0)
            _this.includedYAxes.includeList(options.includedYAxisIds);
        if (((_r = options === null || options === void 0 ? void 0 : options.excludedYAxisIds) === null || _r === void 0 ? void 0 : _r.length) > 0)
            _this.includedYAxes.excludeList(options.excludedYAxisIds);
        return _this;
    }
    Object.defineProperty(ChartModifierBase2D.prototype, "modifierType", {
        /** @inheritDoc */
        get: function () {
            return ModifierType_1.EModifierType.Chart2DModifier;
        },
        enumerable: false,
        configurable: true
    });
    /** @inheritDoc */
    ChartModifierBase2D.prototype.onAttach = function () {
        _super.prototype.onAttach.call(this);
        this.linkAxes();
    };
    Object.defineProperty(ChartModifierBase2D.prototype, "xAxisId", {
        /** @inheritDoc */
        get: function () {
            return this.xAxisIdProperty;
        },
        /** @inheritDoc */
        set: function (xAxisId) {
            if (xAxisId !== this.xAxisIdProperty) {
                this.xAxisIdProperty = xAxisId;
                this.xAxisProperty = undefined;
                this.notifyPropertyChanged(constants_1.PROPERTY.X_AXIS_ID);
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(ChartModifierBase2D.prototype, "yAxisId", {
        /** @inheritDoc */
        get: function () {
            return this.yAxisIdProperty;
        },
        /** @inheritDoc */
        set: function (yAxisId) {
            if (yAxisId !== this.yAxisIdProperty) {
                this.yAxisIdProperty = yAxisId;
                this.yAxisProperty = undefined;
                this.notifyPropertyChanged(constants_1.PROPERTY.Y_AXIS_ID);
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(ChartModifierBase2D.prototype, "xAxis", {
        /** @inheritDoc */
        get: function () {
            return this.xAxisProperty;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(ChartModifierBase2D.prototype, "yAxis", {
        /** @inheritDoc */
        get: function () {
            return this.yAxisProperty;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * Gets all series on the parent surface.
     * @protected
     * @remarks This function allows mocking in tests
     */
    ChartModifierBase2D.prototype.getAllSeries = function () {
        return this.parentSurface.renderableSeries.asArray();
    };
    /**
     * Returns the list of included X axes
     */
    ChartModifierBase2D.prototype.getIncludedXAxis = function () {
        return this.includedXAxes.getIncludedItems(this.parentSurface.xAxes.asArray());
    };
    /**
     * Returns the list of included Y axes
     */
    ChartModifierBase2D.prototype.getIncludedYAxis = function () {
        return this.includedYAxes.getIncludedItems(this.parentSurface.yAxes.asArray());
    };
    /**
     * Includes or excludes X axis
     */
    ChartModifierBase2D.prototype.includeXAxis = function (axis, isIncluded) {
        if (isIncluded) {
            this.includedXAxes.include(axis.id);
        }
        else {
            this.includedXAxes.exclude(axis.id);
        }
    };
    /**
     * Includes or excludes Y axis
     */
    ChartModifierBase2D.prototype.includeYAxis = function (axis, isIncluded) {
        if (isIncluded) {
            this.includedYAxes.include(axis.id);
        }
        else {
            this.includedYAxes.exclude(axis.id);
        }
    };
    /**
     * Includes all X and Y axes
     */
    ChartModifierBase2D.prototype.includeAllAxes = function () {
        this.includedXAxes.includeAll();
        this.includedYAxes.includeAll();
    };
    /**
     * Tests if the series is included or excluded, by default it must also be visible to be included.
     * To ignore the visibility check, override this with
     * ```return this.includedSeries.testIsIncluded(series.id);```
     * @param series
     * @private
     */
    ChartModifierBase2D.prototype.testIsIncludedSeries = function (series) {
        return series.isVisible && this.includedSeries.testIsIncluded(series.id);
    };
    /**
     * Includes renderable series. Returns True if the included items list has changed after the operation.
     */
    ChartModifierBase2D.prototype.includeSeries = function (series, isIncluded) {
        if (isIncluded) {
            var changed = this.includedSeries.include(series.id);
            if (changed && this.isAttached) {
                this.onAttachSeries(series);
            }
            return changed;
        }
        else {
            var changed = this.includedSeries.exclude(series.id);
            if (changed && this.isAttached) {
                this.onDetachSeries(series);
            }
            return changed;
        }
    };
    /**
     * Returns all visible and included renderable series. The list also contains included visible stacked renderable series
     * This calls this.testIsIncludedSeries so it is best to customise the including check behaviour there.
     */
    ChartModifierBase2D.prototype.getIncludedRenderableSeries = function () {
        var _this = this;
        var regularSeries = this.getAllSeries().filter(function (rs) { return !rs.isCollection && _this.testIsIncludedSeries(rs); });
        var stackedSeries = this.getAllSeries().filter(function (el) { return el.isCollection; });
        var allSeries = regularSeries;
        stackedSeries.forEach(function (col) {
            col.getVisibleSeries().forEach(function (childRs) {
                if (_this.testIsIncludedSeries(childRs)) {
                    allSeries.push(childRs);
                }
            });
        });
        return allSeries;
    };
    /** @inheritDoc */
    ChartModifierBase2D.prototype.toJSON = function () {
        var options = {
            id: this.id,
            modifierGroup: this.modifierGroup,
            executeCondition: this.executeCondition,
            secondaryExecuteCondition: this.secondaryExecuteCondition,
            xyDirection: this.xyDirection,
            xAxisId: this.xAxisId,
            yAxisId: this.yAxisId,
            includedXAxisIds: this.includedXAxes.getIncludedItemIds(),
            excludedXAxisIds: this.includedXAxes.getExcludedItemIds(),
            includedYAxisIds: this.includedYAxes.getIncludedItemIds(),
            excludedYAxisIds: this.includedYAxes.getExcludedItemIds(),
            includedSeriesIds: this.includedSeries.getIncludedItemIds(),
            excludedSeriesIds: this.includedSeries.getExcludedItemIds()
        };
        return { type: this.type, options: options };
    };
    /** @inheritDoc */
    ChartModifierBase2D.prototype.linkAxes = function () {
        (0, IWithXYAxes_1.updateAxisIds)(this);
        if (!this.parentSurface)
            return;
        if (!this.xAxisProperty && this.xAxisId) {
            var xAxis = this.parentSurface.getXAxisById(this.xAxisId);
            if (xAxis) {
                this.xAxisProperty = xAxis;
            }
            else {
                console.warn("ChartModifier looked for xAxis Id \"".concat(this.xAxisId, "\" but did not find. Default xAxis will be used"));
                this.xAxisProperty = this.parentSurface.getDefaultXAxis();
            }
        }
        if (!this.yAxisProperty && this.yAxisId) {
            var yAxis = this.parentSurface.getYAxisById(this.yAxisId);
            if (yAxis) {
                this.yAxisProperty = yAxis;
            }
            else {
                console.warn("ChartModifier looked for yAxis Id \"".concat(this.yAxisId, "\" but did not find. Default yAxis will be used"));
                this.yAxisProperty = this.parentSurface.getDefaultYAxis();
            }
        }
    };
    ChartModifierBase2D.prototype.testPropertyChanged = function (propertyName) {
        return this.changedPropertiesList.includes(propertyName);
    };
    ChartModifierBase2D.prototype.notifyPropertyChanged = function (propertyName) {
        if (!this.changedPropertiesList.includes(propertyName)) {
            this.changedPropertiesList.push(propertyName);
        }
        _super.prototype.notifyPropertyChanged.call(this, propertyName);
    };
    /**
     * Grows the Axis by a fraction around the mouse point
     * @param mousePoint the X,Y location of the mouse at the time of the operation
     * @param axis the Axis to grow or shrink
     * @param fraction the fraction, e.g. 0.1 grows the axis by 10%
     */
    ChartModifierBase2D.prototype.growBy = function (mousePoint, axis, fraction) {
        var isHorizontalAxis = axis.isHorizontalAxis, isAxisFlipped = axis.isAxisFlipped, viewRect = axis.viewRect, flippedCoordinates = axis.flippedCoordinates;
        var seriesViewRect = this.parentSurface.seriesViewRect;
        var size = isHorizontalAxis ? viewRect.width : viewRect.height;
        if (axis.isStackedAxis && this.parentSurface) {
            size = isHorizontalAxis ? seriesViewRect.width : seriesViewRect.height;
        }
        var coord = isHorizontalAxis ? mousePoint.x : mousePoint.y;
        // Compute relative fractions to expand or contract the axis VisibleRange by
        var lowFraction = (coord / size) * fraction;
        var highFraction = (1 - coord / size) * fraction;
        // We flip zoom for vertical chart or flippedCoordinates
        var flipZoom = (isAxisFlipped && !flippedCoordinates) || (!isAxisFlipped && flippedCoordinates);
        if (flipZoom) {
            axis.zoomBy(highFraction, lowFraction);
        }
        else {
            axis.zoomBy(lowFraction, highFraction);
        }
    };
    return ChartModifierBase2D;
}(ChartModifierBase_1.ChartModifierBase));
exports.ChartModifierBase2D = ChartModifierBase2D;
var testIsOverAxes = function (xAxisArr, mousePoint) {
    var result = false;
    xAxisArr.forEach(function (x) {
        if (x.viewRect) {
            var _a = x.viewRect, left = _a.left, right = _a.right, top_1 = _a.top, bottom = _a.bottom;
            if ((0, pointUtil_1.testIsInBounds)(mousePoint.x, mousePoint.y, left, bottom, right, top_1)) {
                result = true;
            }
        }
    });
    return result;
};
exports.testIsOverAxes = testIsOverAxes;
var getActiveAxes = function (xAxisArr, mousePoint) {
    var result = [];
    xAxisArr.forEach(function (x) {
        if (x.viewRect) {
            var _a = x.viewRect, left = _a.left, right = _a.right, top_2 = _a.top, bottom = _a.bottom;
            if ((0, pointUtil_1.testIsInBounds)(mousePoint.x, mousePoint.y, left, bottom, right, top_2)) {
                result.push(x);
            }
        }
    });
    return result;
};
exports.getActiveAxes = getActiveAxes;
