import { G, getWindow } from '@svgdotjs/svg.js'
import { getMoseDownFunc, transformPoint } from './utils'

export class PointSelectHandler {
  constructor(el) {
    this.el = el
    el.remember('_pointSelectHandler', this)
    this.selection = new G()
    this.order = ['lt', 't', 'rt', 'r', 'rb', 'b', 'lb', 'l', 'rot']
    this.mutationHandler = this.mutationHandler.bind(this)

    const win = getWindow()
    this.observer = new win.MutationObserver(this.mutationHandler)
  }

  init(options) {
    this.createHandle = options.createHandle || this.createHandleFn
    this.updateHandle = options.updateHandle || this.updateHandleFn

    // mount group
    this.el.root().put(this.selection)

    this.updatePoints()
    this.createSelection()
    this.createPointHandles()
    this.updatePointHandles()
    this.observer.observe(this.el.node, { attributes: true })
  }

  active(val, options) {
    // Disable selection
    if (!val) {
      this.selection.clear().remove()
      this.observer.disconnect()
      return
    }

    // Enable selection
    this.init(options)
  }

  createSelection() {
    this.selection.polygon(this.points).addClass('svg_select_shape_pointSelect')
  }

  updateSelection() {
    this.selection.get(0).plot(this.points)
  }

  createPointHandles() {
    this.points.forEach((p, index, arr) => {
      this.createHandle.call(this, this.selection, p, index, arr)

      this.selection
        .get(index + 1)
        .addClass('svg_select_handle_point')
        .on('mousedown.selection touchstart.selection', getMoseDownFunc('point', this.el, this.points, index))
    })
  }

  createHandleFn(group) {
    group.circle(5)
  }

  updateHandleFn(shape, point) {
    shape.center(point[0], point[1])
  }

  updatePointHandles() {
    this.points.forEach((p, index, arr) => {
      this.updateHandle.call(this, this.selection.get(index + 1), p, index, arr)
    })
  }

  // gets new bounding box points and transform them into the elements space
  updatePoints() {
    const fromShapeToUiMatrix = this.el.root().screenCTM().inverseO().multiplyO(this.el.screenCTM())
    this.points = this.el.array().map((p) => transformPoint(p, fromShapeToUiMatrix))
  }

  mutationHandler() {
    this.updatePoints()

    this.updateSelection()
    this.updatePointHandles()
  }
}
