/*
 *  Draco Econometrics
 *  Copyright (C) 2006-2007 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.main.ui;

import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileFilter;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Component;
import java.awt.MenuComponent;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;

import ca.guydavis.swing.desktop.JWindowsMenu;

import com.approximatrix.draco.application.ChildFrame;
import com.approximatrix.draco.application.ApplicationManager;
import com.approximatrix.draco.datamodel.StatTableModel;
import com.approximatrix.draco.io.DracoLoader;
import com.approximatrix.draco.io.LoadDracoSQL;
import com.approximatrix.draco.io.LoadEASY;
import com.approximatrix.draco.io.LoadODS;
import com.approximatrix.draco.io.PreLoadODS;
import com.approximatrix.draco.io.filters.EASYFilter;
import com.approximatrix.draco.io.filters.ODSFilter;
import com.approximatrix.draco.io.filters.SQLFilter;
import com.approximatrix.draco.io.ui.ExportData;
import com.approximatrix.draco.io.ui.ImportData;
import com.approximatrix.draco.io.ui.ImportODS;

import com.approximatrix.draco.general.ui.InfoWindow;
import com.approximatrix.draco.general.ui.AboutDialog;

public class DynamicMainMenuBar extends JMenuBar implements ActionListener {
	
	public static final int FILE_MENU_IDX = 0;
	public static final int EDIT_MENU_IDX = 1;
	public static final int DATA_MENU_IDX = 2;
	public static final int HELP_MENU_IDX = 3;
	
	private static final String[] CONSTANT_MENUS = { 
		"File",	"Edit", 
		"Data", "Help"
	};
	
	public static final String WINDOWS_MENU_TEXT = "Windows";
	
	/** Returns a new JMenu object with the "File" designation
	 * 
	 * @return a new, empty JMenu object with "File" designation
	 */
	public static JMenu GetGenericFileMenu() {
		return GetGenericMenu(FILE_MENU_IDX);
	}
	
	/** Returns a new JMenu object with the "Edit" designation
	 * 
	 * @return a new, empty JMenu object with "Edit" designation
	 */
	public static JMenu GetGenericEditMenu() {
		return GetGenericMenu(EDIT_MENU_IDX);
	}
	
	/** Returns a new JMenu object with the "Data" designation
	 * 
	 * @return a new, empty JMenu object with "Data" designation
	 */
	public static JMenu GetGenericDataMenu() {
		return GetGenericMenu(DATA_MENU_IDX);
	}

	/** Returns a new JMenu object with the "Help" designation
	 * 
	 * @return a new, empty JMenu object with "Help" designation
	 */
	public static JMenu GetGenericHelpMenu() {
		return GetGenericMenu(HELP_MENU_IDX);
	}
	
	/** Creates a JMenu object reflecting the specified generic
	 * menu type.  Other public functions wrap this generic call.
	 *  
	 * @param type the index of the CONSTANT_MENUS text to use in the JMenu
	 * @return a new JMenu object with the specified text, or null if a bad index is passed
	 */
	private static JMenu GetGenericMenu(int type) {
		if(type<0 || type >= CONSTANT_MENUS.length)
			return null;
		return new JMenu(CONSTANT_MENUS[type]);
	}
	
	/** Constant used by the getNewPanelChoice() method signifying
	 * the user has requested a new window for a new/imported panel
	 * data set.
	 */
	private static final int IMPORT_PANEL_NEW_WINDOW = 0;
	
	/** Constant used by the getNewPanelChoice() method signifying
	 * the user has requested overwriting current data for a 
	 * new/imported paneldata set.
	 */
	private static final int IMPORT_PANEL_OVERWRITE  = 1;
	
	
	
	/** Location in the default menu bar to insert new JMenu's when adding dynamic elements */
	private static final int INSERT_POSITION_FROM_LEFT = 3;

	// Data menu
	private JMenu data_menu = null;
		private JMenuItem m_view_constants = null;
	
	// Help menu
	private JMenu help_menu = null;
		private JMenuItem m_about = null;
		private JMenuItem m_contents = null;
		private JMenuItem m_topical_help = null;
	
	// File menu
	private JMenu file_menu = null;
		private JMenu file_new_menu = null;
			private JMenuItem m_new_time_series = null;
			private JMenuItem m_new_panel_data = null;
		private JMenuItem m_load = null;
		private JMenuItem m_save = null;
		private JMenuItem m_saveas = null;
		
		private JMenu import_submenu = null;
			private JMenu import_text_submenu = null;
				private JMenuItem m_import_panel = null;
				private JMenuItem m_import_timeseries = null;
			private JMenuItem m_import_ods = null;	
		private JMenu export_submenu = null;
			private JMenu export_text_submenu = null;
				private JMenuItem m_export_columns = null;
				private JMenuItem m_export_all = null;
			private JMenuItem m_export_ods = null;

		private JMenu file_options_submenu = null;
			private JCheckBoxMenuItem m_quick_save_only = null;
		
		private JMenuItem m_quit = null;
		private JMenuItem m_exit = null;
	
	// Edit menu
	private JMenu edit_menu = null;
		private JMenuItem m_open_text_editor = null;
		
	/** The dynamic menu listing open windows */
	private JWindowsMenu windows_menu = null;
	
	/** The last focused ChildFrame object, which is used for
	 * removing menu items from the menu before adding the new
	 * dialog's items
	 */
	private ChildFrame last = null;
	
	/** The window owning this menu bar, needed for menu handling */
	private MainWindow parent = null;
	
	/** Array holding the number of items added to each of the default
	 * constant menus that must be transfered back to their original
	 * JMenu object when removing them from the visible menus.
	 */
	int[] backtolast = null;
	
	
	
	/** Creates a generic Cut menu item.  This does not add an ActionListener;
	 * any event handling is the responsibility of the requestor.
	 * 
	 * @return a new Cut menu item
	 */
	public static JMenuItem GetGenericCutMenuItem() {
		return new JMenuItem("Cut");
	}
	
	/** Creates a generic Copy menu item.  This does not add an ActionListener;
	 * any event handling is the responsibility of the requestor.
	 * 
	 * @return a new Copy menu item
	 */
	public static JMenuItem GetGenericCopyMenuItem() {
		return new JMenuItem("Copy");
	}
	
	/** Creates a generic Paste menu item.  This does not add an ActionListener;
	 * any event handling is the responsibility of the requestor.
	 * 
	 * @return a new Copy menu item
	 */
	public static JMenuItem GetGenericPasteMenuItem() {
		return new JMenuItem("Paste");
	}
	
	/** Constructs the default menu bar for the MainWindow object
	 * 
	 * @param parent the window that owns this dynamic menu bar
	 */
	public DynamicMainMenuBar(MainWindow parent) {
		super();
		
		this.parent = parent;
		
		initialize();
	}
	
	/** Initializes the menu bar, constructing all the default
	 * menus and their associated items.
	 */
	private void initialize() {
		this.add(getFile_menu());
		this.add(getEdit_menu());
		this.add(getData_menu());
		
		this.add(getWindows_menu());
		
		this.add(Box.createHorizontalGlue());
		this.add(getHelp_menu());
		
		// Set up the index storage system
		backtolast =  new int[CONSTANT_MENUS.length];
		zeroBackToLast();
	}
	
	/** Creates the file menu and all its items
	 * 
	 * @return the File menu object
	 */
	private JMenu getFile_menu() {
		if(file_menu == null) {
			file_menu = new JMenu(CONSTANT_MENUS[FILE_MENU_IDX]);
			
			file_menu.add(getFileNew_menu());
			
			m_load = new JMenuItem("Open...");
			m_load.addActionListener(this);
			file_menu.add(m_load);
			
			m_save = new JMenuItem("Save");
			m_save.addActionListener(this);
			file_menu.add(m_save);
			
			m_saveas = new JMenuItem("Save As...");
			m_saveas.addActionListener(this);
			file_menu.add(m_saveas);
			
			file_menu.addSeparator();
			
			file_menu.add(getImport_menu());
			file_menu.add(getExport_menu());
			
			file_menu.addSeparator();
			
			file_menu.add(getFileOptions_menu());
			
			file_menu.addSeparator();

			m_quit = new JMenuItem("Close Worksheet");
			m_quit.addActionListener(this);
			file_menu.add(m_quit);
			
			m_exit = new JMenuItem("Exit "+ApplicationManager.APP_NAME);
			m_exit.addActionListener(this);
			file_menu.add(m_exit);
			
		}
		return file_menu;
	}
	
	/** Creates the file/new menu and all its items
	 * 
	 *  @return the File/New menu object
	 */
	private JMenu getFileNew_menu() {
		if(file_new_menu == null) {
			file_new_menu = new JMenu("New");
			
			m_new_time_series = new JMenuItem("Time Series Data...");
			m_new_time_series.addActionListener(this);
			file_new_menu.add(m_new_time_series);
			
			m_new_panel_data = new JMenuItem("Panel Data...");
			m_new_panel_data.addActionListener(this);
			file_new_menu.add(m_new_panel_data);
		}
		return file_new_menu;
	}
	
	/** Creates the file/import menu and all its items
	 * 
	 * @return the File/Import menu object
	 */
	private JMenu getImport_menu() {
		if(import_submenu == null) {
			import_submenu = new JMenu("Import");
			
			import_submenu.add(getImportText_menu());
			
			m_import_ods = new JMenuItem("OpenDocument Spreadsheet...");
			m_import_ods.addActionListener(this);
			import_submenu.add(m_import_ods);
			
		}
		return import_submenu;
	}
	
	/** Creates the file/export menu and all its items
	 * 
	 * @return the File/Export menu object
	 */
	private JMenu getExport_menu() {
		if(export_submenu == null) {
			export_submenu = new JMenu("Export");
			
			export_submenu.add(getExportText_menu());
			
			m_export_ods = new JMenuItem("OpenDocument Spreadsheet...");
			m_export_ods.addActionListener(this);
			export_submenu.add(m_export_ods);
			
		}
		return export_submenu;
	}
	
	/** Creates the file/import/text menu and all its items
	 * 
	 * @return the File/Import/Text menu object
	 */
	private JMenu getImportText_menu() {
		if(import_text_submenu == null) {
			import_text_submenu = new JMenu("Text");
			
			m_import_timeseries = new JMenuItem("Time Series Data...");
			m_import_timeseries.addActionListener(this);
			import_text_submenu.add(m_import_timeseries);
			
			m_import_panel = new JMenuItem("Cross-Sectional Data...");
			m_import_panel.addActionListener(this);
			import_text_submenu.add(m_import_panel);
			
		}
		return import_text_submenu;
	}
	
	/** Creates the file/import/text menu and all its items
	 * 
	 * @return the File/Import/Text menu object
	 */
	private JMenu getExportText_menu() {
		if(export_text_submenu == null) {
			export_text_submenu = new JMenu("Text");
			
			m_export_columns = new JMenuItem("Select Columns...");
			m_export_columns.addActionListener(this);
			export_text_submenu.add(m_export_columns);
			
			m_export_all = new JMenuItem("All Columns...");
			m_export_all.addActionListener(this);
			export_text_submenu.add(m_export_all);
		}
		return export_text_submenu;
	}
	
	/** Creates the file/options menu and all its items
	 * 
	 * @return the File/Options menu object
	 */
	private JMenu getFileOptions_menu() {
		if(file_options_submenu == null) {
			file_options_submenu = new JMenu("Options");
			
			m_quick_save_only = new JCheckBoxMenuItem("Use Quicksave Only (Breaks ODS Compatability)");
			m_quick_save_only.setSelected(false);
			m_quick_save_only.addActionListener(this);
			file_options_submenu.add(m_quick_save_only);
		}
		return file_options_submenu;
	}
	
	/** Creates the edit menu and all its items
	 * 
	 * @return the Edit menu object
	 */
	private JMenu getEdit_menu() {
		if(edit_menu == null) {
			edit_menu = new JMenu(CONSTANT_MENUS[EDIT_MENU_IDX]);
			
			m_open_text_editor = new JMenuItem("Open text editor...");
			m_open_text_editor.addActionListener(this);
			edit_menu.add(m_open_text_editor);
		}
		return edit_menu;
	}
	
	/** Creates the data menu and all its items
	 * 
	 * @return the Data menu object
	 */
	private JMenu getData_menu() {
		if(data_menu == null) {
			data_menu = new JMenu(CONSTANT_MENUS[DATA_MENU_IDX]);
			
			m_view_constants = new JMenuItem("View Constants...");
			m_view_constants.addActionListener(this);
			data_menu.add(m_view_constants);
		}
		return data_menu;
	}
	
	/** Creates the help menu and all its items
	 * 
	 * @return the Help menu object
	 */
	private JMenu getHelp_menu() {
		if(help_menu == null) {
			help_menu = new JMenu(CONSTANT_MENUS[HELP_MENU_IDX]);
			
			m_topical_help = new JMenuItem("Help on focused window...");
			m_topical_help.addActionListener(this);
			help_menu.add(m_topical_help);
			
			m_contents = new JMenuItem("Contents...");
			m_contents.addActionListener(this);
			help_menu.add(m_contents);
			
			m_about = new JMenuItem("About "+ApplicationManager.APP_NAME);
			m_about.addActionListener(this);
			help_menu.add(m_about);
		}
		return help_menu;
	}
	
	private JWindowsMenu getWindows_menu() {
		if(windows_menu == null) {
			windows_menu = new JWindowsMenu(WINDOWS_MENU_TEXT,parent.getDesktop());
		}
		return windows_menu;
	}
	
	/** Called when a new frame is focussed in the MainWindow.  Extracts
	 * the menu items and places them in the MDI menu.
	 * 
	 * @param infront 
	 */
	public void setFocusedChild(ChildFrame infront) {
		if(last != null)
			removeItems(last.getMenuItems());
		if(infront != null)
			addItems(infront.getMenuItems());
		
		last = infront;
		
		// Execute the Swing update later
		//Runnable updateMenu = new Runnable() {
        //    public void run() {
        //    	DynamicMainMenuBar.super.doLayout();
        //    	DynamicMainMenuBar.super.repaint();
        //    }
        //};
        //SwingUtilities.invokeLater(updateMenu);
		super.validate();
		super.repaint();
		//super.getParent().repaint(100); 
		
	}
	
	/** Removes the specified menus and their items from the
	 * MDI menu system.
	 * 
	 * @param menus an array of menus and items to remove
	 */
	private void removeItems(JMenu[] menus) {
		if(menus == null)
			return;
		for(int imenu = 0; imenu < menus.length; imenu++) {
			
			int menu_index = getConstantMenuIndex(menus[imenu].getText());
			if(menu_index >= 0) {
				int stor_index = getConstantMenuArrayIndex(menus[imenu].getText());
				
				JMenu removefrom = this.getMenu(menu_index);
				
				//Component[] old_items = menus[imenu].getMenuComponents();
				
				//System.out.print("Working ");
				//System.out.print(backtolast[stor_index]);
				//System.out.println(" items in "+removefrom.getText());
				
				for(int iback=backtolast[stor_index]-1;iback >=0;iback--) {
					Component mc = removefrom.getMenuComponent(iback);
					removefrom.remove(mc);
					menus[imenu].add(mc,0);
				}
				
			} else {
				this.remove(menus[imenu]);
			}
		}
		
		// Erase any indicators of old menu items 
		zeroBackToLast();
		
	}
	
	/** Adds the specified menus and their items to the MDI menu
	 * system.
	 * 
	 * @param menus an array of menus with items to add
	 */ 
	private void addItems(JMenu[] menus) {
		
		// Erase any indicators of old menu items 
		zeroBackToLast();
		
		if(menus == null)
			return;
		
		for(int imenu = 0; imenu < menus.length; imenu++) {

			//System.out.print("Menu: "+menus[imenu].getText()+" #");
			//System.out.println(menus[imenu].getMenuComponentCount());
			
			int menu_index = getConstantMenuIndex(menus[imenu].getText());
			
			if(menu_index >= 0) {
				int stor_index = getConstantMenuArrayIndex(menus[imenu].getText());
				
				JMenu addto = this.getMenu(menu_index);
				Component[] new_items = menus[imenu].getMenuComponents();
				for(int ielements=new_items.length-1;ielements>=0;ielements--) {
					addto.add(new_items[ielements],0);
					
					//menus[imenu].add(new MenuItem(new_items[ielements].toString()));
					
					//System.out.println(menus[imenu].getMenuComponents().length);
				}
				
				backtolast[stor_index] = new_items.length;
				
			} else {
				this.insertMenu(menus[imenu]);
			}
			
		}
	}
	
	/** Inserts a menu at the proper location onto the menubar
	 * 
	 * @param toinsert the JMenu object to insert
	 */
	private void insertMenu(JMenu toinsert) {
		// Add our new menu
		this.add(toinsert,this.getComponentCount()-INSERT_POSITION_FROM_LEFT);
	}
	
	/** Returns the index of the existing menu that matches this name, or
	 * -1 if this menu name is new.
	 * 
	 * @param name the name of the JMenu to look for
	 * @return the index of the matching, existing JMenu, or -1 if it does not exist
	 */
	private int getConstantMenuIndex(String name) {
		for(int i=0;i<CONSTANT_MENUS.length;i++) {
			if(name.compareToIgnoreCase(CONSTANT_MENUS[i])==0)
				return i;
		}
		return -1;
	}
	
	/** Handles all menu actions using a nice, giant "if" structure
	 * 
	 */
	public void actionPerformed(ActionEvent e) {
		Object source = e.getSource();
		
		// ---------------------------- File Menu
		if(source == m_new_time_series)
			newWorksheet(true); // true for time series
		else if(source == m_new_panel_data)
			newWorksheet(false); // false for panel data
		else if(source == m_load)
			loadWorksheet();
		else if(source == m_save)
			saveWorksheet(false);
		else if(source == m_saveas)
			saveWorksheet(true);
		else if(source == m_quit)
			parent.closeWindow();
		else if(source == m_exit)
			ApplicationManager.RequestExit();

		// ---------------------------- File/Import Menu
		else if(source == m_import_timeseries)
			parent.openWindow(new NewTimeSeriesDialog(true));
		else if(source == m_import_panel)
			importTextPanelData();
		else if(source == m_import_ods)
			importODS();
		
		// ---------------------------- File/Export Menu
		else if(source == m_export_columns)
			parent.openWindow(new ExportData(parent.getWindowTableModel(),false));
		else if(source == m_export_all)
			new ExportData(parent.getWindowTableModel(),true);
		else if(source == m_export_ods)
			exportODS();
		
		// ---------------------------- Other
		else if(source == m_open_text_editor)
			parent.openWindow(new InfoWindow());
		else if(source == m_view_constants) 
			viewConstants();
		else if(source == m_about)
			parent.openWindow(new AboutDialog());
		else if(source == m_contents)
			ApplicationManager.RequestHelp("Contents");
		else if(source == m_topical_help)
			ApplicationManager.RequestHelp(last.getHelpKey());
	}
	
	/** Wrapper for creating a new worksheet from the
	 * menu options
	 * 
	 * @param time_series true if a time series is requested, false for panel data
	 */
	public void newWorksheet(boolean time_series) {
		if(time_series)
			parent.openWindow(new NewTimeSeriesDialog());
		else {
			switch(getNewPanelChoice("Create New Panel Data")) {
			case IMPORT_PANEL_NEW_WINDOW:
				ApplicationManager.RequestNewWindow();
				break;
			case IMPORT_PANEL_OVERWRITE:
				parent.setWindowTableModel(new StatTableModel());
				break;
			}
		}
	}
	
	/** Wrapper providing worksheet loading using a file chooser
	 * 
	 */
	public void loadWorksheet() {
		JFileChooser chooser = new JFileChooser();
		//chooser.addChoosableFileFilter(new ODSFilter());
		chooser.addChoosableFileFilter(new EASYFilter());
		chooser.addChoosableFileFilter(new SQLFilter());
		
		if(parent.getCurrentFilename() != null) {
			chooser.setCurrentDirectory(new java.io.File(parent.getCurrentFilename()));
		}
	    chooser.setDialogTitle("Choose File to Load...");
	    if (chooser.showOpenDialog(chooser) == JFileChooser.APPROVE_OPTION) { 
	    	String filename = chooser.getSelectedFile().toString();
	    	
	    	DracoLoader loader = null;
	    	
	    	MainWindow mw = ApplicationManager.RequestAndReturnNewWindow();
	    	
	    	if(new EASYFilter().accept(chooser.getSelectedFile()))
	    		loader = new LoadEASY(filename,mw);
	    	else
	    		loader = new LoadDracoSQL(filename,mw);
	    	loader.load();
	    	StatTableModel data = null;
	    	
	    	if(loader.stepSuccess())
	    		data = loader.getLoadedData();
	    
	    	if(data != null) {
	    		mw.setWindowTableModel(loader.getLoadedData(),filename);
	    		if(parent.isInitialWindow()) {
	    			SwingUtilities.invokeLater(new Runnable() {
	    				public void run() {
	    					ApplicationManager.CloseWindow(parent);
	    					parent.dispose();
	    				}
	    			});
	    		}
	    	} else {
	    		ApplicationManager.CloseWindow(mw);
	    		if(loader.getError() != null)
	    			JOptionPane.showMessageDialog(parent,loader.getError(),ApplicationManager.APP_NAME+" Error",JOptionPane.ERROR_MESSAGE);
	    		else
	    			JOptionPane.showMessageDialog(parent,"Problem loading file...",ApplicationManager.APP_NAME+" Error",JOptionPane.ERROR_MESSAGE);		
	    	}
	    			    		
	    }
	}
	
	/** Forces a file to be saved
	 * 
	 * @param demand_name true if a filename needs specification
	 */
	public void saveWorksheet(boolean demand_name) {
		if(demand_name || parent.getCurrentFilename() == null)
			parent.saveNeedFilename();
		else
			parent.saveFile();
	}
	
	/** Wrapper providing panel data import functionality
	 * 
	 */
	private void importTextPanelData() {
		switch(getNewPanelChoice("Import Panel Data")) {
		case IMPORT_PANEL_NEW_WINDOW:
			MainWindow new_window = ApplicationManager.RequestAndReturnNewWindow();
			new_window.forceImportWindow(false);
			new_window = null;
			break;
		case IMPORT_PANEL_OVERWRITE:
			parent.openWindow(new ImportData(false));
			break;
		}
	}
	
	/** Wrapper to handle importing ODS documents seamlessly
	 */
	private void importODS() {
		JFileChooser chooser = new JFileChooser();
		chooser.addChoosableFileFilter(new ODSFilter());
		//chooser.addChoosableFileFilter(new EASYFilter());
		if(parent.getCurrentFilename() != null) {
			chooser.setCurrentDirectory(new java.io.File(parent.getCurrentFilename()));
		}
		chooser.setDialogTitle("Choose File to Load...");
		if (chooser.showOpenDialog(chooser) == JFileChooser.APPROVE_OPTION) { 
			String filename = chooser.getSelectedFile().toString();

			PreLoadODS loader = new PreLoadODS(filename,parent);
			loader.load();

			String[] worksheets = null;
			if(loader.stepSuccess())
				worksheets = loader.getAvailableSheets();
			else {
				if(loader.getError() != null)
					JOptionPane.showMessageDialog(parent,loader.getError(),ApplicationManager.APP_NAME+" Error",JOptionPane.ERROR_MESSAGE);
				else
					JOptionPane.showMessageDialog(parent,"Problem loading file...",ApplicationManager.APP_NAME+" Error",JOptionPane.ERROR_MESSAGE);
				return;
			}

			ImportODS importdialog = new ImportODS(parent, filename, worksheets);
			importdialog.setVisible(true);

			if(importdialog.getSelectedSheet() == null) 
				return;
			
			// Needs some mods
			LoadODS new_loader = new LoadODS(filename,parent,
					importdialog.getSelectedSheet(),
					importdialog.getHeaderRow(),
					importdialog.getColumnString(),
					importdialog.getStartRow(),
					importdialog.getEndRow());
			new_loader.load();

			StatTableModel data = null;
			if(loader.stepSuccess())
				data = new_loader.getLoadedData();

			if(data != null)
				parent.setWindowTableModel(data,filename);
			else {
				if(loader.getError() != null)
					JOptionPane.showMessageDialog(parent,loader.getError(),ApplicationManager.APP_NAME+" Error",JOptionPane.ERROR_MESSAGE);
				else
					JOptionPane.showMessageDialog(parent,"Problem importing file...",ApplicationManager.APP_NAME+" Error",JOptionPane.ERROR_MESSAGE);
				return;
			}

		}
	}
	
	/** Exports the current model to a valid ODS spreadsheet file
	 */
	private void exportODS() {
		JFileChooser chooser = new JFileChooser();
		if(parent.getCurrentFilename() != null) {
			chooser.setCurrentDirectory(new java.io.File(parent.getCurrentFilename()));
		}
		chooser.setDialogTitle("Export ODS As...");
		chooser.setDialogType(JFileChooser.SAVE_DIALOG);
		chooser.addChoosableFileFilter(new ODSFilter());
		String filename = null;
		if (chooser.showSaveDialog(chooser) == JFileChooser.APPROVE_OPTION) { 
			filename = chooser.getSelectedFile().toString();

			FileFilter chosen = chooser.getFileFilter();

			if(!chosen.accept(new File(filename))) {
				String desired_extension = null;
				if(chosen.getClass() == ODSFilter.class) {
					desired_extension = ODSFilter.EXTENSION;
				}
				filename = filename+"."+desired_extension;
			}

			parent.saveFile(filename,false);
		}
	}
	
	/** Opens or focuses the View Constants window */
	public void viewConstants() {
		Object[] cd = parent.getWindowsByClass(ConstantsDialog.class);
		if(cd == null) {
			parent.openWindow(new ConstantsDialog(parent.getWindowTableModel()));
		} else {
			parent.toFront((ChildFrame)cd[0]);
		}
	}
	
	/** Returns true if Quicksave-only option is selected in the File/Options menu
	 * 
	 * @return true to perform strictly quicksaves, false to use ODS format where applicable
	 */
	public boolean allowQuicksaveOnly() {
		return m_quick_save_only.isSelected();
	}
	
	/** Wrapper that will signal the proper functions that ctrl_c (or equiv) 
	 * has been pressed.
	 */
	public void signalCopy() {
		String tmp = GetGenericCopyMenuItem().getText();
		signalMenuItemByText(edit_menu,tmp);
	}
	
	/** Wrapper that will signal the proper functions that ctrl_v (or equiv) 
	 * has been pressed.
	 */
	public void signalPaste() {
		String tmp = GetGenericPasteMenuItem().getText();
		signalMenuItemByText(edit_menu,tmp);
	}
	
	/** Wrapper that will signal the proper functions that ctrl_x (or equiv) 
	 * has been pressed.
	 */
	public void signalCut() {
		String tmp = GetGenericCutMenuItem().getText();
		signalMenuItemByText(edit_menu,tmp);
	}
	
	/** Forces the Windows menu to redraw, which is necessary if the names of
	 * any of the internal frames have changed.
	 */
	public void updateWindowsList() {
		getWindows_menu().updateWindowsList();
	}
	
	/** Finds a menu item matching the passed text in the passed JMenu object.
	 * When found, an ActionEvent is created originating from the found item and
	 * passed to each of the item's ActionListeners.
	 * 
	 * @param menu a valid JMenu
	 * @param text the text to locate in the menu items of menu
	 */ 
	private void signalMenuItemByText(JMenu menu, String text) {
		for(int i=0;i<edit_menu.getComponentCount();i++) {
			if(edit_menu.getComponent(i).getClass().isAssignableFrom(JMenuItem.class)) {
				JMenuItem item = (JMenuItem)edit_menu.getComponent(i);
				
				ActionListener[] listeners = item.getActionListeners();
				if(listeners != null) {
					// Generate an ActionEvent
					ActionEvent ae = new ActionEvent(item,ActionEvent.ACTION_PERFORMED,null);
					for(int j=0;j<listeners.length;j++) {
						if(listeners[j] != null) 
							listeners[j].actionPerformed(ae);
					}
				}
				
			}
		}
	}
	
	/** Provides a standard dialog for importing or creating new panel
	 * data sets by asking whether the user wishes to create a new
	 * MainWindow or overwrite the current data set.
	 * 
	 * @param title the text to use in titling the dialog
	 * @return the request number
	 */
	private int getNewPanelChoice(String title) {
		String[] array = new String[3];
		array[IMPORT_PANEL_NEW_WINDOW] = "Create New";
		array[IMPORT_PANEL_OVERWRITE] = "Overwrite Current";
		array[2] = "Cancel";
		int request = JOptionPane.showOptionDialog(this.getParent(), "Should the new data be loaded onto a new\nworksheet or overwrite the current worksheet?",
				title,
				JOptionPane.YES_NO_CANCEL_OPTION,
				JOptionPane.QUESTION_MESSAGE,
				null,
				array,
				array[0]);
		
		return request;
	}
	
	/** Returns the constant menu array index given a sample of text by
	 * searching the constant array CONSTANT_MENUS for a matching string.
	 * 
	 * @param text the menu name to look for
	 * @return the index of this menu in CONSTANT_MENUS or -1 if not found
	 */
	private int getConstantMenuArrayIndex(String text) {
		for(int i=0;i<CONSTANT_MENUS.length;i++) {
			if(text.compareTo(CONSTANT_MENUS[i])==0)
				return i;
		}
		return -1;
	}
	
	/** Simple function for clearing the constant menu items
	 * added count buffer.  This routine should be called 
	 *
	 */
	private void zeroBackToLast() {
		for(int i=0;i<backtolast.length;i++)
			backtolast[i] = 0;
	}
}
