import { _decorator, instantiate, Node, NodePool, Prefab, Vec3 } from "cc";

const { ccclass } = _decorator;

/**
 * 对象池管理器
 */
@ccclass("PoolManager")
export class PoolManager {
  /** 单例实例 */
  private static _instance: PoolManager;

  /** 对象池字典 */
  private _dictPool: { [key: string]: NodePool } = {};

  /** 预制体字典 */
  private _dictPrefab: { [key: string]: Node } = {};

  /** 获取单例 */
  public static get instance(): PoolManager {
    if (!this._instance) {
      this._instance = new PoolManager();
    }
    return this._instance;
  }

  /**
   * 复制节点
   * @param sourceNode 源节点
   * @param parent 父节点
   * @returns 复制的节点
   */
  public copyNode(sourceNode: Node, parent?: Node): Node {
    const name = sourceNode.name;
    this._dictPrefab[name] = sourceNode;

    let node = null;
    if (this._dictPool.hasOwnProperty(name)) {
      // 从对象池获取
      const pool = this._dictPool[name];
      node = pool.size() > 0 ? pool.get() : instantiate(sourceNode);
    } else {
      // 创建新的对象池
      const pool = new NodePool();
      this._dictPool[name] = pool;
      node = instantiate(sourceNode);
    }

    if (parent) {
      node.parent = parent;
      node.active = true;
    }

    return node;
  }

  /**
   * 获取节点
   * @param prefab 预制体或预制体名称
   * @param parent 父节点
   * @param position 位置
   * @returns 节点实例
   */
  public getNode(prefab: Node | Prefab | string, parent?: Node, position?: Vec3): Node {
    let prefabNode: Node | Prefab;
    let prefabName: string;

    if (typeof prefab === "string") {
      prefabName = prefab;
      prefabNode = this._dictPrefab[prefab];
      if (!prefabNode) {
        console.log("Pool invalid prefab name = ", prefabName);
        return null;
      }
    } else {
      prefabNode = prefab;
      prefabName = prefab["data"].name;
    }

    let node = null;
    if (this._dictPool.hasOwnProperty(prefabName)) {
      // 从对象池获取
      const pool = this._dictPool[prefabName];
      node = pool.size() > 0 ? pool.get() : instantiate(prefabNode);
    } else {
      // 创建新的对象池
      this._dictPool[prefabName] = new NodePool();
      node = instantiate(prefabNode);
    }

    if (parent) {
      node.parent = parent;
      node.active = true;
      if (position) {
        node.position = position;
      }
    }

    return node;
  }

  /**
   * 回收节点
   * @param node 要回收的节点
   */
  public putNode(node: Node): void {
    if (!node) {
      console.log("putNode-node is null");
      return;
    }

    const name = node.name;
    let pool: NodePool = null;

    if (this._dictPool.hasOwnProperty(name)) {
      pool = this._dictPool[name];
    } else {
      pool = new NodePool();
      this._dictPool[name] = pool;
    }

    pool.put(node);
  }

  /**
   * 清空指定名称的对象池
   * @param name 对象池名称
   */
  public clearPool(name: string): void {
    if (this._dictPool.hasOwnProperty(name)) {
      this._dictPool[name].clear();
    }
  }

  /**
   * 设置预制体
   * @param name 预制体名称
   * @param prefab 预制体
   */
  public setPrefab(name: string, prefab: Node): void {
    this._dictPrefab[name] = prefab;
  }

  /**
   * 获取预制体
   * @param name 预制体名称
   * @returns 预制体
   */
  public getPrefab(name: string): Node {
    return this._dictPrefab[name];
  }
}