import * as tslib_1 from "tslib";
import { OrderedSet, AEventDispatcher } from '../internal';
import { isGroup } from '../model';
import { cssClass, engineCssClass } from '../styles';
import { forEachIndices } from '../model/internal';
import { rangeSelection } from '../provider/utils';
/** @internal */
var SelectionManager = /** @class */ (function (_super) {
    tslib_1.__extends(SelectionManager, _super);
    function SelectionManager(ctx, body) {
        var _this = _super.call(this) || this;
        _this.ctx = ctx;
        _this.body = body;
        _this.start = null;
        var root = body.parentElement.parentElement;
        var hr = root.querySelector('hr');
        if (!hr) {
            hr = root.ownerDocument.createElement('hr');
            root.appendChild(hr);
        }
        _this.hr = hr;
        _this.hr.classList.add(cssClass('hr'));
        var mouseMove = function (evt) {
            _this.showHint(evt);
        };
        var mouseUp = function (evt) {
            _this.body.removeEventListener('mousemove', mouseMove);
            _this.body.removeEventListener('mouseup', mouseUp);
            _this.body.removeEventListener('mouseleave', mouseUp);
            if (!_this.start) {
                return;
            }
            var row = engineCssClass('tr');
            var startNode = _this.start.node.classList.contains(row) ? _this.start.node : _this.start.node.closest("." + row);
            // somehow on firefox the mouseUp will be triggered on the original node
            // thus search the node explicitly
            var end = _this.body.ownerDocument.elementFromPoint(evt.clientX, evt.clientY);
            var endNode = end.classList.contains(row) ? end : (end.closest("." + row));
            _this.start = null;
            _this.body.classList.remove(cssClass('selection-active'));
            _this.hr.classList.remove(cssClass('selection-active'));
            _this.select(evt.ctrlKey, startNode, endNode);
        };
        body.addEventListener('mousedown', function (evt) {
            var r = root.getBoundingClientRect();
            _this.start = { x: evt.clientX, y: evt.clientY, xShift: r.left, yShift: r.top, node: evt.target };
            _this.body.classList.add(cssClass('selection-active'));
            body.addEventListener('mousemove', mouseMove, {
                passive: true
            });
            body.addEventListener('mouseup', mouseUp, {
                passive: true
            });
            body.addEventListener('mouseleave', mouseUp, {
                passive: true
            });
        }, {
            passive: true
        });
        return _this;
    }
    SelectionManager.prototype.createEventList = function () {
        return _super.prototype.createEventList.call(this).concat([SelectionManager.EVENT_SELECT_RANGE]);
    };
    SelectionManager.prototype.on = function (type, listener) {
        return _super.prototype.on.call(this, type, listener);
    };
    SelectionManager.prototype.select = function (additional, startNode, endNode) {
        var _this = this;
        if (!startNode || !endNode || startNode === endNode) {
            return; // no single
        }
        var startIndex = parseInt(startNode.dataset.index, 10);
        var endIndex = parseInt(endNode.dataset.index, 10);
        var from = Math.min(startIndex, endIndex);
        var end = Math.max(startIndex, endIndex);
        if (from === end) {
            return; // no single
        }
        // bounce event end
        requestAnimationFrame(function () { return _this.fire(SelectionManager.EVENT_SELECT_RANGE, from, end, additional); });
    };
    SelectionManager.prototype.showHint = function (end) {
        var start = this.start;
        var sy = start.y;
        var ey = end.clientY;
        var visible = Math.abs(sy - ey) > SelectionManager.MIN_DISTANCE;
        this.hr.classList.toggle(cssClass('selection-active'), visible);
        this.hr.style.transform = "translate(" + (start.x - start.xShift) + "px," + (sy - start.yShift) + "px)scale(1," + Math.abs(ey - sy) + ")rotate(" + (ey > sy ? 90 : -90) + "deg)";
    };
    SelectionManager.prototype.remove = function (node) {
        node.onclick = undefined;
    };
    SelectionManager.prototype.add = function (node) {
        var _this = this;
        node.onclick = function (evt) {
            var dataIndex = parseInt(node.dataset.i, 10);
            if (evt.shiftKey) {
                var relIndex = parseInt(node.dataset.index, 10);
                var ranking = node.parentElement.dataset.ranking;
                if (rangeSelection(_this.ctx.provider, ranking, dataIndex, relIndex, evt.ctrlKey)) {
                    return;
                }
            }
            _this.ctx.provider.toggleSelection(dataIndex, evt.ctrlKey);
        };
    };
    SelectionManager.prototype.selectRange = function (rows, additional) {
        if (additional === void 0) { additional = false; }
        var current = new OrderedSet(additional ? this.ctx.provider.getSelection() : []);
        var toggle = function (dataIndex) {
            if (current.has(dataIndex)) {
                current.delete(dataIndex);
            }
            else {
                current.add(dataIndex);
            }
        };
        rows.forEach(function (d) {
            if (isGroup(d)) {
                forEachIndices(d.order, toggle);
            }
            else {
                toggle(d.dataIndex);
            }
        });
        this.ctx.provider.setSelection(Array.from(current));
    };
    SelectionManager.prototype.updateState = function (node, dataIndex) {
        if (this.ctx.provider.isSelected(dataIndex)) {
            node.classList.add(cssClass('selected'));
        }
        else {
            node.classList.remove(cssClass('selected'));
        }
    };
    SelectionManager.prototype.update = function (node, selectedDataIndices) {
        var dataIndex = parseInt(node.dataset.i, 10);
        if (selectedDataIndices.has(dataIndex)) {
            node.classList.add(cssClass('selected'));
        }
        else {
            node.classList.remove(cssClass('selected'));
        }
    };
    SelectionManager.EVENT_SELECT_RANGE = 'selectRange';
    SelectionManager.MIN_DISTANCE = 10;
    return SelectionManager;
}(AEventDispatcher));
export default SelectionManager;
//# sourceMappingURL=SelectionManager.js.map