/**  
 * @since Last modified: 2024-07-04 11:01:20
 * @class Search
 * @description A bubble attached to a target node.
 * @param {getEl} elem - Target element.    
 * @param {object} [options] - Parameters 
 * 
 * @param {string} [options.insName] - The name of the instance, which can be retrieved through the "ax.instance.find" method after filling in, it should be a unique value.
 * @param {string} [options.storName] - The name of the cache, after filling in, it can automatically save the parameters of this instance, and refresh the page can also keep the original state, it should be a unique value.
 * @param {string[]} [options.storKeys=[]] - The fields of the cache, property set from options, default is null that is, automatically save the whole options object, you can customize the property set of options that need to be saved by this parameters, for example: storKeys:['content','placement']
 * @param {breakpoints} [options.breakpoints={}] - The breakpoints settings, set options for different terminals or different screen sizes, please refer to the function: "ax.breakpoints".
 * @param {object} [options.lang={}] - The module language packs, after filling in, will override the corresponding module language packs under "ax.lang", through "ax.lang" to see the language items that can be set in this module.
 * @param {function} [options.onReady=null] - The listener function, which is executed after completion of the constructor and before initialization begins, supports one parameter i.e. the callback function, which has no parameters.
 * @param {function} [options.onStart=null] - The listener function, after the completion of the constructor and just after the initialization of the execution, supports one parameter i.e. the callback function, which has no parameters.
 * @param {function} [options.onInit=null] - The listener function, executed after the completion of the initialization, supports one parameter i.e. the callback function, which has no parameters.
 * @param {function} [options.onDestroy=null] - The listener function, executed after the destruction of the instance, supports one parameter i.e. callback function, which has no parameters.
 * @param {function} [options.onReset=null] - The listener function,executed after resetting the parameters, supports one parameter i.e. callback function, which has no parameters.
 * @param {function} [options.onUpdate=null] - The listener function, which executes after updating the parameters, supports one two parameters: the user parameters and the callback function, which has one parameter i.e. the user parameters.
 * @param {function} [options.onSave=null] - The listener function, which executes after saving the parameters, supports one parameter i.e. the callback function which has one parameter i.e. the parameter being saved.
 * 
 * @param {string} [options.heading=''] - The retrievaltitle, optional, if not fill in the title node will not be displayed.
 * @param {boolean} [options.divider=false] - If or not show the split line between title and content, default is false that is not show, can use true that is show. 
 * @param {'top-start'|'top-center'|'top-end'|'bottom-start'|'bottom-center'|'bottom-end'|'left-start'|'left-center'|'left-end'|'right-start'|'right-center'|'right-end'|'top-max'|'bottom-max'|'left-max'|'right-max'|'max'|'center'|'left'|'right'|'top'|'bottom'} [options.placement='top'] - The display position of the search.
 * @param {'sm'|'md'|'lg'|'xl'|'xxl'} [options.size='sm'] - The retrievalwidth.
 * @param {number} [options.duration=0] - The animation duration to open and close the search, if it is 0 then use the animation duration defined in css, in ms.
 * @param {boolean} [options.asleep=false] - Does the retrievalnot close after opening.
 * @param {classes} [options.classes=''] - The classes of the search, can fill in more than one, write the same "ax.classes.add"
 * @param {string|boolean} [options.padding=true] - Whether or not to show the inner padding of the search, can be a boolean value or a class name, default with padding, can be filled with false,true,"_p","_p-xxl", etc.
 * @param {getContent} [options.content=''] - The retrievalcontent, can be filled with a string (#id or html),a node,a json,an object,an array,a function name,a Promise or an AsyncFunction, the same as "getContent" function.
 * @param {'text'|'html'|'image'|'video'|'audio'|'iframe'|'form'|'async'|'auto'} [options.contType='text'] - Specify the type of retrievalcontent.If you fill in "auto", it means that the content is not text, and the system will automatically determine the content type, including "Function", "Promise", "AsyncFunction", "Object", "Array" and "HTMLElement".
 * @param {'post'|'get'} [options.ajaxType='post'] - The asynchronous submission method.
 * @param {object} [options.contData={}] - This parameter can be filled in if "contType" is "async" and "dataType" is "post"; this parameter can be used if you need to append attributes to the media node.
 * @param {string} [options.actClass='_opened'] - The class name added by target after opening the search.
 * @param {string} [options.tplStr=''] - If the data obtained is an object or an array, the content needs to be created automatically by the template, the parameter can be filled with a template id or a complete template text.
 * @param {function|null} [options.tplEng=null] - If or not using a third-party template engine, fill in "template" for Art-template engine, "mustache.render" for Mustache engine, "_.template" for Underscore engine, "ejs.render" for EJS engine.
 * @param {number} [options.zIndex=0] - The retrievallevel, the default is 0 that is, not set, if with other components occurs to obscure please set your own.
 * @param {object} [options.position={}] - The parameters of the positioning engine "ax.Position".
 * @param {object} [options.media={}] - The media data, used when contType is "image", "video", "audio" or "iframe".
 * @param {object} [options.media.caption] - The media caption/title.
 * @param {object} [options.media.brief] - The media brief/description.Multi-line text is allowed.
 * @param {object} [options.wing] - Setting up additional buttons to open the search.
 * @param {string} [options.wing.actClass=''] - The class name added by wing node after opening the search.
 * @param {object|boolean} [options.tools=true] - The tools Data(In the upper right corner of the search).
 * @param {boolean} [options.tools.enable=true] - Whether to display the tools.
 * @param {'inside'|'outside'} [options.tools.placement='inside'] - The placement of tools.
 * @param {createTools} [options.tools.children=['close']] - The placement of tools.Write the same as "ax.createTools".
 * @param {object|boolean} [options.footer=true] - The footer Data(In the bottom of the search).
 * @param {boolean} [options.footer.enable=true] - Whether to display the footer.
 * @param {'center'|'plain'|'right'|'left'} [options.footer.layout='plain'] - Buttons of footer Layout.
 * @param {createTools} [options.footer.note=false] - Show or not show note.Write the same as "ax.createTools".
 * @param {boolean} [options.footer.divider=false] - Whether or not to show the splitter line between footer and content.
 * @param {boolean} [options.footer.padding=false] - Whether to show the inner padding of the footer.
 * @param {createTools} [options.footer.children=['cancel', 'confirm']] - The placement of tools.Write the same as "ax.createTools".
 * 
 * @param {function|null} [options.onBeforeFill=null] - The listener function, executed after getting the content and before setting it, takes one argument, content, which may be a string, an object, or an array.
 * @param {function|null} [options.onBeforeShow=null] - The listener function, executed before the retrievalis displayed, no parameters.
 * @param {function|null} [options.onBeforeHide=null] - The listener function, executed before the retrievalis closed, no parameters.
 * @param {function|null} [options.onShow=null] - The listener function, executed after the retrievalis displayed, no parameters.
 * @param {function|null} [options.onHide=null] - The listener function, executed after the retrievalis closed, no parameters.
 * @param {function|null} [options.onValid=null] - The listener function, executed after form validation, support for a parameter that is the result of validation.
 * @param {function|null} [options.onUpdateCont=null] - The listener function, executed after the content is updated (asynchronous behavior), support for a parameter content that is the content of the update.
 * @param {function|null} [options.onChangePosition=null] - The listener function, executed when the retrievalposition is updated, supports one parameter placement.
 * @param {function|null} [options.onTransferPosition=null] - The listener function, executed after the replacement retrievalhost node is updated, supports two parameters i.e. the new host node and placement.
 * @param {function|null} [options.onConfirm=null] - The listener function, executed when the confirm button is clicked, supports one parameter, the button itself.
 * @param {function|null} [options.onCancel=null] - The listener function, executed when the cancel button is clicked, supports one parameter, the button itself.
 * 
 * @see {@link https://codepen.io/axui/pen/yLwbrvm|demo @ codepen}
 * @example
 * ax.Search('#id');
 */




