import {CoreGraphNode as CoreGraphNode2} from "../../../core/graph/CoreGraphNode";
import {SceneEvent as SceneEvent2} from "../../poly/SceneEvent";
import {SceneEventType} from "./events/SceneEventsController";
const FPS = 60;
export class TimeController {
  constructor(scene) {
    this.scene = scene;
    this._frame = 1;
    this._time = 0;
    this._prev_performance_now = 0;
    this._frame_range = [1, 600];
    this._realtimeState = true;
    this._frameRangeLocked = [true, true];
    this._playing = false;
    this._graph_node = new CoreGraphNode2(scene, "time controller");
  }
  get PLAY_EVENT_CONTEXT() {
    return this._PLAY_EVENT_CONTEXT = this._PLAY_EVENT_CONTEXT || {event: new Event(SceneEventType.PLAY)};
  }
  get PAUSE_EVENT_CONTEXT() {
    return this._PAUSE_EVENT_CONTEXT = this._PAUSE_EVENT_CONTEXT || {event: new Event(SceneEventType.PAUSE)};
  }
  get TICK_EVENT_CONTEXT() {
    return this._TICK_EVENT_CONTEXT = this._TICK_EVENT_CONTEXT || {event: new Event(SceneEventType.TICK)};
  }
  get graph_node() {
    return this._graph_node;
  }
  get frame() {
    return this._frame;
  }
  get time() {
    return this._time;
  }
  get frame_range() {
    return this._frame_range;
  }
  get frameRangeLocked() {
    return this._frameRangeLocked;
  }
  get realtimeState() {
    return this._realtimeState;
  }
  setFrameRange(start_frame, end_frame) {
    this._frame_range[0] = Math.floor(start_frame);
    this._frame_range[1] = Math.floor(end_frame);
    this.scene.dispatchController.dispatch(this._graph_node, SceneEvent2.FRAME_RANGE_UPDATED);
  }
  setFrameRange_locked(start_locked, end_locked) {
    this._frameRangeLocked[0] = start_locked;
    this._frameRangeLocked[1] = end_locked;
    this.scene.dispatchController.dispatch(this._graph_node, SceneEvent2.FRAME_RANGE_UPDATED);
  }
  set_realtimeState(state) {
    this._realtimeState = state;
    this.scene.dispatchController.dispatch(this._graph_node, SceneEvent2.REALTIME_STATUS_UPDATED);
  }
  setTime(time, update_frame = true) {
    if (time != this._time) {
      this._time = time;
      if (update_frame) {
        const new_frame = Math.floor(this._time * FPS);
        const bounded_frame = this._ensure_frame_within_bounds(new_frame);
        if (new_frame != bounded_frame) {
          this.setFrame(bounded_frame, true);
        } else {
          this._frame = new_frame;
        }
      }
      this.scene.dispatchController.dispatch(this._graph_node, SceneEvent2.FRAME_UPDATED);
      this.scene.uniforms_controller.update_time_dependent_uniform_owners();
      this.scene.cooker.block();
      this.graph_node.setSuccessorsDirty();
      this.scene.cooker.unblock();
      this.scene.eventsDispatcher.sceneEventsController.processEvent(this.TICK_EVENT_CONTEXT);
    }
  }
  setFrame(frame, update_time = true) {
    if (frame != this._frame) {
      frame = this._ensure_frame_within_bounds(frame);
      if (frame != this._frame) {
        this._frame = frame;
        if (update_time) {
          this.setTime(this._frame / FPS, false);
        }
      }
    }
  }
  increment_time_if_playing() {
    if (this._playing) {
      if (!this.scene.root().are_children_cooking()) {
        this.increment_time();
      }
    }
  }
  increment_time() {
    if (this._realtimeState) {
      const performance_now = performance.now();
      const delta = (performance_now - this._prev_performance_now) / 1e3;
      const new_time = this._time + delta;
      this._prev_performance_now = performance_now;
      this.setTime(new_time);
    } else {
      this.setFrame(this.frame + 1);
    }
  }
  _ensure_frame_within_bounds(frame) {
    if (this._frameRangeLocked[0] && frame < this._frame_range[0]) {
      return this._frame_range[1];
    }
    if (this._frameRangeLocked[1] && frame > this._frame_range[1]) {
      return this._frame_range[0];
    }
    return frame;
  }
  get playing() {
    return this._playing === true;
  }
  pause() {
    if (this._playing == true) {
      this._playing = false;
      this.scene.dispatchController.dispatch(this._graph_node, SceneEvent2.PLAY_STATE_UPDATED);
      this.scene.eventsDispatcher.sceneEventsController.processEvent(this.PAUSE_EVENT_CONTEXT);
    }
  }
  play() {
    if (this._playing !== true) {
      this._playing = true;
      this._prev_performance_now = performance.now();
      this.scene.dispatchController.dispatch(this._graph_node, SceneEvent2.PLAY_STATE_UPDATED);
      this.scene.eventsDispatcher.sceneEventsController.processEvent(this.PLAY_EVENT_CONTEXT);
    }
  }
  toggle_play_pause() {
    if (this.playing) {
      this.pause();
    } else {
      this.play();
    }
  }
}
