import { BaseSelfControl } from './BaseSelfControl';
import { IControlSimulateKey } from '../Page/Events';
import { ValidationEventArgs, ValidationChain } from '../chainOfResponsibility';
import { EnumValidateState } from '../enums';

export class SelfString extends BaseSelfControl<
  string,
  string,
  string,
  HTMLInputElement
> {
  minLength: number | undefined;
  maxLength: number | undefined;

  private validateNormal = (eventArgs: ValidationEventArgs) => { };
  private validateRequired = (eventArgs: ValidationEventArgs) => {
    if (this.required) {
      if (!this.value) {
        eventArgs.error = 'اطلاعاتی وارد نشده است';
        eventArgs.state = EnumValidateState.empty;
        eventArgs.cancel = true;
      }
    }
  };
  private validateMinLength = (eventArgs: ValidationEventArgs) => {
    if (this.minLength) {
      if (typeof this.value !== 'string' || this.value === '') {
        if (this.required) {
          eventArgs.error = `اطلاعاتی وارد نشده  است. حداقل طول مجاز: ${this.minLength}`;
          eventArgs.state = EnumValidateState.maxLength;
          eventArgs.cancel = true;
        }
      } else if (this.value.length < this.minLength) {
        eventArgs.error = `طول مقدار وارد شده کمتر از مقدار مجاز میباشد. حداقل طول مجاز:  ${this.minLength}`;
        eventArgs.state = EnumValidateState.maxLength;
        eventArgs.cancel = true;
      }
    }
  };
  private validateMaxLength = (eventArgs: ValidationEventArgs) => {
    if (this.maxLength) {
      if (this.value && this.value.length > this.maxLength) {
        eventArgs.error = `طول مقدار وارد شده بیشتر از مقدار مجاز میباشد. حداکثر طول مجاز: ${this.maxLength}`;
        eventArgs.state = EnumValidateState.maxLength;
        eventArgs.cancel = true;
      }
    }
  };

  isValueEmpty = () => {
    return typeof this.#value === 'string' && this.#value !== '';
  }
  isValueNotEmpty = () => {
    return !this.isValueEmpty();
  }

  validate = () => {
    var validationChain = new ValidationChain();

    validationChain.validators.add(this.validateNormal);
    validationChain.validators.add(this.validateRequired);
    validationChain.validators.add(this.validateMinLength);
    validationChain.validators.add(this.validateMaxLength);

    this.validation = validationChain.validate();
  };

  public cleaningClassInitializer = () => {
    this.timerOfIncorrectChar && clearTimeout(this.timerOfIncorrectChar);
    this.timer && clearTimeout(this.timer);
    this.hasChange = false;
    this.defaultValue = undefined;
    this.initializeProperties = false;
    this.initializeListener = false;
    this.validation = true;
  };

  public refreshHasChange = () => {
    if (this.showHasChangeFlag) {
      this.hasChange = this.defaultValue !== this.#value;
    }
  };
  public restartDefaultValue = () => {
    this.defaultValue = this.value;
    this.refreshHasChange();
  };

  #value: string;
  public get value() {
    return this.#value;
  }
  public set value(value: string) { }

  public setValue = (value: string) => {
    this.#value = value;
    this.refreshHasChange();
  };

  public deserialize = (value: string) => {
    this.#value = value;
    this.restartDefaultValue();
  };

  public useAsFilter: boolean = false;
  public timer?: NodeJS.Timeout | null;
  public triggerChangeFilters?: () => void;

  constructor(value: string) {
    super();
    this.#value = value;
    this.restartDefaultValue();
  }

  static empty(): SelfString {
    return new SelfString('');
  }
  static deserialize(value?: string): SelfString {
    return new SelfString(value || '');
  }
}

export interface INewPropertiesStringN {
  propertyName: string;
  onChangePropertyName: string | undefined;
  controlRef: React.RefObject<HTMLInputElement>;
  caption: string;
  showHasChangeFlag: boolean;
  maxLength: number | undefined;
  onErrorSimulateKey?: IControlSimulateKey;
}

export class SelfStringN extends BaseSelfControl<
  string | null,
  string | null,
  string | null,
  HTMLInputElement
> {
  private validateNormal = (eventArgs: ValidationEventArgs) => { };
  private validateRequired = (eventArgs: ValidationEventArgs) => {
    if (!this.value) {
      eventArgs.error = 'اطلاعاتی وارد نشده است';
      eventArgs.state = EnumValidateState.empty;
      eventArgs.cancel = true;
    }
  };
  private validateMinLength = (eventArgs: ValidationEventArgs) => { };
  private validateMaxLength = (eventArgs: ValidationEventArgs) => { };

  isValueEmpty = () => {
    return this.#value !== null;
  }
  isValueNotEmpty = () => {
    return !this.isValueEmpty();
  }
  public validate = () => {
    this.validation = true;
  };

  public cleaningClassInitializer = () => {
    this.hasChange = false;
    this.defaultValue = undefined;
    this.initializeProperties = false;
    this.initializeListener = false;
    this.validation = true;
  };

  public refreshHasChange = () => {
    if (this.showHasChangeFlag) {
      this.hasChange = this.defaultValue !== this.#value;
    }
  };
  public restartDefaultValue = () => {
    this.defaultValue = this.value;
    this.refreshHasChange();
  };

  #value: string | null;
  public get value() {
    return this.#value;
  }
  public set value(value: any) { }

  public setValue = (value: string | null) => {
    this.#value = value;
    this.refreshHasChange();
  };

  public deserialize = (value: string | null) => {
    this.#value = value;
    this.restartDefaultValue();
  };

  private _properties?: INewPropertiesStringN;
  public get properties() {
    return this._properties!;
  }
  public set properties(value: INewPropertiesStringN) {
    this._properties = value;
  }

  constructor(value: string | null) {
    super();
    this.#value = value;
    this.restartDefaultValue();
  }
  static empty(value?: string): SelfStringN {
    return new SelfStringN(value || null);
  }
  static deserialize(value?: string): SelfStringN {
    return new SelfStringN(value || null);
  }
  static createCopy(old: SelfStringN) {
    return new SelfStringN(old.#value);
  }
}
