import { BaseTool } from './base';
import { Events } from '../enums';
import { getEnabledElement, StackViewport } from '@cornerstonejs/core';
import { getViewportIdsWithToolToRender } from '../utilities/viewportFilters';
import triggerAnnotationRenderForViewportIds from '../utilities/triggerAnnotationRenderForViewportIds';
import { state } from '../store/state';
import { Enums } from '@cornerstonejs/core';
import { hideElementCursor, resetElementCursor, } from '../cursors/elementCursor';
const MAGNIFY_VIEWPORT_ID = 'magnify-viewport';
class MagnifyTool extends BaseTool {
    constructor(toolProps = {}, defaultToolProps = {
        supportedInteractionTypes: ['Mouse', 'Touch'],
        configuration: {
            magnifySize: 10,
            magnifyWidth: 250,
            magnifyHeight: 250,
        },
    }) {
        super(toolProps, defaultToolProps);
        this._hasBeenRemoved = false;
        this.preMouseDownCallback = (evt) => {
            const eventDetail = evt.detail;
            const { element, currentPoints } = eventDetail;
            const enabledElement = getEnabledElement(element);
            const { viewport, renderingEngine } = enabledElement;
            if (!(viewport instanceof StackViewport)) {
                throw new Error('MagnifyTool only works on StackViewports');
            }
            const referencedImageId = this._getReferencedImageId(viewport);
            if (!referencedImageId) {
                throw new Error('MagnifyTool: No referenced image id found, reconstructed planes not supported yet');
            }
            const viewportIdsToRender = getViewportIdsWithToolToRender(element, this.getToolName());
            this.editData = {
                referencedImageId,
                viewportIdsToRender,
                enabledElement,
                renderingEngine,
                currentPoints,
            };
            this._createMagnificationViewport();
            this._activateDraw(element);
            hideElementCursor(element);
            evt.preventDefault();
            triggerAnnotationRenderForViewportIds(viewportIdsToRender);
            return true;
        };
        this.preTouchStartCallback = (evt) => {
            this.preMouseDownCallback(evt);
        };
        this._createMagnificationViewport = () => {
            const { enabledElement, referencedImageId, viewportIdsToRender, renderingEngine, currentPoints, } = this.editData;
            const { viewport } = enabledElement;
            const { element } = viewport;
            const viewportProperties = viewport.getProperties();
            const { canvas: canvasPos, world: worldPos } = currentPoints;
            let magnifyToolElement;
            magnifyToolElement = element.querySelector('.magnifyTool');
            if (magnifyToolElement === null) {
                const magnifyElement = document.createElement('div');
                magnifyElement.classList.add('magnifyTool');
                magnifyElement.style.display = 'block';
                magnifyElement.style.width = `${this.configuration.magnifyWidth}px`;
                magnifyElement.style.height = `${this.configuration.magnifyHeight}px`;
                magnifyElement.style.position = 'absolute';
                magnifyToolElement = magnifyElement;
                const viewportElement = element.querySelector('.viewport-element');
                viewportElement.appendChild(magnifyElement);
                const viewportInput = {
                    viewportId: MAGNIFY_VIEWPORT_ID,
                    type: Enums.ViewportType.STACK,
                    element: magnifyToolElement,
                };
                renderingEngine.enableElement(viewportInput);
            }
            magnifyToolElement.style.top = `${canvasPos[1] - this.configuration.magnifyHeight / 2}px`;
            magnifyToolElement.style.left = `${canvasPos[0] - this.configuration.magnifyWidth / 2}px`;
            const magnifyViewport = renderingEngine.getViewport(MAGNIFY_VIEWPORT_ID);
            magnifyViewport.setStack([referencedImageId]).then(() => {
                if (this._hasBeenRemoved) {
                    return;
                }
                magnifyViewport.setProperties(viewportProperties);
                const { parallelScale } = viewport.getCamera();
                const { focalPoint, position, viewPlaneNormal } = magnifyViewport.getCamera();
                const distance = Math.sqrt(Math.pow(focalPoint[0] - position[0], 2) +
                    Math.pow(focalPoint[1] - position[1], 2) +
                    Math.pow(focalPoint[2] - position[2], 2));
                const updatedFocalPoint = [
                    worldPos[0],
                    worldPos[1],
                    worldPos[2],
                ];
                const updatedPosition = [
                    updatedFocalPoint[0] + distance * viewPlaneNormal[0],
                    updatedFocalPoint[1] + distance * viewPlaneNormal[1],
                    updatedFocalPoint[2] + distance * viewPlaneNormal[2],
                ];
                magnifyViewport.setCamera({
                    parallelScale: parallelScale * (1 / this.configuration.magnifySize),
                    focalPoint: updatedFocalPoint,
                    position: updatedPosition,
                });
                magnifyViewport.render();
            });
            magnifyToolElement.style.display = 'block';
            triggerAnnotationRenderForViewportIds(viewportIdsToRender);
        };
        this._dragCallback = (evt) => {
            const eventDetail = evt.detail;
            const { deltaPoints, element, currentPoints } = eventDetail;
            const deltaPointsWorld = deltaPoints.world;
            const canvasPos = currentPoints.canvas;
            const enabledElement = getEnabledElement(element);
            const { renderingEngine } = enabledElement;
            const magnifyViewport = renderingEngine.getViewport(MAGNIFY_VIEWPORT_ID);
            const magnifyElement = element.querySelector('.magnifyTool');
            if (!magnifyElement) {
                return;
            }
            magnifyElement.style.top = `${canvasPos[1] - this.configuration.magnifyHeight / 2}px`;
            magnifyElement.style.left = `${canvasPos[0] - this.configuration.magnifyWidth / 2}px`;
            const { focalPoint, position } = magnifyViewport.getCamera();
            const updatedPosition = [
                position[0] + deltaPointsWorld[0],
                position[1] + deltaPointsWorld[1],
                position[2] + deltaPointsWorld[2],
            ];
            const updatedFocalPoint = [
                focalPoint[0] + deltaPointsWorld[0],
                focalPoint[1] + deltaPointsWorld[1],
                focalPoint[2] + deltaPointsWorld[2],
            ];
            magnifyViewport.setCamera({
                focalPoint: updatedFocalPoint,
                position: updatedPosition,
            });
            magnifyViewport.render();
        };
        this._dragEndCallback = (evt) => {
            const { element } = evt.detail;
            const enabledElement = getEnabledElement(element);
            const { renderingEngine } = enabledElement;
            renderingEngine.disableElement(MAGNIFY_VIEWPORT_ID);
            const viewportElement = element.querySelector('.viewport-element');
            const magnifyToolElement = viewportElement.querySelector('.magnifyTool');
            viewportElement.removeChild(magnifyToolElement);
            this._deactivateDraw(element);
            resetElementCursor(element);
            this._hasBeenRemoved = true;
        };
        this._activateDraw = (element) => {
            state.isInteractingWithTool = true;
            this._hasBeenRemoved = false;
            element.addEventListener(Events.MOUSE_UP, this._dragEndCallback);
            element.addEventListener(Events.MOUSE_DRAG, this._dragCallback);
            element.addEventListener(Events.MOUSE_CLICK, this._dragEndCallback);
            element.addEventListener(Events.TOUCH_END, this._dragEndCallback);
            element.addEventListener(Events.TOUCH_DRAG, this._dragCallback);
        };
        this._deactivateDraw = (element) => {
            state.isInteractingWithTool = false;
            element.removeEventListener(Events.MOUSE_UP, this._dragEndCallback);
            element.removeEventListener(Events.MOUSE_DRAG, this._dragCallback);
            element.removeEventListener(Events.MOUSE_CLICK, this._dragEndCallback);
            element.removeEventListener(Events.TOUCH_END, this._dragEndCallback);
            element.removeEventListener(Events.TOUCH_DRAG, this._dragCallback);
        };
    }
    _getReferencedImageId(viewport) {
        const targetId = this.getTargetId(viewport);
        let referencedImageId;
        if (viewport instanceof StackViewport) {
            referencedImageId = targetId.split('imageId:')[1];
        }
        return referencedImageId;
    }
}
MagnifyTool.toolName = 'Magnify';
export default MagnifyTool;
