
import {
  VolumeViewport,
  utilities as csUtils,
} from '@cornerstonejs/core'
import * as cornerstoneTools from '@cornerstonejs/tools'
const {
  utilities,
  annotation,
  drawing

} = cornerstoneTools

const { getAnnotations } = annotation.state
const { isAnnotationVisible } = annotation.visibility
const { isAnnotationLocked } = annotation.locking


const drawHandlesSvg = drawing.drawHandles
// const drawRectSvg = drawing.drawRectByCoordinates
const drawLinkedTextBoxSvg = drawing.drawLinkedTextBox
const { getTextBoxCoordsCanvas } = utilities.drawing
const setAttributesIfNecessary = drawing.setAttributesIfNecessary
const setNewAttributesIfValid = drawing.setNewAttributesIfValid
const _getHash = (
  annotationUID,
  drawingElementType,
  nodeUID
) => {
  return `${annotationUID}::${drawingElementType}::${nodeUID}`;
}
const drawRectSvg = (
  svgDrawingHelper,
  annotationUID,
  rectangleUID,
  canvasCoordinates,
  options = {},
  dataId = ''
) => {
  const {
    color,
    width: _width,
    lineWidth,
    lineDash,
  } = Object.assign(
    {
      color: 'rgb(255, 255, 0)',
      width: '2',
      lineWidth: undefined,
      lineDash: undefined,
    },
    options
  );

  // for supporting both lineWidth and width options

  const strokeWidth = lineWidth || _width;

  const svgns = 'http://www.w3.org/2000/svg';
  const svgNodeHash = _getHash(annotationUID, 'rect', rectangleUID);
  const existingRect = svgDrawingHelper.getSvgNode(svgNodeHash);

  const [topLeft, topRight, bottomLeft, bottomRight] = canvasCoordinates;

  const width = Math.hypot(topLeft[0] - topRight[0], topLeft[1] - topRight[1]);
  const height = Math.hypot(
    topLeft[0] - bottomLeft[0],
    topLeft[1] - bottomLeft[1]
  );

  const center = [
    (bottomRight[0] + topLeft[0]) / 2,
    (bottomRight[1] + topLeft[1]) / 2,
  ];
  const leftEdgeCenter = [
    (bottomLeft[0] + topLeft[0]) / 2,
    (bottomLeft[1] + topLeft[1]) / 2,
  ];
  const angle =
    (Math.atan2(center[1] - leftEdgeCenter[1], center[0] - leftEdgeCenter[0]) *
      180) /
    Math.PI;

  const attributes = {
    x: `${center[0] - width / 2}`,
    y: `${center[1] - height / 2}`,
    width: `${width}`,
    height: `${height}`,
    stroke: color,
    fill: 'rgba(0, 0, 0, 1)',
    transform: `rotate(${angle} ${center[0]} ${center[1]})`,
    'stroke-width': strokeWidth,
    'stroke-dasharray': lineDash,
  };

  if (existingRect) {
    setAttributesIfNecessary(attributes, existingRect);

    svgDrawingHelper.setNodeTouched(svgNodeHash);
  } else {
    const svgRectElement = document.createElementNS(svgns, 'rect');

    if (dataId !== '') {
      svgRectElement.setAttribute('data-id', dataId);
    }

    setNewAttributesIfValid(attributes, svgRectElement);

    svgDrawingHelper.appendNode(svgRectElement, svgNodeHash);
  }
}
/**
 * RectangleROIAnnotation let you draw annotations that measures the statistics
 * such as area, max, mean and stdDev of a Rectangular region of interest.
 * You can use RectangleROIAnnotation in all perpendicular views (axial, sagittal, coronal).
 * Note: annotation tools in cornerstone3DTools exists in the exact location
 * in the physical 3d space, as a result, by default, all annotations that are
 * drawing in the same frameOfReference will get shared between viewports that
 * are in the same frameOfReference. RectangleROI tool's text box lines are dynamically
 * generated based on the viewport's underlying Modality. For instance, if
 * the viewport is displaying CT, the text box will shown the statistics in Hounsfield units,
 * and if the viewport is displaying PET, the text box will show the statistics in
 * SUV units.
 *
 * The resulting annotation's data (statistics) and metadata (the
 * state of the viewport while drawing was happening) will get added to the
 * ToolState manager and can be accessed from the ToolState by calling getAnnotations
 * or similar methods.
 *
 * ```js
 * cornerstoneTools.addTool(RectangleROITool)
 *
 * const toolGroup = ToolGroupManager.createToolGroup('toolGroupId')
 *
 * toolGroup.addTool(RectangleROITool.toolName)
 *
 * toolGroup.addViewport('viewportId', 'renderingEngineId')
 *
 * toolGroup.setToolActive(RectangleROITool.toolName, {
 *   bindings: [
 *    {
 *       mouseButton: MouseBindings.Primary, // Left Click
 *     },
 *   ],
 * })
 * ```
 *
 * Read more in the Docs section of the website.
 */

