/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
import { Emitter, EventBufferer } from '../../../common/event';
import { tail2 } from '../../../common/arrays';
var IndexTreeModel = /** @class */ (function () {
    function IndexTreeModel(list, options) {
        if (options === void 0) { options = {}; }
        this.list = list;
        this.root = {
            parent: undefined,
            element: undefined,
            children: [],
            depth: 0,
            collapsible: false,
            collapsed: false,
            renderNodeCount: 0,
            visible: true,
            filterData: undefined
        };
        this.eventBufferer = new EventBufferer();
        this._onDidChangeCollapseState = new Emitter();
        this.onDidChangeCollapseState = this.eventBufferer.wrapEvent(this._onDidChangeCollapseState.event);
        this._onDidChangeRenderNodeCount = new Emitter();
        this.onDidChangeRenderNodeCount = this.eventBufferer.wrapEvent(this._onDidChangeRenderNodeCount.event);
        this.filter = options.filter;
    }
    IndexTreeModel.prototype.getListIndex = function (location) {
        return this.getTreeNodeWithListIndex(location).listIndex;
    };
    IndexTreeModel.prototype.setCollapsed = function (location, collapsed) {
        var _this = this;
        var _a = this.getTreeNodeWithListIndex(location), node = _a.node, listIndex = _a.listIndex, revealed = _a.revealed;
        return this.eventBufferer.bufferEvents(function () { return _this._setCollapsed(node, listIndex, revealed, collapsed); });
    };
    IndexTreeModel.prototype.toggleCollapsed = function (location) {
        var _this = this;
        var _a = this.getTreeNodeWithListIndex(location), node = _a.node, listIndex = _a.listIndex, revealed = _a.revealed;
        this.eventBufferer.bufferEvents(function () { return _this._setCollapsed(node, listIndex, revealed); });
    };
    IndexTreeModel.prototype._setCollapsed = function (node, listIndex, revealed, collapsed) {
        if (!node.collapsible) {
            return false;
        }
        if (typeof collapsed === 'undefined') {
            collapsed = !node.collapsed;
        }
        if (node.collapsed === collapsed) {
            return false;
        }
        node.collapsed = collapsed;
        if (revealed) {
            var previousRenderNodeCount = node.renderNodeCount;
            var toInsert = this.updateNodeAfterCollapseChange(node);
            this.list.splice(listIndex + 1, previousRenderNodeCount - 1, toInsert.slice(1));
            this._onDidChangeCollapseState.fire(node);
        }
        return true;
    };
    IndexTreeModel.prototype.updateNodeAfterCollapseChange = function (node) {
        var previousRenderNodeCount = node.renderNodeCount;
        var result = [];
        this._updateNodeAfterCollapseChange(node, result);
        this._updateAncestorsRenderNodeCount(node.parent, result.length - previousRenderNodeCount);
        return result;
    };
    IndexTreeModel.prototype._updateNodeAfterCollapseChange = function (node, result) {
        if (node.visible === false) {
            return 0;
        }
        result.push(node);
        node.renderNodeCount = 1;
        if (!node.collapsed) {
            for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
                var child = _a[_i];
                node.renderNodeCount += this._updateNodeAfterCollapseChange(child, result);
            }
        }
        this._onDidChangeRenderNodeCount.fire(node);
        return node.renderNodeCount;
    };
    IndexTreeModel.prototype._updateAncestorsRenderNodeCount = function (node, diff) {
        if (diff === 0) {
            return;
        }
        while (node) {
            node.renderNodeCount += diff;
            this._onDidChangeRenderNodeCount.fire(node);
            node = node.parent;
        }
    };
    // expensive
    IndexTreeModel.prototype.getTreeNodeWithListIndex = function (location) {
        var _a = this.getParentNodeWithListIndex(location), parentNode = _a.parentNode, listIndex = _a.listIndex, revealed = _a.revealed;
        var index = location[location.length - 1];
        if (index < 0 || index > parentNode.children.length) {
            throw new Error('Invalid tree location');
        }
        var node = parentNode.children[index];
        return { node: node, listIndex: listIndex, revealed: revealed };
    };
    IndexTreeModel.prototype.getParentNodeWithListIndex = function (location, node, listIndex, revealed) {
        if (node === void 0) { node = this.root; }
        if (listIndex === void 0) { listIndex = 0; }
        if (revealed === void 0) { revealed = true; }
        var index = location[0], rest = location.slice(1);
        if (index < 0 || index > node.children.length) {
            throw new Error('Invalid tree location');
        }
        // TODO@joao perf!
        for (var i = 0; i < index; i++) {
            listIndex += node.children[i].renderNodeCount;
        }
        revealed = revealed && !node.collapsed;
        if (rest.length === 0) {
            return { parentNode: node, listIndex: listIndex, revealed: revealed };
        }
        return this.getParentNodeWithListIndex(rest, node.children[index], listIndex + 1, revealed);
    };
    // TODO@joao perf!
    IndexTreeModel.prototype.getNodeLocation = function (node) {
        var location = [];
        while (node.parent) {
            location.push(node.parent.children.indexOf(node));
            node = node.parent;
        }
        return location.reverse();
    };
    IndexTreeModel.prototype.getParentNodeLocation = function (location) {
        if (location.length <= 1) {
            return [];
        }
        return tail2(location)[0];
    };
    return IndexTreeModel;
}());
export { IndexTreeModel };
