import * as cornerstoneTools from 'cornerstone-tools'
// State
const getToolState = cornerstoneTools.getToolState
const toolStyle = cornerstoneTools.toolStyle
const toolColors = cornerstoneTools.toolColors

// Drawing
const getNewContext = cornerstoneTools.import('drawing/getNewContext')
const draw = cornerstoneTools.import('drawing/draw')
const setShadow = cornerstoneTools.import('drawing/setShadow')
const drawLine = cornerstoneTools.import('drawing/drawLine')
const drawLinkedTextBox = cornerstoneTools.import('drawing/drawLinkedTextBox')
const drawHandles = cornerstoneTools.import('drawing/drawHandles')

// util
const lineSegDistance = cornerstoneTools.import('util/lineSegDistance')
const lengthCursor = cornerstoneTools.import('tools/cursors')
const getPixelSpacing = cornerstoneTools.import('util/getPixelSpacing')
const throttle = cornerstoneTools.import('util/throttle')
const getModule = cornerstoneTools.getModule

/**
 * @public
 * @class LengthTool
 * @memberof Tools.Annotation
 * @classdesc Tool for measuring distances.
 * @extends Tools.Base.BaseAnnotationTool
 */
export default class LengthTool extends cornerstoneTools.LengthTool {
  constructor(props = {}) {
    const defaultProps = {
      name: 'Length',
      supportedInteractionTypes: ['Mouse', 'Touch'],
      svgCursor: lengthCursor,
      configuration: {
        drawHandles: true,
        drawHandlesOnHover: false,
        hideHandlesIfMoving: false,
        renderDashed: false,
        digits: 2,
      },
    }

    super(props, defaultProps)

    this.throttledUpdateCachedStats = throttle(this.updateCachedStats, 50)
  }
  createNewMeasurement(eventData) {
    const goodEventData =
      eventData && eventData.currentPoints && eventData.currentPoints.image
    console.log('createNewMeasurement: ',goodEventData)
    if (!goodEventData) {
      console.log(
        `required eventData not supplied to tool ${this.name}'s createNewMeasurement`
      )

      return
    }

    const { x, y } = eventData.currentPoints.image

    return {
      visible: true,
      active: true,
      color: undefined,
      invalidated: true,
      handles: {
        start: {
          x,
          y,
          highlight: true,
          active: false
        },
        end: {
          x,
          y,
          highlight: true,
          active: true
        },
        textBox: {
          active: false,
          hasMoved: false,
          movesIndependently: false,
          drawnIndependently: true,
          allowedOutsideImage: true,
          hasBoundingBox: true
        },
        allowedOutsideImage:true
      }
    }
  }

  /**
   *
   *
   * @param {*} element
   * @param {*} data
   * @param {*} coords
   * @returns {Boolean}
   */
  pointNearTool(element, data, coords) {
    const hasStartAndEndHandles =
      data && data.handles && data.handles.start && data.handles.end
    const validParameters = hasStartAndEndHandles

    if (!validParameters) {
      console.log(
        `invalid parameters supplied to tool ${this.name}'s pointNearTool`
      )

      return false
    }
    if (data.visible === false) {
      return false
    }

    return (
      lineSegDistance(element, data.handles.start, data.handles.end, coords) <
      25
    )
  }

  updateCachedStats(image, element, data) {
    const {
      digits
    } = this.configuration
    const { rowPixelSpacing, colPixelSpacing } = getPixelSpacing(image)

    // Set rowPixelSpacing and columnPixelSpacing to 1 if they are undefined (or zero)
    const dx =
      (data.handles.end.x - data.handles.start.x) * (colPixelSpacing || 1)
    const dy =
      (data.handles.end.y - data.handles.start.y) * (rowPixelSpacing || 1)

    // Calculate the length, and create the text variable with the millimeters or pixels suffix
    const length = Math.sqrt(dx * dx + dy * dy)

    // Store the length inside the tool for outside access
    data.length = length.toFixed(digits)
    data.invalidated = false
  }

