export abstract class Registry<K, V> {
  private _parent: Registry<K, V>;
  private _map: Map<K, V>;

  protected constructor(parent?: Registry<K, V>) {
    this._parent = parent;
    this._map = new Map<K, V>();
  }

  public get parent(): Registry<K, V> | undefined {
    return this._parent;
  }

  public get size(): number {
    return this._map.size;
  }

  public get(key: K): V | undefined {
    let v = this._map.get(key);
    if (undefined === v && undefined !== this._parent) {
      v = this._parent.get(key);
    }

    return v;
  }

  public has(key: K): boolean {
    let exist = this._map.has(key);
    if (!exist && undefined !== this._parent) {
      exist = this._parent.has(key);
    }
    return exist;
  }

  public set(key: K, value: V): void {
    this._map.set(key, value);
  }

  public entries(): IterableIterator<[K, V]> {
    return this._map.entries();
  }

  public keys(): IterableIterator<K> {
    return this._map.keys();
  }

  public values(): IterableIterator<V> {
    return this._map.values();
  }

  public clear(): void {
    this._map.clear();
  }

  public delete(key: K): boolean {
    let result = this._map.delete(key);
    if (!result && undefined !== this._parent) {
      result = this._parent.delete(key);
    }
    return result;
  }

  public forEach(callback: (vlaue: V, key: K, map: Map<K, V>) => void, thisArg?: any): void {
    this._map.forEach(callback, thisArg);
  }
}
