'use strict'

import { Container } from '@pixi/display';

import { Effect } from './effect';
import { Vector } from '../vector';

/**
 * A panning effect that makes the camera focus on a point in the container.
 */
export class PanTo extends Effect {
  /**
   * The (x, y) coordinate pair to pan to.
   * 
   * @private
   * 
   * @property {Vector}
   */
  private _coordinates: Vector;

  /**
   * The difference in coordinates from the current and the desired.
   * 
   * @private
   * 
   * @property {Vector}
   */
  private _difference: Vector;

  /**
   * Indicates whether the desired x is greater than the current x or not.
   * 
   * @private
   * 
   * @property {boolean}
   * 
   * @default false
   */
  private _xIsGreater = false;

  /**
   * Indicates whether the desired y is greater than the current y or not.
   * 
   * @private
   * 
   * @property {boolean}
   * 
   * @default false
   */
  private _yIsGreater = false;

  /**
   * @param {Container} container A reference to the container to apply the panto effect to.
   * @param {number} x The x coordinate to pan to.
   * @param {number} y The y coordinate to pan to.
   * @param {number} duration The amount of time, in milliseconds, that the effect should take.
   */
  constructor(container: Container, x: number, y: number, duration: number) {
    super(container);

    this._coordinates = { x, y };
    this.duration = duration;

    if (this._coordinates.x > this.container.pivot.x) this._xIsGreater = true;
    if (this._coordinates.y > this.container.pivot.y) this._yIsGreater = true;

    this._difference = { x: Math.abs(this._coordinates.x - this.container.pivot.x), y: Math.abs(this._coordinates.y - this.container.pivot.y) };
  }

  /**
   * Updates the status of this effect on a frame by frame basis.
   */
  update() {
    if (this.criteriaMet()) {
      this.finished.dispatch();
      return;
    }

    this.current = performance.now();
    
    const timeDiffPercentage = (this.current - this.started) / this.duration;
    const timeDiffPercentageNegative = (this.duration - this.current) / this.duration;

    const xPanAmount = this._xIsGreater ? this._difference.x * timeDiffPercentage : this._difference.x * timeDiffPercentageNegative;
    const yPanAmount = this._yIsGreater ? this._difference.y * timeDiffPercentage : this._difference.y * timeDiffPercentageNegative;

    this.container.pivot.x = xPanAmount;
    this.container.pivot.y = yPanAmount;

    if (this.useRAF) this.id = requestAnimationFrame(() => this.update());
  }

  /**
   * Checks to see if the panto criteria has been met so that the effect can end.
   * 
   * @returns {boolean} Returns true if the panto effect is finished or false otherwise.
   */
  criteriaMet(): boolean {
    if (this.container.pivot.x > this._coordinates.x - 5 && this.container.pivot.x < this._coordinates.x + 5  && this.container.pivot.y > this._coordinates.y - 5 && this.container.pivot.y < this._coordinates.y + 5) return true;
    return false;
  }
}