/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: OpenFile.java
 *
 * Copyright (c) 2003, Static Free Software. All rights reserved.
 *
 * Electric(tm) is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Electric(tm) is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.sun.electric.tool.user.dialogs;

import com.sun.electric.database.EditingPreferences;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.io.FileType;
import com.sun.electric.tool.io.input.LibDirs;
import com.sun.electric.tool.user.User;
import com.sun.electric.tool.user.menus.FileMenu;
import com.sun.electric.tool.user.ui.TopLevel;
import com.sun.electric.util.TextUtils;

import java.io.File;
import java.util.Iterator;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileSystemView;

/**
 * Class to handle file selection dialogs.
 */
public class OpenFile
{
	public static class OpenFileSwing extends JFileChooser
	{
		/** True if this is a file save dialog */									private boolean saveDialog;
		/** True to set new directory as working directory (default is true) */		private boolean setSelectedDirAsWorkingDir;
		/** Holds the last DELIB file visited in isTraversable */ 					File lastDELIBVisit = null;
		private FileType fileType;

		/** Private constructor, use factory methods chooseInputFile or
		 * chooseOutputFile instead.
		 */
		private OpenFileSwing() {}

		/**
		 * Method called when the user clicks "OK" during file choosing.
		 * Prevents overwriting of existing files.
		 */
		public void approveSelection()
		{
			File f = getSelectedFile();
			if (saveDialog)
			{
				String filename = f.getName();
                FileType selectedType = FileType.getType(getFileFilter());
                String extension = TextUtils.getExtension(filename);
                FileType givenExtension = FileType.findTypeByExtension(extension);
                // givenExtension is null if extension is not one of the predefined ones.
                String actualGivenExtension = (givenExtension != null) ? givenExtension.getFirstExtension() : extension;

                // givenExtension != selectedType to prevent jelib.delib file for example
                if (givenExtension != selectedType &&
                    !extension.toLowerCase().equals(actualGivenExtension.toLowerCase()) )
                {
                    f = new File(f.getAbsolutePath() + "." + selectedType.getFirstExtension());
                }
                if (f.exists())
				{
					int result = JOptionPane.showConfirmDialog(this, "The file "+f.getName()+" already exists, would you like to overwrite it?",
						"Overwrite?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
					if (result != JOptionPane.OK_OPTION) return;
				}
			} else {
				// IF: Opening file found in LIBDIR redirect, then
				// if user clicks on file and hits OK, it acts as if file
				// is in current directory, which it is not.  We need to check
				// libdir directories in this case.
				FileSystemView view = getFileSystemView();
				if ((view instanceof LibDirs.LibDirFileSystemView) && !f.exists()) {
					for (Iterator<String> it = LibDirs.getLibDirs(); it.hasNext(); ) {
						String dirName = it.next();
						File dir = new File(dirName);
						if (!dir.exists()) continue;
						if (!dir.isDirectory()) continue;
						File newFile = new File(dir, f.getName());
						if (newFile.exists()) {
							// assume it's this one
							f = newFile;
							break;
						}
					}
				}
			}

			setSelectedFile(f);
			if (setSelectedDirAsWorkingDir)
				User.setWorkingDirectory(getCurrentDirectory().getPath());

			if (fileType != null)
				fileType.setGroupPath(getCurrentDirectory().getPath());
			super.approveSelection();
		}

		/**
		 * Directories ending in .delib are treated as files.  Specifically, library files.
		 * @param f the file
		 * @return true if the file is traversable, false otherwise
		 */
		public boolean isTraversable(File f) {
			lastDELIBVisit = null;
			if (f == null) return false;
			if (f.getName().toLowerCase().endsWith("."+FileType.DELIB.getFirstExtension())) {
				lastDELIBVisit = f; // has to remember this value otherwise BasicFileChooserUI:actionPerformed will
				// not ready DELIB file just typed in the TextField because isDir=true and isDirSelEnabled=false
				// if ((isDir || !isFileSelEnabled)
				//   && (!isDir || !isDirSelEnabled)
				//   && (!isDirSelEnabled || selectedFile.exists()))
				return false;
			}
			return super.isTraversable(f);
		}

		/**
		 * Overridden to return true when the currently selected file is a .delib file.
		 * This allows .DELIB to be treated as files for the approve (open/save) button.
		 * @return true if the directory can be selected.
		 */
		public boolean isDirectorySelectionEnabled() {
			File file = getSelectedFile();
			if (file == null && lastDELIBVisit != null)
				file = lastDELIBVisit;
			// return true if a .delib file is selected, otherwise call the parent method
			if (file != null &&
				(super.getFileSelectionMode() != JFileChooser.DIRECTORIES_ONLY) &&
				file.getName().toLowerCase().endsWith("."+FileType.DELIB.getFirstExtension())) {
				return true;
			}
			return super.isDirectorySelectionEnabled();
		}

        public void setSelectedFile(File file) {
            super.setSelectedFile(file);
        }
    }

//	/** the location of the open file dialog */		private static Point location = null;