import getEl from '../utils/getEl';
import extend from '../utils/extend';
import isEmpty from '../utils/isEmpty';
import instance from '../utils/instance';

import preventDft from '../utils/preventDft';

import { T_el, T_fn, T_fn_obj, T_obj, T_required, T_sel } from '../../../types/ax';
import contains from '../utils/contains';
import getEls from '../utils/getEls';
import getContent from '../utils/getContent';
import getDataType from '../utils/getDataType';
import Position from './Position';
import createFooter from '../utils/createFooter';
import renderTpl from '../utils/renderTpl';
import tplToEl from '../utils/tplToEl';
import isMobi from '../utils/isMobi';
import style from '../utils/style';
import easeHeight from '../utils/easeHeight';
import PubBase from './PubBase';
import pipe from '../utils/pipe';
import PubListen from './PubListen';
import PubUpdate from './PubUpdate';
import PubCommon from './PubCommon';
import Hover from './Hover';
import createTools from '../utils/createTools';
import ax from '../ax';
import classes from '../utils/classes';

import deepClone from '../utils/deepClone';
import validTools from '../utils/validTools';
import formTools from '../utils/formTools';
import { T_retrieval} from '../../../types/search';
import elState from '../utils/elState';
import { T_footer, T_btn_ft } from '../../../types/utils';
import delay from '../utils/delay';
import setContent from '../utils/setContent';
import optRetrievalfrom '../options/optSearch';
import prefix from '../global/prefix';
import Bubble from './Bubble';
import bulletinTools from '../utils/bulletinTools';

class Retrievalextends pipe(Bubble, PubListen, PubUpdate, PubCommon)(PubBase) {
    
