"use strict";

import {Utils} from "../Utils/Utils.ecma.js";

/**
 * @typedef {import("../Application/OpoTests.ecma.js").OpoTests} OpoTests
 */

/**
 * @class IdentifiersManager
 * @constructor
 * @param {!OpoTests} ot 
 * @returns {void}
 * @access public
 * @static
 */
export const IdentifiersManager = (function(){

    /**
     * @constructs IdentifiersManager
     * @param {!OpoTests} ot 
     * @returns {void}
     * @access private
     * @static
     */
    const IdentifiersManager = function(ot){

        /** @type {IdentifiersManager} */
        const self = this, 
              /** @type {Array.<string>} */
              identifiers = [];
        /** @type {Array.<string>|string} */
        let alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 
            /** @type {number} */
            length = 11;

        /**
         * @returns {void}
         * @access private
         */
        const constructor = () => {

            alphabet = ot.settings.get(["identifiers_alphabet", "default_identifiers_alphabet"], null, alphabet);
            length = ot.settings.get(["identifiers_length", "default_identifiers_length"], null, length);

        };

        /**
         * @param {!(string|Array.<string>)} keys 
         * @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null] 
         * @param {?any} [_default = null] 
         * @returns {any|null}
         * @access public
         */
        this.get = () => {

            /** @type {string} */
            let identifier;

            do{
                identifier = "";
                while((identifier += Utils.get_random(alphabet)).length < length);
            }while(
                identifiers.includes(identifier) || 
                /^[^a-z]/i.test(identifier) || 
                document.querySelector("." + identifier + ",#" + identifier + ",[name=" + identifier + "]")
            );
            identifiers.push(identifier);

            return identifier;
        };

        /**
         * @param {!string} identifier 
         * @returns {void}
         */
        this.remove = identifier => {
            identifier in identifiers && identifiers.splice(identifiers.indexOf(identifier), 1);
        };

        constructor();

    };

    /** @type {Object.<string, any|null>} */
    IdentifiersManager.DEFAULT_SETTINGS = {};

    return IdentifiersManager;
})();