import ax from '../ax';
import createEl from '../utils/createEl';
import createTools from '../utils/createTools';
import elState from '../utils/elState';
import getAttrArr from '../utils/getAttrArr';
import getAttrBool from '../utils/getAttrBool';
import isEmpty from '../utils/isEmpty';
import renderTpl from '../utils/renderTpl';
import PlainElem from './PlainElem';
class InputElem extends PlainElem {
    constructor() {
        super();
        super.createObs();
        this.getRawData();
        this.fillWrap(this.propsProxy);
        this.inputEvent = new Event('input');
        this.reset = () => {
            for (let k in this.propsRaw) {
                (this.propsRaw[k] !== null && this.propsRaw[k] !== false) ? this.setAttribute(k, this.propsRaw[k]) : this.removeAttribute(k);
            }
            this.inputEl.value = '';
            this.inputEl.dispatchEvent(this.inputEvent);
            this.listen({ name: 'reset' });
        };
        this.clear = () => {
            this.inputEl.value = '';
            this.inputEl.dispatchEvent(this.inputEvent);
            this.listen({ name: 'clear' });
        };
        this.observer.ins.on('set', (data) => {
            this.initialized && this.updateCache({ [data.key]: data.value });
        });
    }
    static get observedAttributes() {
        return ['value', ...this.custAttrs, ...this.boolAttrs];
    }
    attributeChangedCallback(name, oldVal, newVal) {
        this.propsProxy[name] = InputElem.boolAttrs.includes(name) ? getAttrBool(newVal) : name === 'tools' ? getAttrArr(newVal, 'close') : newVal;
        if (InputElem.boolAttrs.includes(name)) {
            this.inputEl[name === 'readonly' ? 'readOnly' : name] = this.propsProxy[name];
        }
        else if (name === 'tools') {
            this.toolsEl && this.toolsEl.remove();
            if (this.propsProxy.tools.length > 0) {
                this.getToolsEl(this.propsProxy.tools);
                this.propsProxy.tools.forEach((k) => {
                    if (k.name === 'close') {
                        k.wrapEl.onclick = () => {
                            this.clear();
                        };
                    }
                    else {
                        k.action && k.action.bind(this);
                    }
                });
            }
        }
        else if (name === 'value') {
            let tmp = this.inputEl.value;
            this.inputEl.value = newVal;
            if (tmp !== newVal) {
                this.listen({ name: 'change', params: [{ name, oldVal: tmp, newVal }] });
            }
        }
        else if (name === 'limit') {
            this.updateLimit();
        }
        else if (['name', 'type', 'placeholder'].includes(name)) {
            this.inputEl.setAttribute(name, newVal);
        }
    }
    connectedCallback() {
        this.render();
        this.initialized = true;
        this.listen({ name: 'init' });
    }
    disconnectedCallback() {
    }
    adoptedCallback() {
    }
    getRawData() {
        [...InputElem.custAttrs, ...InputElem.lazyAttrs].forEach((k) => {
            this.propsRaw[k] = this.getAttribute(k);
        });
        InputElem.boolAttrs.forEach((k) => {
            this.propsRaw[k] = getAttrBool(this.getAttribute(k));
        });
        this.propsRaw.value = this.getAttribute('value') || this.innerHTML;
        for (let k in this.propsRaw) {
            this.propsProxy[k] = this.propsRaw[k];
        }
        this.propsProxy['tools'] = getAttrArr(this.getAttribute('tools'), 'close');
        this.innerHTML = '';
    }
    getToolsEl(data) {
        if (!isEmpty(data)) {
            this.toolsEl = createTools(data, this.wrapEl);
            this.toolsEl.setAttribute('role', 'tools');
        }
    }
    fillWrap(data) {
        this.wrapEl = createEl('div', { role: 'wrap' });
        this.inputEl = createEl('input', { type: data.type || 'text', name: data.name, placeholder: data.placeholder || ax.lang.form.placeholder });
        data.value && (this.inputEl.value = data.value);
        this.inputEl.multiple = data.multiple;
        this.wrapEl.appendChild(this.inputEl);
        this.getToolsEl(data.tools);
        this.limitEl = createEl('div', { role: 'limit' });
    }
    updateLimit() {
        let total = ~~this.propsProxy.limit, value = this.propsProxy.value, len = value.length, tmp = total - len, remaining = tmp <= 0 ? 0 : tmp;
        if (!total) {
            return this;
        }
        this.limitEl.innerHTML = renderTpl(ax.lang.form.maxLength, { total, value: len, remaining });
        if (tmp <= 0) {
            if (tmp < 0) {
                this.inputEl.value = value.slice(0, total);
                this.inputEl.dispatchEvent(this.inputEvent);
            }
            this.setAttribute('exceeded', '');
        }
        else {
            this.removeAttribute('exceeded');
        }
        elState(this.limitEl).isVirtual && this.appendChild(this.limitEl);
    }
    render() {
        this.appendChild(this.wrapEl);
        ~~this.propsProxy.limit && this.appendChild(this.limitEl);
        this.inputEl.addEventListener('input', (e) => {
            let tmp = this.propsProxy.value;
            this.propsProxy.value = this.inputEl.value;
            this.updateLimit();
            let data = { name: 'value', oldVal: tmp, newVal: this.inputEl.value };
            this.listen({ name: 'input', params: [data] });
            (tmp !== this.inputEl.value) && this.listen({ name: 'change', params: [data] });
        }, false);
    }
}
InputElem.lazyAttrs = ['stor-name'];
InputElem.custAttrs = [
    'class',
    'name', 'placeholder', 'type', 'size', 'limit', 'tools',
    'on-init', 'on-reset', 'on-clear', 'on-change', 'on-input', 'on-set',
];
InputElem.boolAttrs = ['disabled', 'readonly', 'multiple'];
window.customElements.define("ax-input", InputElem);
export default InputElem;
