/// <reference path="../util/ArrayUtils.ts" />
/// <reference path="./IListFilter.ts" />
var econda;
(function (econda) {
    var collection;
    (function (collection) {
        var ArrayUtils = econda.util.ArrayUtils;
        /**
         * Generic class for lists.
         * @class econda.collection.List
         */
        var List = (function () {
            function List(cfg) {
                // should be protected, but this is not possible in current typescript version. Fix as soon as available.
                this._items = [];
                this._itemsById = {};
                this._idProperty = null;
                /**
                 * Callbacks on all list changes (add, remove, clear)
                 */
                this.onChange = [];
                if (cfg instanceof List) {
                    return cfg;
                }
                if (typeof cfg === 'object') {
                    this._idProperty = cfg.idProperty || null;
                    this._items = [];
                    if (typeof cfg.items !== 'undefined') {
                        this._setItems(cfg.items);
                    }
                    if (typeof cfg.onChange !== 'undefined') {
                        this.setOnChange(cfg.onChange);
                    }
                }
            }
            List.prototype.setOnChange = function (callback) {
                ArrayUtils.isArray(callback)
                    ? this.onChange = callback
                    : this.onChange = [callback];
            };
            /**
             * Run callbacks registered for onChange event.
             * @private
             */
            List.prototype._fireOnChangeEvent = function (item) {
                for (var i = 0; i < this.onChange.length; i++) {
                    this.onChange[i](item);
                }
            };
            /**
             * Add item to list
             */
            List.prototype.add = function (item) {
                this._items.push(item);
                if (this._idProperty !== null && typeof item[this._idProperty] != 'undefined') {
                    this._itemsById["" + item[this._idProperty]] = item;
                }
                this._collectionChanged();
                this._fireOnChangeEvent(item);
                return this;
            };
            /**
             * True if given item exists in collection
             * @param {Object} needle
             * @returns {Boolean}
             */
            List.prototype.contains = function (needle) {
                return ArrayUtils.contains(this._items, needle);
            };
            /**
             * Returns number of items in collection
             * @returns {Number}
             */
            List.prototype.length = function () {
                return this._items.length;
            };
            List.prototype.sort = function (compareFunctionOrProperty) {
                var compareFunction = (typeof compareFunctionOrProperty === 'string')
                    ? this._createCompareFunction(compareFunctionOrProperty)
                    : compareFunctionOrProperty;
                return this._items.sort(compareFunction);
            };
            List.prototype._createCompareFunction = function (propertyName) {
                return function (a, b) {
                    if (a[propertyName] > b[propertyName])
                        return 1;
                    if (a[propertyName] < b[propertyName])
                        return -1;
                    return 0;
                };
            };
            /**
             * Get index of given item
             * @param {Object} needle
             * @returns {Number}
             */
            List.prototype.indexOf = function (needle) {
                return ArrayUtils.indexOf(this._items, needle);
            };
            /**
             * Get item by id. idProperty must have been configured in constructor
             * @param {String} id
             * @returns {Object}
             */
            List.prototype.getItemById = function (id) {
                if (typeof this._itemsById["" + id] === 'undefined') {
                    return null;
                }
                return this._itemsById["" + id];
            };
            /**
             * Get item at index. Returns null if no item exists at given index.
             * @param {Number} index
             */
            List.prototype.get = function (index) {
                return (typeof this._items[index] !== 'undefined')
                    ? this._items[index]
                    : null;
            };
            /**
             * Get all items
             * @returns {ItemType[]}
             */
            List.prototype.getAll = function () {
                return this._items;
            };
            List.prototype.getFilteredItems = function (filter) {
                var matches = [];
                if (typeof filter.match === 'function') {
                    // object that implements IListFilter
                    for (var n = 0; n < this._items.length; n++) {
                        if (filter.match(this._items[n]) === true) {
                            matches.push(this._items[n]);
                        }
                    }
                }
                else {
                    // filter function
                    for (var n = 0; n < this._items.length; n++) {
                        if (filter(this._items[n]) === true) {
                            matches.push(this._items[n]);
                        }
                    }
                }
                return matches;
            };
            /**
             * Executes callback function with each item in collection
             */
            List.prototype.forEach = function (callback, scope) {
                for (var n = 0; n < this._items.length; n++) {
                    callback.call(scope, this._items[n]);
                }
            };
            /**
             * Remove all items from collection
             */
            List.prototype.clear = function () {
                this._setItems(null);
                return this;
            };
            List.prototype._setItems = function (items) {
                this._items = [];
                this._itemsById = {};
                if (items === null) {
                    return;
                }
                // array as parameter
                if (typeof items.length !== 'undefined') {
                    this._items = items;
                }
                else if (typeof items === 'object') {
                    // object as parameter
                    for (var propertyName in items) {
                        if (items.hasOwnProperty(propertyName)) {
                            this._items.push(items[propertyName]);
                        }
                    }
                }
                if (this._idProperty !== null) {
                    for (var n = 0; n < this._items.length; n++) {
                        this._itemsById["" + this._items[n][this._idProperty]] = this._items[n];
                    }
                }
                this._collectionChanged();
                this.forEach(this._fireOnChangeEvent, this);
            };
            /**
             * Callback for extending classes. Called one time if items in collection were added or removed.
             * Must be called before any events are fired.
             */
            List.prototype._collectionChanged = function () { };
            return List;
        }());
        collection.List = List;
    })(collection = econda.collection || (econda.collection = {}));
})(econda || (econda = {}));