/**  
 * @since Last modified: 2024-09-10 09:46:00
 * @class Dodge
 * @description Basic class, you can extend any subclasses.
 * @param {getEl} elem - The target node.The writing is the same as getEl.
 * @param {Object} [options] - The parameters 
 * @see {@link https://codepen.io/axui/pen/jOREowx|demo @ codepen}
 * @example
 * ax.Dodge('#id');
 */
import { T_obj, T_opt_base, T_required } from "../../../types/ax";
import createEl from "../utils/createEl";
import getEl from "../utils/getEl";
import instance from "../utils/instance";
import pipe from "../utils/pipe";
import PubBase from "./PubBase";
import PubListen from "./PubListen";
import ax from "../ax";
import PubCommon from "./PubCommon";
import optDodge from "../options/optDodge";
import PubUpdate from "./PubUpdate";
import { T_dodge } from "../../../types/dodge";
import config from "../global/config";
import prefix from "../global/prefix";
class Dodge extends pipe(PubListen, PubUpdate, PubCommon)(PubBase) {
    options: Required<T_dodge> | T_obj = {};
    static hostType = 'node';
    constructor(elem: any, options?: T_dodge,initial:boolean=true) {
        super();
        this.ready({
            options,
            host:elem,
            maps: optDodge,
        });
        /**
        * @name Dodge.targetEl
        * @description Target element.
        * @type getEl
        */
        /**
        * @name Dodge.rawOpts
        * @description Raw Parameters of the instance from map.
        * @type object
        */
        /**
         * @name Dodge.dftOpts
         * @description Default Parameters of the instance from merging.The reset method requires this variable.
         * @type object
         */
        /**
         * @name Dodge.options
         * @description Parameters of the instance.
         * @type object
         */
        /**
         * @name Dodge.destroyed
         * @description Destruction state.
         * @type boolean
         */
        /**
        * @name Dodge.plans
        * @description Plans for listening.
        * @type object
        */
        /**
        * @name Dodge.storKeys
        * @description The set of parameter fields to save.
        * @type array
        */
        /**
         * @name Dodge.storTmp
         * @description Cache object.The "updateCache" method will update the variable.
         * @type object
         */
        /**
        * @name Dodge.storObs
        * @description Cache listener(proxy) that listens for "storTmp" changes and automatically updates the local storage.
        * @type any
        */
        /**
        * @name Dodge.timestamp
        * @description Instance creation time.
        * @type number
        */
        /**
        * @function Dodge.save
        * @description Storing settings locally.
        * @param {fn_cb_options} [cb] - Callback execution after saving local storage.
        * @returns {any} Return the instance itself
        */
        /**
        * @function Dodge.reset
        * @description Re-initialization of old parameters.
        * @param {fn_cb_none} [cb] - Call back after reset settings.
        * @returns {*} Return the instance itself
        */
        this.timestamp = Date.now();
        /**
        * @name Dodge.inputEl
        * @description Input node.Usually an input or textarea.
        * @type HTMLElement
        */
        this.inputEl = this.targetEl.querySelector("input,textarea");
        if (!this.inputEl) {
            throw new Error('Form field node not found!');
         }
        /**
        * @name Dodge.labelEl
        * @description Indicator text node for dodge.
        * @type HTMLElement
        */
         this.labelEl = null;
        /**
        * @name Dodge.isFocus
        * @description Whether input node is focused or not.
        * @type boolean
        */
        this.isFocus = false;
        this.toggle = {
            focus: () => {
                this.inputEl.focus();
                this.inputEl.removeAttribute('readonly');
                this.targetEl.setAttribute('dodged', '');
                this.isFocus = true;
            },
            blur: (e: any) => {
                console.log(e.target)
                this.inputEl.blur();
                this.inputEl.setAttribute('readonly', '');
                !this.inputEl.value ? this.targetEl.removeAttribute('dodged') : this.targetEl.setAttribute('dodged', '');
                this.isFocus = false;
            }
        }
         super.listen({ name: 'ready' });
        initial && this.init() ;
    }
    /**
    * @description Initialization instance.
    * @param {fn_cb_none} [cb] - Callback execution after initialization.
    * @returns {Promise<any>} - Returns a proimise whose argument is the instance itself.
    */
    async init(cb?: any): Promise<any> {
         super.listen({ name: 'launch' });
        this.options.b4Init && await this.options.b4Init.call(this);
        /**
        * @name Dodge.placeholder
        * @description The placeholder text.
        * @type string
        */
        this.placeholder = this.getPlaceholder();
        this.setAttrs();
        this.render();
        this.inputEl.addEventListener('focus', this.toggle.focus, false);
        this.inputEl.addEventListener('blur', this.toggle.blur, false);
        this.labelEl.onclick = () => {
            this.toggle.focus();
        };
        this.inputEl.value ? this.toggle.focus() : null;
        super.listen({ name: 'init', cb });
        return this;
    }
    getPlaceholder() {
        let inputHolder = this.inputEl.getAttribute('placeholder');
        return this.options.placeholder ? this.options.placeholder :
            inputHolder ? inputHolder : config.lang.form.placeholder;
    }
    render() {
        if (!this.labelEl) {
            this.labelEl = createEl('label', '', this.placeholder);
            this.inputEl.removeAttribute("placeholder");
            this.inputEl.insertAdjacentElement('afterend', this.labelEl);
        }
    }
    setAttrs() {
        this.targetEl.classList.add(`${prefix}dodge`);
        this.inputEl.setAttribute('readonly', '');
        this.inputEl.classList.contains("ax-lg") ? this.targetEl.classList.add("ax-lg") : null;
    }
    /**
    * @description Trigger dodge by setting a value.
    * @param {string} value - The value to be set.
    * @param {fn_cb_data} [cb] - Call back after setting the dodge state.Supports the value of a parameter that is about to be set.
    * @returns {*} Return the instance itself
    */
    set(value: string, cb?: any):any {
        if (this.destroyed) { return this; }
        if (value) {
            this.inputEl.value = value;
            this.toggle.focus();
        } else {
            this.inputEl.focus();
        }
        super.listen({ name: 'set', cb, parmas: [value] });
        return this;
    }
    /**
    * @description Cancel the status of dodge.
    * @param {fn_cb_none} [cb] - Call back after canceling the dodge state.
    * @returns {*} Return the instance itself
    */
    cancel(cb?: any):any {
        if (this.destroyed) { return this; }
        this.inputEl.value = '';
        this.inputEl.blur();
        this.toggle.blur();
        super.listen({ name: 'cancel', cb });
        return this;
    }
    /**
     * @description Destroy instance and prohibit use.
     * @param {fn_cb_none} [cb] - Callback execution after destruction.
     * @returns {any} - Return the instance itself.
     */
    destroy(cb?: any): any {
        if (this.destroyed) {
            return this;
        }
        this.labelEl.onclick = null;
        this.inputEl.removeEventListener('focus', this.toggle.focus);
        this.inputEl.removeEventListener('blur', this.toggle.blur);
        this.destroyed = true;
        super.listen({ name: 'destroy', cb });
        return this;
    }
}
export default Dodge;
