"use strict";

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

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

/**
 * @class AlternativesFormat
 * @constructor
 * @param {!FormatModule} format 
 * @returns {void}
 * @access public
 * @static
 */
export const AlternativesFormat = (function(){

    /**
     * @constructs AlternativesFormat
    * @param {!FormatModule} format 
     * @returns {void}
     * @access private
     * @static
     */
    const AlternativesFormat = function(format){

        /** @type {AlternativesFormat} */
        const self = this;

        /**
         * @returns {void}
         * @access private
         */
        const constructor = () => {
            ["alt", "alts", "alternative", "alternatives"].forEach(name => {
                format.modes[name] = self.get;
                format.checks[name] = self.check;
            });
            ["Alt", "Alts", "Alternative", "Alternatives"].forEach(name => {
                format.modes[name] = self.get;
                format.checks[name] = self.check;
            });
        };
        
        /**
         * @param {[number, number]} coordenates 
         * @param {!(string|Array.<any|null>)} inputs 
         * @param {!Object.<string, any|null>} [shared = {}] 
         * @param {!Array.<string>} [fragments = []] 
         * @returns {string}
         * @access public
         */
        this.get = ([i, j], inputs, shared = {}, fragments = []) => {

            /** @type {[string, boolean, string|Array.<string>]} */
            const [language, mutable, content_base] = (
                      Check.is_string(inputs) ? ((_, language, mutable, options) => [
                          language, mutable == "1", options
                      ])(...inputs.match(/^([^,]+),([01]),(.*)$/)) :
                      Check.is_array(inputs) ? inputs : 
                  []), 
                  /** @type {string} */
                  content = Check.is_array(content_base) ? content_base.join("\n") : content_base;
            /** @type {string|null} */
            let block = null;

            if(mutable){
                if(shared && shared.uniques_cache){
                    for(let _ = 0; _ < 100; _ ++){

                        /** @type {string} */
                        const temporary = format.execute([i, j], content, shared, fragments);

                        if(!shared.uniques_cache.includes(temporary)){
                            block = temporary;
                            shared.uniques_cache.push(temporary);
                            break;
                        };

                    };
                }else 
                    block = format.execute([i, j], content, shared, fragments);
            };

            return "```" + language + "`" + (
                block === null ? format.restore_fragments(content, fragments) :
            block) + "```";
        };

        /**
         * @param {[number, number]} coordenates 
         * @param {!string} string 
         * @param {!(string|Array.<string>)} inputs 
         * @param {!Object.<string, any|null>} [shared = {}] 
         * @param {!Array.<string>} [fragments = []] 
         * @returns {number}
         * @access public
         */
        this.check = ([i, j], string, inputs, shared = {}, fragments = []) => {

            /** @type {[string, boolean, string|Array.<string>]} */
            const [language, mutable, content_base] = (
                      Check.is_string(inputs) ? ((_, language, mutable, options) => [
                          language, mutable == "1", options
                      ])(...inputs.match(/^([^,]+),([01]),(.*)$/)) :
                      Check.is_array(inputs) ? inputs : 
                  []), 
                  /** @type {string} */
                  content = Check.is_array(content_base) ? content_base.join("\n") : content_base;
            /** @type {number} */
            let k = -1, 
                /** @type {string} */
                clone = "" + string;
            
            if(clone.startsWith("```" + language + "`")){

                /** @type {number} */
                const end = (clone = clone.substring(6 + language.length)).indexOf("```");

                end != -1 && 
                (k = (
                    mutable ? format.get_check_length([i, j], clone.substring(0, end), [content], shared, fragments) : 
                clone.startsWith(content + "```") ? content.length : -1)) != -1 && 
                (k += 7 + language.length);

            };

            return k;
        };

        constructor();

    };

    return AlternativesFormat;
})();