/**
 * @since Last modified: 2024/03/04 15:57:45
 * @namespace multiField
 * @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 getDataType from './getDataType';
import getEl from './getEl';
import isEmpty from './isEmpty';
const multiField = {
    /**
 * @memberOf multiField
 * @description Get array data of multi-valued form fields, including select-one, select-multiple, checkbox, radio and file types.
 * @param {object} obj  - Parameters.
 * @param {getEl} obj.el  - Dom selector of input.
 * @param {select|file|checkbox|radio} [obj.type="checkbox"]  - The input type.If el itself is not a form field, you need to use this parameter to specify the form field type.
 * @param {""|"string"|"array"} [obj.format=""]  - Output value type.
 * @param {getEl} [obj.parent=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.multiField.get('select');
 * <!--return ['BJ','SH','TJ']-->
 */
    get: ({ el, type = 'checkbox', format = '', parent, separator = ',' }) => {
        let items, values = [], none = format === 'array' ? [] : format === 'string' ? '' : null, elType = getDataType(el), input, inputType, isMulti = false, result;
        try {
            if (elType === 'Array' || elType === 'NodeList') {
                if (el.length > 0) {
                    let node = el[0].type;
                    if (['checkbox', 'radio'].includes(node)) {
                        type = node;
                        items = [...el];
                        isMulti = type === 'checkbox' ? true : false;
                    }
                    else {
                        items = [];
                    }
                }
                else {
                    return none;
                }
            }
            else {
                input = getEl(el);
                inputType = input?.type;
                if (input) {
                    let parentDom = getEl(parent) || input.closest('form') || document.body;
                    if (['select-one', 'select-multiple', 'file', 'checkbox', 'radio'].includes(inputType)) {
                        items = (inputType.includes('select')) ? [...input.options] : //select类型即是其选项节点
                            (inputType === 'file') ? [...input.files] : //file类型即是其文件数据
                                (inputType === 'checkbox' || inputType === 'radio') ? [...parentDom.querySelectorAll(`[name="${input.name}"]`)] : [];
                        type = (inputType.includes('select')) ? 'select' : inputType;
                        isMulti = (type === 'checkbox') ? true :
                            (type === 'radio') ? false : input.multiple;
                    }
                    else {
                        let host = (type === 'select') ? input.querySelector('select') :
                            (type === 'file') ? input.querySelector(`input[type="${type}"]`) : { multiple: false }, temp = (type === 'select') ? host?.options :
                            (type === 'file') ? host?.files :
                                (type === 'checkbox' || type === 'radio') ? input.querySelectorAll(`input[type="${type}"]`) : null;
                        if (temp) {
                            items = [...temp];
                            isMulti = (type === 'checkbox') ? true :
                                (type === 'radio') ? false : host.multiple;
                        }
                        else {
                            items = [];
                        }
                    }
                }
                else {
                    return none;
                }
            }
            if (type === 'select') {
                values = items.filter((k) => k.selected && k.getAttribute('value')).map(k => k.value.trim()).filter(Boolean);
            }
            else if (type === 'radio' || type === 'checkbox') {
                values = items.filter((k) => k.checked && k.getAttribute('value')).map(k => k.value.trim()).filter(Boolean);
            }
            else if (type === 'file') {
                values = items;
            }
            if (format === 'string') {
                result = (type === 'file') ? values.map((k) => k.name.trim()).join(separator) : values.join(separator);
            }
            else if (format === 'array') {
                result = values;
            }
            else {
                result = (type === 'file' && !isMulti) ? (values[0] || null) :
                    (!isMulti) ? (values[0] || '') : values;
            }
            return result;
        }
        catch {
            return none;
        }
    },
    /**
    * @memberOf multiField
    * @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.multiField.set({'#demo',val:['read','travel']});
    * <!--return null-->
    */
    set: ({ el, val, parent, cb }) => {
        let fieldDom = getEl(el), fieldType = fieldDom?.type, data = isEmpty(val) ? [] : (!Array.isArray(val) ? [val] : val), types = ['select-one', 'select-multiple', 'checkbox', 'radio'], parentDom = getEl(parent) || fieldDom?.closest('form') || document.body;
        if (!fieldDom || !types.includes(fieldType)) {
            return;
        }
        try {
            if (fieldType.includes('select')) {
                let options = [...fieldDom.options];
                options.forEach((k) => {
                    k.selected = data.includes(k.value) ? true : false;
                });
            }
            else if (fieldType === 'checkbox' || fieldType === 'radio') {
                let fields = [...parentDom.querySelectorAll(`[name="${fieldDom.name}"]`)];
                fields.forEach((k) => {
                    k.checked = data.includes(k.value) ? true : false;
                });
            }
            cb && cb(fieldDom, data);
        }
        catch (e) {
        }
        ;
    },
    /**
    * @memberOf multiField
    * @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.multiField.reset({el:'#demo'});
    * <!--return null-->
    */
    reset: ({ el, parent, zero = false }) => {
        let fieldDom = getEl(el), type = fieldDom?.type;
        if (type) {
            if (type?.includes('select')) {
                [...fieldDom.options].forEach((i) => i.selected = zero ? i.defaultSelected : false);
            }
            else if (type === 'checkbox' || type === 'radio') {
                let parentDom = getEl(parent) || fieldDom?.closest('form') || document.body, fields = [...parentDom.querySelectorAll(`[name="${fieldDom.name}"]`)];
                fields.forEach((k) => {
                    k.checked = zero ? k.defaultChecked : false;
                });
            }
            else {
                fieldDom.value = zero ? fieldDom.defaultValue : '';
            }
        }
    }
};
export default multiField;