class Note_RectangleRoiTool extends cornerstoneTools.RectangleROITool {
  static toolName = "Note_RectangleRoi"
  constructor(
    toolProps,
    defaultToolProps
  ) {
    super(toolProps, defaultToolProps);
  }

  /**
   * it is used to draw the rectangleROI annotation in each
   * request animation frame. It calculates the updated cached statistics if
   * data is invalidated and cache it.
   *
   * @param enabledElement - The Cornerstone's enabledElement.
   * @param svgDrawingHelper - The svgDrawingHelper providing the context for drawing.
   */
  renderAnnotation = (
    enabledElement,
    svgDrawingHelper
  ) => {
    let renderStatus = false;
    const { viewport } = enabledElement;
    const { element } = viewport;

    let annotations = getAnnotations(this.getToolName(), element);

    if (!annotations?.length) {
      return renderStatus;
    }

    annotations = this.filterInteractableAnnotationsForElement(
      element,
      annotations
    );

    if (!annotations?.length) {
      return renderStatus;
    }

    const targetId = this.getTargetId(viewport);
    const renderingEngine = viewport.getRenderingEngine();

    const styleSpecifier = {
      toolGroupId: this.toolGroupId,
      toolName: this.getToolName(),
      viewportId: enabledElement.viewport.id,
    };

    for (let i = 0; i < annotations.length; i++) {
      const annotation = annotations[i];
      const { annotationUID, data } = annotation;
      const { points, activeHandleIndex } = data.handles;
      const canvasCoordinates = points.map((p) => viewport.worldToCanvas(p));

      styleSpecifier.annotationUID = annotationUID;

      const { lineWidth, lineDash } = this.getAnnotationStyle({
        annotation,
        styleSpecifier,
      });
      let color = 'rgb(255, 255, 0)'
      const { viewPlaneNormal, viewUp } = viewport.getCamera();

      // If cachedStats does not exist, or the unit is missing (as part of import/hydration etc.),
      // force to recalculate the stats from the points
      if (
        !data.cachedStats[targetId] ||
        data.cachedStats[targetId].areaUnit == null
      ) {
        data.cachedStats[targetId] = {
          Modality: null,
          area: null,
          max: null,
          mean: null,
          stdDev: null,
          areaUnit: null,
        };

        this._calculateCachedStats(
          annotation,
          viewPlaneNormal,
          viewUp,
          renderingEngine,
          enabledElement
        );
      } else if (annotation.invalidated) {
        this._throttledCalculateCachedStats(
          annotation,
          viewPlaneNormal,
          viewUp,
          renderingEngine,
          enabledElement
        );

        // If the invalidated data is as a result of volumeViewport manipulation
        // of the tools, we need to invalidate the related stackViewports data if
        // they are not at the referencedImageId, so that
        // when scrolling to the related slice in which the tool were manipulated
        // we re-render the correct tool position. This is due to stackViewport
        // which doesn't have the full volume at each time, and we are only working
        // on one slice at a time.
        if (viewport instanceof VolumeViewport) {
          const { referencedImageId } = annotation.metadata;

          // invalidate all the relevant stackViewports if they are not
          // at the referencedImageId
          for (const targetId in data.cachedStats) {
            if (targetId.startsWith('imageId')) {
              const viewports = renderingEngine.getStackViewports();

              const invalidatedStack = viewports.find((vp) => {
                // The stack viewport that contains the imageId but is not
                // showing it currently
                const referencedImageURI =
                  csUtils.imageIdToURI(referencedImageId);
                const hasImageURI = vp.hasImageURI(referencedImageURI);
                const currentImageURI = csUtils.imageIdToURI(
                  vp.getCurrentImageId()
                );
                return hasImageURI && currentImageURI !== referencedImageURI;
              });

              if (invalidatedStack) {
                delete data.cachedStats[targetId];
              }
            }
          }
        }
      }

      // If rendering engine has been destroyed while rendering
      if (!viewport.getRenderingEngine()) {
        console.warn('Rendering Engine has been destroyed');
        return renderStatus;
      }

      let activeHandleCanvasCoords;

      if (!isAnnotationVisible(annotationUID)) {
        continue;
      }

      if (
        !isAnnotationLocked(annotationUID) &&
        !this.editData &&
        activeHandleIndex !== null && activeHandleIndex !== undefined
      ) {
        // Not locked or creating and hovering over handle, so render handle.
        activeHandleCanvasCoords = [canvasCoordinates[activeHandleIndex]];
      }

      if (activeHandleCanvasCoords) {
        const handleGroupUID = '0';

        drawHandlesSvg(
          svgDrawingHelper,
          annotationUID,
          handleGroupUID,
          activeHandleCanvasCoords,
          {
            color,
          }
        );
      }

      const dataId = `${annotationUID}-rect`;
      const rectangleUID = '0';
      drawRectSvg(
        svgDrawingHelper,
        annotationUID,
        rectangleUID,
        canvasCoordinates,
        {
          color,
          lineDash,
          lineWidth,
        },
        dataId
      );

      renderStatus = true;
    }

    return renderStatus;
  };

}


export default Note_RectangleRoiTool;
