text: import OHIF from '@ohif/core';
  import { SimpleDialog } from '@ohif/ui';
  import cornerstone from 'cornerstone-core';
  import csTools from 'cornerstone-tools';
  import merge from 'lodash.merge';
  import initCornerstoneTools from './initCornerstoneTools.js';
  import measurementServiceMappingsFactory from './utils/measurementServiceMappings/measurementServiceMappingsFactory';
  
  /**
   *
   * @param {Object} servicesManager
   * @param {Object} configuration
   * @param {Object|Array} configuration.csToolsConfig
   */
  export default function init({ servicesManager, configuration }) {
    const { UIDialogService, MeasurementService } = servicesManager.services;
  
    const callInputDialog = (data, event, callback) => {
      if (UIDialogService) {
        let dialogId = UIDialogService.create({
          centralize: true,
          isDraggable: false,
          content: SimpleDialog.InputDialog,
          useLastPosition: false,
          showOverlay: true,
          contentProps: {
            title: 'Enter your annotation',
            label: 'New label',
            measurementData: data ? { description: data.text } : {},
            onClose: () => UIDialogService.dismiss({ id: dialogId }),
            onSubmit: value => {
              callback(value);
              UIDialogService.dismiss({ id: dialogId });
            },
          },
        });
      }
    };
  
    const { csToolsConfig } = configuration;
    const metadataProvider = OHIF.cornerstone.metadataProvider;
  
    cornerstone.metaData.addProvider(
      metadataProvider.get.bind(metadataProvider),
      9999
    );
  
    // ~~
    const defaultCsToolsConfig = csToolsConfig || {
      globalToolSyncEnabled: true,
      showSVGCursors: true,
      autoResizeViewports: false,
    };
  
    initCornerstoneTools(defaultCsToolsConfig);
  
    const toolsGroupedByType = {
      touch: [csTools.PanMultiTouchTool, csTools.ZoomTouchPinchTool],
      annotations: [
        csTools.ArrowAnnotateTool,
        csTools.BidirectionalTool,
        csTools.LengthTool,
        csTools.AngleTool,
        csTools.FreehandRoiTool,
        csTools.EllipticalRoiTool,
        csTools.DragProbeTool,
        csTools.RectangleRoiTool,
      ],
      segmentation: [csTools.BrushTool],
      other: [
        csTools.PanTool,
        csTools.ZoomTool,
        csTools.WwwcTool,
        csTools.WwwcRegionTool,
        csTools.MagnifyTool,
        csTools.StackScrollTool,
        csTools.StackScrollMouseWheelTool,
        csTools.OverlayTool,
      ],
    };
  
    let tools = [];
    Object.keys(toolsGroupedByType).forEach(toolsGroup =>
      tools.push(...toolsGroupedByType[toolsGroup])
    );
  
    /* Measurement Service */
    _connectToolsToMeasurementService(MeasurementService);
  
    /* Add extension tools configuration here. */
    const internalToolsConfig = {
      ArrowAnnotate: {
        configuration: {
          getTextCallback: (callback, eventDetails) =>
            callInputDialog(null, eventDetails, callback),
          changeTextCallback: (data, eventDetails, callback) =>
            callInputDialog(data, eventDetails, callback),
        },
      },
    };
  
    /* Abstract tools configuration using extension configuration. */
    const parseToolProps = (props, tool) => {
      const { annotations } = toolsGroupedByType;
      // An alternative approach would be to remove the `drawHandlesOnHover` config
      // from the supported configuration properties in `cornerstone-tools`
      const toolsWithHideableHandles = annotations.filter(
        tool => !['RectangleRoiTool', 'EllipticalRoiTool'].includes(tool.name)
      );
  
      let parsedProps = { ...props };
  
      /**
       * drawHandles - Never/Always show handles
       * drawHandlesOnHover - Only show handles on handle hover (pointNearHandle)
       *
       * Does not apply to tools where handles aren't placed in predictable
       * locations.
       */
      if (
        configuration.hideHandles !== false &&
        toolsWithHideableHandles.includes(tool)
      ) {
        if (props.configuration) {
          parsedProps.configuration.drawHandlesOnHover = true;
        } else {
          parsedProps.configuration = { drawHandlesOnHover: true };
        }
      }
  
      return parsedProps;
    };
  
    /* Add tools with its custom props through extension configuration. */
    tools.forEach(tool => {
      const toolName = tool.name.replace('Tool', '');
      const externalToolsConfig = configuration.tools || {};
      const externalToolProps = externalToolsConfig[toolName] || {};
      const internalToolProps = internalToolsConfig[toolName] || {};
      const props = merge(
        internalToolProps,
        parseToolProps(externalToolProps, tool)
      );
      csTools.addTool(tool, props);
    });
  
    // TODO -> We need a better way to do this with maybe global tool state setting all tools passive.
    const BaseAnnotationTool = csTools.importInternal('base/BaseAnnotationTool');
    tools.forEach(tool => {
      if (tool.prototype instanceof BaseAnnotationTool) {
        // BaseAnnotationTool would likely come from csTools lib exports
        const toolName = new tool().name;
        csTools.setToolPassive(toolName); // there may be a better place to determine name; may not be on uninstantiated class
      }
    });
  
    csTools.setToolActive('Pan', { mouseButtonMask: 4 });
    csTools.setToolActive('Zoom', { mouseButtonMask: 2 });
    csTools.setToolActive('Wwwc', { mouseButtonMask: 1 });
    csTools.setToolActive('StackScrollMouseWheel', {}); // TODO: Empty options should not be required
    csTools.setToolActive('PanMultiTouch', { pointers: 2 }); // TODO: Better error if no options
    csTools.setToolActive('ZoomTouchPinch', {});
    csTools.setToolEnabled('Overlay', {});
  }
  
  const _initMeasurementService = measurementService => {
    /* Initialization */
    const { toAnnotation, toMeasurement } = measurementServiceMappingsFactory(
      measurementService
    );
    const csToolsVer4MeasurementSource = measurementService.createSource(
      'CornerstoneTools',
      '4'
    );
  
    /* Matching Criterias */
    const matchingCriteria = {
      valueType: measurementService.VALUE_TYPES.POLYLINE,
      points: 2,
    };
  
    /* Mappings */
    measurementService.addMapping(
      csToolsVer4MeasurementSource,
      'Length',
      matchingCriteria,
      toAnnotation,
      toMeasurement
    );
  
    return csToolsVer4MeasurementSource;
  };
  
  const _connectToolsToMeasurementService = measurementService => {
    const csToolsVer4MeasurementSource = _initMeasurementService(
      measurementService
    );
    const {
      id: sourceId,
      addOrUpdate,
      getAnnotation,
    } = csToolsVer4MeasurementSource;
  
    /* Measurement Service Events */
    cornerstone.events.addEventListener(
      cornerstone.EVENTS.ELEMENT_ENABLED,
      event => {
        const {
          MEASUREMENT_ADDED,
          MEASUREMENT_UPDATED,
        } = measurementService.EVENTS;
  
        measurementService.subscribe(
          MEASUREMENT_ADDED,
          ({ source, measurement }) => {
            if (![sourceId].includes(source.id)) {
              const annotation = getAnnotation('Length', measurement.id);
  
              console.log(
                'Measurement Service [Cornerstone]: Measurement added',
                measurement
              );
              console.log('Mapped annotation:', annotation);
            }
          }
        );
  
        measurementService.subscribe(
          MEASUREMENT_UPDATED,
          ({ source, measurement }) => {
            if (![sourceId].includes(source.id)) {
              const annotation = getAnnotation('Length', measurement.id);
  
              console.log(
                'Measurement Service [Cornerstone]: Measurement updated',
                measurement
              );
              console.log('Mapped annotation:', annotation);
            }
          }
        );
  
        const addOrUpdateMeasurement = csToolsAnnotation => {
          try {
            const { toolName, toolType, measurementData } = csToolsAnnotation;
            const csTool = toolName || measurementData.toolType || toolType;
            csToolsAnnotation.id = measurementData._measurementServiceId;
            const measurementServiceId = addOrUpdate(csTool, csToolsAnnotation);
  
            if (!measurementData._measurementServiceId) {
              addMeasurementServiceId(measurementServiceId, csToolsAnnotation);
            }
          } catch (error) {
            console.warn('Failed to add or update measurement:', error);
          }
        };
  
        const addMeasurementServiceId = (id, csToolsAnnotation) => {
          const { measurementData } = csToolsAnnotation;
          Object.assign(measurementData, { _measurementServiceId: id });
        };
  
        [
          csTools.EVENTS.MEASUREMENT_ADDED,
          csTools.EVENTS.MEASUREMENT_MODIFIED,
        ].forEach(csToolsEvtName => {
          event.detail.element.addEventListener(
            csToolsEvtName,
            ({ detail: csToolsAnnotation }) => {
              console.log(`Cornerstone Element Event: ${csToolsEvtName}`);
              addOrUpdateMeasurement(csToolsAnnotation);
            }
          );
        });
      }
    );
  };
  