import { IndexInterface, DocumentInterface } from "./type.js";
import { create_object, is_object } from "./common.js";

/**
 * @param {boolean|number=} limit
 * @constructor
 */

function CacheClass(limit) {

    /** @private */
    this.limit = !0 !== limit && limit;

    /** @private */
    this.cache = create_object();

    /** @private */
    this.queue = [];

    //this.clear();
}

export default CacheClass;

/**
 * @param {string|Object} query
 * @param {number|Object=} limit
 * @param {Object=} options
 * @this {IndexInterface}
 * @returns {Array<number|string>}
 */

export function searchCache(query, limit, options) {

    if (is_object(query)) {

        query = query.query;
    }

    let cache = this.cache.get(query);

    if (!cache) {

        cache = this.search(query, limit, options);
        this.cache.set(query, cache);
    }

    return cache;
}

// CacheClass.prototype.clear = function(){
//
//     /** @private */
//     this.cache = create_object();
//
//     /** @private */
//     this.queue = [];
// };

CacheClass.prototype.set = function (key, value) {

    if (!this.cache[key]) {

        // it is just a shame that native function array.shift() performs so bad

        // const length = this.queue.length;
        //
        // this.queue[length] = key;
        //
        // if(length === this.limit){
        //
        //     delete this.cache[this.queue.shift()];
        // }

        // the same bad performance

        // this.queue.unshift(key);
        //
        // if(this.queue.length === this.limit){
        //
        //     this.queue.pop();
        // }

        // fast implementation variant

        // let length = this.queue.length;
        //
        // if(length === this.limit){
        //
        //     length--;
        //
        //     delete this.cache[this.queue[0]];
        //
        //     for(let x = 0; x < length; x++){
        //
        //         this.queue[x] = this.queue[x + 1];
        //     }
        // }
        //
        // this.queue[length] = key;

        // current fastest implementation variant
        // theoretically that should not perform better compared to the example above

        let length = this.queue.length;

        if (length === this.limit) {

            delete this.cache[this.queue[length - 1]];
        } else {

            length++;
        }

        for (let x = length - 1; 0 < x; x--) {

            this.queue[x] = this.queue[x - 1];
        }

        this.queue[0] = key;
    }

    this.cache[key] = value;
};

CacheClass.prototype.get = function (key) {

    const cache = this.cache[key];

    if (this.limit && cache) {

        // probably the indexOf() method performs faster when matched content is on front (left-to-right)
        // using lastIndexOf() does not help, it performs almost slower

        const pos = this.queue.indexOf(key);

        // if(pos < this.queue.length - 1){
        //
        //     const tmp = this.queue[pos];
        //     this.queue[pos] = this.queue[pos + 1];
        //     this.queue[pos + 1] = tmp;
        // }

        if (pos) {

            const tmp = this.queue[pos - 1];
            this.queue[pos - 1] = this.queue[pos];
            this.queue[pos] = tmp;
        }
    }

    return cache;
};

CacheClass.prototype.del = function (id) {

    for (let i = 0, item, key; i < this.queue.length; i++) {

        key = this.queue[i];
        item = this.cache[key];

        if (item.includes(id)) {

            this.queue.splice(i--, 1);
            delete this.cache[key];
        }
    }
};