import { EnumValidateState } from './enums';
import { IResultOfValidate } from './Page/ValidatingControl';

interface ICancellableEvent<T> {
  add(eventHandler: (eventArgs: T) => void): void;
  remove(eventHandler: (eventArgs: T) => void): void;
}

interface ICancellableEventArgs {
  cancel: boolean;
}

export class CancellableEvent<T extends ICancellableEventArgs>
  implements ICancellableEvent<T> {
  private _eventHandlers = new Array<(eventArgs: T) => void>();

  public add(eventHandler: (eventArgs: T) => void): void {
    if (this._eventHandlers.indexOf(eventHandler) === -1) {
      this._eventHandlers.push(eventHandler);
    }
  }

  public remove(eventHandler: (eventArgs: T) => void): void {
    var i = this._eventHandlers.indexOf(eventHandler);
    if (i !== -1) {
      this._eventHandlers.splice(i, 1);
    }
  }

  public raise(e: T): void {
    var eventHandlers = this._eventHandlers.slice(0);
    for (var i = 0, j = eventHandlers.length; i < j && !e.cancel; i++) {
      try {
        eventHandlers[i](e);
      } catch (ex) {
        console.error(ex, e);
      }
    }
  }
}

export class ValidationEventArgs implements ICancellableEventArgs {
  public state: EnumValidateState = EnumValidateState.valid;
  public cancel: boolean = false;
  public error: string = '';

  public result = (): IResultOfValidate => {
    if (this.state === EnumValidateState.valid) {
      return true;
    } else {
      return [this.error, this.state];
    }
  };
}

export class ValidationChain {
  private _validators = new CancellableEvent<ValidationEventArgs>();

  public get validators(): ICancellableEvent<ValidationEventArgs> {
    return this._validators;
  }

  public validate(): IResultOfValidate {
    const eventArgs = new ValidationEventArgs();

    this._validators.raise(eventArgs);

    return eventArgs.result();
  }
}
