"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EntityList = void 0;
const exception_js_1 = require("../../exception.js");
const entity_js_1 = require("./entity.js");
class EntityList extends entity_js_1.Entity {
    constructor($owner, $key, specs) {
        super($owner);
        this.items = [];
        this.$key = $key;
        const specItems = Array.isArray(specs) ? specs : specs?.items || [];
        for (const spec of specItems) {
            this.insert(spec);
        }
    }
    toJSON() {
        return { items: this.items };
    }
    get $path() {
        return this.$owner.$path + '/' + this.$key;
    }
    *[Symbol.iterator]() {
        yield* this.items;
    }
    get length() {
        return this.items.length;
    }
    indexOf(item) {
        return this.items.indexOf(item);
    }
    get first() {
        return this.items[0] || null;
    }
    get last() {
        return this.items[this.length - 1] || null;
    }
    get(index) {
        return this.items[index] || null;
    }
    find(predicate) {
        return this.items.find(predicate) || null;
    }
    filter(predicate) {
        return this.items.filter(predicate);
    }
    map(fn) {
        return this.items.map(fn);
    }
    *previousSiblings(item) {
        const index = this.indexOf(item);
        for (let i = index - 1; i >= 0; i -= 1) {
            yield this.items[i];
        }
    }
    *nextSiblings(item) {
        const index = this.indexOf(item);
        for (let i = index + 1; i < this.length; i += 1) {
            yield this.items[i];
        }
    }
    previousSibling(item) {
        return this.previousSiblings(item).next().value;
    }
    nextSibling(item) {
        return this.nextSiblings(item).next().value;
    }
    insert(spec, index = this.length) {
        index = Math.max(0, Math.min(index, this.length));
        const item = this.create(spec);
        this.items.splice(index, 0, item);
        this.$idDatabase.registerId(item.id, item);
        return item;
    }
    removeAt(index) {
        const item = this.get(index);
        if (index > -1 && item) {
            this.items.splice(index, 1);
            this.unregisterIds(item);
        }
    }
    remove(item) {
        this.removeAt(this.indexOf(item));
    }
    removeWhere(predicate) {
        for (let i = 0; i < this.length; i += 1) {
            const item = this.items[i];
            if (predicate(item, i)) {
                this.items.splice(i, 1);
                this.unregisterIds(item);
                i -= 1;
            }
        }
    }
    replace(item, newSpec) {
        const i = this.indexOf(item);
        if (i > -1) {
            this.unregisterIds(item);
            const newItem = this.create(newSpec);
            this.items.splice(i, 1, newItem);
            return newItem;
        }
        throw new exception_js_1.Exception({
            name: 'IllegalManipulation',
            message: 'Could not replace node: source node not found',
            retry: false,
        });
    }
    move(item, newIndex) {
        const oldIndex = this.indexOf(item);
        this.items.splice(oldIndex, 1);
        this.items.splice(newIndex, 0, item);
    }
    unregisterIds(item) {
        const ids = this.collectIds(item);
        for (const id of ids) {
            this.$idDatabase.unregisterId(id);
        }
    }
    collectIds(obj) {
        const ids = new Set();
        JSON.stringify(obj, (k, v) => {
            if (k === 'id') {
                ids.add(v);
            }
            return v;
        });
        return ids;
    }
}
exports.EntityList = EntityList;
//# sourceMappingURL=list.js.map