import {
  PropertyKeyType,
} from '../type';

import {
  TypeUtil,
} from '../util/TypeUtil';

import { AccessibleObject } from './AccessibleObject';
import { Class } from './Class';
import { Member } from './Member';
import { Parameter } from './Parameter';

export abstract class Executable extends AccessibleObject implements Member {
  private _clazz: Class;
  private _name: PropertyKeyType;
  private _parameters: Parameter[];

  protected constructor(declaringClazz: Class, name: PropertyKeyType, parameterTypes?: any[]) {
    super();

    this._clazz = declaringClazz;
    this._name = name;

    if (undefined === parameterTypes) {
      return;
    }

    const parameterNames = TypeUtil.getParameterNames(declaringClazz.getType(), name);
    this._parameters = [];

    for (let i = 0; i < parameterTypes.length; i++) {
      const parameterType = parameterTypes[i];
      const parameterName = parameterNames[i];
      const parameter: Parameter = new Parameter(this, parameterType, parameterName, i);
      this._parameters.push(parameter);
    }
  }

  public getDeclaringClass(): Class {
    return this._clazz;
  }

  public getName(): PropertyKeyType {
    return this._name;
  }

  /**
   * getParameterCount
   */
  public getParameterCount(): number {
    if (null === this._parameters) {
      return 0;
    }
    return this._parameters.length;
  }
  /**
   * getParameters
   */
  public getParameters(): Parameter[] | undefined {
    return this._parameters;
  }
  /**
   * getParameter
   */
  public getParameter(index: number): Parameter | undefined {
    if (null === this._parameters) {
      return undefined;
    }
    if (0 > index || this._parameters.length <= index) {
      return undefined;
    }
    return this._parameters[index];
  }
}
