import {BaseSopOperation} from "./_Base";
import {Group as Group3} from "three/src/objects/Group";
import {InputCloneMode as InputCloneMode2} from "../../../engine/poly/InputCloneMode";
import {TypeAssert} from "../../../engine/poly/Assert";
export var HierarchyMode;
(function(HierarchyMode2) {
  HierarchyMode2["ADD_PARENT"] = "add_parent";
  HierarchyMode2["REMOVE_PARENT"] = "remove_parent";
  HierarchyMode2["ADD_CHILD"] = "add_child";
})(HierarchyMode || (HierarchyMode = {}));
export const HIERARCHY_MODES = [
  HierarchyMode.ADD_PARENT,
  HierarchyMode.REMOVE_PARENT,
  HierarchyMode.ADD_CHILD
];
export class HierarchySopOperation extends BaseSopOperation {
  static type() {
    return "hierarchy";
  }
  cook(input_contents, params) {
    const core_group = input_contents[0];
    const mode = HIERARCHY_MODES[params.mode];
    switch (mode) {
      case HierarchyMode.ADD_PARENT: {
        const objects = this._add_parent_to_core_group(core_group, params);
        return this.create_core_group_from_objects(objects);
      }
      case HierarchyMode.REMOVE_PARENT: {
        const objects = this._remove_parent_from_core_group(core_group, params);
        return this.create_core_group_from_objects(objects);
      }
      case HierarchyMode.ADD_CHILD: {
        const objects = this._add_child_to_core_group(core_group, input_contents[1], params);
        return this.create_core_group_from_objects(objects);
      }
    }
    TypeAssert.unreachable(mode);
  }
  _add_parent_to_core_group(core_group, params) {
    if (params.levels == 0) {
      return core_group.objects();
    } else {
      const new_object = this._add_parent_to_object(core_group.objects(), params);
      return [new_object];
    }
  }
  _add_parent_to_object(objects, params) {
    let new_parent = new Group3();
    new_parent.matrixAutoUpdate = false;
    new_parent.add(...objects);
    if (params.levels > 0) {
      for (let i = 0; i < params.levels - 1; i++) {
        new_parent = this._add_new_parent(new_parent, params);
      }
    }
    return new_parent;
  }
  _add_new_parent(object, params) {
    const new_parent2 = new Group3();
    new_parent2.matrixAutoUpdate = false;
    new_parent2.add(object);
    return new_parent2;
  }
  _remove_parent_from_core_group(core_group, params) {
    if (params.levels == 0) {
      return core_group.objects();
    } else {
      const new_objects = [];
      for (let object of core_group.objects()) {
        const new_children = this._remove_parent_from_object(object, params);
        for (let new_child of new_children) {
          new_objects.push(new_child);
        }
      }
      return new_objects;
    }
  }
  _remove_parent_from_object(object, params) {
    let current_children = object.children;
    for (let i = 0; i < params.levels - 1; i++) {
      current_children = this._get_children_from_objects(current_children, params);
    }
    return current_children;
  }
  _get_children_from_objects(objects, params) {
    let object;
    const children = [];
    while (object = objects.pop()) {
      if (object.children) {
        for (let child of object.children) {
          children.push(child);
        }
      }
    }
    return children;
  }
  _add_child_to_core_group(core_group, child_core_group, params) {
    const objects = core_group.objects();
    if (!child_core_group) {
      this.states?.error.set("input 1 is invalid");
      return [];
    }
    const childObjects = child_core_group.objects();
    const mask = params.objectMask.trim();
    const maskValid = mask != "";
    const parentObjects = maskValid ? this._findObjectsByMaskFromObjects(mask, objects) : objects;
    if (params.debugObjectMask) {
      console.log(parentObjects);
    }
    for (let i = 0; i < parentObjects.length; i++) {
      const parentObject = parentObjects[i];
      const childObject = childObjects[i] || childObjects[0];
      if (!childObject) {
        this.states?.error.set("no objects found in input 1");
        return [];
      }
      parentObject.add(childObject);
    }
    return objects;
  }
  _findObjectsByMaskFromObjects(mask, objects) {
    const list = [];
    for (let object of objects) {
      this.scene.objectsController.objectsByMaskInObject(mask, object, list);
    }
    return list;
  }
}
HierarchySopOperation.DEFAULT_PARAMS = {
  mode: 0,
  levels: 1,
  objectMask: "",
  debugObjectMask: false
};
HierarchySopOperation.INPUT_CLONED_STATE = InputCloneMode2.FROM_NODE;
