"use strict";

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

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

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

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

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

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

            format.modes.select = self.get;
            format.checks.select = self.check;

            format.modes.Select = ([i, j], inputs, shared, fragments) => self.get([i, j], inputs, {
                ...shared, capitalized : true
            }, fragments);
            format.checks.Select = ([i, j], string, inputs, shared, fragments) => self.check([i, j], string, inputs, {
                ...shared, capitalized : true
            }, fragments);

            ["select_uniques", "selectUniques", "selectuniques"].forEach(key => {
                format.modes[key] = ([i, j], inputs, shared, fragments) => self.get([i, j], inputs, {
                    ...shared, uniques : true
                }, fragments);
                format.checks[key] = ([i, j], string, inputs, shared, fragments) => self.check([i, j], string, inputs, {
                    ...shared, uniques : true
                }, fragments);
            });

            ["Select_uniques", "Select_Uniques", "SelectUniques"].forEach(key => {
                format.modes[key] = ([i, j], inputs, shared, fragments) => self.get([i, j], inputs, {
                    ...shared, capitalized : true, uniques : true
                }, fragments);
                format.checks[key] = ([i, j], string, inputs, shared, fragments) => self.check([i, j], string, inputs, {
                    ...shared, capitalized : true, uniques : true
                }, fragments);
            });

        };

        /**
         * @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 {[[number, number], string, Array.<string>]} */
            const [range, separator, original_items] = (
                Check.is_string(inputs) ? ((_, range, separator, items) => [
                    range.split("-").map(Number), separator, items.split("|")
                ])(...inputs.match(/^([^,]+),([^,]+),(.*)$/)) :
                Check.is_array(inputs) ? inputs : 
            []);

            return format.get_items([i, j], original_items, range, separator, fragments, shared);
        };

        /**
         * @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 {[[number, number], string, Array.<string>]} */
            const [[minimum, maximum], separator, original_items] = (
                      Check.is_string(inputs) ? ((_, range, separator, options) => [
                          range.split("-").map(Number), separator, options.split("|")
                      ])(...inputs.match(/^([^,]+),([^,]+),(.*)$/)) :
                      Check.is_array(inputs) ? inputs : 
                  []), 
                  /** @type {Array.<string>} */
                  items = format.get_list([i, j], [...original_items]);
            
            return format.check_select([i, j], string, [[minimum, maximum], separator, items], shared, fragments);
        };

        constructor();

    };

    return SelectFormat;
})();