content: /*
   * The MIT License (MIT)
   *
   * Copyright (c) 2011-2020 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 NONINFRINGEMENT. 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;
  
  import org.broad.igv.Globals;
  import org.broad.igv.exceptions.DataLoadException;
  import org.broad.igv.ui.util.FileDialogUtils;
  
  import javax.swing.*;
  import javax.swing.filechooser.FileSystemView;
  import java.io.File;
  import java.io.IOException;
  import java.util.prefs.Preferences;
  
  /**
   * @author Jim Robinson
   * @since 3/19/12
   */
  public class DirectoryManager {
  
      private final static String HIC_DIR_USERPREF = "hicDir";
      private static File USER_HOME;
      private static File USER_DIRECTORY;    // FileSystemView.getFileSystemView().getDefaultDirectory();
      private static File HIC_DIRECTORY;     // The HIC application directory
  
      private static File getUserHome() {
          if (USER_HOME == null) {
              String userHomeString = System.getProperty("user.home");
              USER_HOME = new File(userHomeString);
          }
          return USER_HOME;
      }
  
      /**
       * The user directory.  On Mac and Linux this should be the user home directory.  On Windows platforms this
       * is the "My Documents" directory.
       */
      public static synchronized File getUserDirectory() {
          if (USER_DIRECTORY == null) {
              System.out.print("Fetching user directory... ");
              USER_DIRECTORY = FileSystemView.getFileSystemView().getDefaultDirectory();
              //Mostly for testing, in some environments USER_DIRECTORY can be null
              if (USER_DIRECTORY == null) {
                  USER_DIRECTORY = getUserHome();
              }
          }
          return USER_DIRECTORY;
      }
  
  
      public static File getHiCDirectory() {
  
          if (HIC_DIRECTORY == null) {
  
              // Hack for known Java / Windows bug.   Attempt to remove (possible) read-only bit from user directory
              if (System.getProperty("os.name").startsWith("Windows")) {
                  try {
                      Runtime.getRuntime().exec("attrib -r \"" + getUserDirectory().getAbsolutePath() + "\"");
                  } catch (Exception e) {
                      // We tried
                  }
              }
  
              HIC_DIRECTORY = getHiCDirectoryOverride();
  
              // If still null, try the default place
              if (HIC_DIRECTORY == null) {
                  File rootDir = getUserHome();
                  HIC_DIRECTORY = new File(rootDir, "juicebox");
  
                  if (!HIC_DIRECTORY.exists()) {
                      try {
                          boolean wasSuccessful = HIC_DIRECTORY.mkdir();
                          if (!wasSuccessful) {
                              System.err.println("Failed to create user directory!");
                              HIC_DIRECTORY = null;
                          }
                      } catch (Exception e) {
                          System.err.println("Error creating juicebox directory" + e.getLocalizedMessage());
                      }
                  }
              }
  
  
              // The HIC directory either doesn't exist or isn't writeable.  This situation can arise with Windows Vista
              // and Windows 7 due to a Java bug (http://bugs.sun.com/view_bug.do?bug_id=4787931)
              if (HIC_DIRECTORY == null || !HIC_DIRECTORY.exists() || !canWrite(HIC_DIRECTORY)) {
                  if (Globals.isHeadless() || Globals.isSuppressMessages()) {
                      System.err.println("Cannot write to hic directory: " + HIC_DIRECTORY.getAbsolutePath());
                      HIC_DIRECTORY = (new File(".")).getParentFile();
                  } else {
                      int option = JOptionPane.showConfirmDialog(null,
                              "<html>The default Hi-C directory (" + HIC_DIRECTORY + ") " +
                                      "cannot be accessed.  Click Yes to choose a new folder or No to exit.<br>" +
                                      "This folder will be used to create the 'hic' directory",
                              "Hi-C Directory Error", JOptionPane.YES_NO_OPTION);
  
                      if (option == JOptionPane.YES_OPTION) {
                          File parentDirectory = FileDialogUtils.chooseDirectory("Select a location for the hic directory", null);
                          if (parentDirectory != null) {
                              HIC_DIRECTORY = new File(parentDirectory, "hic");
                              HIC_DIRECTORY.mkdir();
                              Preferences prefs = Preferences.userNodeForPackage(Globals.class);
                              prefs.put(HIC_DIR_USERPREF, HIC_DIRECTORY.getAbsolutePath());
                          }
                      }
                  }
              }
  
  
              if (HIC_DIRECTORY == null || !HIC_DIRECTORY.canRead()) {
                  throw new DataLoadException("Cannot read from user directory", HIC_DIRECTORY.getAbsolutePath());
              } else if (!canWrite(HIC_DIRECTORY)) {
                  throw new DataLoadException("Cannot write to user directory", HIC_DIRECTORY.getAbsolutePath());
              }
  
              System.err.println("HiC Directory: " + HIC_DIRECTORY.getAbsolutePath());
          }
          return HIC_DIRECTORY;
      }
  
      private static File getHiCDirectoryOverride() {
          Preferences userPrefs = null;
          File override = null;
          try {
              // See if an override location has been specified.  This is stored with the Java Preferences API
              userPrefs = Preferences.userNodeForPackage(Globals.class);
              String userDir = userPrefs.get(HIC_DIR_USERPREF, null);
              if (userDir != null) {
                  override = new File(userDir);
                  if (!override.exists()) {
                      override = null;
                      userPrefs.remove(HIC_DIR_USERPREF);
                  }
              }
          } catch (Exception e) {
              assert userPrefs != null;
              userPrefs.remove(HIC_DIR_USERPREF);
              override = null;
              System.err.println("Error creating user directory");
              e.printStackTrace();
          }
          return override;
      }
  
      private static boolean canWrite(File directory) {
          // There are bugs in the Windows Java JVM that can cause user directories to be non-writable (target fix is
          // Java 7).  The only way to know if the directory is writable for sure is to try to write something.
          if (Globals.IS_WINDOWS) {
              File testFile = null;
              try {
                  testFile = new File(directory, "hic332415dsfjdsklt.testfile");
                  if (testFile.exists()) {
                      testFile.delete();
                  }
                  testFile.deleteOnExit();
                  testFile.createNewFile();
                  return testFile.exists();
              } catch (IOException e) {
                  return false;
              } finally {
                  assert testFile != null;
                  if (testFile.exists()) {
                      testFile.delete();
                  }
              }
          } else {
              return directory.canWrite();
          }
  
      }
  }
  