  renderToolData(evt) {
    const eventData = evt.detail
    const {
      handleRadius,
      drawHandlesOnHover,
      hideHandlesIfMoving,
      renderDashed,
      digits
    } = this.configuration
    const toolData = getToolState(evt.currentTarget, this.name)
    if (!toolData) {
      return
    }

    // We have tool data for this element - iterate over each one and draw it
    const context = getNewContext(eventData.canvasContext.canvas)
    const { image, element } = eventData
    const { rowPixelSpacing, colPixelSpacing } = getPixelSpacing(image)

    const lineWidth = toolStyle.getToolWidth()
    const lineDash = getModule('globalConfiguration').configuration.lineDash

    for (let i = 0; i < toolData.data.length; i++) {
      const data = toolData.data[i]

      if (data.visible === false) {
        continue
      }

      draw(context, context => {
        // Configurable shadow
        setShadow(context, this.configuration)

        const color = toolColors.getColorIfActive(data)

        const lineOptions = { color }

        if (renderDashed) {
          lineOptions.lineDash = lineDash
        }

        // Draw the measurement line
        drawLine(
          context,
          element,
          data.handles.start,
          data.handles.end,
          lineOptions
        )

        // Draw the handles
        const handleOptions = {
          color,
          handleRadius,
          drawHandlesIfActive: drawHandlesOnHover,
          hideHandlesIfMoving
        }

        if (this.configuration.drawHandles) {
          drawHandles(context, eventData, data.handles, handleOptions)
        }

        if (!data.handles.textBox.hasMoved) {
          const coords = {
            x: Math.max(data.handles.start.x, data.handles.end.x)
          }

          // Depending on which handle has the largest x-value,
          // Set the y-value for the text box
          if (coords.x === data.handles.start.x) {
            coords.y = data.handles.start.y
          } else {
            coords.y = data.handles.end.y
          }

          data.handles.textBox.x = coords.x
          data.handles.textBox.y = coords.y
        }

        // Move the textbox slightly to the right and upwards
        // So that it sits beside the length tool handle
        const xOffset = 10

        // Update textbox stats
        if (data.invalidated === true) {
          if (data.length) {
            this.throttledUpdateCachedStats(image, element, data)
          } else {
            this.updateCachedStats(image, element, data)
          }
        }
        const text = []
        if (data.hasOwnProperty('remark')) {
          if (data.hasOwnProperty('status') && data.status) {
            text.push(`${data.remark}(${data.status})`)
          } else {
            text.push(data.remark)
          }
        }

        text.push(textBoxText(data, rowPixelSpacing, colPixelSpacing))
        drawLinkedTextBox(
          context,
          element,
          data.handles.textBox,
          text,
          data.handles,
          textBoxAnchorPoints,
          color,
          lineWidth,
          xOffset,
          true
        )
      })
    }

    // - SideEffect: Updates annotation 'suffix'
    function textBoxText(annotation, rowPixelSpacing, colPixelSpacing) {
      const measuredValue = _sanitizeMeasuredValue(annotation.length)

      // Measured value is not defined, return empty string
      if (!measuredValue) {
        return ''
      }

      // Set the length text suffix depending on whether or not pixelSpacing is available
      let suffix = 'mm'

      if (!rowPixelSpacing || !colPixelSpacing) {
        suffix = 'pixels'
      }

      annotation.unit = suffix

      return `${measuredValue.toFixed(digits)} ${suffix}`
    }

    function textBoxAnchorPoints(handles) {
      const midpoint = {
        x: (handles.start.x + handles.end.x) / 2,
        y: (handles.start.y + handles.end.y) / 2
      }

      return [handles.start, midpoint, handles.end]
    }
  }
}

/**
 * Attempts to sanitize a value by casting as a number; if unable to cast,
 * we return `undefined`
 *
 * @param {*} value
 * @returns a number or undefined
 */
function _sanitizeMeasuredValue(value) {
  const parsedValue = Number(value)
  const isNumber = !isNaN(parsedValue)

  return isNumber ? parsedValue : undefined
}
