import {TypedCameraControlsEventNode} from "./_BaseCameraControls";
import {NodeParamsConfig, ParamConfig} from "../utils/params/ParamsConfig";
import {EventConnectionPoint, EventConnectionPointType} from "../utils/io/connections/Event";
import {OrbitControls as OrbitControls2} from "../../../modules/core/controls/OrbitControls";
import {CameraControlsNodeType} from "../../poly/NodeContext";
const OUTPUT_START = "start";
const OUTPUT_CHANGE = "change";
const OUTPUT_END = "end";
var KeysMode;
(function(KeysMode2) {
  KeysMode2["PAN"] = "pan";
  KeysMode2["ROTATE"] = "rotate";
})(KeysMode || (KeysMode = {}));
const KEYS_MODES = [KeysMode.PAN, KeysMode.ROTATE];
class CameraOrbitEventParamsConfig extends NodeParamsConfig {
  constructor() {
    super(...arguments);
    this.enabled = ParamConfig.BOOLEAN(1);
    this.allowPan = ParamConfig.BOOLEAN(1);
    this.allowRotate = ParamConfig.BOOLEAN(1);
    this.allowZoom = ParamConfig.BOOLEAN(1);
    this.tdamping = ParamConfig.BOOLEAN(1);
    this.damping = ParamConfig.FLOAT(0.1, {
      visibleIf: {tdamping: true}
    });
    this.screenSpacePanning = ParamConfig.BOOLEAN(1);
    this.rotateSpeed = ParamConfig.FLOAT(0.5);
    this.minDistance = ParamConfig.FLOAT(1, {
      range: [0, 100],
      rangeLocked: [true, false]
    });
    this.maxDistance = ParamConfig.FLOAT(50, {
      range: [0, 100],
      rangeLocked: [true, false]
    });
    this.limitAzimuthAngle = ParamConfig.BOOLEAN(0);
    this.azimuthAngleRange = ParamConfig.VECTOR2(["-2*$PI", "2*$PI"], {
      visibleIf: {limitAzimuthAngle: 1}
    });
    this.polarAngleRange = ParamConfig.VECTOR2([0, "$PI"]);
    this.target = ParamConfig.VECTOR3([0, 0, 0], {
      cook: false,
      computeOnDirty: true,
      callback: (node) => {
        CameraOrbitControlsEventNode.PARAM_CALLBACK_update_target(node);
      }
    });
    this.enableKeys = ParamConfig.BOOLEAN(0);
    this.keysMode = ParamConfig.INTEGER(KEYS_MODES.indexOf(KeysMode.PAN), {
      visibleIf: {enableKeys: 1},
      menu: {
        entries: KEYS_MODES.map((name, value) => {
          return {name, value};
        })
      }
    });
    this.keysPanSpeed = ParamConfig.FLOAT(7, {
      range: [0, 10],
      rangeLocked: [false, false],
      visibleIf: {enableKeys: 1, keysMode: KEYS_MODES.indexOf(KeysMode.PAN)}
    });
    this.keysRotateSpeedVertical = ParamConfig.FLOAT(1, {
      range: [0, 1],
      rangeLocked: [false, false],
      visibleIf: {enableKeys: 1, keysMode: KEYS_MODES.indexOf(KeysMode.ROTATE)}
    });
    this.keysRotateSpeedHorizontal = ParamConfig.FLOAT(1, {
      range: [0, 1],
      rangeLocked: [false, false],
      visibleIf: {enableKeys: 1, keysMode: KEYS_MODES.indexOf(KeysMode.ROTATE)}
    });
  }
}
const ParamsConfig2 = new CameraOrbitEventParamsConfig();
export class CameraOrbitControlsEventNode extends TypedCameraControlsEventNode {
  constructor() {
    super(...arguments);
    this.params_config = ParamsConfig2;
    this._controls_by_element_id = new Map();
    this._target_array = [0, 0, 0];
  }
  static type() {
    return CameraControlsNodeType.ORBIT;
  }
  initializeNode() {
    this.io.outputs.setNamedOutputConnectionPoints([
      new EventConnectionPoint(OUTPUT_START, EventConnectionPointType.BASE),
      new EventConnectionPoint(OUTPUT_CHANGE, EventConnectionPointType.BASE),
      new EventConnectionPoint(OUTPUT_END, EventConnectionPointType.BASE)
    ]);
  }
  async create_controls_instance(camera, element) {
    const controls = new OrbitControls2(camera, element);
    controls.addEventListener("end", () => {
      this._on_controls_end(controls);
    });
    this._controls_by_element_id.set(element.id, controls);
    this._bind_listeners_to_controls_instance(controls);
    return controls;
  }
  _bind_listeners_to_controls_instance(controls) {
    controls.addEventListener("start", () => {
      this.dispatch_event_to_output(OUTPUT_START, {});
    });
    controls.addEventListener("change", () => {
      this.dispatch_event_to_output(OUTPUT_CHANGE, {});
    });
    controls.addEventListener("end", () => {
      this.dispatch_event_to_output(OUTPUT_END, {});
    });
  }
  setup_controls(controls) {
    controls.enabled = this.pv.enabled;
    controls.enablePan = this.pv.allowPan;
    controls.enableRotate = this.pv.allowRotate;
    controls.enableZoom = this.pv.allowZoom;
    controls.enableDamping = this.pv.tdamping;
    controls.dampingFactor = this.pv.damping;
    controls.rotateSpeed = this.pv.rotateSpeed;
    controls.screenSpacePanning = this.pv.screenSpacePanning;
    controls.minDistance = this.pv.minDistance;
    controls.maxDistance = this.pv.maxDistance;
    this._set_azimuth_angle(controls);
    controls.minPolarAngle = this.pv.polarAngleRange.x;
    controls.maxPolarAngle = this.pv.polarAngleRange.y;
    controls.target.copy(this.pv.target);
    if (controls.enabled) {
      controls.update();
    }
    controls.enableKeys = this.pv.enableKeys;
    if (controls.enableKeys) {
      controls.keyMode = KEYS_MODES[this.pv.keysMode];
      controls.keyRotateSpeedVertical = this.pv.keysRotateSpeedVertical;
      controls.keyRotateSpeedHorizontal = this.pv.keysRotateSpeedHorizontal;
      controls.keyPanSpeed = this.pv.keysPanSpeed;
    }
  }
  _set_azimuth_angle(controls) {
    if (this.pv.limitAzimuthAngle) {
      controls.minAzimuthAngle = this.pv.azimuthAngleRange.x;
      controls.maxAzimuthAngle = this.pv.azimuthAngleRange.y;
    } else {
      controls.minAzimuthAngle = Infinity;
      controls.maxAzimuthAngle = Infinity;
    }
  }
  update_required() {
    return this.pv.tdamping;
  }
  _on_controls_end(controls) {
    if (!this.pv.allowPan) {
      return;
    }
    controls.target.toArray(this._target_array);
    this.p.target.set(this._target_array);
  }
  static PARAM_CALLBACK_update_target(node) {
    node._update_target();
  }
  _update_target() {
    const src_target = this.pv.target;
    this._controls_by_element_id.forEach((control, element_id) => {
      const dest_target = control.target;
      if (!dest_target.equals(src_target)) {
        dest_target.copy(src_target);
        control.update();
      }
    });
  }
  dispose_controls_for_html_element_id(html_element_id) {
    const controls = this._controls_by_element_id.get(html_element_id);
    if (controls) {
      this._controls_by_element_id.delete(html_element_id);
    }
  }
}
