var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/// <reference path="leaf.ts" />
/// <reference path="widget.ts" />
var Leaf;
(function (Leaf) {
    var List = (function (_super) {
        __extends(List, _super);
        function List(el) {
            var _this = _super.call(this, el, "List", []) || this;
            _this._length = 0;
            _this.length = 0;
            var arrayFnsNames = ["map", "forEach", "slice", "every", "some", "filter"];
            var _loop_1 = function (name_1) {
                this_1[name_1] = function () {
                    var args = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        args[_i] = arguments[_i];
                    }
                    var arr = _this.toArray();
                    return arr[name_1].apply(arr, args);
                };
            };
            var this_1 = this;
            for (var _i = 0, arrayFnsNames_1 = arrayFnsNames; _i < arrayFnsNames_1.length; _i++) {
                var name_1 = arrayFnsNames_1[_i];
                _loop_1(name_1);
            }
            Object.defineProperty(_this, "length", {
                get: function () {
                    return _this._length;
                },
                set: function (v) {
                    var toRemove = [];
                    if (v > _this._length) {
                        throw new Error("can't asign length larger than the orig");
                    }
                    if (typeof v != "number") {
                        throw new TypeError();
                    }
                    for (var i = v; i < _this.length; i++) {
                        toRemove.push(_this[i]);
                        delete _this[i];
                    }
                    _this._length = v;
                    for (var _i = 0, toRemove_1 = toRemove; _i < toRemove_1.length; _i++) {
                        var item = toRemove_1[_i];
                        _this.detach(item);
                    }
                }
            });
            _this._length = 0;
            return _this;
        }
        List.prototype.indexOf = function (item) {
            for (var i = 0; i < this.length; i++) {
                if (this[i] === item) {
                    return i;
                }
            }
            return -1;
        };
        List.prototype.check = function (item) {
            if (!(item instanceof Leaf.Widget)) {
                throw new Error("List expect item to be Widget");
            }
            for (var i = 0; i < this.length; i++) {
                if (this[i] === item) {
                    throw new Error("Duplicate ListItem");
                }
            }
            return true;
        };
        List.prototype.push = function () {
            var items = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                items[_i] = arguments[_i];
            }
            for (var _a = 0, items_1 = items; _a < items_1.length; _a++) {
                var item = items_1[_a];
                this.check(item);
                this[this._length] = item;
                if (this._length != 0) {
                    item.after(this[this._length - 1]);
                }
                else {
                    item.appendTo(this.node);
                }
                this._length += 1;
                this.attach(item);
            }
        };
        List.prototype.pop = function () {
            if (this._length === 0)
                return null;
            this._length -= 1;
            var item = this[this._length];
            delete this[this._length];
            return item;
        };
        List.prototype.unshift = function (item) {
            this.check(item);
            if (this._length === 0) {
                item.prependTo(this.node);
                this[0] = item;
                this._length = 1;
                this.attach(item);
                return;
            }
            for (var index = this._length; index > 0; index -= 1) {
                this[index] = this[index - 1];
            }
            this[0] = item;
            this._length += 1;
            item.before(this[1]);
            this.attach(item);
            return this._length;
        };
        List.prototype.shift = function () {
            var result = this[0];
            for (var index = 0; index < this.length; index++) {
                this[index] = this[index + 1];
            }
            this.length -= 1;
            this.detach(result);
            return result;
        };
        List.prototype.splice = function (index, count) {
            var _this = this;
            var toAdd = [];
            for (var _i = 2; _i < arguments.length; _i++) {
                toAdd[_i - 2] = arguments[_i];
            }
            var result = [];
            var toRemoves = [];
            if (typeof count != "number" || index + count > this._length) {
                count === this._length - index;
            }
            for (var i = 0; i < count; i++) {
                var item = this[index + i];
                toRemoves.push(item);
                result.push(item);
            }
            var toAddFinal = toAdd;
            var frag = document.createDocumentFragment();
            toAddFinal.forEach(function (item) {
                _this.check(item);
                frag.appendChild(item.node);
            });
            if (index < this.length && this.length > 0) {
                this.node.insertBefore(frag, this[index].node);
            }
            else {
                this.node.appendChild(frag);
            }
            // make a hole
            var increase = toAddFinal.length - count;
            if (increase < 0) {
                for (var origin = index + count; origin < this._length; origin++) {
                    this[origin + increase] = this[origin];
                }
            }
            else if (increase > 0) {
                for (var origin = this._length - 1; origin > index + count - 1; origin--) {
                    this[origin + increase] = this[origin];
                }
            }
            // fill the hole
            for (var offset = 0; offset < toAddFinal.length; offset++) {
                var item = toAddFinal[offset];
                this[index + offset] = item;
            }
            this._length += increase;
            for (var _a = 0, toRemoves_1 = toRemoves; _a < toRemoves_1.length; _a++) {
                var item = toRemoves_1[_a];
                this.detach(item);
            }
            for (var _b = 0, toAddFinal_1 = toAddFinal; _b < toAddFinal_1.length; _b++) {
                var item = toAddFinal_1[_b];
                this.attach(item);
            }
            return result;
        };
        List.prototype.removeItem = function (item) {
            var index = this.indexOf(item);
            if (index < 0)
                return;
            this.splice(index, 1);
            return item;
        };
        List.prototype.attach = function (item) {
            item["parentList"] = this;
            this.events.emit("child/add", item);
            this.events.emit("child/change");
        };
        List.prototype.detach = function (item) {
            item["parentList"] = null;
            var node = item.node;
            if (node && node.parentElement === this.node) {
                this.node.removeChild(node);
            }
            this.events.emit("child/remove", item);
            this.events.emit("child/change");
        };
        List.prototype.toArray = function () {
            var result = [];
            for (var i = 0; i < this.length; i++) {
                result.push(this[i]);
            }
            return result;
        };
        return List;
    }(Leaf.Widget));
    Leaf.List = List;
})(Leaf || (Leaf = {}));
//# sourceMappingURL=list.js.map