import { Utils } from './Utils';

/**
 * 
 * @class TupleDictionary
 */
export class TupleDictionary {
    /**
     * The data storage
     * @property data
     * @type {Object}
     */
    data: Object;

    /**
     * Keys that are currently used.
     * @property {Array} keys
     */
    keys: any[];

    /**
     * @constructor
     */
    constructor() {
        this.data = {};
        this.keys = [];
    }

    /**
     * Generate a key given two integers
     * @method getKey
     * @param  {number} i
     * @param  {number} j
     * @return {string}
     */
    getKey(id1: number, id2: number): number {
        id1 = id1 | 0;
        id2 = id2 | 0;

        if ((id1 | 0) === (id2 | 0)) {
            return -1;
        }

        // valid for values < 2^16
        return ((id1 | 0) > (id2 | 0) ?
            (id1 << 16) | (id2 & 0xFFFF) :
            (id2 << 16) | (id1 & 0xFFFF)) | 0
            ;
    };

    /**
     * @method getByKey
     * @param  {Number} key
     * @return {Object}
     */
    getByKey(key: number): Object {
        key = key | 0;
        return this.data[key];
    };

    /**
     * @method get
     * @param  {Number} i
     * @param  {Number} j
     * @return {Number}
     */
    get(i: number, j: number): Object {
        return this.data[this.getKey(i, j)];
    };

    /**
     * Set a value.
     * @method set
     * @param  {Number} i
     * @param  {Number} j
     * @param {Number} value
     */
    set(i: number, j: number, value) {
        if (!value) {
            throw new Error("No data!");
        }

        var key = this.getKey(i, j);

        // Check if key already exists
        if (!this.data[key]) {
            this.keys.push(key);
        }

        this.data[key] = value;

        return key;
    };

    /**
     * Remove all data.
     * @method reset
     */
    reset(): void {
        var data = this.data,
            keys = this.keys;

        var l = keys.length;
        while (l--) {
            delete data[keys[l]];
        }
        keys.length = 0;
    };

    /**
     * Copy another TupleDictionary. Note that all data in this dictionary will be removed.
     * @method copy
     * @param {TupleDictionary} dict The TupleDictionary to copy into this one.
     */
    copy(dict: TupleDictionary) {
        this.reset();
        Utils.appendArray(this.keys, dict.keys);
        var l = dict.keys.length;
        while (l--) {
            var key = dict.keys[l];
            this.data[key] = dict.data[key];
        }
    };
}