function _array_like_to_array(arr, len) {
    if (len == null || len > arr.length) len = arr.length;
    for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
    return arr2;
}
function _array_with_holes(arr) {
    if (Array.isArray(arr)) return arr;
}
function _assert_this_initialized(self) {
    if (self === void 0) {
        throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
    }
    return self;
}
function _call_super(_this, derived, args) {
    derived = _get_prototype_of(derived);
    return _possible_constructor_return(_this, _is_native_reflect_construct() ? Reflect.construct(derived, args || [], _get_prototype_of(_this).constructor) : derived.apply(_this, args));
}
function _class_call_check(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
    }
}
function _defineProperties(target, props) {
    for(var i = 0; i < props.length; i++){
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor) descriptor.writable = true;
        Object.defineProperty(target, descriptor.key, descriptor);
    }
}
function _create_class(Constructor, protoProps, staticProps) {
    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
    if (staticProps) _defineProperties(Constructor, staticProps);
    return Constructor;
}
function _define_property(obj, key, value) {
    if (key in obj) {
        Object.defineProperty(obj, key, {
            value: value,
            enumerable: true,
            configurable: true,
            writable: true
        });
    } else {
        obj[key] = value;
    }
    return obj;
}
function _get_prototype_of(o) {
    _get_prototype_of = Object.setPrototypeOf ? Object.getPrototypeOf : function getPrototypeOf(o) {
        return o.__proto__ || Object.getPrototypeOf(o);
    };
    return _get_prototype_of(o);
}
function _inherits(subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
        throw new TypeError("Super expression must either be null or a function");
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
            value: subClass,
            writable: true,
            configurable: true
        }
    });
    if (superClass) _set_prototype_of(subClass, superClass);
}
function _instanceof(left, right) {
    "@swc/helpers - instanceof";
    if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
        return !!right[Symbol.hasInstance](left);
    } else {
        return left instanceof right;
    }
}
function _iterable_to_array_limit(arr, i) {
    var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
    if (_i == null) return;
    var _arr = [];
    var _n = true;
    var _d = false;
    var _s, _e;
    try {
        for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
            _arr.push(_s.value);
            if (i && _arr.length === i) break;
        }
    } catch (err) {
        _d = true;
        _e = err;
    } finally{
        try {
            if (!_n && _i["return"] != null) _i["return"]();
        } finally{
            if (_d) throw _e;
        }
    }
    return _arr;
}
function _non_iterable_rest() {
    throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _possible_constructor_return(self, call) {
    if (call && (_type_of(call) === "object" || typeof call === "function")) {
        return call;
    }
    return _assert_this_initialized(self);
}
function _set_prototype_of(o, p) {
    _set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) {
        o.__proto__ = p;
        return o;
    };
    return _set_prototype_of(o, p);
}
function _sliced_to_array(arr, i) {
    return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
}
function _type_of(obj) {
    "@swc/helpers - typeof";
    return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
}
function _unsupported_iterable_to_array(o, minLen) {
    if (!o) return;
    if (typeof o === "string") return _array_like_to_array(o, minLen);
    var n = Object.prototype.toString.call(o).slice(8, -1);
    if (n === "Object" && o.constructor) n = o.constructor.name;
    if (n === "Map" || n === "Set") return Array.from(n);
    if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
}
function _is_native_reflect_construct() {
    try {
        var result = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}));
    } catch (_) {}
    return (_is_native_reflect_construct = function() {
        return !!result;
    })();
}
import { groups, max, min, quantile } from "d3-array";
import { select } from "d3-selection";
import { merge } from "@d3plus/data";
import { assign, elem } from "@d3plus/dom";
import { accessor, BaseClass, configPrep, constant } from "../utils/index.js";
import Circle from "./Circle.js";
import Rect from "./Rect.js";
import Whisker from "./Whisker.js";
var shapes = {
    Circle: Circle,
    Rect: Rect
};
var Box = /*#__PURE__*/ function(BaseClass) {
    "use strict";
    _inherits(Box, BaseClass);
    function Box() {
        _class_call_check(this, Box);
        var _this;
        _this = _call_super(this, Box), _define_property(_this, "_medianConfig", void 0), _define_property(_this, "_orient", void 0), _define_property(_this, "_outlier", void 0), _define_property(_this, "_outlierConfig", void 0), _define_property(_this, "_rectConfig", void 0), _define_property(_this, "_rectWidth", void 0), _define_property(_this, "_whiskerConfig", void 0), _define_property(_this, "_whiskerMode", void 0), _define_property(_this, "_x", void 0), _define_property(_this, "_y", void 0), _define_property(_this, "_data", void 0), _define_property(_this, "_select", void 0), _define_property(_this, "_box", void 0), _define_property(_this, "_median", void 0), _define_property(_this, "_whisker", void 0), _define_property(_this, "_whiskerEndpoint", void 0), _define_property(_this, "_duration", void 0);
        _this._medianConfig = {
            fill: constant("black")
        };
        _this._orient = accessor("orient", "vertical");
        _this._outlier = accessor("outlier", "Circle");
        _this._outlierConfig = {
            Circle: {
                r: accessor("r", 5)
            },
            Rect: {
                height: function height(d, i) {
                    return _this._orient(d, i) === "vertical" ? 5 : 20;
                },
                width: function width(d, i) {
                    return _this._orient(d, i) === "vertical" ? 20 : 5;
                }
            }
        };
        _this._rectConfig = {
            fill: constant("white"),
            stroke: constant("black"),
            strokeWidth: constant(1)
        };
        _this._rectWidth = constant(50);
        _this._whiskerConfig = {};
        _this._whiskerMode = [
            "tukey",
            "tukey"
        ];
        _this._x = accessor("x", 250);
        _this._y = accessor("y", 250);
        _this._whiskerEndpoint = [];
        return _this;
    }
    _create_class(Box, [
        {
            /**
      Draws the Box.
*/ key: "render",
            value: function render() {
                var _this = this;
                if (this._select === void 0) {
                    this.select(select("body").append("svg").style("width", "".concat(window.innerWidth, "px")).style("height", "".concat(window.innerHeight, "px")).style("display", "block").node());
                }
                var outlierData = [];
                var filteredData = groups(this._data, function(d, i) {
                    return _this._orient(d, i) === "vertical" ? _this._x(d, i) : _this._y(d, i);
                }).map(function(param) {
                    var _param = _sliced_to_array(param, 2), key = _param[0], groupData = _param[1];
                    var d = {
                        key: key,
                        values: groupData
                    };
                    d.data = merge(d.values);
                    d.i = _this._data.indexOf(d.values[0]);
                    d.orient = _this._orient(d.data, d.i);
                    var values = d.values.map(d.orient === "vertical" ? _this._y : _this._x);
                    values.sort(function(a, b) {
                        return a - b;
                    });
                    d.first = quantile(values, 0.25);
                    d.median = quantile(values, 0.5);
                    d.third = quantile(values, 0.75);
                    var mode = _this._whiskerMode;
                    if (mode[0] === "tukey") {
                        d.lowerLimit = d.first - (d.third - d.first) * 1.5;
                        if (d.lowerLimit < min(values)) d.lowerLimit = min(values);
                    } else if (mode[0] === "extent") d.lowerLimit = min(values);
                    else if (typeof mode[0] === "number") d.lowerLimit = quantile(values, mode[0]);
                    if (mode[1] === "tukey") {
                        d.upperLimit = d.third + (d.third - d.first) * 1.5;
                        if (d.upperLimit > max(values)) d.upperLimit = max(values);
                    } else if (mode[1] === "extent") d.upperLimit = max(values);
                    else if (typeof mode[1] === "number") d.upperLimit = quantile(values, mode[1]);
                    var rectLength = d.third - d.first;
                    // Compute values for vertical orientation.
                    if (d.orient === "vertical") {
                        d.height = rectLength;
                        d.width = _this._rectWidth(d.data, d.i);
                        d.x = _this._x(d.data, d.i);
                        d.y = d.first + rectLength / 2;
                    } else if (d.orient === "horizontal") {
                        // Compute values for horizontal orientation.
                        d.height = _this._rectWidth(d.data, d.i);
                        d.width = rectLength;
                        d.x = d.first + rectLength / 2;
                        d.y = _this._y(d.data, d.i);
                    }
                    // Compute data for outliers.
                    d.values.forEach(function(eachValue, index) {
                        var value = d.orient === "vertical" ? _this._y(eachValue, index) : _this._x(eachValue, index);
                        if (value < d.lowerLimit || value > d.upperLimit) {
                            var dataObj = {};
                            dataObj.__d3plus__ = true;
                            dataObj.data = eachValue;
                            dataObj.i = index;
                            dataObj.outlier = _this._outlier(eachValue, index);
                            if (d.orient === "vertical") {
                                dataObj.x = d.x;
                                dataObj.y = value;
                                outlierData.push(dataObj);
                            } else if (d.orient === "horizontal") {
                                dataObj.y = d.y;
                                dataObj.x = value;
                                outlierData.push(dataObj);
                            }
                        }
                    });
                    d.__d3plus__ = true;
                    return d;
                });
                // Draw box.
                this._box = new Rect().data(filteredData).x(function(d) {
                    return d.x;
                }).y(function(d) {
                    return d.y;
                }).select(elem("g.d3plus-Box", {
                    parent: this._select
                }).node())// eslint-disable-next-line @typescript-eslint/no-explicit-any
                .config(configPrep.bind(this)(this._rectConfig, "shape")).render();
                // Draw median.
                this._median = new Rect().data(filteredData).x(function(d) {
                    return d.orient === "vertical" ? d.x : d.median;
                }).y(function(d) {
                    return d.orient === "vertical" ? d.median : d.y;
                }).height(function(d) {
                    return d.orient === "vertical" ? 1 : d.height;
                }).width(function(d) {
                    return d.orient === "vertical" ? d.width : 1;
                }).select(elem("g.d3plus-Box-Median", {
                    parent: this._select
                }).node())// eslint-disable-next-line @typescript-eslint/no-explicit-any
                .config(configPrep.bind(this)(this._medianConfig, "shape")).render();
                // Draw 2 lines using Whisker class.
                // Construct coordinates for whisker startpoints and push it to the whiskerData.
                var whiskerData = [];
                filteredData.forEach(function(d, i) {
                    var x = d.x;
                    var y = d.y;
                    var topLength = d.first - d.lowerLimit;
                    var bottomLength = d.upperLimit - d.third;
                    if (d.orient === "vertical") {
                        var topY = y - d.height / 2;
                        var bottomY = y + d.height / 2;
                        whiskerData.push({
                            __d3plus__: true,
                            data: d,
                            i: i,
                            x: x,
                            y: topY,
                            length: topLength,
                            orient: "top"
                        }, {
                            __d3plus__: true,
                            data: d,
                            i: i,
                            x: x,
                            y: bottomY,
                            length: bottomLength,
                            orient: "bottom"
                        });
                    } else if (d.orient === "horizontal") {
                        var topX = x + d.width / 2;
                        var bottomX = x - d.width / 2;
                        whiskerData.push({
                            __d3plus__: true,
                            data: d,
                            i: i,
                            x: topX,
                            y: y,
                            length: bottomLength,
                            orient: "right"
                        }, {
                            __d3plus__: true,
                            data: d,
                            i: i,
                            x: bottomX,
                            y: y,
                            length: topLength,
                            orient: "left"
                        });
                    }
                });
                // Draw whiskers.
                this._whisker = new Whisker().data(whiskerData).select(elem("g.d3plus-Box-Whisker", {
                    parent: this._select
                }).node())// eslint-disable-next-line @typescript-eslint/no-explicit-any
                .config(configPrep.bind(this)(this._whiskerConfig, "shape")).render();
                // Draw outliers.
                this._whiskerEndpoint = [];
                groups(outlierData, function(d) {
                    return d.outlier;
                }).forEach(function(param) {
                    var _param = _sliced_to_array(param, 2), shapeName = _param[0], values = _param[1];
                    _this._whiskerEndpoint.push(new shapes[shapeName]().data(values).select(elem("g.d3plus-Box-Outlier-".concat(shapeName), {
                        parent: _this._select
                    }).node())// eslint-disable-next-line @typescript-eslint/no-explicit-any
                    .config(configPrep.bind(_this)(_this._outlierConfig, "shape", shapeName)).render());
                });
                return this;
            }
        },
        {
            /**
      The active highlight state for all sub-shapes in this Box.
*/ key: "active",
            value: function active(_) {
                if (this._box) this._box.active(_);
                if (this._median) this._median.active(_);
                if (this._whisker) this._whisker.active(_);
                if (this._whiskerEndpoint) this._whiskerEndpoint.forEach(function(endPoint) {
                    return endPoint.active(_);
                });
            }
        },
        {
            key: "data",
            value: function data(_) {
                return arguments.length ? (this._data = _, this) : this._data;
            }
        },
        {
            /**
      The hover highlight state for all sub-shapes in this Box.
*/ key: "hover",
            value: function hover(_) {
                if (this._box) this._box.hover(_);
                if (this._median) this._median.hover(_);
                if (this._whisker) this._whisker.hover(_);
                if (this._whiskerEndpoint) this._whiskerEndpoint.forEach(function(endPoint) {
                    return endPoint.hover(_);
                });
            }
        },
        {
            key: "medianConfig",
            value: function medianConfig(_) {
                return arguments.length ? (this._medianConfig = assign(this._medianConfig, _), this) : this._medianConfig;
            }
        },
        {
            key: "orient",
            value: function orient(_) {
                return arguments.length ? (this._orient = typeof _ === "function" ? _ : constant(_), this) : this._orient;
            }
        },
        {
            key: "outlier",
            value: function outlier(_) {
                return arguments.length ? (this._outlier = typeof _ === "function" ? _ : constant(_), this) : this._outlier;
            }
        },
        {
            key: "outlierConfig",
            value: function outlierConfig(_) {
                return arguments.length ? (this._outlierConfig = assign(this._outlierConfig, _), this) : this._outlierConfig;
            }
        },
        {
            key: "rectConfig",
            value: function rectConfig(_) {
                return arguments.length ? (this._rectConfig = assign(this._rectConfig, _), this) : this._rectConfig;
            }
        },
        {
            key: "rectWidth",
            value: function rectWidth(_) {
                return arguments.length ? (this._rectWidth = typeof _ === "function" ? _ : constant(_), this) : this._rectWidth;
            }
        },
        {
            key: "select",
            value: function select1(_) {
                return arguments.length ? (this._select = select(_), this) : this._select;
            }
        },
        {
            key: "whiskerConfig",
            value: function whiskerConfig(_) {
                return arguments.length ? (this._whiskerConfig = assign(this._whiskerConfig, _), this) : this._whiskerConfig;
            }
        },
        {
            key: "whiskerMode",
            value: function whiskerMode(_) {
                return arguments.length ? (this._whiskerMode = _instanceof(_, Array) ? _ : [
                    _,
                    _
                ], this) : this._whiskerMode;
            }
        },
        {
            key: "x",
            value: function x(_) {
                return arguments.length ? (this._x = typeof _ === "function" ? _ : accessor(_), this) : this._x;
            }
        },
        {
            key: "y",
            value: function y(_) {
                return arguments.length ? (this._y = typeof _ === "function" ? _ : accessor(_), this) : this._y;
            }
        }
    ]);
    return Box;
}(BaseClass);
/**
    Creates SVG box based on an array of data.
*/ export { Box as default };