	/**
	 * Factory method to create a new open dialog box using the default Type.
	 * @param type the type of file to read. Defaults to ANY if null.
	 * @param title dialog title to use; if null uses "Open 'type'".
	 */
	public static String chooseInputFile(FileType type, String title, EditingPreferences ep)
	{
		if (ep == null) ep = EditingPreferences.getInstance();
		return chooseInputFile(type, title, false, ep.getWorkingDirectory(), true, ep);
	}

	/**
	 * Factory method to create a new open dialog box to search for a directory.
	 * @param title dialog title to use; if null uses "Select Directory".
	 */
	public static String chooseDirectory(String title)
	{
		return chooseInputFile(null, title, true, User.getWorkingDirectory(), true, EditingPreferences.getInstance());
	}

	/**
	 * Factory method to create a new open dialog box using the default Type.
	 * @param type the type of file to read. Defaults to ANY if null.
	 * @param title dialog title to use; if null uses "Open 'type'".
	 * @param wantDirectory true to request a directory be selected, instead of a file.
	 */
	public static String chooseInputFile(FileType type, String title, boolean wantDirectory) {
		return chooseInputFile(type, title, wantDirectory, User.getWorkingDirectory(), true, EditingPreferences.getInstance());
	}

	/**
	 * Factory method to create a new open dialog box using the default Type.
	 * @param type the type of file to read. Defaults to ANY if null.
	 * @param title dialog title to use; if null uses "Open 'type'".
	 * @param wantDirectory true to request a directory be selected, instead of a file.
	 * @param initialDir the initial directory
	 * @param setSelectedDirAsWorkingDir if the user approves the selection,
	 * set the directory as the current working directory if this is true.
	 */
	public static String chooseInputFile(FileType type, String title, boolean wantDirectory,
										 String initialDir, boolean setSelectedDirAsWorkingDir, EditingPreferences ep)
	{
		if (title == null)
		{
			if (type != null)
			{
				if (wantDirectory) title = "Choose Directory with " + type.getDescription() + " files"; else
					title = "Open " + type.getDescription();
			} else
			{
				if (wantDirectory) title = "Choose Directory"; else
					title = "Open file";
			}
		}

//		boolean useSwing = true;
		String path = (type != null && ep != null) ? type.getGroupPath(ep) : null;
		if (path != null)
			initialDir = path;

//		if (useSwing)
//		{
			OpenFileSwing dialog = new OpenFileSwing();
			dialog.saveDialog = false;
			dialog.setSelectedDirAsWorkingDir = setSelectedDirAsWorkingDir;
			dialog.fileType = type;
			dialog.setDialogTitle(title);
			File dir = new File(initialDir);
			if (!dir.exists() || !dir.isDirectory()) dir = new File(User.getWorkingDirectory());
			dialog.setCurrentDirectory(dir);
			if (type != null) {
				if (type == FileType.ELIB || type == FileType.JELIB || type == FileType.DELIB ||
					type == FileType.LIBFILE || type == FileType.LIBRARYFORMATS) {
					LibDirs.LibDirFileSystemView view = LibDirs.newLibDirFileSystemView(dialog.getFileSystemView());
					dialog.setFileSystemView(view);
					dialog.setFileView(new LibDirs.LibDirFileView(view));
				}
				dialog.setFileFilter(type.getFileFilterSwing());
			}
			if (wantDirectory) dialog.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
//			dialog.setLocation(location.x, location.y);
//			dialog.addComponentListener(new MoveComponentListener());
			JFrame chooseFrame = new JFrame();
			chooseFrame.setIconImage(TopLevel.getFrameIcon().getImage());
			int returnVal = dialog.showOpenDialog(chooseFrame);
			if (returnVal == JFileChooser.APPROVE_OPTION)
			{
				File file = dialog.getSelectedFile();
				return file.getPath();
			}
			return null;
//		}

//		// the AWT way
//		FileDialog dialog = new FileDialog(TopLevel.getCurrentJFrame(), title, FileDialog.LOAD);
//		dialog.setDirectory(User.getWorkingDirectory());
//		if (type != null) dialog.setFilenameFilter(type.getFileFilterAWT());
//		dialog.setVisible(true);
//		String fileName = dialog.getFile();
//		if (fileName == null) return null;
//		User.setWorkingDirectory(dialog.getDirectory());
//		return dialog.getDirectory() + fileName;
	}

//	private static class MoveComponentListener implements ComponentListener
//	{
//		public void componentHidden(ComponentEvent e) {}
//		public void componentShown(ComponentEvent e) {}
//		public void componentResized(ComponentEvent e) {}
//		public void componentMoved(ComponentEvent e)
//		{
//			Rectangle bound = ((JFileChooser)e.getSource()).getBounds();
//			location.x = (int)bound.getMinX();
//			location.y = (int)bound.getMinY();
//System.out.println("Moved to "+location);
//		}
//	}

