import * as cornerstoneTools from 'cornerstone-tools'
const EVENTS = cornerstoneTools.EVENTS
const triggerEvent = cornerstoneTools.import('util/triggerEvent')
const external = cornerstoneTools.external
// State
const getToolState = cornerstoneTools.getToolState
const textStyle = cornerstoneTools.textStyle
const toolColors = cornerstoneTools.toolColors
const toolStyle = cornerstoneTools.toolStyle
// Drawing
const getNewContext = cornerstoneTools.import('drawing/getNewContext')
const draw = cornerstoneTools.import('drawing/draw')
const drawHandles = cornerstoneTools.import('drawing/drawHandles')
const drawTextBox = cornerstoneTools.import('drawing/drawTextBox')
const drawLink = cornerstoneTools.import('drawing/drawLink')

const drawLinkedTextBox = cornerstoneTools.import('drawing/drawLinkedTextBox')
// Utilities
const getRGBPixels = cornerstoneTools.import('util/getRGBPixels')
const calculateSUV = cornerstoneTools.import('util/calculateSUV')
const getROITextBoxCoords = cornerstoneTools.import('util/getROITextBoxCoords')
// import { probeCursor } from '../cursors/index.js';
// import { getLogger } from '../../util/logger.js';
const throttle = cornerstoneTools.import('util/throttle')
const getModule = cornerstoneTools.getModule
const getPixelSpacing = cornerstoneTools.import('util/getPixelSpacing')
// import numbersWithCommas from './../../util/numbersWithCommas.js';
const numbersWithCommas = cornerstoneTools.import('util/numbersWithCommas')
const clipBoxToDisplayedArea = cornerstoneTools.import('util/clip')

// const logger = getLogger('tools:annotation:ProbeTool');
import calculateEllipseStatistics from './calculateEllipseStatistics'
import getCircleCoords from './getCircleCoords'
/**
 * @public
 * @class ProbeTool
 * @memberof Tools.Annotation
 * @classdesc Tool which provides a probe of the image data at the
 * desired position.
 * @extends Tools.Base.BaseAnnotationTool
 */
const getHandle = (x, y, index, extraAttributes = {}) =>
  Object.assign(
    {
      x,
      y,
      index,
      drawnIndependently: false,
      allowedOutsideImage: false,
      highlight: true,
      active: false
    },
    extraAttributes
  )
export default class ProbeTool extends cornerstoneTools.ProbeTool {
  constructor(props = {}) {
    const defaultProps = {
      name: 'Probe',
      supportedInteractionTypes: ['Mouse', 'Touch'],
      // svgCursor: probeCursor,
      configuration: {
        drawHandles: true,
        renderDashed: false,
        handleRadius: 0,
        fixedRadius: 0,
        hideHandlesIfMoving: false,
        digits: 1,
        showRadius: false,
      },
    };

    super(props, defaultProps);

    this.throttledUpdateCachedStats = throttle(this.updateCachedStats, 110);
  }

  createNewMeasurement(eventData) {
    const goodEventData =
      eventData && eventData.currentPoints && eventData.currentPoints.image;

    if (!goodEventData) {
      logger.error(
        `required eventData not supplied to tool ${this.name}'s createNewMeasurement`
      );

      return;
    }
    const { x, y } = eventData.currentPoints.image
    
    return {
      visible: true,
      active: false,
      color: undefined,
      invalidated: true,
      handles: {
        // start: {
        //   x: eventData.currentPoints.image.x,
        //   y: eventData.currentPoints.image.y,
        //   highlight: true,
        //   active: false,
        // },
        end: {
          x: eventData.currentPoints.image.x,
          y: eventData.currentPoints.image.y,
          highlight: false,
          active: false,
          radius: 0
        },
        // textBox: {
        //   active: false,
        //   hasMoved: false,
        //   movesIndependently: false,
        //   drawnIndependently: true,
        //   allowedOutsideImage: true,
        //   hasBoundingBox: true,
        // }
        textBox: getHandle(x, y - 30, null, {
          highlight: false,
          hasMoved: true,
          active: false,
          movesIndependently: false,
          drawnIndependently: true,
          allowedOutsideImage: true,
          hasBoundingBox: true
        })
      },
    };
  }