    targetEl: any;
    options: T_required<T_search<0>> | T_obj = {};
    destroyed: any;
    
    plans: any;
    
    storKeys: any;
    storObs: any;
    storTmp: any;
    dftOpts: any;
    rawOpts: any;
    
    mainEl: any;
    contEl: any;
    formEl: any;
    wrapEl: any;
    bodyEl: any;
    headEl: any;
    footEl: any;
    confirmEl: any;
    cancelEl: any;
    closeEl: any;
    state: any;
    triggerShow: any;
    toggleShow: any;
    wings: any;
    content: any;
    template: any;
    duration: any;
    wrapHeight: any;
    contXhr: any;
    submitXhr: any;
    constructor(elem: T_sel, options: T_retrieval= {}, inital: boolean = true) {
        super();
        super.ready({
            options,
            host: elem,
            maps: optSearch,
            component: true,
            spread: ['status']
        });
        /**
        * @name Search.targetEl
        * @description Target element.
        * @type getEl
        */
        

        /**
        * @name Search.rawOpts
        * @description Raw Parameters of the instance from map.
        * @type object
        */
        
        /**
         * @name Search.dftOpts
         * @description Default Parameters of the instance from merging.The reset method requires this variable.
         * @type object
         */
        
        /**
         * @name Search.options
         * @description Parameters of the instance.
         * @type object
         */
        
        /**
         * @name Search.destroyed
         * @description Destruction state.
         * @type boolean
         */
        
        /**
        * @name Search.plans
        * @description Plans for listening.
        * @type object
        */
        
        /**
        * @name Search.storKeys
        * @description The set of parameter fields to save.
        * @type array
        */
        

        /**
         * @name Search.storTmp
         * @description Cache object.The "updateCache" method will update the variable.
         * @type object
         */
        
        /**
        * @name Search.storObs
        * @description Cache listener(proxy) that listens for "storTmp" changes and automatically updates the local storage.
        * @type any
        */
        
        /**
        * @name Search.timestamp
        * @description Instance creation time.
        * @type number
        */
        


        



        /**
        * @function Search.save
        * @description Storing settings locally.
        * @param {fn_cb_options} [cb] - Callback execution after saving local storage.
        * @returns {any} Return the instance itself
        */
        

        /**
        * @function Search.reset
        * @description Re-initialization of old parameters.
        * @param {fn_cb_none} [cb] - Call back after reset settings.
        * @returns {*} Return the instance itself
        */
        


        
    
        
        this.timestamp = new Date().getTime();


  

        
        super.listen({ name: 'ready' });
        
        inital ? this.init() : null;
    }
    /**
    * @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?: T_fn): Promise<any> {
        
        super.listen({ name: 'start' });
        
        this.setEmpty();
        

        


        
        super.listen({ name: 'init', cb });
        return this;
    }
    
    setAttrs() {
        
        this.targetEl.classList.add(`${prefix}search`)
        
        this.options.classes ? classes.add(this.targetEl, this.options.classes) : null;
        
        this.targetEl.setAttribute('scheme', this.options.scheme);
        
        this.options.dispose ? this.dispose() : null;
        
        this.options.expose ? this.targetEl.setAttribute('expose', '') : null;
        
        this.options.spill && !this.options.row.enable ? this.targetEl.setAttribute('spill', '') : null;
        
        this.options.gapless ? this.targetEl.setAttribute('gapless', '') : null;
        
        this.options.lamp ? this.targetEl.setAttribute('lamp', this.options.lamp) : null;
        
        this.options.full && !this.options.row.enable ? this.targetEl.setAttribute('full', '') : null;
        
        this.options.zIndex ? this.targetEl.style.zIndex = this.options.zIndex : null;
        
        if (this.options.row.enable) {
            
            this.targetEl.setAttribute('row', '');
            
            this.options.row.align ? this.targetEl.setAttribute('align', this.options.row.align) : null;
            
            if (this.options.row.headWidth) {
                let firstObj = this.flatData.filter((k: any) => k.floor === this.options.floorStart);
                firstObj.forEach((k: any) => {
                    k.wrapEl.style.width = this.options.row.headWidth;
                });
            }
            
            if (this.options.row.bodyWidth) {
                this.flatData.forEach((k: any) => {
                    k.bodyEl ? k.bodyEl.style.width = this.options.row.bodyWidth : null;
                })
            }
            
            if (this.options.row.marginLeft) {
                this.flatData.filter((k: any) => k.floor === this.options.floorStart).forEach((k: any) => {
                    k.wrapEl.style.marginLeft = this.options.row.marginLeft;
                })
            }
            if (this.options.row.marginRight) {
                this.flatData.filter((k: any) => k.floor === this.options.floorStart).forEach((k: any) => {
                    k.wrapEl.style.marginRight = this.options.row.marginRight;
                })
            }
        }
    }
   
}
export default Search;
