/*!
 * KoliBri - The accessible HTML-Standard
 */
import { validateMultiple, validateOptionsWithOptgroup, validateRequired, validateRows, watchJsonArrayString } from "../../schema";
import { InputIconController } from "../@deprecated/input/controller-icon";
import { fillKeyOptionMap } from "../input-radio/controller";
export class SelectController extends InputIconController {
    constructor(component, name, host) {
        super(component, name, host);
        this.keyOptionMap = new Map();
        this.getOptionByKey = (key) => this.keyOptionMap.get(key);
        this.isValueInOptions = (value, options) => {
            return (options.find((option) => typeof option.value === 'string'
                ? option.value === value
                : Array.isArray(option.options)
                    ? this.isValueInOptions(value, option.options)
                    : false) !== undefined);
        };
        this.filterValuesInOptions = (values, options) => {
            return values.filter((value) => this.isValueInOptions(value, options) !== undefined);
        };
        this.afterPatchOptions = (value, _state, _component, key) => {
            if (key === '_value') {
                this.setFormAssociatedValue(value);
            }
        };
        this.beforePatchOptions = (_value, nextState) => {
            const raw = nextState.get('_value');
            if (raw !== undefined && !Array.isArray(raw)) {
                nextState.set('_value', [raw]);
            }
            const options = nextState.has('_options') ? nextState.get('_options') : this.component.state._options;
            if (Array.isArray(options) && options.length > 0) {
                this.keyOptionMap.clear();
                fillKeyOptionMap(this.keyOptionMap, options);
                const value = nextState.has('_value') ? nextState.get('_value') : this.component.state._value;
                const selected = this.filterValuesInOptions(Array.isArray(value) && value.length > 0 ? value : [], options);
                if (this.component._multiple === false && selected.length === 0) {
                    nextState.set('_value', [
                        options[0].value,
                    ]);
                }
                else if (Array.isArray(value) && selected.length < value.length) {
                    nextState.set('_value', selected);
                }
            }
        };
        this.component = component;
    }
    validateOptions(value) {
        validateOptionsWithOptgroup(this.component, value, {
            hooks: {
                afterPatch: this.afterPatchOptions,
                beforePatch: this.beforePatchOptions,
            },
        });
    }
    validateMultiple(value) {
        this.assertComponentValueMatchesMultiplicity(value === true);
        validateMultiple(this.component, value, {
            hooks: {
                afterPatch: this.afterPatchOptions,
                beforePatch: this.beforePatchOptions,
            },
        });
    }
    validateRequired(value) {
        validateRequired(this.component, value);
    }
    validateRows(value) {
        validateRows(this.component, value);
    }
    validateValue(value) {
        this.assertValueMatchesMultiplicity(value);
        watchJsonArrayString(this.component, '_value', () => true, value === undefined ? [] : Array.isArray(value) ? value : [value], undefined, {
            hooks: {
                afterPatch: this.afterPatchOptions,
                beforePatch: this.beforePatchOptions,
            },
        });
    }
    componentWillLoad() {
        super.componentWillLoad();
        this.validateOptions(this.component._options);
        this.validateMultiple(this.component._multiple);
        this.validateRequired(this.component._required);
        this.validateRows(this.component._rows);
        this.validateValue(this.component._value);
    }
    assertValueMatchesMultiplicity(value) {
        const isArray = Array.isArray(value);
        const isMultiple = this.component._multiple === true;
        if (isMultiple) {
            if (value !== undefined && !isArray) {
                throw new Error(`↑ The schema for the property (_value) is not valid for multiple mode. Expected an array. The value will not be changed. (received = ${JSON.stringify(value)})`);
            }
        }
        else {
            if (isArray) {
                throw new Error(`↑ The schema for the property (_value) is not valid for single mode. Expected a single value. The value will not be changed. (received = ${JSON.stringify(value)})`);
            }
        }
    }
    assertComponentValueMatchesMultiplicity(isMultiple) {
        const rawValue = this.component._value;
        if (isMultiple) {
            if (rawValue !== undefined && !Array.isArray(rawValue)) {
                throw new Error(`↑ The schema for the property (_value) is not valid for multiple mode. Expected an array. The value will not be changed. (current = ${JSON.stringify(rawValue)})`);
            }
        }
        else {
            if (Array.isArray(rawValue)) {
                throw new Error(`↑ The schema for the property (_value) is not valid for single mode. Expected a single value. The value will not be changed. (current = ${JSON.stringify(rawValue)})`);
            }
        }
    }
}
//# sourceMappingURL=controller.js.map
