import {Arc} from '../shapes/arc'
import {Tool} from './tool'
import Vector from 'math/vector';
import {distance} from "math/distance";

export class AddArcTool extends Tool {

  constructor(viewer) {
    super('arc', viewer);
    this.arc = null;
    this.point = null;
    this._v = new Vector(0, 0, 0);
  }

  restart() {
    this.sendHint('specify center');
  }

  mousemove(e) {
    const p = this.viewer.screenToModel(e);
    if (this.point != null) {
      this.point.x = p.x;
      this.point.y = p.y;
      
      if (this.point.id === this.arc.b.id) {
        //force placement second point on the arc
        const r = this.radiusOfFirstPoint();
        const v = this._v;
        v.set(this.arc.b.x - this.arc.c.x, this.arc.b.y - this.arc.c.y, 0);
        v._normalize()._multiply(r);
        this.arc.b.x = v.x + this.arc.c.x;
        this.arc.b.y = v.y + this.arc.c.y;
      } else {
        this.demoSecondPoint();
      }
      this.arc.syncGeometry();

      this.viewer.snap(p.x, p.y, [this.arc.a, this.arc.b, this.arc.c]);
      this.viewer.refresh();
    } else {
      this.viewer.snap(p.x, p.y, []);
      this.viewer.refresh();
    }
  }
  
  mouseup(e) {
    if (this.arc == null) {
      const center = this.viewer.screenToModel(e);
      this.createArcStep(center);
    } else if (this.point.id === this.arc.a.id) {
      this.snapIfNeed(this.arc.a);
      this.startingPointSetStep();
    } else {
      this.snapIfNeed(this.arc.b);
      this.finishStep();
    }
  }
  
  createArcStep(p) {
    this.viewer.historyManager.checkpoint();
    this.arc = new Arc(
      p.x, p.y,
      p.x, p.y,
      p.x, p.y
    );
    this.point = this.arc.a;
    this.viewer.activeLayer.add(this.arc);
    this.snapIfNeed(this.arc.c);
    this.pointPicked(p.x, p.y);
    this.sendHint('specify arc starting point');
    this.viewer.refresh();
  }

  startingPointSetStep() {
    this.point = this.arc.b;
    this.pointPicked(this.arc.a.x, this.arc.a.y);
    this.sendHint('specify angle')
  }

  finishStep() {
    this.arc.stabilize(this.viewer);
    this.pointPicked(this.arc.b.x, this.arc.b.y);
    this.viewer.parametricManager.refresh();
    this.viewer.toolManager.releaseControl();
  }

  demoSecondPoint() {
    const r = this.radiusOfFirstPoint();
    let ang = Math.atan2(this.arc.a.y - this.arc.c.y, this.arc.a.x - this.arc.c.x) + (2 * Math.PI - 0.3);
    ang %= 2 * Math.PI;
    this.arc.b.x = this.arc.c.x + r * Math.cos(ang);
    this.arc.b.y = this.arc.c.y + r * Math.sin(ang);
  }

  radiusOfFirstPoint() {
    return distance(this.arc.a.x, this.arc.a.y, this.arc.c.x, this.arc.c.y);
  }

  processCommand(command) {
    if (this.arc == null) {
      const result = Tool.ParseVector(this.viewer.referencePoint, command);
      if(typeof result === 'string') return result;
      this.viewer.cleanSnap();
      this.createArcStep(result);
    } else if (this.point.id === this.arc.a.id) {
      const result = Tool.ParseVector(this.viewer.referencePoint, command);
      if(typeof result === 'string') return result;
      this.arc.a.x = result.x;
      this.arc.a.y = result.y;
      this.startingPointSetStep();
      this.demoSecondPoint();
      this.viewer.refresh();
    } else {
      const startingAngle = Math.atan2(this.point.y - this.arc.c.y, this.point.x - this.arc.c.x);
      const result = Tool.ParseNumberWithRef(command, startingAngle); // treated as radius and angle
      const r = this.radiusOfFirstPoint();
      if(typeof result === 'string') return result;
      let angle = result / 180 * Math.PI;
      angle %= 2 * Math.PI;
      this.arc.b.x = this.arc.c.x + r * Math.cos(angle);
      this.arc.b.y = this.arc.c.y + r * Math.sin(angle);
      this.finishStep();
    }
  }
}
