content: /*
   * The MIT License (MIT)
   *
   * Copyright (c) 2011-2021 Broad Institute, Aiden Lab, Rice University, Baylor College of Medicine
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy
   * of this software and associated documentation files (the "Software"), to deal
   * in the Software without restriction, including without limitation the rights
   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the Software is
   * furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in
   * all copies or substantial portions of the Software.
   *
   *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   *  FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
   *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   *  THE SOFTWARE.
   */
  
  package juicebox.gui;
  
  import juicebox.HiC;
  import juicebox.HiCGlobals;
  import juicebox.MainWindow;
  import juicebox.assembly.AssemblyStateTracker;
  import juicebox.data.*;
  import juicebox.data.anchor.MotifAnchorTools;
  import juicebox.data.basics.Chromosome;
  import juicebox.mapcolorui.HeatmapPanel;
  import juicebox.mapcolorui.PearsonColorScale;
  import juicebox.mapcolorui.PearsonColorScaleEditor;
  import juicebox.state.ImportStateFileDialog;
  import juicebox.state.LoadStateFromXMLFile;
  import juicebox.state.Slideshow;
  import juicebox.state.XMLFileHandling;
  import juicebox.tools.utils.norm.CustomNormVectorFileHandler;
  import juicebox.track.LoadAction;
  import juicebox.track.LoadEncodeAction;
  import juicebox.track.feature.*;
  import juicebox.windowui.*;
  import juicebox.windowui.layers.LayersPanel;
  import juicebox.windowui.layers.UnsavedAnnotationWarning;
  import org.broad.igv.ui.util.FileDialogUtils;
  import org.broad.igv.ui.util.MessageUtils;
  
  import javax.swing.*;
  import javax.swing.border.LineBorder;
  import java.awt.*;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.awt.geom.Point2D;
  import java.io.File;
  import java.io.FilenameFilter;
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.List;
  import java.util.Properties;
  
  /**
   * Created by muhammadsaadshamim on 8/4/15.
   */
  public class SuperAdapter {
      private static final List<Feature2D> previousTempSelectedGroup = new ArrayList<>();
      public static String currentlyLoadedMainFiles = "";
      public static String currentlyLoadedControlFiles = "";
      public static boolean assemblyModeCurrentlyActive = false;
      private static String datasetTitle = "";
      private static String controlTitle;
      private final List<AnnotationLayerHandler> annotationLayerHandlers = new ArrayList<>();
      private MainWindow mainWindow;
      private HiC hic;
      private MainViewPanel mainViewPanel;
      private HiCZoom initialZoom;
      private AnnotationLayerHandler activeLayer;
      private AssemblyStateTracker assemblyStateTracker;
      private PearsonColorScale pearsonColorScale;
      private LayersPanel layersPanel;
      private boolean layerPanelIsVisible = false;
  
      public static String getDatasetTitle() {
          return datasetTitle;
      }
  
      public static void setDatasetTitle(String newDatasetTitle) {
          datasetTitle = newDatasetTitle;
      }
  
      public static void showMessageDialog(String message) {
          JOptionPane.showMessageDialog(MainWindow.getInstance(), message);
      }
  
      public static int showConfirmDialog(String message) {
          return JOptionPane.showConfirmDialog(
                  MainWindow.getInstance(),
                  message, "Confirm bundling",
                  JOptionPane.YES_NO_OPTION);
      }
  
      public void setAdapters(MainWindow mainWindow, HiC hic, MainViewPanel mainViewPanel) {
          this.mainWindow = mainWindow;
          this.hic = hic;
          this.mainViewPanel = mainViewPanel;
      }
  
      public boolean unsavedEditsExist() {
          return mainViewPanel.unsavedEditsExist();
      }
  
      public void addRecentMapMenuEntry(String title, boolean status) {
          mainViewPanel.addRecentMapMenuEntry(title, status);
      }
  
  //    public Slideshow getSlideshow() { return new Slideshow(mainWindow,this); }
  
      public void showDataSetMetrics(boolean isControl) {
          if (hic.getDataset() == null) {
              JOptionPane.showMessageDialog(mainWindow, "File must be loaded to show info", "Error", JOptionPane.ERROR_MESSAGE);
          } else {
              try {
                  String title = mainWindow.getTitle() + " QC Stats";
                  if (isControl) title += " (control)";
                  new QCDialog(mainWindow, hic, title, isControl);
              } catch (Exception e) {
                  // TODO - test on hic file with no stats file specified
                  e.printStackTrace();
                  JOptionPane.showMessageDialog(mainWindow, "Unable to launch QC Statistics", "Error",
                          JOptionPane.ERROR_MESSAGE);
              }
          }
      }
  
      public void exportDataLauncher() {
          if (hic.getDataset() == null) {
              JOptionPane.showMessageDialog(mainWindow, "File must be loaded to show info",
                      "Error", JOptionPane.ERROR_MESSAGE);
          } else {
              new DumpDialog(mainWindow, hic);
          }
      }
  
      public void setEnableForAllElements(boolean status) {
          mainViewPanel.setEnableForAllElements(this, status);
          for (AnnotationLayerHandler handler : annotationLayerHandlers) {
              handler.setImportAnnotationsEnabled(status);
          }
      }
  
      public void resetControlMap() {
          hic.setControlDataset(null);
          mainViewPanel.setSelectedDisplayOption(false, false);
          currentlyLoadedControlFiles = null;
          controlTitle = null;
          updateTitle();
      }
  
      public void toggleAdvancedViews() {
          MatrixType.toggleAdvancedViews();
          mainViewPanel.setSelectedDisplayOption(false, hic.isControlLoaded());
      }
  
      public void launchSlideShow() {
          new Slideshow(mainWindow, this);
      }
  
      public void launchImportState(File fileForExport) {
          new ImportStateFileDialog(fileForExport, mainWindow);
      }
  
      public void launchLoadStateFromXML(String mapPath) {
          LoadStateFromXMLFile.reloadSelectedState(this, mapPath);
      }
  
      public void launchPearsonColorScaleEditor() {
          if (pearsonColorScale != null) new PearsonColorScaleEditor(this, pearsonColorScale);
      }
  
      public void launchSetPseudoCountEditor() {
          new PseudoCountEditor(this);
      }
  
      public void restoreLocation(String loc) {
          hic.restoreLocation(loc);
      }
  
      public LoadEncodeAction getEncodeAction() {
          if (layersPanel == null) {
              layersPanel = new LayersPanel(this);
              setLayersPanelVisible(false);
          }
          return layersPanel.getEncodeAction();
      }
  
      public LoadAction getTrackLoadAction() {
          return layersPanel.getTrackLoadAction();
      }
  
      public void updatePrevStateNameFromImport(String path) {
          mainViewPanel.updatePrevStateNameFromImport(path);
      }
  
      public void loadFromListActionPerformed(boolean control) {
          UnsavedAnnotationWarning unsaved = new UnsavedAnnotationWarning(this);
          if (unsaved.checkAndDelete(datasetTitle.length() > 0)) {
              HiCFileLoader.loadFromListActionPerformed(this, control);
          }
      }
  
      public void launchExportPDF() {
          new SaveImageDialog(null, hic, mainWindow, mainViewPanel.getHiCPanel(), ".pdf");
      }
  
      public void launchExportSVG() {
          new SaveImageDialog(null, hic, mainWindow, mainViewPanel.getHiCPanel(), ".svg");
      }
  
      public void loadFromRecentActionPerformed(String url, String title, boolean control) {
          UnsavedAnnotationWarning unsaved = new UnsavedAnnotationWarning(this);
          if (unsaved.checkAndDelete(datasetTitle.length() > 0)) {
              HiCFileLoader.loadFromRecentActionPerformed(this, url, title, control);
          }
      }
  
      public int clearCustomAnnotationDialog() {
          return JOptionPane.showConfirmDialog(
                  mainWindow,
                  "Are you sure you want to clear this layer's annotations?",
                  "Confirm",
                  JOptionPane.YES_NO_OPTION);
      }
  
      public int deleteCustomAnnotationDialog(String layerName) {
          return JOptionPane.showConfirmDialog(
                  mainWindow,
                  "Are you sure you want to delete this layer (" + layerName + ")?",
                  "Confirm",
                  JOptionPane.YES_NO_OPTION);
      }
  
      public void repaint() {
          mainWindow.revalidate();
          mainWindow.repaint();
          if (layersPanel != null) layersPanel.repaint();
      }
  
      public void safeLoadFromURLActionPerformed(final Runnable refresh1DLayers) {
          Runnable runnable = new Runnable() {
              public void run() {
                  if (hic.getDataset() == null) {
                      JOptionPane.showMessageDialog(mainWindow, "HiC file must be loaded to load tracks", "Error", JOptionPane.ERROR_MESSAGE);
                      return;
                  }
  
                  String url = JOptionPane.showInputDialog("Enter URL: ");
  
                  if (url != null && url.length() > 0) {
                      if (HiCFileTools.isDropboxURL(url)) {
                          url = HiCFileTools.cleanUpDropboxURL(url);
                      }
                      url = url.trim();
                      hic.unsafeLoadTrack(url);
                  }
                  refresh1DLayers.run();
              }
          };
          mainWindow.executeLongRunningTask(runnable, "Load from url");
      }
  
      public String getLocationDescription() {
          return hic.getLocationDescription();
      }
  
      public String getDescription(String item) {
          return JOptionPane.showInputDialog(mainWindow, "Enter description for saved " + item + ":",
                  hic.getDefaultLocationDescription());
      }
  
      public void addNewStateToXML(String stateDescription) {
          XMLFileHandling.addNewStateToXML(stateDescription, this);
      }
  
      public void setNormalizationDisplayState() {
          mainViewPanel.setNormalizationDisplayState(hic);
      }
  
      public void centerMap(int xBP, int yBP) {
          hic.center(xBP, yBP);
      }
  
      public void moveMapBy(int dxBP, int dyBP) {
          hic.moveBy(dxBP, dyBP);
      }
  
      public boolean shouldVisibleWindowBeRendered() {
          return hic != null && hic.getXContext() != null;
      }
  
      public double getHiCScaleFactor() {
          return hic.getScaleFactor();
      }
  
      public Point2D.Double getHiCOrigin() {
          return new Point2D.Double(hic.getXContext().getBinOrigin(), hic.getYContext().getBinOrigin());
      }
  
      public Point2D.Double getHiCScale(int width, int height) {
          // TODO - why does this sometimes return null?
          try {
              return new Point2D.Double((double) hic.getZd().getXGridAxis().getBinCount() / width,
                      (double) hic.getZd().getYGridAxis().getBinCount() / height);
          } catch (Exception e) {
              return null; // TODO is there a good default to return?
          }
      }
  
      public Point getHeatMapPanelDimensions() {
          return new Point(mainViewPanel.getHeatmapPanel().getWidth(), mainViewPanel.getHeatmapPanel().getHeight());
      }
  
      public void initializeMainView(Container contentPane, Dimension screenSize, int taskBarHeight) {
          mainViewPanel.initializeMainView(this, contentPane, screenSize, taskBarHeight);
      }
  
      private void unsafeSetInitialZoom() {
  
          //For now, in case of Pearson - set initial to 500KB resolution.
          if (hic.isInPearsonsMode()) {
              initialZoom = hic.getMatrix().getFirstPearsonZoomData(HiC.Unit.BP).getZoom();
          } else if (ChromosomeHandler.isAllByAll(hic.getXContext().getChromosome())) {
              mainViewPanel.getResolutionSlider().setEnabled(false);
              initialZoom = hic.getMatrix().getFirstZoomData().getZoom();
          } else {
              mainViewPanel.getResolutionSlider().setEnabled(true);
  
              // todo this is throwing null pointer exceptions
              initialZoom = hic.getMatrix().getFirstZoomData().getZoom();
  
              // If this is the initial load hic.currentZoom will be null
              if (hic.getZoom() != null) {
                  HiC.Unit currentUnit = hic.getZoom().getUnit();
                  List<HiCZoom> zooms = (currentUnit == HiC.Unit.BP ? hic.getDataset().getBpZooms() :
                          hic.getDataset().getFragZooms());
  //            Find right zoom level
                  int pixels = mainViewPanel.getHeatmapPanel().getMinimumDimension();
                  long len;
                  if (currentUnit == HiC.Unit.BP) {
                      len = (Math.max(hic.getXContext().getChrLength(), hic.getYContext().getChrLength()));
                  } else {
                      len = Math.max(hic.getDataset().getFragmentCounts().get(hic.getXContext().getChromosome().getName()),
                              hic.getDataset().getFragmentCounts().get(hic.getYContext().getChromosome().getName()));
                  }
  
                  int maxNBins = pixels;
                  long bp_bin = len / maxNBins;
                  initialZoom = zooms.get(zooms.size() - 1);
                  for (int z = 1; z < zooms.size(); z++) {
                      if (zooms.get(z).getBinSize() < bp_bin) {
                          initialZoom = zooms.get(z - 1);
                          break;
                      }
                  }
              }
          }
          hic.unsafeActuallySetZoomAndLocation(hic.getXContext().getChromosome().toString(), hic.getYContext().getChromosome().toString(),
                  initialZoom, 0, 0, -1, true, HiC.ZoomCallType.INITIAL, true, isResolutionLocked() ? 1 : 0, true);
      }
  
      public void refresh() {
          mainViewPanel.getHeatmapPanel().clearTileCache();
          mainViewPanel.updateThumbnail(hic);
          repaint();
      }
  
      public void unsafeClearAllMatrixZoomCache() {
          //not sure if this is a right place for this
          hic.clearAllMatrixZoomDataCache();
      }
  
      private void refreshMainOnly() {
          mainViewPanel.getHeatmapPanel().clearTileCache();
          repaint();
      }
  
      private static boolean genomesAreCompatible(Dataset dataset1, Dataset dataset2) {
          if (dataset1.getGenomeId().equalsIgnoreCase(dataset2.getGenomeId())) {
              return true;
          }
  
          String[] g1 = dataset1.getGenomeId().split("/");
          String[] g2 = dataset2.getGenomeId().split("/");
          if (g1[g1.length - 1].equalsIgnoreCase(g2[g2.length - 1])) {
              return true;
          }
          //todo can go chromosome by chromosome and check names/sizes
          System.err.println("Genome IDs do not match:\n" +
                  dataset1.getGenomeId().toLowerCase() + "  vs  " + dataset2.getGenomeId().toLowerCase());
          return false;
      }
  
      private boolean unsafeLoad(final List<String> files, final boolean control, boolean restore) throws IOException {
  
          StringBuilder newFilesToBeLoaded = new StringBuilder();
          boolean allFilesAreHiC = true;
          for (String file : files) {
              if (newFilesToBeLoaded.length() > 1) {
                  newFilesToBeLoaded.append("##");
              }
              newFilesToBeLoaded.append(file);
              allFilesAreHiC &= file.endsWith(".hic");
          }
  
          if ((!control) && newFilesToBeLoaded.toString().equals(currentlyLoadedMainFiles)) {
              if (!restore) {
                  JOptionPane.showMessageDialog(mainWindow, "File(s) already loaded");
              }
              return false;
          }
          if (control && newFilesToBeLoaded.toString().equals(currentlyLoadedControlFiles)) {
              if (!restore) {
                  JOptionPane.showMessageDialog(mainWindow, "File(s) already loaded");
              }
              return false;
          }
  
          if (allFilesAreHiC) {
              mainViewPanel.setIgnoreUpdateThumbnail(true);
              //heatmapPanel.setBorder(LineBorder.createBlackLineBorder());
              //thumbnailPanel.setBorder(LineBorder.createBlackLineBorder());
              mainViewPanel.getMouseHoverTextPanel().setBorder(LineBorder.createGrayLineBorder());
  
              DatasetReader reader = DatasetReaderFactory.getReader(files);
              if (reader == null) return false;
              Dataset dataset = reader.read();
              if (reader.getVersion() < HiCGlobals.minVersion) {
                  JOptionPane.showMessageDialog(mainWindow, "This version of \"hic\" format is no longer supported");
                  return false;
              }
              if (control && !genomesAreCompatible(dataset, hic.getDataset())) {
                  JOptionPane.showMessageDialog(mainWindow, "Cannot load maps with different genomes");
                  return false;
              }
              if (control && dataset.getVersion() != hic.getDataset().getVersion() &&
                      (dataset.getVersion() < 7 || hic.getDataset().getVersion() < 7)) {
                  JOptionPane.showMessageDialog(mainWindow, "Cannot load control with .hic files less than version 7");
                  return false;
              }
  
              if (assemblyModeCurrentlyActive) {
                  if (!exitAssemblyMode()) {
                      return false; //if user does not exit assembly mode then do not load new map
                  }
              }
  
              if (!control && hic.getDataset() != null && !dataset.getGenomeId().equals(hic.getDataset().getGenomeId())) {
                  resetControlMap();
              }
  
              if (control) {
                  hic.setControlDataset(dataset);
                  mainViewPanel.setEnabledForNormalization(true, hic.getNormalizationOptions(true),
                          dataset.getVersion() >= HiCGlobals.minVersion);
              } else {
                  hic.reset();
                  hic.setDataset(dataset);
                  hic.setChromosomeHandler(dataset.getChromosomeHandler());
                  mainViewPanel.setChromosomes(hic.getChromosomeHandler());
  
                  mainViewPanel.setEnabledForNormalization(false, hic.getNormalizationOptions(false),
                          dataset.getVersion() >= HiCGlobals.minVersion);
  
                  hic.resetContexts();
                  updateTrackPanel();
                  mainViewPanel.getMenuBar().getRecentLocationMenu().setEnabled(true);
                  mainWindow.getContentPane().invalidate();
                  mainWindow.repaint();
                  mainViewPanel.resetResolutionSlider(hic.getDefaultUnit());
                  mainViewPanel.unsafeRefreshChromosomes(SuperAdapter.this);
  
              }
              mainViewPanel.setSelectedDisplayOption(control, hic.isControlLoaded());
              setEnableForAllElements(true);
  
              if (control) {
                  currentlyLoadedControlFiles = newFilesToBeLoaded.toString();
              } else {
                  currentlyLoadedMainFiles = newFilesToBeLoaded.toString();
              }
  
              mainViewPanel.getMenuBar().updateMainMapHasBeenLoaded(true);
              if (control) {
                  mainViewPanel.getMenuBar().updateControlMapHasBeenLoaded(true);
              }
              mainViewPanel.setIgnoreUpdateThumbnail(false);
          } else {
              JOptionPane.showMessageDialog(mainWindow, "Please choose a .hic file to load");
          }
          return true;
      }
  
      public void safeLoad(final List<String> files, final boolean control, final String title) {
          addRecentMapMenuEntry(title.trim() + RecentMenu.delimiter + files.get(0), true);
          Runnable runnable = new Runnable() {
              public void run() {
                  boolean isRestorenMode = false;
                  unsafeLoadWithTitleFix(files, control, title, isRestorenMode);
              }
          };
          mainWindow.executeLongRunningTask(runnable, "MainWindow safe load");
      }
  
      public void unsafeLoadWithTitleFix(List<String> files, boolean control, String title, boolean restore) {
          String resetTitle = datasetTitle;
          if (control) resetTitle = controlTitle;
  
          getHeatmapPanel().disableAssemblyEditing();
          resetAnnotationLayers();
          HiCGlobals.hicMapScale = 1;
  //        refresh();
  
          ActionListener l = mainViewPanel.getDisplayOptionComboBox().getActionListeners()[0];
          try {
              mainViewPanel.getDisplayOptionComboBox().removeActionListener(l);
              if (unsafeLoad(files, control, restore)) {
                  //mainViewPanel.updateThumbnail(hic);
                  refresh();
                  updateTitle(control, title);
              }
          } catch (IOException e) {
              // TODO somehow still have trouble reloading the previous file
              System.err.println("Error loading hic file " + e.getLocalizedMessage());
              JOptionPane.showMessageDialog(mainWindow, "Error loading .hic file", "Error", JOptionPane.ERROR_MESSAGE);
              mainViewPanel.updateThumbnail(hic);
              updateTitle(control, resetTitle);
          } finally {
              mainViewPanel.getDisplayOptionComboBox().addActionListener(l);
          }
      }
  
      public KeyEventDispatcher getNewHiCKeyDispatcher() {
          return new HiCKeyDispatcher(this, hic, mainViewPanel.getDisplayOptionComboBox());
      }
  
      public LoadDialog launchLoadFileDialog(Properties properties) {
          return new LoadDialog(mainWindow, properties, this);
      }
  
      void safeRefreshButtonActionPerformed() {
          Runnable runnable = new Runnable() {
              @Override
              public void run() {
                  mainViewPanel.unsafeRefreshChromosomes(SuperAdapter.this);
              }
          };
          mainWindow.executeLongRunningTask(runnable, "Refresh Button");
      }
  
      public boolean safeDisplayOptionComboBoxActionPerformed() {
          final boolean[] retVal = new boolean[1];
          Runnable runnable = new Runnable() {
              public void run() {
                  retVal[0] = unsafeDisplayOptionComboBoxActionPerformed();
              }
          };
          mainWindow.executeLongRunningTask(runnable, "DisplayOptionsComboBox");
          return retVal[0];
      }
  
      void safeNormalizationComboBoxActionPerformed(final ActionEvent e, final boolean isForControl) {
          Runnable runnable = new Runnable() {
              public void run() {
                  unsafeNormalizationComboBoxActionPerformed(isForControl);
              }
          };
          mainWindow.executeLongRunningTask(runnable, "Normalization ComboBox");
      }
  
      public boolean unsafeDisplayOptionComboBoxActionPerformed() {
  
          MatrixType option = (MatrixType) (mainViewPanel.getDisplayOptionComboBox().getSelectedItem());
          if (hic.isWholeGenome() && !MatrixType.isValidGenomeWideOption(option)) {
              JOptionPane.showMessageDialog(mainWindow, option + " matrix is not available for whole-genome view.");
              mainViewPanel.getDisplayOptionComboBox().setSelectedItem(hic.getDisplayOption());
              return false;
          }
  
          mainViewPanel.getColorRangePanel().handleNewFileLoading(option);
  
          if (MatrixType.isVSTypeDisplay(option)) {
              if (hic.getMatrix().isNotIntra()) {
                  JOptionPane.showMessageDialog(mainWindow, "Observed VS Control is not available for inter-chr views.");
                  mainViewPanel.getDisplayOptionComboBox().setSelectedItem(hic.getDisplayOption());
                  return false;
              }
          }
  
          if (MatrixType.isPearsonType(option)) {
              if (hic.getMatrix().isNotIntra()) {
                  JOptionPane.showMessageDialog(mainWindow, "Pearson's matrix is not available for inter-chr views.");
                  mainViewPanel.getDisplayOptionComboBox().setSelectedItem(hic.getDisplayOption());
                  return false;
  
              } else {
                  try {
                      if (hic.isPearsonsNotAvailableForFile(false)) {
                          JOptionPane.showMessageDialog(mainWindow, "Pearson's matrix is not available at this resolution");
                          mainViewPanel.getDisplayOptionComboBox().setSelectedItem(hic.getDisplayOption());
                          return false;
                      }
                      if (MatrixType.isControlPearsonType(option) && hic.isPearsonsNotAvailableForFile(true)) {
                          JOptionPane.showMessageDialog(mainWindow, "Control's Pearson matrix is not available at this resolution");
                          mainViewPanel.getDisplayOptionComboBox().setSelectedItem(hic.getDisplayOption());
                          return false;
                      }
                  } catch (Exception ex) {
                      JOptionPane.showMessageDialog(mainWindow, "Pearson's matrix is not available at this region");
                      mainViewPanel.getDisplayOptionComboBox().setSelectedItem(hic.getDisplayOption());
                      return false;
                  }
              }
          }
  
          hic.setDisplayOption(option);
          refresh(); // necessary to invalidate minimap when changing view
          return true;
      }
  
      /**
       * TODO deprecate
       *
       * @return hic
       */
      public HiC getHiC() {
          return hic;
      }
  
      /**
       * TODO deprecate
       *
       * @return mainwindow
       */
      public MainWindow getMainWindow() {
          return mainWindow;
      }
  
      public LayersPanel getLayersPanel() {
          return layersPanel;
      }
  
      public MainMenuBar getMainMenuBar() {
          return mainViewPanel.getMenuBar();
      }
  
      public void revalidate() {
          mainWindow.revalidate();
          if (layersPanel != null) layersPanel.revalidate();
      }
  
      public void updateMainViewPanelToolTipText(String text) {
          mainViewPanel.updateToolTipText(text);
      }
  
      public void setPositionChrTop(String positionChrTop) {
          mainViewPanel.setPositionChrTop(positionChrTop);
      }
  
      public void setPositionChrLeft(String positionChrLeft) {
          mainViewPanel.setPositionChrLeft(positionChrLeft);
      }
  
      public String getToolTip() {
          return mainViewPanel.getToolTip();
      }
  
      public void repaintTrackPanels() {
          mainViewPanel.repaintTrackPanels();
      }
  
      public void repaintGridRulerPanels() {
          mainViewPanel.repaintGridRulerPanels();
      }
  
      // only hic should call this
      public boolean isResolutionLocked() {
          return mainViewPanel.isResolutionLocked();
      }
  
      public void updateThumbnail() {
          mainViewPanel.updateThumbnail(hic);
      }
  
      public void updateZoom(HiCZoom newZoom) {
          mainViewPanel.updateZoom(newZoom);
      }
  
      public void updateAndResetZoom(HiCZoom newZoom) {
          mainViewPanel.updateAndResetZoom(newZoom);
      }
  
      public void launchFileLoadingError(String urlString) {
          JOptionPane.showMessageDialog(mainWindow, "Error while trying to load " + urlString, "Error",
                  JOptionPane.ERROR_MESSAGE);
      }
  
      private void updateTitle(boolean control, String title) {
          if (title != null && title.length() > 0) {
              if (control) controlTitle = title;
              else datasetTitle = title;
              updateTitle();
          }
      }
  
      private void updateTitle() {
          String newTitle = datasetTitle;
          String fileVersions = "";
          try {
              fileVersions += hic.getDataset().getVersion() + "";
          } catch (Exception ignored) {
          }
  
          if (controlTitle != null && controlTitle.length() > 0) {
              newTitle += "  (control=" + controlTitle + ")";
              try {
                  fileVersions += "/" + hic.getControlDataset().getVersion();
              } catch (Exception ignored) {
              }
          }
          mainWindow.setTitle(HiCGlobals.juiceboxTitle + "<" + fileVersions + ">: " + newTitle);
      }
  
      public void launchGenericMessageDialog(String message, String error, int errorMessage) {
          JOptionPane.showMessageDialog(mainWindow, message, error, errorMessage);
      }
  
      public HeatmapPanel getHeatmapPanel() {
          return mainViewPanel.getHeatmapPanel();
      }
  
      public void updateTrackPanel() {
          mainViewPanel.updateTrackPanel(hic.getLoadedTracks().size() > 0);
      }
  
      private void unsafeNormalizationComboBoxActionPerformed(boolean isForControl) {
          if (isForControl) {
              String value = (String) mainViewPanel.getControlNormalizationComboBox().getSelectedItem();
              hic.setControlNormalizationType(value);
          } else {
              String value = (String) mainViewPanel.getObservedNormalizationComboBox().getSelectedItem();
              hic.setObsNormalizationType(value);
          }
          refreshMainOnly();
      }
  
      public MainViewPanel getMainViewPanel() {
          return mainViewPanel;
      }
  
      public boolean isTooltipAllowedToUpdated() {
          return mainViewPanel.isTooltipAllowedToUpdate();
      }
  
      public void toggleToolTipUpdates(boolean b) {
          mainViewPanel.toggleToolTipUpdates(b);
      }
  
      public void executeLongRunningTask(Runnable runnable, String s) {
          mainWindow.executeLongRunningTask(runnable, s);
      }
  
      public void updateRatioColorSlider(int max, double val) {
          mainViewPanel.updateRatioColorSlider(hic, max, val);
      }
  
      public void updateColorSlider(double low, double high) {
          mainViewPanel.updateColorSlider(hic, low, high, high * 2);
      }
  
      public void unsafeSetSelectedChromosomes(Chromosome xC, Chromosome yC) {
          mainViewPanel.unsafeSetSelectedChromosomes(this, xC, yC);
      }
  
      public void setSelectedChromosomesNoRefresh(Chromosome chrX, Chromosome chrY) {
          mainViewPanel.setSelectedChromosomesNoRefresh(chrX, chrY, hic.getXContext(), hic.getYContext());
          initialZoom = null;
      }
  
      public void unsafeUpdateHiCChromosomes(Chromosome chrX, Chromosome chrY) {
          hic.setSelectedChromosomes(chrX, chrY);
          mainViewPanel.getRulerPanelX().setContext(hic.getXContext(), HiCRulerPanel.Orientation.HORIZONTAL);
          mainViewPanel.getRulerPanelY().setContext(hic.getYContext(), HiCRulerPanel.Orientation.VERTICAL);
  
          mainViewPanel.getChromosomeFigPanelX().setContext(hic.getXContext(), HiCChromosomeFigPanel.Orientation.HORIZONTAL);
          mainViewPanel.getChromosomeFigPanelY().setContext(hic.getYContext(), HiCChromosomeFigPanel.Orientation.VERTICAL);
  
          unsafeSetInitialZoom();
      }
  
      public void setShowChromosomeFig(boolean status) {
          mainViewPanel.setShowChromosomeFig(status);
      }
  
      public boolean getShowGridLines() {
          return mainViewPanel.getShowGridLines();
      }
  
      public void setShowGridLines(boolean status) {
          mainViewPanel.setShowGridLines(status);
      }
  
      public AnnotationLayerHandler getActiveLayerHandler() {
          return activeLayer;
      }
  
      public void setActiveLayerHandler(AnnotationLayerHandler activeLayer) {
          this.activeLayer = activeLayer;
          for (AnnotationLayerHandler layer : annotationLayerHandlers) {
              layer.setActiveLayerButtonStatus(false);
          }
          activeLayer.setActiveLayerButtonStatus(true);
      }
  
      public List<AnnotationLayerHandler> getAllLayers() {
          return annotationLayerHandlers;
      }
  
      // mhoeger - Used for contig layer, currently returns the first element
      public List<AnnotationLayerHandler> getAssemblyLayerHandlers() {
          List<AnnotationLayerHandler> handlers = new ArrayList<>();
          for (AnnotationLayerHandler annotationLayerHandler : annotationLayerHandlers) {
              if (annotationLayerHandler.getAnnotationLayerType() == AnnotationLayer.LayerType.SCAFFOLD || annotationLayerHandler.getAnnotationLayerType() == AnnotationLayer.LayerType.SUPERSCAFFOLD || annotationLayerHandler.getAnnotationLayerType() == AnnotationLayer.LayerType.EDIT) {
                  handlers.add(annotationLayerHandler);
              }
          }
          if (handlers.size() == 0) {
              handlers.add(annotationLayerHandlers.get(0));
          }
          return handlers;
      }
  
      private AnnotationLayerHandler getAssemblyLayerHandler(AnnotationLayer.LayerType layerType) {
          for (AnnotationLayerHandler annotationLayerHandler : getAssemblyLayerHandlers()) {
              if (annotationLayerHandler.getAnnotationLayerType() == layerType) {
                  return annotationLayerHandler;
              }
          }
          return null;
      }
  
      public AnnotationLayerHandler getMainLayer() {
          return getAssemblyLayerHandler(AnnotationLayer.LayerType.SCAFFOLD);
      }
  
      public AnnotationLayerHandler getGroupLayer() {
          return getAssemblyLayerHandler(AnnotationLayer.LayerType.SUPERSCAFFOLD);
      }
  
      public AnnotationLayerHandler getEditLayer() {
          return getAssemblyLayerHandler(AnnotationLayer.LayerType.EDIT);
      }
  
      public void exitActionPerformed() {
          UnsavedAnnotationWarning unsaved = new UnsavedAnnotationWarning(this);
          if (unsaved.checkAndDelete(true)) {
              mainWindow.exitActionPerformed();
          }
      }
  
      /**
       * @param temp file, otherwise just pass null
       * @return active AnnotationLayerHandler
       */
      public AnnotationLayerHandler createNewLayer(File temp) {
          if (temp != null) {
              activeLayer = new AnnotationLayerHandler(Feature2DParser.loadFeatures(
                      temp.getAbsolutePath(), hic.getChromosomeHandler(),
                      true, null, false));
          } else {
              activeLayer = new AnnotationLayerHandler();
          }
  
          annotationLayerHandlers.add(activeLayer);
          setActiveLayerHandler(activeLayer); // call this anyways because other layers need to fix button settings
          return activeLayer;
      }
  
      public void updateLayerDeleteStatus() {
          boolean isDeleteAllowed = annotationLayerHandlers.size() > 1;
          for (AnnotationLayerHandler handler : annotationLayerHandlers) {
              handler.setDeleteLayerButtonStatus(isDeleteAllowed);
          }
      }
  
      public int removeLayer(AnnotationLayerHandler handler) {
          int returnCode = -1;
          if (annotationLayerHandlers != null && annotationLayerHandlers.size() > 1) {
              // must have at least 1 layer
              returnCode = annotationLayerHandlers.size() - 1 - annotationLayerHandlers.indexOf(handler);
              annotationLayerHandlers.remove(handler);
              if (handler == activeLayer) {
                  // need to set a new active layer; let's use first one as default
                  setActiveLayerHandler(annotationLayerHandlers.get(0));
              }
          }
          updateLayerDeleteStatus();
          return returnCode;
      }
  
      private void resetAnnotationLayers() {
          annotationLayerHandlers.clear();
          // currently must have at least 1 layer
          getActiveLayerHandler().getAnnotationLayer().resetCounter();
          createNewLayer(null);
          updateMiniAnnotationsLayerPanel();
          updateMainLayersPanel();
      }
     
      public int moveDownIndex(AnnotationLayerHandler handler) {
          int currIndex = annotationLayerHandlers.indexOf(handler);
          int n = annotationLayerHandlers.size();
          if (currIndex > 0) {
              Collections.swap(annotationLayerHandlers, currIndex, currIndex - 1);
              return n - currIndex;
          }
          return n - 1 - currIndex;
      }
  
      public int moveUpIndex(AnnotationLayerHandler handler) {
          int currIndex = annotationLayerHandlers.indexOf(handler);
          int n = annotationLayerHandlers.size();
          if (currIndex < n - 1) {
              Collections.swap(annotationLayerHandlers, currIndex, currIndex + 1);
              return n - 2 - currIndex;
          }
          return n - 1 - currIndex;
      }
  
      public void setPearsonColorScale(PearsonColorScale pearsonColorScale) {
          this.pearsonColorScale = pearsonColorScale;
      }
  
      public String getTrackPanelPrintouts(int x, int y) {
          return mainViewPanel.getTrackPanelPrintouts(x, y);
      }
  
      public void setLayersPanelVisible(boolean status) {
          this.layerPanelIsVisible = status;
          if (layersPanel == null) {
              if (status) layersPanel = new LayersPanel(this);
          }
          layersPanel.setVisible(status);
          setLayersPanelGUIControllersSelected(status);
      }
  
      public void intializeLayersPanel() {
          layersPanel = new LayersPanel(this);
      }
  
      public void setLayersPanelGUIControllersSelected(boolean status) {
          mainViewPanel.setAnnotationsPanelToggleButtonSelected(status);
      }
  
      public void togglePanelVisible() {
          setLayersPanelVisible(!layerPanelIsVisible);
      }
  
      public AssemblyStateTracker getAssemblyStateTracker() {
          return assemblyStateTracker;
      }
  
      public void setAssemblyStateTracker(AssemblyStateTracker assemblyStateTracker) {
          this.assemblyStateTracker = assemblyStateTracker;
      }
  
      public void createCustomChromosomesFromBED() {
  
          FilenameFilter bedFilter = new FilenameFilter() {
              public boolean accept(File dir, String name) {
                  return name.toLowerCase().endsWith(".bed");
              }
          };
  
          File[] files = FileDialogUtils.chooseMultiple("Choose .bed file(s)",
                  LoadDialog.LAST_LOADED_HIC_FILE_PATH, bedFilter);
  
          if (files != null && files.length > 0) {
              LoadDialog.LAST_LOADED_HIC_FILE_PATH = files[0];
  
              int minSize = MotifAnchorTools.getMinSizeForExpansionFromGUI();
  
              for (File f : files) {
                  Chromosome custom = hic.getChromosomeHandler().generateCustomChromosomeFromBED(f, minSize);
                  updateChrHandlerAndMVP(custom);
              }
          }
      }
  
      public void createAssemblyChromosome() {
          Chromosome assembly = hic.getChromosomeHandler().generateAssemblyChromosome();
          updateChrHandlerAndMVP(assembly);
      }
  
      public void createCustomChromosomeMap(Feature2DList featureList, String chrName) {
          Chromosome custom = hic.getChromosomeHandler().addCustomChromosome(featureList, chrName);
          updateChrHandlerAndMVP(custom);
      }
  
      private void updateChrHandlerAndMVP(Chromosome custom) {
          hic.setChromosomeHandler(hic.getChromosomeHandler());
          mainViewPanel.getChrBox1().addItem(custom);
          mainViewPanel.getChrBox2().addItem(custom);
      }
  
      public void updateMiniAnnotationsLayerPanel() {
          try {
              getMainViewPanel().updateMiniAnnotationsLayerPanel(this);
          } catch (Exception ignored) {
          }
      }
  
      public void updateMainLayersPanel() {
          try {
              getLayersPanel().updateLayers2DPanel(this);
          } catch (Exception ignored) {
          }
      }
  
      public void updatePreviousTempSelectedGroups(Feature2D tempSelectedGroup) {
          previousTempSelectedGroup.add(tempSelectedGroup);
      }
  
      public void safeClearAllMZDCache() {
          Runnable runnable = new Runnable() {
              public void run() {
                  unsafeClearAllMatrixZoomCache(); //split clear current zoom and put the rest in background? Seems to taking a lot of time
                  refresh();
              }
          };
          executeLongRunningTask(runnable, "Assembly clear MZD cache");
      }
  
      public boolean exitAssemblyMode() {
          MainMenuBar.exitAssemblyMode();
          int dialogButton = JOptionPane.YES_NO_OPTION;
          int dialogResult = JOptionPane.showConfirmDialog(mainWindow, "This action will discard all unsaved assembly changes. Continue?", "Continue", dialogButton);
          if (dialogResult == JOptionPane.NO_OPTION) {
              return false;
          } else {
              if (layersPanel != null) {
                  layersPanel.createNewLayerAndAddItToPanels(this, null);
              }
              if (getAssemblyLayerHandlers() != null) {
                  for (AnnotationLayerHandler annotationLayerHandler : getAssemblyLayerHandlers())
                      removeLayer(annotationLayerHandler);
                  if (layersPanel != null) {
                      layersPanel.updateBothLayersPanels(this);
                  }
                  assemblyModeCurrentlyActive = false;
                  safeClearAllMZDCache();
                  repaint();
              }
              resetAnnotationLayers();
              return true;
          }
      }
  
      public void safeLaunchImportNormalizations(boolean isControl) {
  
          final File[] files = FileDialogUtils.chooseMultiple("Choose custom normalization file(s)",
                  LoadDialog.LAST_LOADED_HIC_FILE_PATH, null);
  
          Runnable runnable = new Runnable() {
              public void run() {
                  if (files != null && files.length > 0) {
                      LoadDialog.LAST_LOADED_HIC_FILE_PATH = files[0];
  
  
                      CustomNormVectorFileHandler.unsafeHandleUpdatingOfNormalizations(SuperAdapter.this, files, isControl, 1);
  
                      boolean versionStatus = hic.getDataset().getVersion() >= HiCGlobals.minVersion;
                      if (isControl) {
                          versionStatus = hic.getControlDataset().getVersion() >= HiCGlobals.minVersion;
                      }
  
                      mainViewPanel.setEnabledForNormalization(isControl, hic.getNormalizationOptions(isControl), versionStatus);
                      repaint();
                  }
              }
          };
          mainWindow.executeLongRunningTask(runnable, "safe add custom norms");
  
      }
  
      public void createGenomewideChromosomeFromChromDotSizes() {
          Chromosome custom = hic.getChromosomeHandler().addGenomeWideChromosome();
          updateChrHandlerAndMVP(custom);
      }
  
      public static int getNewResolutionGUI() {
          int newResolution = -1;
          String newSize = MessageUtils.showInputDialog("Specify a new resolution", "");
          try {
              newResolution = Integer.parseInt(newSize);
          } catch (Exception e) {
              if (HiCGlobals.guiIsCurrentlyActive) {
                  SuperAdapter.showMessageDialog("Invalid resolution given (not integer): " + newSize);
              } else {
                  MessageUtils.showMessage("Invalid resolution given (not integer): " + newSize);
              }
          }
          return newResolution;
      }
  
      public void safeLaunchCreateNewResolution() {
          int newResolution = getNewResolutionGUI();
          if (newResolution > 0) {
              hic.createNewDynamicResolutions(newResolution);
              refresh();
              getMainViewPanel().getResolutionSlider().reset();
  
          }
      }
  
      public void clearEditsAndUpdateLayers() {
          getEditLayer().clearAnnotations();
          if (getActiveLayerHandler() != getMainLayer()) {
              setActiveLayerHandler(getMainLayer());
              getLayersPanel().updateBothLayersPanels(this);
          }
      }
  }
  