import { r as registerInstance, c as createEvent, h, g as getElement, H as Host } from './index-442cf464.js';
import { f as findRelevantOptions } from './mutation-oberserver-ac258d15.js';

const FormValidation = class {
  constructor(hostRef) {
    registerInstance(this, hostRef);
    this.luFormValidationValueChange = createEvent(this, "luFormValidationValueChange", 7);
    this.luFormValidationDidLoad = createEvent(this, "luFormValidationDidLoad", 7);
    this.luFormValidationDidUnload = createEvent(this, "luFormValidationDidUnload", 7);
    this.formValidationId = `lu-form-validation-${validationCompIds++}`;
    /**
     * List of form groups
     */
    this.formGroups = [];
    /**
     * wrapping validation valid state
     */
    this.wrappingValidationIsValid = false;
    /**
     * wrapping validation invalid state
     */
    this.wrappingValidationIsInvalid = false;
    /**
     * failed wrapping validators
     */
    this.failedWrappingValidatorsData = [];
    /**
     * You can pass an error message with a custom wrapping validation function that receives a validation state array
     */
    this.wrappingValidation = [];
    /**
     * values of form
     */
    this.value = [];
    this.useId = this.formValidationId;
    /**
     * Shows form is valid
     */
    this.isValid = false;
    /**
     * Shows form is invalid
     */
    this.isInvalid = false;
    this.mutationCallback = (mutationList, _observer) => {
      mutationList.forEach((record) => {
        if (record.type === 'childList') {
          for (let i = 0; i < record.addedNodes.length; i++) {
            const relevantOptions = findRelevantOptions(record.addedNodes[i], 'lu-form-group');
            if (relevantOptions)
              relevantOptions.forEach((option) => this.handleNewFormGroup(option, false));
          }
          for (let i = 0; i < record.removedNodes.length; i++) {
            const relevantOptions = findRelevantOptions(record.removedNodes[i], 'lu-form-group');
            if (relevantOptions)
              relevantOptions.forEach(this.luFormGroupDidUnload);
          }
        }
      });
    };
    this.handleNewFormGroup = async (formGroup, dontReAdd = false) => {
      formGroup.addEventListener('luFormGroupDidUpdate', (ev) => this.luFormGroupDidUpdate(ev.target));
      if (!dontReAdd) {
        this.formGroups = [...this.formGroups, formGroup];
      }
      this.updateAllValues();
    };
    this.luFormGroupDidUpdate = async (_formGroup) => {
      this.updateAllValues();
    };
    this.luFormGroupDidUnload = (formGroup) => {
      this.unloadCommon(formGroup);
      this.updateAllValues();
    };
    this.unloadCommon = (formGroup) => {
      formGroup.removeEventListener('luFormGroupDidUpdate', (ev) => this.luFormGroupDidUpdate(ev.target));
      const index = this.formGroups.indexOf(formGroup);
      if (index > -1) {
        this.formGroups.splice(index, 1);
      }
    };
  }
  async valueUpdated() {
    await this.validateFormWithCurrentValues();
    this.luFormValidationValueChange.emit(await this.getValidationValue());
  }
  /**
   * This provides a way to update values of the form while preventing immediate re-validation
   * Don't forget that you need the name and value for checkbox [{name: string, checked: boolean}]
   * For selects pass the name for the option
   * @param updates
   */
  async updateValues(updates) {
    updates.forEach((update) => {
      const currentValue = this.value.filter((value) => {
        return value.name === update.name;
      })[0];
      if (currentValue) {
        const foundGroup = this.formGroups.filter((formGroup) => {
          return formGroup.id === currentValue.id;
        })[0];
        foundGroup.updateValue(update.value);
      }
      else {
        console.error('Attempted to set value with an invalid name.');
      }
    });
  }
  /**
   * forces validation on all components and return the validation object
   */
  async forceValidation() {
    const promises = [];
    this.formGroups.forEach((group) => {
      promises.push(group.validate());
    });
    await Promise.all(promises);
    await this.sleep(100);
    return this.getValidationValue();
  }
  async connectedCallback() {
    this.formGroups = Array.from(this.el.querySelectorAll('lu-form-group'));
    this.formGroups.forEach((fg) => this.handleNewFormGroup(fg, true));
    const el = this.el;
    this.mutationO = new MutationObserver(this.mutationCallback);
    this.mutationO.observe(el, {
      childList: true,
      subtree: true
    });
  }
  async disconnectedCallback() {
    this.formGroups.forEach((formGroup) => {
      formGroup.removeEventListener('luFormGroupDidUpdate', (ev) => this.luFormGroupDidUpdate(ev.target));
    });
    this.formGroups = [];
    this.mutationO.disconnect();
    this.mutationO = undefined;
  }
  async updateAllValues() {
    let promises = [];
    this.formGroups.forEach((formGroup) => {
      promises.push(formGroup.getValidationValues());
    });
    this.value = await Promise.all(promises);
    return this.value;
  }
  async getElementValidationState(formGroup) {
    return await formGroup.getValidationValues();
  }
  async getValidationValue() {
    return {
      id: this.useId,
      primaryCompoundId: this.primaryCompoundId,
      isValid: this.isValid,
      isInvalid: this.isInvalid,
      value: this.value,
      wrappingValidation: {
        isValid: this.wrappingValidationIsValid,
        isInvalid: this.wrappingValidationIsInvalid,
        failedWrappingValidations: this.failedWrappingValidatorsData
      }
    };
  }
  componentDidLoad() {
    this.luFormValidationDidLoad.emit();
  }
  /**
   * @Deprecated
   */
  componentDidUnload() {
    this.luFormValidationDidUnload.emit();
  }
  async validateWrappingValidators() {
    this.failedWrappingValidatorsData = this.wrappingValidation.filter((functionValidator) => !functionValidator.function(this.value)).map((validator) => {
      return {
        name: validator.name,
        message: validator.message
      };
    });
    if (this.failedWrappingValidatorsData.length > 0)
      this.setWrappingValidationStateAsInvalid();
    if (this.failedWrappingValidatorsData.length === 0 || this.wrappingValidation.length === 0)
      this.setWrappingValidationStateAsValid();
  }
  async validateFormWithCurrentValues() {
    await this.validateWrappingValidators();
    this.isInvalid = this.value.filter(({ isInvalid }) => isInvalid === true).length > 0 || this.value.filter(({ isValid }) => isValid === false).length > 0 || this.wrappingValidationIsInvalid;
    this.isValid = this.value.filter(({ isInvalid }) => isInvalid === true).length === 0 && this.value.filter(({ isValid }) => isValid === false).length === 0 && this.wrappingValidationIsValid;
  }
  /**
   * sets state properly for invalid
   */
  setWrappingValidationStateAsInvalid() {
    this.wrappingValidationIsValid = false;
    this.wrappingValidationIsInvalid = true;
  }
  /**
   * sets state properly for valid
   */
  setWrappingValidationStateAsValid() {
    this.wrappingValidationIsValid = true;
    this.wrappingValidationIsInvalid = false;
  }
  sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
  render() {
    return (h(Host, { id: this.useId }));
  }
  get el() { return getElement(this); }
  static get watchers() { return {
    "value": ["valueUpdated"]
  }; }
};
let validationCompIds = 0;

export { FormValidation as lu_form_validation };

//# sourceMappingURL=lu-form-validation.entry.js.map