	/**
	 * Factory method to create a new save dialog box using the
	 * default EFileFilter.
	 * @param type the type of file. Defaults to ANY if null.
	 * @param title dialog title to use; if null uses "Write 'type'".
	 * @param defaultFile default file name to write.
	 */
	public static String chooseOutputFile(FileType type, String title, String defaultFile)
	{
		FileType [] types;
		if (type == null) types = null;
		else types = new FileType [] {type};
		return chooseOutputFile(types, title, defaultFile);
	}

	/**
	 * Factory method to create a new save dialog box using the
	 * default EFileFilter.
	 * @param types the types of file. Defaults to ANY if null.
	 * @param title dialog title to use; if null uses "Write 'type'".
	 * @param defaultFile default file name to write.
	 */
	public static String chooseOutputFile(FileType [] types, String title, String defaultFile)
	{
		if (title == null)
		{
			if (types != null) title = "Write " + types[0].getDescription(); else
				title = "Write file";
		}
		if (types == null) types = new FileType [] {com.sun.electric.tool.io.FileType.ANY};

        // If AWT is used, a path with ":" instead of "/" is retrieved from FileOpen.getFile()
//		boolean useSwing = true;
//		if (Client.isOSMac())
//			useSwing = false;

		String initialDir = User.getWorkingDirectory();
		String path = types[0].getGroupPath();
		if (path != null)
			initialDir = path;

//		if (useSwing)
//		{
			OpenFileSwing dialog = new OpenFileSwing();
			dialog.saveDialog = true;
			dialog.setDialogTitle(title);
			for (int i=0; i<types.length; i++) {
				dialog.addChoosableFileFilter(types[i].getFileFilterSwing());
			}
			dialog.setCurrentDirectory(new File(initialDir));
			if (defaultFile != null)
			{
				dialog.setFileFilter(FileMenu.getLibraryFormat(defaultFile, types[0]).getFileFilterSwing());
				dialog.setSelectedFile(new File(defaultFile));
			}
			JFrame chooseFrame = new JFrame();
			chooseFrame.setIconImage(TopLevel.getFrameIcon().getImage());
			int returnVal = dialog.showSaveDialog(chooseFrame);
			if (returnVal == JFileChooser.APPROVE_OPTION)
			{
				File file = dialog.getSelectedFile();
				String fileName = file.getPath();
				FileType selectedType = FileType.getType(dialog.getFileFilter());
				if (selectedType != null)
				{
					String dir = TextUtils.getFilePath(TextUtils.makeURLToFile(fileName));
					selectedType.setGroupPath(dir);
                    String [] exts = selectedType.getExtensions();
                    boolean validExtension = exts != null && exts.length > 0;
                    if (validExtension)  // a known extension
                    {
                        String extension = exts[0];
                        int dotPos = fileName.lastIndexOf('.');
                        if (dotPos < 0)
                            fileName += "." + extension;
                        else
                        {
                            if (!fileName.substring(dotPos+1).startsWith(extension))
                                fileName = fileName + "." + extension;
                        }
                    }
                }
				return fileName;
			}
			return null;
//		}

//		// the AWT way
//		FileDialog awtDialog = new FileDialog(TopLevel.getCurrentJFrame(), title, FileDialog.SAVE);
//		awtDialog.setDirectory(initialDir);
//		awtDialog.setFile(defaultFile);
//		awtDialog.setFilenameFilter(types[0].getFileFilterAWT());
//		awtDialog.setVisible(true);
//		String fileName = awtDialog.getFile();
//		if (fileName == null) return null;
//		types[0].setGroupPath(awtDialog.getDirectory());
//		return awtDialog.getDirectory() + fileName;
	}

	/**
	 * Method to determine OpenFile type based on extension
	 * @param libName
	 * @return OpenFile.Type extension
	 */
	public static FileType getOpenFileType(String libName, FileType def)
	{
		File libFile = new File(libName);
		libName = libFile.getName();
		// remove trailing file separator if file is a directory (as it is with .delib)
		if (libName.endsWith(File.separator)) {
			libName = libName.substring(0, libName.length()-1);
		}

		if (libName.endsWith(".elib"))
			return com.sun.electric.tool.io.FileType.ELIB;
		else if (libName.endsWith(".jelib"))
			return com.sun.electric.tool.io.FileType.JELIB;
		else if (libName.endsWith(".delib"))
			return com.sun.electric.tool.io.FileType.DELIB;
		else if (libName.endsWith(".txt"))
			return com.sun.electric.tool.io.FileType.READABLEDUMP;
		return (def);
	}
}
