import {
  TOOL_INFO_CLASSNAME,
  WIDE_CLASSNAME,
  ZOOM_IN_FACTOR,
  ZOOM_OUT_FACTOR,
} from '../config.js';
import {Tool} from '../tool.js';
import {zero} from '../vector.js';

export class Zoom extends Tool {
  currentScaleEl = undefined;

  get displayScaleText() {
    return `Scale: ${this.sim.getScaleDisplay()}`;
  }

  setContainer(container) {
    super.setContainer(container);

    this.currentScaleEl.innerHTML = this.displayScaleText;

    this.sim.onZoom(() => {
      this.currentScaleEl.innerHTML = this.displayScaleText;
    });
  }

  constructor() {
    super();

    const currentScale = document.createElement('button')
    const zoomOut = document.createElement('button');
    const zoomIn = document.createElement('button');
    const zoomAll = document.createElement('button');
    const zeroVelocity = document.createElement('button');

    this.currentScaleEl = currentScale;

    this.div.appendChild(currentScale);
    this.div.appendChild(zoomOut);
    this.div.appendChild(zoomIn);
    this.div.appendChild(zoomAll);
    this.div.appendChild(zeroVelocity);

    currentScale.classList.add(WIDE_CLASSNAME);
    currentScale.classList.add(TOOL_INFO_CLASSNAME);

    zoomOut.innerHTML = 'Zoom<br>Out';
    zoomIn.innerHTML = 'Zoom<br>In';
    zoomAll.innerHTML = 'Zoom to Fit';
    zeroVelocity.innerHTML = 'Zero Momentum';

    zoomOut.addEventListener('click', () => {
      // Aim at center of view
      const x = this.sim.display.width * this.sim.display.scale / 2;
      const y = this.sim.display.height * this.sim.display.scale / 2;
      this.sim.scheduleZoom(this.sim.screenToSim(x, y), ZOOM_OUT_FACTOR);
    });

    zoomIn.addEventListener('click', () => {
      // Aim at center of view
      const x = this.sim.display.width * this.sim.display.scale / 2;
      const y = this.sim.display.height * this.sim.display.scale / 2;
      this.sim.scheduleZoom(this.sim.screenToSim(x, y), ZOOM_IN_FACTOR);
    });

    zoomAll.addEventListener('click', () => {
      // Determine bounding box
      const objects = this.sim.select.selectedGroup;
      const box = this.sim.system.getBoundingBox(objects);
      const x = (box.start.x + box.end.x) / 2;
      const y = (box.start.y + box.end.y) / 2;
      const widthRatio = Math.abs(box.start.x - box.end.x) / this.sim.display.width;
      const heightRatio = Math.abs(box.start.y - box.end.y) / this.sim.display.height;
      const ratio = Math.max(widthRatio, heightRatio) * 4;
      const factor = Math.ceil(Math.log2(1 / ratio));

      // Determine average momentum and set panning velocity to match
      const {netMomentum, totalMass} = this.sim.system.computeSystemCenter(objects);
      const netVelocity = {
        x: netMomentum.x / totalMass,
        y: netMomentum.y / totalMass,
      };
      this.sim.scheduleZoom({x, y}, factor, netVelocity)
    });

    zeroVelocity.addEventListener('click', () => {
      // Determine center of mass and average momentum
      const objects = this.sim.select.selectedGroup;
      const {netMomentum} = this.sim.system.computeSystemCenter(objects);
      const {totalMass} = this.sim.system.computeSystemCenter();
      const netVelocity = {
        x: netMomentum.x / totalMass,
        y: netMomentum.y / totalMass,
      };

      // Apply offset to all object velocities
      this.sim.system.forEachObject(obj => {
        obj.velocity.x -= netVelocity.x;
        obj.velocity.y -= netVelocity.y;
      });

      // Cancel panning
      this.sim.panning.setVelocity(zero);
    });
  }
}
