/*
 * Copyright (c) 2007-2010 by The Broad Institute, Inc. and the Massachusetts Institute of Technology.
 * All Rights Reserved.
 *
 * This software is licensed under the terms of the GNU Lesser General Public License (LGPL), Version 2.1 which
 * is available at http://www.opensource.org/licenses/lgpl-2.1.php.
 *
 * THE SOFTWARE IS PROVIDED "AS IS." THE BROAD AND MIT MAKE NO REPRESENTATIONS OR WARRANTIES OF
 * ANY KIND CONCERNING THE SOFTWARE, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT
 * OR OTHER DEFECTS, WHETHER OR NOT DISCOVERABLE.  IN NO EVENT SHALL THE BROAD OR MIT, OR THEIR
 * RESPECTIVE TRUSTEES, DIRECTORS, OFFICERS, EMPLOYEES, AND AFFILIATES BE LIABLE FOR ANY DAMAGES OF
 * ANY KIND, INCLUDING, WITHOUT LIMITATION, INCIDENTAL OR CONSEQUENTIAL DAMAGES, ECONOMIC
 * DAMAGES OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF WHETHER THE BROAD OR MIT SHALL
 * BE ADVISED, SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF THE POSSIBILITY OF THE
 * FOREGOING.
 */


package org.broad.igv.ui;

//~--- non-JDK imports --------------------------------------------------------

import javax.swing.*;
import java.awt.*;
import java.io.File;

/**
 * Utility class for showing file dialogs.
 *
 * @author Joshua Gould
 */
public class MacCompatibleFileChooser {
    static JFileChooser fileChooser;

    /**
     * Shows a confirm dialog that asks whether the user wants to overwrite an existing file.
     *
     * @param parent The parent component.
     * @param f      The file to overwrite.
     * @return <tt>true</tt> to overwrite the file, <tt>false</tt> otherwise.
     */
    public static boolean overwriteFile(Component parent, File f) {
        if (!f.exists()) {
            return true;
        }

        String message =
                "An item named " + f.getName()
                        + " already exists in this location.\nDo you want to replace it with the one that you are saving?";

        int result = JOptionPane.showConfirmDialog(parent, message, "", JOptionPane.YES_NO_OPTION);

        if (result == JOptionPane.NO_OPTION) {
            return false;
        }

        return true;
    }

    public static File showOpenDialog(Container parent) {
        return showOpenDialog(parent, null);
    }

    /**
     * Shows a file open dialog and returns the selected file or <tt>null</tt>.
     *
     * @param parent The parent component.
     * @param title  The dialog title.
     * @return The selected file or <tt>null</tt>.
     */
    public static File showOpenDialog(Container parent, String title) {
        return showOpenDialog(parent, title, null);

    }

    /**
     * Shows a file open dialog and returns the selected file or <tt>null</tt>.
     *
     * @param parent    The parent component.
     * @param title     The dialog title.
     * @param directory The selected directory or <tt>null</tt>
     * @return The selected file or <tt>null</tt>.
     */
    public static File showOpenDialog(Container parent, String title, File directory) {
        if (parent == null) {
            parent = JOptionPane.getRootFrame();
        }

        if (UIConstants.IS_MAC && ((parent instanceof Frame) || (parent instanceof Dialog))) {
            return showAwtFileDialog(parent, FileDialog.LOAD, directory, title, false);
        }

        if (fileChooser == null) {
            fileChooser = new JFileChooser();
        }

        if (directory != null) {
            fileChooser.setCurrentDirectory(directory);
        }

        fileChooser.setDialogTitle(title);
        fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

        if (fileChooser.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION) {
            return fileChooser.getSelectedFile();
        }

        return null;

    }

    /**
     * Shows a file save dialog and returns the selected file or <tt>null</tt>.
     *
     * @param parent The parent component.
     * @return The selected file or <tt>null</tt>.
     */
    public static File showSaveDialog(Container parent) {
        return showSaveDialog(parent, null);
    }

    /**
     * Shows a file save dialog and returns the selected file or <tt>null</tt>.
     *
     * @param parent            The parent component.
     * @param selectedDirectory The initially selected directory.
     * @return The selected file or <tt>null</tt>.
     */

    public static File showSaveDialog(Container parent, File selectedDirectory) {
        return showSaveDialog(parent, selectedDirectory, null, null, "");
    }

