/*
 ecsjs is an entity component system library for JavaScript
 Copyright (C) 2014 Peter Flannery

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as
 published by the Free Software Foundation, either version 3 of the
 License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
import { ComponentClassesMapKey, ComponentMapKey, type KeyCollection } from './types.js';

/**
 * Component map for storing entity ids and related component data
 * @category Maps
 */
export class ComponentMap<TComponentInstance> extends Map<number, TComponentInstance> {

  /**
   * Returns the first entity entry
   */
  firstEntry(): [entityId: number, value: TComponentInstance] | undefined {
    if (this.size === 0) return undefined;

    const iterator = this.entries();
    const result = iterator.next();
    return result.value;
  }

  /**
   * Returns the first entity id
   */
  firstKey(): number | undefined {
    if (this.size === 0) return undefined;

    const iterator = this.keys();
    const result = iterator.next();
    return result.value;
  }

  /**
   * Returns the first entity value
   */
  firstValue(): TComponentInstance | undefined {
    if (this.size === 0) return undefined;

    const iterator = this.values();
    const result = iterator.next();
    return result.value;
  }

  /**
   * Called when using JSON.stringify
   */
  toJSON() {
    return { [ComponentMapKey]: 1, iterable: [...this.entries()] };
  }

  toTable(excludeKeys = false): any[] {
    const table = []
    for (const [key, value] of this.entries()) {
      const entity = value as { new(): TComponentInstance };
      const meta: KeyCollection<any> = {};
      if (excludeKeys == false) meta["entity.key"] = key;
      meta["entity.type"] = entity.constructor.name;
      table.push({ ...meta, ...entity });
    }
    return table;
  }

  /**
   * Prints entity data in a tabular format to the console
   */
  printTable(excludeKeys = false): void {
    console.table(this.toTable(excludeKeys));
  }

  static get [Symbol.species]() {
    return Map;
  }

}

/**
 * Component class map for storing registered component maps
 * @category Maps
 */
export class ComponentClassesMap extends Map<string, ComponentMap<any>> {

  /**
   * Called when using JSON.stringify
   */
  toJSON() {
    return { [ComponentClassesMapKey]: 1, iterable: [...this.entries()] };
  }

  static get [Symbol.species]() {
    return Map;
  }

}