/** FileSystemView that handles some specific unix-isms. */
class UnixFileSystemView extends FileSystemView {

  private static final String newFolderString = UIManager.getString("FileChooser.other.newFolder");
  private static final String newFolderNextString =
      UIManager.getString("FileChooser.other.newFolder.subsequent");

  /** Creates a new folder with a default folder name. */
  public File createNewFolder(File containingDir) throws IOException {
    if (containingDir == null) {
      throw new IOException("Containing directory is null:");
    }
    File newFolder;
    // Unix - using OpenWindows' default folder name. Can't find one for Motif/CDE.
    newFolder = createFileObject(containingDir, newFolderString);
    int i = 1;
    while (newFolder.exists() && i < 100) {
      newFolder =
          createFileObject(
              containingDir, MessageFormat.format(newFolderNextString, new Integer(i)));
      i++;
    }

    if (newFolder.exists()) {
      throw new IOException("Directory already exists:" + newFolder.getAbsolutePath());
    } else {
      newFolder.mkdirs();
    }

    return newFolder;
  }

  public boolean isFileSystemRoot(File dir) {
    return dir != null && dir.getAbsolutePath().equals("/");
  }

  public boolean isDrive(File dir) {
    return isFloppyDrive(dir);
  }

  public boolean isFloppyDrive(File dir) {
    // Could be looking at the path for Solaris, but wouldn't be reliable.
    // For example:
    // return (dir != null && dir.getAbsolutePath().toLowerCase().startsWith("/floppy"));
    return false;
  }

  public boolean isComputerNode(File dir) {
    if (dir != null) {
      String parent = dir.getParent();
      if (parent != null && parent.equals("/net")) {
        return true;
      }
    }
    return false;
  }
}
/** Fallthrough FileSystemView in case we can't determine the OS. */
class GenericFileSystemView extends FileSystemView {

  private static final String newFolderString = UIManager.getString("FileChooser.other.newFolder");

  /** Creates a new folder with a default folder name. */
  public File createNewFolder(File containingDir) throws IOException {
    if (containingDir == null) {
      throw new IOException("Containing directory is null:");
    }
    // Using NT's default folder name
    File newFolder = createFileObject(containingDir, newFolderString);

    if (newFolder.exists()) {
      throw new IOException("Directory already exists:" + newFolder.getAbsolutePath());
    } else {
      newFolder.mkdirs();
    }

    return newFolder;
  }
}
/** FileSystemView that handles some specific windows concepts. */
class WindowsFileSystemView extends FileSystemView {

  private static final String newFolderString = UIManager.getString("FileChooser.win32.newFolder");
  private static final String newFolderNextString =
      UIManager.getString("FileChooser.win32.newFolder.subsequent");

  public Boolean isTraversable(File f) {
    return Boolean.valueOf(isFileSystemRoot(f) || isComputerNode(f) || f.isDirectory());
  }

  public File getChild(File parent, String fileName) {
    if (fileName.startsWith("\\") && !fileName.startsWith("\\\\") && isFileSystem(parent)) {

      // Path is relative to the root of parent's drive
      String path = parent.getAbsolutePath();
      if (path.length() >= 2 && path.charAt(1) == ':' && Character.isLetter(path.charAt(0))) {

        return createFileObject(path.substring(0, 2) + fileName);
      }
    }
    return super.getChild(parent, fileName);
  }

  /**
   * Type description for a file, directory, or folder as it would be displayed in a system file
   * browser. Example from Windows: the "Desktop" folder is desribed as "Desktop".
   *
   * <p>The Windows implementation gets information from the ShellFolder class.
   */
  public String getSystemTypeDescription(File f) {
    if (f == null) {
      return null;
    }

    try {
      return getShellFolder(f).getFolderType();
    } catch (FileNotFoundException e) {
      return null;
    }
  }

  /** @return the Desktop folder. */
  public File getHomeDirectory() {
    return getRoots()[0];
  }

  /** Creates a new folder with a default folder name. */
  public File createNewFolder(File containingDir) throws IOException {
    if (containingDir == null) {
      throw new IOException("Containing directory is null:");
    }
    // Using NT's default folder name
    File newFolder = createFileObject(containingDir, newFolderString);
    int i = 2;
    while (newFolder.exists() && i < 100) {
      newFolder =
          createFileObject(
              containingDir, MessageFormat.format(newFolderNextString, new Integer(i)));
      i++;
    }

    if (newFolder.exists()) {
      throw new IOException("Directory already exists:" + newFolder.getAbsolutePath());
    } else {
      newFolder.mkdirs();
    }

    return newFolder;
  }

  public boolean isDrive(File dir) {
    return isFileSystemRoot(dir);
  }

  public boolean isFloppyDrive(final File dir) {
    String path =
        AccessController.doPrivileged(
            new PrivilegedAction<String>() {
              public String run() {
                return dir.getAbsolutePath();
              }
            });

    return path != null && (path.equals("A:\\") || path.equals("B:\\"));
  }

  /** Returns a File object constructed from the given path string. */
  public File createFileObject(String path) {
    // Check for missing backslash after drive letter such as "C:" or "C:filename"
    if (path.length() >= 2 && path.charAt(1) == ':' && Character.isLetter(path.charAt(0))) {
      if (path.length() == 2) {
        path += "\\";
      } else if (path.charAt(2) != '\\') {
        path = path.substring(0, 2) + "\\" + path.substring(2);
      }
    }
    return super.createFileObject(path);
  }

  protected File createFileSystemRoot(File f) {
    // Problem: Removable drives on Windows return false on f.exists()
    // Workaround: Override exists() to always return true.
    return new FileSystemRoot(f) {
      public boolean exists() {
        return true;
      }
    };
  }
}