module BABYLON {
    export class SmartCollection {
        public count = 0;
        public items: any;

        private _keys: string[];
        private _initialCapacity: number;

        constructor(capacity: number = 10) {
            this._initialCapacity = capacity;
            this.items = {};
            this._keys = new Array(this._initialCapacity);
        }

        public add(key: any, item: any): number {
            if (this.items[key] != undefined) {
                return -1;
            }
            this.items[key] = item;
            
            //literal keys are always strings, but we keep source type of key in _keys array
            this._keys[this.count++] = key;
            if (this.count > this._keys.length) {
                this._keys.length *= 2;
            }

            return this.count;
        }

        public remove(key: any): number {
            if (this.items[key] == undefined) {
                return -1;
            }

            return this.removeItemOfIndex(this.indexOf(key));
        }

        public removeItemOfIndex(index: number): number {
            if (index < this.count && index > -1) {
                delete this.items[this._keys[index]];
                    
                //here, shifting by hand is better optimised than .splice
                while (index < this.count) {
                    this._keys[index] = this._keys[index + 1]; index++;
                }
            }
            else {
                return -1;
            }

            return --this.count;
        }

        public indexOf(key: any): number {
            for (var i = 0; i !== this.count; i++) {
                if (this._keys[i] === key) {
                    return i;
                }
            }
            return -1;
        }

        public item(key: any): any {
            return this.items[key];
        }

        public getAllKeys(): any[] {
            if (this.count > 0) {
                var keys = new Array(this.count);
                for (var i = 0; i < this.count; i++) {
                    keys[i] = this._keys[i];
                }
                return keys;
            }
            else {
                return undefined;
            }
        }

        public getKeyByIndex(index: number): any {
            if (index < this.count && index > -1) {
                return this._keys[index];
            }
            else {
                return undefined;
            }
        }

        public getItemByIndex(index: number): any {
            if (index < this.count && index > -1) {
                return this.items[this._keys[index]];
            }
            else {
                return undefined;
            }
        }

        public empty(): void {
            if (this.count > 0) {
                this.count = 0;
                this.items = {};
                this._keys = new Array(this._initialCapacity);
            }
        }
    }
} 