(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports", "./AtomBinder"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    const AtomBinder_1 = require("./AtomBinder");
    const isSelectableItem = {};
    class AtomSelectableList {
        constructor(allowMultipleSelection = false, valuePath, labelPath) {
            this.allowMultipleSelection = allowMultipleSelection;
            this.valuePath = valuePath;
            this.labelPath = labelPath;
            this.selectedItems = [];
            this.mValue = undefined;
            if (!this.valuePath) {
                this.valuePath = (x) => x;
            }
            if (!this.labelPath) {
                this.labelPath = (x) => x.label || x;
            }
            this.items = [];
        }
        get selectedIndex() {
            if (this.selectedItems.length) {
                return this.items.indexOf(this.selectedItems[0]);
            }
            return -1;
        }
        set selectedIndex(n) {
            this.selectedItems.clear();
            if (n === -1) {
                this.updateBindings(true);
                return;
            }
            this.selectedItems.add(this.items[n]);
        }
        get selectedItem() {
            if (!this.selectedItems.length) {
                return null;
            }
            const s = this.selectedItems[0];
            return s ? s.item : null;
        }
        set selectedItem(item) {
            this.selectedItems.clear();
            if (!item) {
                this.updateBindings(true);
                return;
            }
            const si = this.items.find((s) => s.item === item);
            si.select();
        }
        get label() {
            const labels = this.selectedItems.map((x) => this.labelPath(x.item));
            if (this.allowMultipleSelection) {
                return labels;
            }
            return labels[0] || null;
        }
        get selectAll() {
            if (this.items.length) {
                return this.items.length === this.selectedItems.length;
            }
            return false;
        }
        set selectAll(v) {
            if (v) {
                this.selectedItems.splice(0, this.selectedItems.length, ...this.items);
            }
            else {
                this.selectedItems.clear();
            }
            AtomBinder_1.AtomBinder.refreshItems(this.selectedItems);
            for (const iterator of this.items) {
                AtomBinder_1.AtomBinder.refreshValue(iterator, "selected");
            }
        }
        get value() {
            if (this.allowMultipleSelection && this.items.length) {
                return this.selectedItems.map((x) => this.valuePath(x.item));
            }
            if (this.selectedItems.length) {
                return this.valuePath(this.selectedItems[0].item);
            }
            return this.mValue;
        }
        set value(v) {
            this.mValue = v;
            if (!this.allowMultipleSelection) {
                v = [v];
            }
            const va = v;
            this.replaceSelectedInternal(va, false);
        }
        /**
         * Remove all items
         * @param clearValue clear Selection
         */
        clear(clearValue = false) {
            if (clearValue) {
                this.replaceSelectedInternal([], false);
            }
            this.items.clear();
        }
        /**
         * Append to existing items
         * @param source source items
         * @param total total number of items
         */
        append(source, total) {
            let values = this.value;
            if (!this.allowMultipleSelection) {
                values = [values];
            }
            const map = source.map((x) => {
                const item = this.newItem(x);
                if (values && values.length) {
                    const v = this.valuePath(x);
                    if (values.find((v1) => v1 === v)) {
                        item.selected = true;
                    }
                }
                return item;
            });
            this.total = total;
            this.items.addAll(map);
            this.mValue = undefined;
            this.updateBindings(true);
        }
        replace(source, start, size) {
            let values = this.value;
            if (!this.allowMultipleSelection) {
                values = [values];
            }
            this.selectedItems.clear();
            const map = source.map((x) => {
                const item = this.newItem(x);
                if (values && values.length) {
                    const v = this.valuePath(x);
                    if (values.find((v1) => v1 === v)) {
                        item.selected = true;
                    }
                }
                return item;
            });
            const a = source;
            if (a.total) {
                map.total = a.total;
            }
            this.items.replace(map, start, size);
            this.mValue = undefined;
            this.updateBindings(true);
        }
        find(item) {
            let itemF = (i) => item(i);
            if (typeof item !== "function") {
                const e = item;
                itemF = (i) => i === e;
            }
            return this.items.find((i) => itemF(i.item));
        }
        select(item) {
            const i = item;
            if (i.itemType === isSelectableItem) {
                i.select();
                return;
            }
            const si = this.items.find((x) => x.item === item);
            si.select();
        }
        deselect(item) {
            const i = item;
            if (i.itemType === isSelectableItem) {
                i.deselect();
                return;
            }
            const si = this.items.find((x) => x.item === item);
            si.deselect();
        }
        toggle(item) {
            const i = item;
            if (i.itemType === isSelectableItem) {
                i.toggle();
                return;
            }
            const si = this.items.find((x) => x.item === item);
            si.toggle();
        }
        replaceSelected(va) {
            this.replaceSelectedInternal(va, true);
        }
        replaceSelectedInternal(va = [], refreshValue = true) {
            const newItems = !va ? [] : this.items.filter((x) => {
                const vp = this.valuePath(x.item);
                const existing = va.find((y) => y === vp);
                return existing ? true : false;
            });
            const s = this.selectedItems.slice();
            this.selectedItems.clear();
            for (const iterator of s) {
                AtomBinder_1.AtomBinder.refreshValue(iterator, "selected");
            }
            if (newItems.length) {
                this.selectedItems.replace(newItems);
            }
            this.updateBindings(refreshValue);
        }
        updateBindings(refreshValue = true) {
            // to prevent recursive updates...
            if (refreshValue) {
                AtomBinder_1.AtomBinder.refreshValue(this, "value");
            }
            AtomBinder_1.AtomBinder.refreshValue(this, "label");
            AtomBinder_1.AtomBinder.refreshValue(this, "selectAll");
            AtomBinder_1.AtomBinder.refreshValue(this, "selectedItem");
            AtomBinder_1.AtomBinder.refreshValue(this, "selectedIndex");
        }
        newItem(item) {
            const self = this;
            const newItem = {
                item,
                itemType: isSelectableItem,
                select: null,
                deselect: null,
                toggle: null,
                get selected() {
                    return self.selectedItems.find((x) => x === this) ? true : false;
                },
                set selected(v) {
                    if (v) {
                        if (this.selected) {
                            return;
                        }
                        self.clearSelected();
                        self.selectedItems.add(this);
                    }
                    else {
                        self.selectedItems.remove(this);
                    }
                    AtomBinder_1.AtomBinder.refreshValue(this, "selected");
                    self.updateBindings(true);
                }
            };
            newItem.select = () => {
                newItem.selected = true;
            };
            newItem.deselect = () => {
                newItem.selected = false;
            };
            newItem.toggle = () => {
                newItem.selected = !newItem.selected;
            };
            return newItem;
        }
        clearSelected() {
            if (!this.allowMultipleSelection) {
                const si = this.selectedItem;
                this.selectedItems.clear();
                AtomBinder_1.AtomBinder.refreshValue(si, "selected");
            }
        }
    }
    exports.default = AtomSelectableList;
});
//# sourceMappingURL=AtomSelectableList.js.map