text: import { $ } from 'meteor/jquery';
  import { _ } from 'meteor/underscore';
  import { OHIF } from 'meteor/ohif:core';
  import { cornerstone } from 'meteor/ohif:cornerstone';
  
  function renderIntoViewport(measurementData, enabledElement, viewportIndex) {
      const { activateMeasurements, findAndRenderDisplaySet } = OHIF.measurements;
      const { element } = enabledElement;
      const { studyInstanceUid, seriesInstanceUid, sopInstanceUid } = measurementData;
  
      return new Promise((resolve, reject) => {
          const renderedCallback = element => {
              activateMeasurements(element, measurementData);
              $(element).one('cornerstoneimagerendered', () => resolve());
          };
  
          // Find the study by studyInstanceUid and render the display set
          const findAndRender = () => {
              // @TypeSafeStudies
              const study = OHIF.viewer.Studies.findBy({ studyInstanceUid });
  
              // TODO: Support frames? e.g. for measurements on multi-frame instances
              findAndRenderDisplaySet(
                  study.displaySets,
                  viewportIndex,
                  studyInstanceUid,
                  seriesInstanceUid,
                  sopInstanceUid,
                  renderedCallback
              );
          };
  
          // Check if the study / series we need is already the one in the viewport.
          // Otherwise, re-render the viewport with the required study/series, then add a rendered
          // callback to activate the measurements
          if (enabledElement && enabledElement.image) {
              const imageId = enabledElement.image.imageId;
              const series = cornerstone.metaData.get('series', imageId);
              const study = cornerstone.metaData.get('study', imageId);
  
              const isSameStudy = study.studyInstanceUid === measurementData.studyInstanceUid;
              const isSameSeries = series.seriesInstanceUid === measurementData.seriesInstanceUid;
              if (isSameStudy && isSameSeries) {
                  // If it is, activate the measurements in this viewport and stop here
                  OHIF.viewerbase.viewportUtils.resetViewport(viewportIndex);
                  renderedCallback(element);
              } else {
                  findAndRender();
              }
          } else {
              findAndRender();
          }
      });
  }
  
  function syncViewports(viewportsIndexes) {
      const synchronizer = OHIF.viewer.stackImagePositionOffsetSynchronizer;
  
      if(!synchronizer) { return; }
  
      const linkableViewports = synchronizer.getLinkableViewports();
      if (linkableViewports.length) {
          const linkableViewportsIndexes = _.pluck(linkableViewports, 'index');
          const indexes = _.intersection(linkableViewportsIndexes, viewportsIndexes);
          if (indexes.length) {
              OHIF.viewer.stackImagePositionOffsetSynchronizer.activateByViewportIndexes(indexes);
          }
      }
  }
  
  // Store the lastActivatedRowItem to cancel jumping if another rowItem was triggered during loading
  let lastActivatedRowItem;
  
  /**
   * Activates a set of lesions when lesion table row is clicked
   *
   * @param measurementId The unique key for a specific Measurement
   */
  OHIF.measurements.jumpToRowItem = (rowItem, timepoints, childToolKey) => {
      const { isZoomed, zoomedViewportIndex } = OHIF.viewerbase.layoutManager;
  
      lastActivatedRowItem = rowItem;
  
      // Retrieve the list of available viewports
      const $viewports = $('.imageViewerViewport');
      const numViewports = Math.max($viewports.length, 0);
  
      // Clone the timepoint list to prevent modifying the original object
      let timepointList;
      if (isZoomed) {
          timepointList = [timepoints[zoomedViewportIndex]];
      } else {
          timepointList = _.clone(timepoints);
      }
  
      // Reverse the timepointList array if the flag is set
      if (OHIF.viewer.invertViewportTimepointsOrder) {
          timepointList.reverse();
      }
  
      // Retrieve the timepoints that are currently being displayed in the  Measurement Table
      const numTimepoints = Math.max(timepointList.length, 1);
  
      const numViewportsToUpdate = Math.min(numTimepoints, numViewports);
  
      // Retrieve the measurements data
      const measurementsData = [];
      const promises = new Set();
      for (let i = 0; i < numViewportsToUpdate; i++) {
          const { timepointId } = timepointList[i];
  
          const dataAtThisTimepoint = _.where(rowItem.entries, { timepointId });
          if (!dataAtThisTimepoint || !dataAtThisTimepoint.length) {
              measurementsData.push(null);
              continue;
          }
  
          const measurement = dataAtThisTimepoint[0];
          let measurementData = measurement;
          const { toolType } = measurementData;
          const { tool } = OHIF.measurements.getToolConfiguration(toolType);
          if (childToolKey) {
              measurementData = measurementData[childToolKey];
          } else if (Array.isArray(tool.childTools)) {
              tool.childTools.every(key => {
                  measurementData = measurementData[key];
                  return !measurementData;
              });
          }
  
          measurementsData.push(measurementData);
          const promise = OHIF.studies.loadStudy(measurementData.studyInstanceUid);
          promise.then(() => OHIF.measurements.syncMeasurementAndToolData(measurement));
          promises.add(promise);
      }
  
      // Wait for studies metadata to be retrieved before jumpint to the given row item
      Promise.all(promises).then(() => {
          // Stop here if another rowItem was activated during loading process
          if (rowItem !== lastActivatedRowItem) return;
  
          OHIF.measurements.deactivateAllToolData();
  
          const activatedViewportIndexes = [];
  
          // Deactivate stack synchronizer because it will be re-activated later
          const synchronizer = OHIF.viewer.stackImagePositionOffsetSynchronizer;
          if(synchronizer) {
              synchronizer.deactivate();
          }
  
          const renderPromises = [];
          for (let viewportIndex = 0; viewportIndex < numViewportsToUpdate; viewportIndex++) {
              const measurementData = measurementsData[viewportIndex];
              if (!measurementData) continue;
  
              activatedViewportIndexes.push(viewportIndex);
  
              const element = $viewports.get(viewportIndex);
  
              // TODO: Implement isEnabledElement in Cornerstone
              // or maybe just remove the 'error' this throws?
              let enabledElement;
              try {
                  enabledElement = cornerstone.getEnabledElement(element);
              } catch(error) {
                  continue;
              }
  
              const promise = renderIntoViewport(measurementData, enabledElement, viewportIndex);
              renderPromises.push(promise);
          }
  
          // Wait for all viewports to be rendered then sync them
          Promise.all(renderPromises).then(() => syncViewports(activatedViewportIndexes));
      });
  };
  