<template>
  <ThouCanvas
    @mousedown.left="draw_start"
    @mouseup.left="draw_finish"
    @mousedown.right="drag_start"
    @mouseup.right="drag_finish"
    @mousemove="on_mousemove"
    @click.middle="remove_rect"
    @dblclick.left="remove_rect"
  >
    <CalendarDoor
      v-for="(door, index) in doors"
      :key="`door-${index}`"
      :door="door"
      force_visible
    />
    <SVGRect
      v-if="preview_visible"
      variant="success"
      :rectangle="preview_rect"
      visible
    />
  </ThouCanvas>
</template>

<script lang="ts">
import { Door } from "@/lib/rects/door";
import { Rectangle } from "@/lib/rects/rectangle";
import { Vector2D } from "@/lib/rects/vector2d";
import { Options, Vue } from "vue-class-component";

import CalendarDoor from "../calendar/CalendarDoor.vue";
import SVGRect from "../calendar/SVGRect.vue";
import ThouCanvas from "../calendar/ThouCanvas.vue";

enum CanvasState {
  Idle,
  Drawing,
  Dragging,
}

@Options({
  components: {
    CalendarDoor,
    SVGRect,
    ThouCanvas,
  },
  props: {
    doors: Array,
  },
})
export default class extends Vue {
  private readonly min_rect_area = 300;
  private state = CanvasState.Idle;
  public preview_rect = new Rectangle();
  private drag_door?: Door;
  private drag_origin = new Vector2D();
  public doors!: Door[];

  public get preview_visible(): boolean {
    return this.state !== CanvasState.Idle;
  }

  private pop_door(point: Vector2D): Door | undefined {
    const idx = this.doors.findIndex((rect) => rect.position.contains(point));

    if (idx === -1) {
      return;
    }

    return this.doors.splice(idx, 1)[0];
  }

  public draw_start(event: MouseEvent, point: Vector2D) {
    if (this.preview_visible) {
      return;
    }

    this.state = CanvasState.Drawing;
    this.preview_rect = new Rectangle(point, point);
  }

  public draw_finish() {
    if (this.state !== CanvasState.Drawing || this.preview_rect === undefined) {
      return;
    }

    this.state = CanvasState.Idle;

    if (this.preview_rect.area < this.min_rect_area) {
      return;
    }

    this.doors.push(new Door(this.preview_rect));
  }

  public drag_start(event: MouseEvent, point: Vector2D) {
    if (this.preview_visible) {
      return;
    }

    this.drag_door = this.pop_door(point);

    if (this.drag_door === undefined) {
      return;
    }

    this.state = CanvasState.Dragging;
    this.drag_origin = point;

    this.preview_rect = this.drag_door.position;
  }

  public drag_finish() {
    if (
      this.state !== CanvasState.Dragging ||
      this.preview_rect === undefined
    ) {
      return;
    }

    this.state = CanvasState.Idle;
    this.doors.push(new Door(this.preview_rect, this.drag_door!.day));
  }

  public on_mousemove(event: MouseEvent, point: Vector2D) {
    if (this.preview_rect === undefined) {
      return;
    }

    if (this.state === CanvasState.Drawing) {
      this.preview_rect = this.preview_rect.update(undefined, point);
    } else if (this.state === CanvasState.Dragging && this.drag_door) {
      const movement = point.minus(this.drag_origin);
      this.preview_rect = this.drag_door.position.move(movement);
    }
  }

  public remove_rect(event: MouseEvent, point: Vector2D) {
    if (this.preview_visible) {
      return;
    }

    this.pop_door(point);
  }
}
</script>

<style lang="scss" scoped>
svg {
  cursor: crosshair;

  * {
    pointer-events: none;
  }
}
</style>