    /**
     * Shows a file save dialog and returns the selected file or <tt>null</tt>.
     *
     * @param parent            The parent component.
     * @param selectedDirectory The initially selected directory.
     * @param extensions        Check to see file ends with one of supplied extensions (e.g. .jpeg, .jpg)
     * @param dialogTitle       The file save dialog title.
     * @return The selected file or <tt>null</tt>.
     */
    public static File showSaveDialog(Container parent, File selectedDirectory, File selectedFile,
                                      String[] extensions, String dialogTitle) {

        if (UIConstants.IS_MAC && ((parent instanceof Frame) || (parent instanceof Dialog))) {
            return ensureCorrectExtension(parent,
                    showAwtFileDialog(parent, FileDialog.SAVE,
                            selectedDirectory, selectedFile, dialogTitle, false), extensions,
                    true);
        }

        if (fileChooser == null) {
            fileChooser = new JFileChooser();
        }

        fileChooser.setDialogTitle(dialogTitle);

        if (selectedDirectory != null) {
            fileChooser.setCurrentDirectory(selectedDirectory);
        }

        if (selectedFile != null) {
            fileChooser.setSelectedFile(new File(selectedFile.getName()));
        }

        fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

        if (fileChooser.showSaveDialog(parent) == JFileChooser.APPROVE_OPTION) {
            File outputFile = fileChooser.getSelectedFile();

            outputFile = ensureCorrectExtension(parent, outputFile, extensions, false);

            if (!overwriteFile(parent, outputFile)) {
                return null;
            } else {
                return outputFile;
            }
        }

        return null;

    }

    /**
     *
     */
    public static File showSelectDirectoryDialog(Container parent, File selectedDirectory,
                                                 String dialogTitle) {
        if (UIConstants.IS_MAC && ((parent instanceof Frame) || (parent instanceof Dialog))) {
            return showAwtFileDialog(parent, FileDialog.SAVE, selectedDirectory, dialogTitle, true);
        }

        if (fileChooser == null) {
            fileChooser = new JFileChooser();
        }

        fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        fileChooser.setDialogTitle(dialogTitle);

        if (selectedDirectory != null) {
            fileChooser.setCurrentDirectory(selectedDirectory);
        }

        if (fileChooser.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION) {
            return fileChooser.getSelectedFile();
        }

        return null;

    }

    /**
     * @param parent     The parent component.
     * @param file       The file.
     * @param extensions Check to see file ends with one of supplied extensions (e.g. .jpeg, .jpg)
     * @param prompt     Whether to prompt when overwriting.
     * @return The file.
     */
    private static File ensureCorrectExtension(Container parent, File file, String[] extensions,
                                               boolean prompt) {
        if ((file != null) && (extensions != null)) {
            String name = file.getName();

            for (int i = 0, length = extensions.length; i < length; i++) {
                if (name.toLowerCase().endsWith(extensions[i].toLowerCase())) {
                    return file;
                }
            }

            if (extensions.length > 0) {
                name += extensions[0];
                file = new File(file.getParent(), name);

                if (prompt && !overwriteFile(parent, file)) {
                    return null;
                }

                return file;
            }
        }

        return file;
    }

    /**
     * Shows an AWT file dialog.
     *
     * @param parent            The owner of the dialog. A {@link java.awt.Frame} or {@link java.awt.Dialog}.
     * @param mode              the mode of the dialog; either <code>FileDialog.LOAD</code> or <code>FileDialog.SAVE</code>
     * @param selectedDirectory The initially selected directory.
     * @param title             The dialog title.
     * @param directoriesOnly   If <tt>true</tt> select directories only.
     * @return The selected file or <tt>null</tt>.
     */

    private static File showAwtFileDialog(Container parent, int mode, File selectedDirectory,
                                          String title, boolean directoriesOnly) {

        return showAwtFileDialog(parent, mode, selectedDirectory, null,
                title, directoriesOnly);
    }

    /**
     * Shows an AWT file dialog.
     *
     * @param parent            The owner of the dialog. A {@link java.awt.Frame} or {@link java.awt.Dialog}.
     * @param mode              the mode of the dialog; either <code>FileDialog.LOAD</code> or <code>FileDialog.SAVE</code>
     * @param selectedDirectory The initially selected directory.
     * @param title             The dialog title.
     * @param directoriesOnly   If <tt>true</tt> select directories only.
     * @return The selected file or <tt>null</tt>.
     */

    private static File showAwtFileDialog(Container parent, int mode, File selectedDirectory, File selectedFile,
                                          String title, boolean directoriesOnly) {
        if (directoriesOnly) {
            System.setProperty("apple.awt.fileDialogForDirectories", "true");
        } else {
            System.setProperty("apple.awt.fileDialogForDirectories", "false");
        }

        FileDialog fc = null;

        if (parent instanceof Frame) {
            fc = new FileDialog((Frame) parent, title, mode);
        } else if (parent instanceof Dialog) {
            fc = new FileDialog((Dialog) parent, title, mode);
        } else {
            throw new IllegalArgumentException();
        }

        if (selectedDirectory != null) {
            fc.setDirectory(selectedDirectory.getPath());
        }

        if (selectedFile != null) {
            fc.setFile(selectedFile.getName());
        }

        fc.setModal(true);
        fc.setVisible(true);

        String f = fc.getFile();
        String directory = fc.getDirectory();

        if (f != null) {
            File file = new File(directory, f);

            return file;    // mac os x file chooser asks user whether to

            // replace existing file
        }

        return null;
    }

    private MacCompatibleFileChooser() {
    }
}