  addNewMeasurement(evt, interactionType) {
    const eventData = evt.detail
    if (!eventData || !eventData.currentPoints || !eventData.currentPoints.image) {
      return
    }

    const { element, image } = eventData
    const measurementData = this.createNewMeasurement(eventData)

    if (!measurementData) {
      return
    }

    // Click-to-place and finish immediately; avoid default drag listeners.
    measurementData.active = false
    if (measurementData.handles && measurementData.handles.end) {
      measurementData.handles.end.active = false
      measurementData.handles.end.highlight = false
    }

    cornerstoneTools.addToolState(element, this.name, measurementData)

    if (!measurementData.cachedStats && image) {
      this.updateCachedStats(image, element, measurementData)
    }

    external.cornerstone.updateImage(element)

    triggerEvent(element, EVENTS.MEASUREMENT_COMPLETED, {
      toolName: this.name,
      element,
      measurementData
    })
  }

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

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

    if (!validParameters || data.visible === false) {
      return false;
    }

    const probeCoords = external.cornerstone.pixelToCanvas(
      element,
      data.handles.end
    );

    return external.cornerstoneMath.point.distance(probeCoords, coords) < 5;
  }
  // pointNearTool(element, data, coords) {
  //   const hasEndHandle = data && data.handles && data.handles.end;
  //   const validParameters = hasEndHandle;

  //   if (!validParameters) {
  //     logger.warn(
  //       `invalid parameters supplied to tool ${this.name}'s pointNearTool`
  //     );
  //   }

  //   if (!validParameters || data.visible === false) {
  //     return false;
  //   }
  //   // data.handles.end.x = data.handles.end.x + 10
  //   let endCoords = {
  //     x: data.handles.end.x + 50,
  //     y: data.handles.end.y,
  //     highlight: data.handles.end.highlight,
  //     active: data.handles.end.active,
  //   }
  //   const probeCoords = external.cornerstone.pixelToCanvas(
  //     element,
  //     endCoords
  //   );

  //   return external.cornerstoneMath.point.distance(probeCoords, coords) < 5;
  // }

  // updateCachedStats(image, element, data) {
  //   const x = Math.round(data.handles.end.x);
  //   const y = Math.round(data.handles.end.y);

  //   const stats = {};

  //   if (x >= 0 && y >= 0 && x < image.columns && y < image.rows) {
  //     stats.x = x;
  //     stats.y = y;

  //     if (image.color) {
  //       stats.storedPixels = getRGBPixels(element, x, y, 1, 1);
  //     } else {
  //       stats.storedPixels = external.cornerstone.getStoredPixels(
  //         element,
  //         x,
  //         y,
  //         1,
  //         1
  //       );
  //       stats.sp = stats.storedPixels[0];
  //       stats.mo = stats.sp * image.slope + image.intercept;
  //       stats.suv = calculateSUV(image, stats.sp);
  //     }
  //   }

  //   data.cachedStats = stats;
  //   data.invalidated = false;
  // }
  updateCachedStats(image, element, data) {
    const seriesModule =
      external.cornerstone.metaData.get('generalSeriesModule', image.imageId) ||
      {};
    const modality = seriesModule.modality;
    const pixelSpacing = getPixelSpacing(image);
    const { fixedRadius, digits } = this.configuration;
    const stats = _calculateStats(
      image,
      element,
      data.handles,
      modality,
      pixelSpacing,
      fixedRadius,
      digits
    );

    data.cachedStats = stats;
    data.invalidated = false;
  }

  renderToolData(evt) {
    const eventData = evt.detail;
    const { fixedRadius, renderDashed } = 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 fontHeight = textStyle.getFontSize();
    const lineDash = getModule('globalConfiguration').configuration.lineDash;
    const pixelSpacing = getPixelSpacing(image);
    // Meta
    const seriesModule =
      external.cornerstone.metaData.get('generalSeriesModule', image.imageId) ||
      {};

    // Pixel Spacing
    const modality = seriesModule.modality;
    const hasPixelSpacing = pixelSpacing && pixelSpacing.rowPixelSpacing && pixelSpacing.colPixelSpacing;
    for (let i = 0; i < toolData.data.length; i++) {
      const data = toolData.data[i];
      if (data.visible === false) {
        continue;
      }

      draw(context, context => {
        const color = toolColors.getColorIfActive(data);
        const lineWidth = toolStyle.getToolWidth()
        if (this.configuration.drawHandles) {
          // Draw the handles
          let radius = getCanvasRadius(data.handles, fixedRadius, element, pixelSpacing)
          data.handles.end.radius = radius
          const handleOptions = { handleRadius: radius, color };

          if (renderDashed) {
            handleOptions.lineDash = lineDash;
          }
          drawHandles(context, eventData, data.handles, handleOptions);
        }

        // Update textbox stats
        if (data.invalidated === true) {
          if (data.cachedStats) {
            this.throttledUpdateCachedStats(image, element, data);
          } else {
            this.updateCachedStats(image, element, data);
          }
        }

        // let text, str;
        let textLines = []
        const { x, y, area, mean, radius } = data.cachedStats;

        if (x >= 0 && y >= 0 && x < image.columns && y < image.rows) {
          // text = `${x}, ${y}`;
          if (data.remark) {
            textLines.push(`${data.remark}`)
          }
          if (!image.color) {
            // Draw text
            let unit = _getUnit(modality, this.configuration.showHounsfieldUnits);

            // textLines.push(_formatArea(area, hasPixelSpacing));
            if (mean) {
              // str += `mean: ${parseFloat(mean.toFixed(3))}`;
              textLines.push(`Mean: ${mean} ${unit}`)
            }
            // if (radius) {
            //   str += `radius: ${parseFloat(radius.toFixed(3))}`;
            //   textLines.push(`radius: ${parseFloat(radius.toFixed(3))}`)
            // }
          }
          let r = getPixelRadius(fixedRadius, pixelSpacing)
          // Coords for text
         
          if (!data.handles.hasOwnProperty('textBox')) {
            const coords = {
              // Translate the x/y away from the cursor
              x: data.handles.end.x + r,
              y: data.handles.end.y - r,
            };
            const textCoords = external.cornerstone.pixelToCanvas(
              eventData.element,
              coords
            );
            drawTextBox(
              context,
              textLines,
              textCoords.x,
              textCoords.y ,
              color
            );
            return
          }
          // const handles = {
          //   start: {
          //     x: data.handles.end.x,
          //     y: data.handles.end.y
          //   },
          //   end: {
          //     x: data.handles.end.x + r,
          //     y: data.handles.end.y
          //   }
          // }
          let xOffset = 0
          if (data.remark && !isNaN(parseInt(data.remark.slice(-1)))) {
            let i = parseInt(data.remark.slice(-1))
            if (i === 1) {
              xOffset = -60
            } else if (i === 2) {
              xOffset = 0
            } else if (i=== 3) {
              xOffset = 0
            }
          }
          
          // const xOffset = -30
          const textBoxAnchorPoints = handles => [
            handles.end
          ]
          
          _drawLinkedTextBox(
            context,
            element,
            data.handles.textBox,
            textLines,
            data.handles,
            color,
            lineWidth,
            xOffset,
            false
          )
        }
      });
    }
  }
}
function _drawLinkedTextBox(
  context,
  element,
  textBox,
  text,
  handles,
  color,
  lineWidth,
  xOffset,
  yCenter) {
  const { pixelToCanvas } = external.cornerstone;

  // Convert the textbox Image coordinates into Canvas coordinates
  const textCoords = pixelToCanvas(element, textBox);

  if (xOffset) {
    textCoords.x += xOffset;
  }

  const options = {
    centering: {
      x: false,
      y: yCenter,
    },
  };

  options.displacer = box => clipBoxToDisplayedArea(element, box);

  // Draw the text box
  textBox.boundingBox = drawTextBox(
    context,
    text,
    textCoords.x,
    textCoords.y,
    color,
    options
  );
  if (textBox.hasMoved) {
    // Identify the possible anchor points for the tool -> text line
    let arr = [
      {
        x: handles.end.x,
        y: handles.end.y
      },
      {
        x: handles.end.x,
        y: handles.end.y
      }
    ]
    const linkAnchorPoints = arr.map(h =>
      pixelToCanvas(element, h)
    );

    // Draw dashed link line between tool and text
    drawLink(
      linkAnchorPoints,
      textCoords,
      textBox.boundingBox,
      context,
      color,
      lineWidth
    );
  }
}
function _getUnit(modality, showHounsfieldUnits) {
  return modality === 'CT' && showHounsfieldUnits !== false ? 'HU' : '';
}
function _formatArea(area, hasPixelSpacing) {
  const suffix = hasPixelSpacing
    ? ` mm${String.fromCharCode(178)}`
    : ` px${String.fromCharCode(178)}`;

  return `Area: ${numbersWithCommas(area.toFixed(2))}${suffix}`;
}
function getCanvasRadius(handles, fixedRadius, element, pixelSpacing) {
  let startCoords = {
    x: handles.end.x,
    y: handles.end.y
  }
  const handleCanvasStartCoords = external.cornerstone.pixelToCanvas(
    element,
    startCoords
  );
  let r = getPixelRadius(fixedRadius, pixelSpacing)
  let endCoords = {
    x: handles.end.x + r,
    y: handles.end.y
  }
  const handleCanvasEndCoords = external.cornerstone.pixelToCanvas(
    element,
    endCoords
  );
  return Math.abs(handleCanvasEndCoords.x - handleCanvasStartCoords.x)
}
function getPixelRadius(r, pixelSpacing) {
  return r / ((pixelSpacing && pixelSpacing.colPixelSpacing) || 1)
}
function _calculateStats(image, element, handles, modality, pixelSpacing, fixedRadius, digits) {
  // Retrieve the bounds of the ellipse in image coordinates
  let startCoords = {
    x: handles.end.x,
    y: handles.end.y
  }
  let r = getPixelRadius(fixedRadius, pixelSpacing)
  let endCoords = {
    x: handles.end.x + r,
    y: handles.end.y
  }
  const circleCoordinates = getCircleCoords(startCoords, endCoords);

  // Retrieve the array of pixels that the ellipse bounds cover
  const pixels = external.cornerstone.getPixels(
    element,
    circleCoordinates.left,
    circleCoordinates.top,
    circleCoordinates.width,
    circleCoordinates.height
  );
 
  // Calculate the mean & standard deviation from the pixels and the ellipse details.
  const ellipseMeanStdDev = calculateEllipseStatistics(
    pixels,
    circleCoordinates
  );

  let meanStdDevSUV;

  if (modality === 'PT') {
    meanStdDevSUV = {
      mean: calculateSUV(image, ellipseMeanStdDev.mean, true) || 0,
      stdDev: calculateSUV(image, ellipseMeanStdDev.stdDev, true) || 0,
    };
  }

  const radius =
    (circleCoordinates.width *
      ((pixelSpacing && pixelSpacing.colPixelSpacing) || 1)) /
    2;
  const perimeter = 2 * Math.PI * radius;
  const area =
    Math.PI *
    ((circleCoordinates.width *
      ((pixelSpacing && pixelSpacing.colPixelSpacing) || 1)) /
      2) *
    ((circleCoordinates.height *
      ((pixelSpacing && pixelSpacing.rowPixelSpacing) || 1)) /
      2);
  const x = Math.round(handles.end.x);
  const y = Math.round(handles.end.y);

  const stats = {};

  if (x >= 0 && y >= 0 && x < image.columns && y < image.rows) {
    stats.x = x;
    stats.y = y;
  }
  return {
    area: area || 0,
    radius: radius || 0,
    perimeter: perimeter || 0,
    mean: ellipseMeanStdDev.mean.toFixed(digits) || 0,
    stdDev: ellipseMeanStdDev.stdDev.toFixed(digits) || 0,
    min: ellipseMeanStdDev.min.toFixed(digits) || 0,
    max: ellipseMeanStdDev.max.toFixed(digits) || 0,
    meanStdDevSUV,
    x: stats.x,
    y: stats.y
  };
}


