/**
 * @since Last modified: 2024/05/30 16:04:56
 * @namespace fieldTools
 * @description Operations on multi-value form fields, such as select-multiple, file-multiple, checkbox, radio types.
 * @see {@link https://codepen.io/axui/pen/jOJbJMy|demo @ codepen}
 */





'use strict';
import { T_el, T_fn, T_sel } from '../../../types/ax';
import clampVal from './clampVal';
import getDataType from './getDataType';
import getEl from './getEl';
import isEmpty from './isEmpty';

type T_field = {
    getVals: T_fn;
    setVals: T_fn;
    reset: T_fn;
    getType: T_fn;
}
const fieldTools: T_field = {
    getType: (target: T_sel) => {
        let targetEl = getEl(target),
            result = '';
        if (!targetEl) { return result }
        result = (['TEXTAREA', 'SELECT', 'INPUT'].includes(targetEl.nodeName)) ? 'native' :
            (['AX-RADIOS', 'AX-CHECKBOXES'].includes(targetEl.nodeName)) ? 'cmpt-group' :
                (['AX-RADIO', 'AX-CHECKBOXE', 'AX-INPUT', 'AX-FILE', 'AX-TEXTAREA', 'AX-NUMBERR', 'AX-RANGE', 'AX-DATE', 'AX-SELECT'].includes(targetEl.nodeName)) ? 'cmpt-single' : '';
        return result;
    },
    /**
 * @memberOf fieldTools
 * @description Get field data of form fields, including multi-valued form fields and sigle-valued form fields.
 * @param {object} obj  - Parameters.
 * @param {getEl} obj.el  - Dom selector of input.
 * @param {""|"string"|"array"} [obj.format=""]  - Output value type.
 * @param {getEl} [obj.parent=el.closest('form')]  - The parent Dom of input.If el itself is not a form field, you need to use this parameter to specify the parent node of the form field.
 * @param {string} [obj.separator=","]  - The separator character of Output value.if format=false,can use the parameter.
 * @returns {array|string} Return a value array of value string.
 * @see {@link https://codepen.io/axui/pen/jOJbJMy|demo @ codepen}
 * @example
 * ax.fieldTools.getVals({el:'select'});
 * <!--return ['BJ','SH','TJ']-->
 */
    
    
    
    
    
    
    getVals: function ({ el, format = '', parent, separator = ',' }: { el: T_sel, type?: string, format?: '' | 'string' | 'array', parent?: T_sel, separator?: string }): any {
        let targetEl = getEl(el),
            targetType = this.getType(targetEl),
            values: any[] = [],
            none = format === 'array' ? [] : format === 'string' ? '' : null,
            result: any;
        try {
            if (targetEl) {
                if (targetType === 'cmpt-group') {
                    let tmp = targetEl.properties.value.toString();
                    
                    
                    result = format === 'array' ? tmp.split(separator) : tmp;
                } else if (targetType === 'native') {
                    let fieldType = targetEl.type,
                        parentDom = getEl(parent) || targetEl.closest('form') || document.body;
                    if (fieldType.includes('select')) {
                        
                        let options = [...targetEl.options];
                        options.forEach((k: any) => {
                            
                            
                            k.selected && k.getAttribute('value') ? values.push(k.value) : null;
                        });
                    } else if (fieldType === 'checkbox' || fieldType === 'radio') {
                        
                        let fields = [...parentDom.querySelectorAll(`[name="${targetEl.name}"]`)];
                        fields.forEach((k: any) => {
                            
                            
                            k.checked && k.getAttribute('value') ? values.push(k.value) : null;
                        });
                    } else if (fieldType === 'file') {
                        console.log(2)
                        
                        values = [...targetEl.files];
                    } else {
                        
                        values = targetEl.value ? [targetEl.value] : [];
                    }
                    
                    
                    
                    

                    
                    if (format === 'string') {
                        
                        result = (fieldType === 'file') ? values.map((k: any) => k.name.trim()).join(separator) : values.join(separator);
                    } else if (format === 'array') {
                        
                        result = values;
                    } else {
                        
                        result = ['select-multiple', 'checkbox', 'file'].includes(fieldType) ? values : (values[0] || '');
                    }
                }
                return result;
            }
        } catch (err: any) {
            console.warn(err);
            return none;
        }
    },
    /**
    * @memberOf fieldTools
    * @description Set the values of select, checkbox and radio. File cannot be set (it is read-only).
    * @param {object} obj  - Parameters.
    * @param {getEl} obj.el  - Dom selector of field.
    * @param {string | number | string[] | number[]} [obj.val]  - The data for setting.
    * @param {getEl} [obj.parent=closet('form')]  - The parent Dom of input.If el itself is not a form field, you need to use this parameter to specify the parent node of the form field.
    * @returns {null} - Return null.
    * @see {@link https://codepen.io/axui/pen/jOJbJMy|demo @ codepen}
    * @example
    * ax.fieldTools.setVals({'#demo',val:['read','travel']});
    * <!--return null-->
    */
    
    
    
    
    
    setVals: function ({ el, val, parent, separator = ',' }: { el: T_sel, val?: string | number | string[] | number[], parent?: T_sel, separator?: string }): void {
        
        
        
        
        let targetEl = getEl(el),
            
            values = isEmpty(val) ? [] : (!Array.isArray(val) ? [val] : val),
            parentDom = getEl(parent) || targetEl?.closest('form') || document.body,
            fields: any = [];
        if (targetEl) {
            let targetType = this.getType(targetEl);
            if (targetType === 'cmpt') {
                
                let tmp = Array.isArray(val) ? val.join(separator) : val?.toString();
                targetEl.setAttribute('value', tmp);
            } else if (targetType === 'native') {
                let fieldType = targetEl.type;
                if (fieldType.includes('select')) {
                    
                    let options = [...targetEl.options].filter((k: any) => k.getAttribute('value')),
                        
                        tmp: string[] = values.map((k: any) => k.toString());
                    options.forEach((k: any) => {
                        k.selected = tmp.includes(k.value) ? true : false;
                    });
                    
                    fields = [targetEl];
                } else if (fieldType === 'checkbox' || fieldType === 'radio') {
                    
                    fields = [...parentDom.querySelectorAll(`[name="${targetEl.name}"]`)].filter((k: any) => k.getAttribute('value'));
                    
                    let tmp: string[] = values.map((k: any) => k.toString());
                    fields.forEach((k: any) => {
                        k.checked = tmp.includes(k.value) ? true : false;
                    });
                } else if (fieldType === 'file') {
                    
                    targetEl.value = '';
                    console.warn('The field.files property cannot be changed through scripts,this operation is performed by resetting!');
                } else if (fieldType === 'number') {
                    
                    targetEl.value = clampVal({
                        val: values[0] || 0,
                        min: targetEl.min,
                        max: targetEl.max
                    });
                } else if (fieldType === 'range') {
                    
                    targetEl.value = values[0] || targetEl.min || 0;
                } else {
                    
                    targetEl.value = values[0] || '';
                }
            }
        }
    },
    /**
    * @memberOf fieldTools
    * @description Multi-valued fields reset to zero.
    * @param {getEl} obj.el  - Dom selector of field.
    * @param {boolean} [obj.zero=false]  - Whether to return to zero directly.
    * @param {getEl} [obj.parent=closet('form')]  - The parent Dom of input.If el itself is not a form field, you need to use this parameter to specify the parent node of the form field.
    * @returns {null} - Return null.
    * @see {@link https://codepen.io/axui/pen/jOJbJMy|demo @ codepen}
    * @example
    * ax.fieldTools.reset({el:'#demo'});
    * <!--return null-->
    */
    
    
    
    
    reset: function ({ el, parent, zero = false }: { el: T_sel, parent?: T_sel, zero?: boolean }): void {
        let fieldEl = getEl(el);
        if (!fieldEl) { return; }
        let fielType = this.getType(fieldEl),
            type = fieldEl.type;
        if (fielType === 'native') {
            if (type?.includes('select')) {
                
                [...fieldEl?.options].forEach((i: any) => i.selected = !zero ? i.defaultSelected : false);
            } else if (type === 'checkbox' || type === 'radio') {
                
                let parentDom = getEl(parent) || fieldEl?.closest('form') || document.body,
                    fields = [...parentDom.querySelectorAll(`[name="${fieldEl?.name}"]`)];
                fields.forEach((k: any) => {
                    k.checked = !zero ? k.defaultChecked : false;
                });
            } else if (['number', 'range'].includes(type)) {
                
                (fieldEl as T_el).value = !zero ? fieldEl?.defaultValue : (fieldEl?.min || 0);
            } else {
                
                (fieldEl as T_el).value = !zero ? fieldEl?.defaultValue : '';
            }
        } else if (fielType === 'cmpt') {
            
            zero ? fieldEl.clear() : fieldEl.reset();
        } else if (fielType === 'other') {
            
            if (zero && fieldEl.clear) {
                fieldEl.clear();
            } else if (!zero && fieldEl.reset) {
                fieldEl.reset();
            }
        }

    }

}
export default fieldTools;
