/*
 *  Draco Econometrics
 *  Copyright (C) 2006-2008 Approximatrix, LLC
 *  http://www.approximatrix.com
 *  
 *  This program 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.
 *
 *  This program 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.approximatrix.draco.application;

import javax.swing.ImageIcon;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import org.apache.bsf.BSFManager;

import com.approximatrix.draco.datamodel.StatTableModel;
import com.approximatrix.draco.main.ui.MainWindow;
import com.approximatrix.draco.general.ui.SplashFrame;
import com.approximatrix.draco.application.icons.IconLibrary;
import com.approximatrix.draco.application.icons.VectorIcon;
import com.approximatrix.draco.application.plugin.PluginRegistry;
import com.approximatrix.draco.application.preferences.PreferencesManager;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import net.sourceforge.helpgui.gui.MainFrame;
import gnu.getopt.Getopt;

/*
 * Created on Apr 4, 2005
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */

/**
 * @author armstrongj
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class ApplicationManager {

	private static ArrayList<MainWindow> main_window_list = null;
	private static boolean started_from_main = false;
	
	/** The name of the Application */
	public static final String APP_NAME = "Draco";
	
	/** The current version information */
	public static final String APP_VERSION = "Release 1.3";
	
	/** Attempt to use system L&F */
	private static final boolean USE_NATIVE_LF = true;
	
	/** Enable the background image */
	public static final boolean ENABLE_BKGD = true;
	
	/** The icon to be displayed by default for the help window */
	private static final String PATH_TO_HELP_WINDOW_ICON = "/com/approximatrix/draco/application/images/help.png";
	
	/** The key for the directory containing help */
	private static String helpDirectory="../doc";
	
	/** The plugin directory string */
	private static String pluginDirectory="../scripts/ruby/plugins";
	
	// The mainframe for help
	private static MainFrame HelpWindow = null;
	private static final String HELPGUI_STYLE = "crystal";
	private static final String HELP_TITLE = APP_NAME+" Help";
	private static final int HELP_WIDTH = 800;
	private static final int HELP_HEIGHT = 600;
	
	// Splash handling
	private static SplashFrame Splash = null;
	private static final int MS_TO_SPLASH_CLOSE = 3000;
	//private static final boolean SHOW_SPLASH = false; 

	// Icon library
	private static IconLibrary icons = null;
	
	private static volatile boolean enableAutoShutdown = false;
	
	// Plugins
	private static PluginRegistry pluginRegistry = null;
	
	public static void main(String[] args) {
		
		InitializeLookAndFeel();

        List<String> files = ProcessCommandLine(args);
	
   	    // Show the splash screen if necessary
		StartApplication(files);
		//StartWithSplash();
   	    //if(SHOW_SPLASH) 
   	    //	StartWithSplash();
   	    //else
   	    //	StartApplication();
	}
	
	private static void StartWithSplash(List<String> files) {
		Splash = new SplashFrame(files);
   	    Splash.setLocationRelativeTo(null);
   	    Splash.setVisible(true);
   	    Splash.startup();
	}
	
	public static int RequestWindowCount() {
		try {
			return main_window_list.size();
		} catch(IndexOutOfBoundsException e) {
			return 0;
		}
	}
	
	public static void RequestNewWindow() {
		main_window_list.add(new MainWindow());
	}
	
	public static void RequestNewWindow(double[][] data,
			                            String[] column_names) {
		main_window_list.add(new MainWindow(data,column_names));
	}
	
	public static void RequestNewWindow(StatTableModel data) {
		main_window_list.add(new MainWindow(data));
	}
	
	public static MainWindow RequestAndReturnNewWindow() {
		MainWindow new_window = new MainWindow();
		main_window_list.add(new_window);
		return new_window;
	}
	
	public static MainWindow RequestAndReturnNewWindow(StatTableModel data) {
		MainWindow new_window = new MainWindow(data);
		main_window_list.add(new_window);
		return new_window;
	}
	
	public static ChildFrameRegistrar RequestAndReturnNewWindow(File toLoad) {
		MainWindow new_window = new MainWindow(toLoad);
		main_window_list.add(new_window);
		return new_window;
	}
	
	public static void CloseWindow(Object this_window) {
		for(int i=0;i<main_window_list.size();i++) {
			if(main_window_list.get(i)==this_window) {
				main_window_list.remove(i);
				break;
			}
		}
		
		if(main_window_list.size() == 0 && enableAutoShutdown) {
			main_window_list = null;
			if(started_from_main) {
				System.exit(0);
			}
		}		
	}
	
	public static void SetAutoShutdown(boolean value) {
		enableAutoShutdown = value;
	}
	
	public static void RequestExit() {
		while(main_window_list.size()>0) {
			if(!main_window_list.get(0).closeWindow())
				break;
		}
	}
	
	public static void RequestHelp(String topic) {
		if(HelpWindow == null) {
			//HelpWindow = new MainFrame("docs",HELPGUI_STYLE);
			HelpWindow = new MainFrame(helpDirectory,MainFrame.PATH_TYPE_FILESYSTEM,HELPGUI_STYLE);
			HelpWindow.setTitle(HELP_TITLE);
			HelpWindow.setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE);
			HelpWindow.setIconImage(new ImageIcon(ApplicationManager.class.getResource(PATH_TO_HELP_WINDOW_ICON)).getImage());
			HelpWindow.setSize(HELP_WIDTH, HELP_HEIGHT);
		}
		if(!HelpWindow.isVisible()) {
			HelpWindow.setVisible(true);
		}
		HelpWindow.gotoTopic(topic);
		HelpWindow.requestFocus();
	}
	
	private static void StartApplication(List<String> files) {
		
		main_window_list = new ArrayList<MainWindow>();
    	//main_window_list.add(new MainWindow());
    	started_from_main = true;
    	
    	StartWithSplash(files);
	}

	/** Returns an icon from the icon library as defined by the 
	 * passed key
	 *
	 * @param key a String used as the key for accessing the icon
	 * @return an Icon object for display
	 */
	public static VectorIcon GetIcon(String key) {
		try {
			return icons.getIcon(key);
		} catch(NullPointerException npe) {
			return null;
		}
	}
	
	/** Loads the icons from the specified default icon properties file
	 */
	public static void LoadIcons() {
		icons = new IconLibrary(new PreferencesManager().getUIPrefs().getIconSize());
	}
	
	/** Allows access to the icon library.  Should only be used for sizing ops.
	 * 
	 * @return the application's icon library
	 */
	public static IconLibrary GetIconLibrary() {
		return icons;
 	}
	
	/** Initializes the scripting engines */
	public static void InitializeScripting() {
		BSFManager.registerScriptingEngine("ruby", "org.jruby.javasupport.bsf.JRubyEngine", new String[] { "rb" });
		//EquationEvaluation.Compile();
	}
	
	public static void InitializePlugins() {
		if(pluginRegistry == null)
			pluginRegistry = new PluginRegistry();
		List<String> directories = new ArrayList<String>(new PreferencesManager().getPluginPrefs().getDirectories());
		directories.add(0,pluginDirectory); 
		pluginRegistry.register(directories);
	}
	
	public static PluginRegistry GetPluginRegistry() {
		return pluginRegistry;
	}
	
	/** Walks the list of currently opened main windows and
	 * notifies them of the registration of new plugins (or
	 * removal of plugins...)
	 */
	public static void NotifyNewPlugins() {
		for(MainWindow mw : main_window_list)
			mw.notifyPluginsUpdated();
	}
	/** In theory, should reset the look and feel of the program.  However,
	 * there are too many menu items already instantiated that will be unaffected
	 * by a dynamic change to the lnf.  This method is unreliable and should be
	 * avoided.
	 * 
	 * @param lnfClass the class name of the look and feel to set
	 */
	public static void ApplyLookAndFeel(String lnfClass) {
		try {
			UIManager.setLookAndFeel(lnfClass);
			for(MainWindow mw : main_window_list)
				SwingUtilities.updateComponentTreeUI(mw);
			if(HelpWindow != null)
				SwingUtilities.updateComponentTreeUI(HelpWindow);
		} catch (Exception e) { 
			System.out.println("Change of LNF failed...");
		}
	}
	
	private static void InitializeLookAndFeel() {
		try {
			String lnf = new PreferencesManager().getUIPrefs().getLookAndFeel();
			if(lnf != null)
				UIManager.setLookAndFeel(lnf);
			else
				UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception e) { 
			System.out.println("Change of LNF failed...");
		}
	}
	
	private static List<String> ProcessCommandLine(String[] args) {
		if(args == null) return null;
		
		Getopt opt = new Getopt(APP_NAME,args,"hd:p:");
	    opt.setOpterr(false);
	    
        int c;	    
	    while((c = opt.getopt()) != -1) {
	        switch(c) {
	            case 'h':
	                OutputCommandLineOptions();
	                System.exit(0);
	                break;
	            case 'd':
	                helpDirectory = opt.getOptarg();
	                break;
	            case 'p':
	            	pluginDirectory = opt.getOptarg();
	            	break;
	        }
	    }
	    
	    // Load any filenames to open
	    ArrayList<String> files = new ArrayList<String>();
	    for(int i = opt.getOptind(); i < args.length; i++)
	    	files.add(args[i]);
	    
	    return files;
	}
	
	private static void OutputCommandLineOptions() {
	    System.out.println(APP_NAME+" "+APP_VERSION+"\n"+
	        "Copyright 2006-2008 Approximatrix, LLC\n" +
	        "\n"+
	        "Command Line Options:\n"+
	        "\t-h      \tDisplay this help message and exit\n"+
	        "\t-d <dir>\tSpecify the path to the online help files\n"+
	        "\t-p <dir>\tSpecify the path to the plugins directory\n"+
	        "\n");
	}
}
