import { __extends } from "tslib";
import { max, min } from '@antv/util';
import Element from './element';
import { isFunction, isObject, each, removeFromArray, upperFirst, isAllowCapture } from '../util/util';
var SHAPE_MAP = {};
var INDEX = '_INDEX';
/**
 * 设置 canvas
 * @param {IElement} element 元素
 * @param {ICanvas}  canvas  画布
 */
function setCanvas(element, canvas) {
    element.set('canvas', canvas);
    if (element.isGroup()) {
        var children = element.get('children');
        if (children.length) {
            children.forEach(function (child) {
                setCanvas(child, canvas);
            });
        }
    }
}
/**
 * 设置 timeline
 * @param {IElement} element  元素
 * @param {Timeline} timeline 时间轴
 */
function setTimeline(element, timeline) {
    element.set('timeline', timeline);
    if (element.isGroup()) {
        var children = element.get('children');
        if (children.length) {
            children.forEach(function (child) {
                setTimeline(child, timeline);
            });
        }
    }
}
function contains(container, element) {
    var children = container.getChildren();
    return children.indexOf(element) >= 0;
}
function removeChild(container, element, destroy) {
    if (destroy === void 0) { destroy = true; }
    // 不再调用 element.remove() 方法，会出现循环调用
    if (destroy) {
        element.destroy();
    }
    else {
        element.set('parent', null);
        element.set('canvas', null);
    }
    removeFromArray(container.getChildren(), element);
}
function getComparer(compare) {
    return function (left, right) {
        var result = compare(left, right);
        return result === 0 ? left[INDEX] - right[INDEX] : result;
    };
}
var Container = /** @class */ (function (_super) {
    __extends(Container, _super);
    function Container() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    Container.prototype.isCanvas = function () {
        return false;
    };
    // 根据子节点确定 BBox
    Container.prototype.getBBox = function () {
        // 所有的值可能在画布的可视区外
        var minX = Infinity;
        var maxX = -Infinity;
        var minY = Infinity;
        var maxY = -Infinity;
        var xArr = [];
        var yArr = [];
        // 将可见元素、图形以及不为空的图形分组筛选出来，用于包围盒合并
        var children = this.getChildren().filter(function (child) {
            return child.get('visible') && (!child.isGroup() || (child.isGroup() && child.getChildren().length > 0));
        });
        if (children.length > 0) {
            each(children, function (child) {
                var box = child.getBBox();
                xArr.push(box.minX, box.maxX);
                yArr.push(box.minY, box.maxY);
            });
            minX = min(xArr);
            maxX = max(xArr);
            minY = min(yArr);
            maxY = max(yArr);
        }
        else {
            minX = 0;
            maxX = 0;
            minY = 0;
            maxY = 0;
        }
        var box = {
            x: minX,
            y: minY,
            minX: minX,
            minY: minY,
            maxX: maxX,
            maxY: maxY,
            width: maxX - minX,
            height: maxY - minY,
        };
        return box;
    };
    // 获取画布的包围盒
    Container.prototype.getCanvasBBox = function () {
        var minX = Infinity;
        var maxX = -Infinity;
        var minY = Infinity;
        var maxY = -Infinity;
        var xArr = [];
        var yArr = [];
        // 将可见元素、图形以及不为空的图形分组筛选出来，用于包围盒合并
        var children = this.getChildren().filter(function (child) {
            return child.get('visible') && (!child.isGroup() || (child.isGroup() && child.getChildren().length > 0));
        });
        if (children.length > 0) {
            each(children, function (child) {
                var box = child.getCanvasBBox();
                xArr.push(box.minX, box.maxX);
                yArr.push(box.minY, box.maxY);
            });
            minX = min(xArr);
            maxX = max(xArr);
            minY = min(yArr);
            maxY = max(yArr);
        }
        else {
            minX = 0;
            maxX = 0;
            minY = 0;
            maxY = 0;
        }
        var box = {
            x: minX,
            y: minY,
            minX: minX,
            minY: minY,
            maxX: maxX,
            maxY: maxY,
            width: maxX - minX,
            height: maxY - minY,
        };
        return box;
    };
    Container.prototype.getDefaultCfg = function () {
        var cfg = _super.prototype.getDefaultCfg.call(this);
        cfg['children'] = [];
        return cfg;
    };
    Container.prototype.onAttrChange = function (name, value, originValue) {
        _super.prototype.onAttrChange.call(this, name, value, originValue);
        if (name === 'matrix') {
            var totalMatrix = this.getTotalMatrix();
            this._applyChildrenMarix(totalMatrix);
        }
    };
    // 不但应用到自己身上还要应用于子元素
    Container.prototype.applyMatrix = function (matrix) {
        var preTotalMatrix = this.getTotalMatrix();
        _super.prototype.applyMatrix.call(this, matrix);
        var totalMatrix = this.getTotalMatrix();
        // totalMatrix 没有发生变化时，这里仅考虑两者都为 null 时
        // 不继续向下传递矩阵
        if (totalMatrix === preTotalMatrix) {
            return;
        }
        this._applyChildrenMarix(totalMatrix);
    };
    // 在子元素上设置矩阵
    Container.prototype._applyChildrenMarix = function (totalMatrix) {
        var children = this.getChildren();
        each(children, function (child) {
            child.applyMatrix(totalMatrix);
        });
    };
    // 兼容老版本的接口
    Container.prototype.addShape = function () {
        var args = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            args[_i] = arguments[_i];
        }
        var type = args[0];
        var cfg = args[1];
        if (isObject(type)) {
            cfg = type;
        }
        else {
            cfg['type'] = type;
        }
        var shapeType = SHAPE_MAP[cfg.type];
        if (!shapeType) {
            shapeType = upperFirst(cfg.type);
            SHAPE_MAP[cfg.type] = shapeType;
        }
        var ShapeBase = this.getShapeBase();
        var shape = new ShapeBase[shapeType](cfg);
        this.add(shape);
        return shape;
    };
    Container.prototype.addGroup = function () {
        var args = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            args[_i] = arguments[_i];
        }
        var groupClass = args[0], cfg = args[1];
        var group;
        if (isFunction(groupClass)) {
            if (cfg) {
                group = new groupClass(cfg);
            }
            else {
                group = new groupClass({
                    // canvas,
                    parent: this,
                });
            }
        }
        else {
            var tmpCfg = groupClass || {};
            var TmpGroupClass = this.getGroupBase();
            group = new TmpGroupClass(tmpCfg);
        }
        this.add(group);
        return group;
    };
    Container.prototype.getCanvas = function () {
        var canvas;
        if (this.isCanvas()) {
            canvas = this;
        }
        else {
            canvas = this.get('canvas');
        }
        return canvas;
    };
    Container.prototype.getShape = function (x, y, ev) {
        // 如果不支持拾取，则直接返回
        if (!isAllowCapture(this)) {
            return null;
        }
        var children = this.getChildren();
        var shape;
        // 如果容器是 group
        if (!this.isCanvas()) {
            var v = [x, y, 1];
            // 将 x, y 转换成对应于 group 的局部坐标
            v = this.invertFromMatrix(v);
            if (!this.isClipped(v[0], v[1])) {
                shape = this._findShape(children, v[0], v[1], ev);
            }
        }
        else {
            shape = this._findShape(children, x, y, ev);
        }
        return shape;
    };
    Container.prototype._findShape = function (children, x, y, ev) {
        var shape = null;
        for (var i = children.length - 1; i >= 0; i--) {
            var child = children[i];
            if (isAllowCapture(child)) {
                if (child.isGroup()) {
                    shape = child.getShape(x, y, ev);
                }
                else if (child.isHit(x, y)) {
                    shape = child;
                }
            }
            if (shape) {
                break;
            }
        }
        return shape;
    };
    Container.prototype.add = function (element) {
        var canvas = this.getCanvas();
        var children = this.getChildren();
        var timeline = this.get('timeline');
        var preParent = element.getParent();
        if (preParent) {
            removeChild(preParent, element, false);
        }
        element.set('parent', this);
        if (canvas) {
            setCanvas(element, canvas);
        }
        if (timeline) {
            setTimeline(element, timeline);
        }
        children.push(element);
        element.onCanvasChange('add');
        this._applyElementMatrix(element);
    };
    // 将当前容器的矩阵应用到子元素
    Container.prototype._applyElementMatrix = function (element) {
        var totalMatrix = this.getTotalMatrix();
        // 添加图形或者分组时，需要把当前图元的矩阵设置进去
        if (totalMatrix) {
            element.applyMatrix(totalMatrix);
        }
    };
    Container.prototype.getChildren = function () {
        return this.get('children');
    };
    Container.prototype.sort = function () {
        var children = this.getChildren();
        // 稳定排序
        each(children, function (child, index) {
            child[INDEX] = index;
            return child;
        });
        children.sort(getComparer(function (obj1, obj2) {
            return obj1.get('zIndex') - obj2.get('zIndex');
        }));
        this.onCanvasChange('sort');
    };
    Container.prototype.clear = function () {
        this.set('clearing', true);
        if (this.destroyed) {
            return;
        }
        var children = this.getChildren();
        for (var i = children.length - 1; i >= 0; i--) {
            children[i].destroy(); // 销毁子元素
        }
        this.set('children', []);
        this.onCanvasChange('clear');
        this.set('clearing', false);
    };
    Container.prototype.destroy = function () {
        if (this.get('destroyed')) {
            return;
        }
        this.clear();
        _super.prototype.destroy.call(this);
    };
    /**
     * 获取第一个子元素
     * @return {IElement} 第一个元素
     */
    Container.prototype.getFirst = function () {
        return this.getChildByIndex(0);
    };
    /**
     * 获取最后一个子元素
     * @return {IElement} 元素
     */
    Container.prototype.getLast = function () {
        var children = this.getChildren();
        return this.getChildByIndex(children.length - 1);
    };
    /**
     * 根据索引获取子元素
     * @return {IElement} 第一个元素
     */
    Container.prototype.getChildByIndex = function (index) {
        var children = this.getChildren();
        return children[index];
    };
    /**
     * 子元素的数量
     * @return {number} 子元素数量
     */
    Container.prototype.getCount = function () {
        var children = this.getChildren();
        return children.length;
    };
    /**
     * 是否包含对应元素
     * @param {IElement} element 元素
     * @return {boolean}
     */
    Container.prototype.contain = function (element) {
        var children = this.getChildren();
        return children.indexOf(element) > -1;
    };
    /**
     * 移除对应子元素
     * @param {IElement} element 子元素
     * @param {boolean} destroy 是否销毁子元素，默认为 true
     */
    Container.prototype.removeChild = function (element, destroy) {
        if (destroy === void 0) { destroy = true; }
        if (this.contain(element)) {
            element.remove(destroy);
        }
    };
    /**
     * 查找所有匹配的元素
     * @param  {ElementFilterFn}   fn  匹配函数
     * @return {IElement[]} 元素数组
     */
    Container.prototype.findAll = function (fn) {
        var rst = [];
        var children = this.getChildren();
        each(children, function (element) {
            if (fn(element)) {
                rst.push(element);
            }
            if (element.isGroup()) {
                rst = rst.concat(element.findAll(fn));
            }
        });
        return rst;
    };
    /**
     * 查找元素，找到第一个返回
     * @param  {ElementFilterFn} fn    匹配函数
     * @return {IElement|null} 元素，可以为空
     */
    Container.prototype.find = function (fn) {
        var rst = null;
        var children = this.getChildren();
        each(children, function (element) {
            if (fn(element)) {
                rst = element;
            }
            else if (element.isGroup()) {
                rst = element.find(fn);
            }
            if (rst) {
                return false;
            }
        });
        return rst;
    };
    /**
     * 根据 ID 查找元素
     * @param {string} id 元素 id
     * @return {IElement|null} 元素
     */
    Container.prototype.findById = function (id) {
        return this.find(function (element) {
            return element.get('id') === id;
        });
    };
    /**
     * 该方法即将废弃，不建议使用
     * 根据 className 查找元素
     * TODO: 该方式定义暂时只给 G6 3.3 以后的版本使用，待 G6 中的 findByClassName 方法移除后，G 也需要同步移除
     * @param {string} className 元素 className
     * @return {IElement | null} 元素
     */
    Container.prototype.findByClassName = function (className) {
        return this.find(function (element) {
            return element.get('className') === className;
        });
    };
    /**
     * 根据 name 查找元素列表
     * @param {string}      name 元素名称
     * @return {IElement[]} 元素
     */
    Container.prototype.findAllByName = function (name) {
        return this.findAll(function (element) {
            return element.get('name') === name;
        });
    };
    return Container;
}(Element));
export default Container;
//# sourceMappingURL=container.js.map