/* ***************************************************************************+
 * ITX package (cnrg.itx) for telephony application programming.              *
 * Copyright (c) 1999  Cornell University, Ithaca NY                          *
 *                                                                            *
 * This program is free software; you can redistribute it and/or modify       *
 * it under the terms of the GNU General Public Liense as published by        *
 * the Free Software Foundation, either version 2 of the License, or (at      * 
 * your option) any later version.                                            *
 *                                                                            *
 * The ITX package 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.                                                          * 
 *                                                                            *
 * A copy of the license is distributed with this package.  Look in the docs  *
 * directory, filename GPL.                                                   *
 *                                                                            * 
 * Contact information:                                                       *
 * Donna Bergmark                                                             *
 * 484 Rhodes Hall                                                            *
 * Cornell University                                                         *
 * Ithaca, NY 14853-3801                                                      *
 * bergmark@cs.cornell.edu                                                    *
 ******************************************************************************/
package wizard;

import shared.*;
import cnrg.itx.datax.*;
import javax.swing.*;
import javax.swing.filechooser.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.*;

/**
 * The <code>WizardGUI</code> class implements the main Wizard graphical user
 * interface.  It "wraps" around the Wizard class and provides an interface for 
 * recording a presentation, much like the Windows Sound Recorder application.
 * 
 * @version 1.0, 4/14/1999
 * @author Jason Howes
 */
public class WizardGUI extends JFrame implements WindowListener, ActionListener, ItemListener
{
	/**
	 *  'The' client
	 */
	private Wizard mWizard;
	
	/**
	 * Presentation state variables
	 */
	private boolean mPresentationPaused;
	
	/**
	 * SPOT paths
	 */
	private String mSPOTDirectory;
	private String mProjectName;

	/** 
	 * Application defaults
	 */
	private final static String APP_NAME			= new String("SPOT Wizard");
	private final static String EMPTY_ITEM			= new String(" ");

	/** 
	 * Application labels
	 */
	private final static JLabel TITLE_LABEL			= new JLabel("Title:");
	private final static JLabel SLIDE_LABEL			= new JLabel("Slide:");
	private final static JLabel TOPIC_LABEL			= new JLabel("Topic:");
	
	/** 
	 * Component commands
	 */
	private final static String NEW_COMMAND			= "New";
	private final static String CLOSE_COMMAND		= "Close";
	private final static String EXIT_COMMAND		= "Exit";
	private final static String RECORD_COMMAND		= "Record";
	private final static String PAUSE_COMMAND		= "Pause";
	private final static String STOP_COMMAND		= "Stop";
	private final static String REWIND_COMMAND		= "Rewind";
	private final static String PREVIOUS_COMMAND	= "Previous";
	private final static String NEXT_COMMAND		= "Next";
	private final static String FF_COMMAND			= "FF";
	private final static String SLIDE_COMMAND		= "Slide";
	private final static String TOPIC_COMMAND		= "Topic";
	private final static String SET_TOPIC_COMMAND	= "Set Topic";

	/**
	 * GUI controls and other components
	 */ 
	private JMenuBar menuBar;
	private JMenu menuFile;
	private JMenuItem menuFileNew;
	private JMenuItem menuFileClose;
	private JMenuItem menuFileExit;
	
	private JPanel buttonPanel;
	private JPanel controlPanel;
	private JTextField textTitle;
	private JTextField textTopic;
	private JComboBox choiceSlide;
	private JComboBox choiceTopic;

	private JButton buttonRecord;
	private JButton buttonPause;
	private JButton buttonStop;
	private JButton buttonRewind;
	private JButton buttonPrevious;
	private JButton buttonNext;
	private JButton buttonFF;
	private JButton buttonSetTopic;

	/**
	 * Class constructor.
	 * 
	 * @param newClient the client to be controlled
	 */
	public WizardGUI(Wizard newWizard)
	{
		super(APP_NAME);
		
		// Retrieve SPOT preferences
		mSPOTDirectory = (new SPOTPreferences()).getSPOTDirectory();
		
		// Initialize client related data
		mWizard = newWizard;
		mPresentationPaused = false;
	}

	/**
	 * Initializes all GUI components and controls, lays them out 
	 * in the main frame, and then shows the main frame.  Also
	 * starts the client.
	 */
	public void start()
	{			
		// Create the menu
		menuBar = new JMenuBar();
		menuFile = new JMenu("File");
		menuFile.setMnemonic('F');
		menuBar.add(menuFile);
		setJMenuBar(menuBar);
		
		menuFileNew = new JMenuItem("New", KeyEvent.VK_N);
		menuFileNew.setActionCommand(NEW_COMMAND);
		menuFileNew.addActionListener(this);
		menuFileNew.setEnabled(true);
		menuFile.add(menuFileNew);

		menuFileClose = new JMenuItem("Close", KeyEvent.VK_C);
		menuFileClose.setActionCommand(CLOSE_COMMAND);
		menuFileClose.addActionListener(this);
		menuFileClose.setEnabled(false);
		menuFile.add(menuFileClose);
		
		menuFile.addSeparator();
		
		menuFileExit = new JMenuItem("Exit", KeyEvent.VK_X);
		menuFileExit.setActionCommand(EXIT_COMMAND);
		menuFileExit.addActionListener(this);
		menuFile.add(menuFileExit);
		
		// Create and layout the button panel
		buttonPanel = new JPanel();
		BoxLayout buttonLayout = new BoxLayout(buttonPanel, BoxLayout.X_AXIS);
		buttonPanel.setLayout(buttonLayout);
		buttonPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
		
		buttonRecord = new JButton("O");
		buttonRecord.setActionCommand(RECORD_COMMAND);
		buttonRecord.addActionListener(this);
		buttonRecord.setEnabled(false);
		buttonPause = new JButton("\"");
		buttonPause.setActionCommand(PAUSE_COMMAND);
		buttonPause.addActionListener(this);
		buttonPause.setEnabled(false);
		buttonStop= new JButton("[]");
		buttonStop.setActionCommand(STOP_COMMAND);
		buttonStop.addActionListener(this);
		buttonStop.setEnabled(false);
		buttonRewind = new JButton("|<<");
		buttonRewind.setActionCommand(REWIND_COMMAND);
		buttonRewind.addActionListener(this);
		buttonRewind.setEnabled(false);
		buttonPrevious = new JButton("<<");
		buttonPrevious.setActionCommand(PREVIOUS_COMMAND);
		buttonPrevious.addActionListener(this);
		buttonPrevious.setEnabled(false);
		buttonNext = new JButton(">>");
		buttonNext.setActionCommand(NEXT_COMMAND);
		buttonNext.addActionListener(this);
		buttonNext.setEnabled(false);
		buttonFF = new JButton(">>|");
		buttonFF.setActionCommand(FF_COMMAND);
		buttonFF.addActionListener(this);
		buttonFF.setEnabled(false);
		
		// Add all panel components
		buttonPanel.add(buttonRecord);
		buttonPanel.add(buttonPause);
		buttonPanel.add(buttonStop);
		buttonPanel.add(buttonRewind);
		buttonPanel.add(buttonPrevious);
		buttonPanel.add(buttonNext);
		buttonPanel.add(buttonFF);
		
		// Layout the control panel
		controlPanel = new JPanel();	
		GridBagLayout controlLayout = new GridBagLayout();
		GridBagConstraints controlConstraints = new GridBagConstraints();
		controlPanel.setLayout(controlLayout);
		controlPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
		
		textTitle = new JTextField(15);
		textTitle.setEditable(false);
		textTopic = new JTextField(15);
		textTopic.setEnabled(false);
		choiceSlide = new JComboBox();
		choiceSlide.setActionCommand(SLIDE_COMMAND);
		choiceSlide.addItemListener(this);
		choiceSlide.setLightWeightPopupEnabled(false);
		choiceSlide.setEnabled(false);
		choiceTopic = new JComboBox();
		choiceTopic.setActionCommand(TOPIC_COMMAND);
		choiceTopic.setLightWeightPopupEnabled(false);
		choiceTopic.setEnabled(false);
		buttonSetTopic = new JButton("Set Topic");
		buttonSetTopic.setActionCommand(SET_TOPIC_COMMAND);
		buttonSetTopic.addActionListener(this);
		buttonSetTopic.setEnabled(false);		
		
		// Set constraints for all the labels
		controlConstraints.gridwidth = GridBagConstraints.RELATIVE;
		controlConstraints.anchor = GridBagConstraints.WEST;
		controlConstraints.fill = GridBagConstraints.NONE;
		controlConstraints.insets = new Insets(5, 0, 0, 5);
		controlConstraints.weightx = 0.0;
		
		controlLayout.setConstraints(TITLE_LABEL, controlConstraints);
		controlLayout.setConstraints(SLIDE_LABEL, controlConstraints);
		controlLayout.setConstraints(TOPIC_LABEL, controlConstraints);
		controlLayout.setConstraints(buttonSetTopic, controlConstraints);
		
		// Set constraints for the labeled components
		controlConstraints.gridwidth = GridBagConstraints.REMAINDER;
		controlConstraints.anchor = GridBagConstraints.EAST;
		controlConstraints.fill = GridBagConstraints.HORIZONTAL;
		controlConstraints.weightx = 1.0;
		
		controlLayout.setConstraints(textTitle, controlConstraints);
		controlLayout.setConstraints(choiceSlide, controlConstraints);
		controlLayout.setConstraints(choiceTopic, controlConstraints);
		controlLayout.setConstraints(textTopic, controlConstraints);
		
		// Add all panel components
		controlPanel.add(TITLE_LABEL);
		controlPanel.add(textTitle);
		controlPanel.add(SLIDE_LABEL);
		controlPanel.add(choiceSlide);
		controlPanel.add(TOPIC_LABEL);
		controlPanel.add(choiceTopic);
		controlPanel.add(buttonSetTopic);
		controlPanel.add(textTopic);
		
		// Layout the main panel
		JPanel contentPane = (JPanel)getContentPane();
		BoxLayout contentLayout = new BoxLayout(contentPane, BoxLayout.Y_AXIS);
		contentPane.setLayout(contentLayout);
		contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
		
		// Add all panel components
		contentPane.add(buttonPanel);
		contentPane.add(controlPanel);
		
		// Add ourself as a window listener
		addWindowListener(this);
		
		// Set ourself as non-resizable, show the dialog, and center ourself
		setResizable(false);
		pack();
		Dimension paneSize = getSize();
        Dimension screenSize = getToolkit().getScreenSize();
        setLocation((screenSize.width - paneSize.width) / 2,
					(screenSize.height - paneSize.height) / 2);
		show();
	}
	
    public void windowClosing(WindowEvent e) 
	{
		exitApplication();
    }

    public void windowClosed(WindowEvent e) 
	{
    }

    public void windowOpened(WindowEvent e) 
	{
    }

    public void windowIconified(WindowEvent e) 
	{
    }

    public void windowDeiconified(WindowEvent e) 
	{
    }

    public void windowActivated(WindowEvent e) 
	{
    }

    public void windowDeactivated(WindowEvent e) 
	{
    }
	
	/**
	 * <code>ActionEvent</code> handler.
	 * 
	 * @param e event to handle
	 */
    public void actionPerformed(ActionEvent event) 
	{
		String actionCommand = event.getActionCommand();
		
        if (actionCommand.equals(NEW_COMMAND)) 
		{	
			// Allow the user to select a SPOT file
			JFileChooser fileChooser = new JFileChooser();
			fileChooser.setMultiSelectionEnabled(false);
			fileChooser.setCurrentDirectory(new File(mSPOTDirectory));
			fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
			fileChooser.setFileFilter(new SPOTDirectoryFilter());
			fileChooser.showDialog(null, "New");
			
			// Get the selected file
			File file = fileChooser.getSelectedFile();

			// Create the project
			if (file != null)
			{
				// Create the project
				try
				{
					mWizard.newProject(file.getAbsolutePath());
					mProjectName = getProjectName(file.getName());
				}
				catch (WizardException e)
				{
					showErrorDialog("Error creating project: " + e.getMessage());
					return;
				}
				
				// Update the GUI
				menuFileNew.setEnabled(false);
				menuFileClose.setEnabled(true);
				buttonRecord.setEnabled(true);
				buttonPause.setEnabled(false);
				buttonStop.setEnabled(false);
				buttonRewind.setEnabled(false);
				buttonPrevious.setEnabled(false);
				buttonNext.setEnabled(false);
				buttonFF.setEnabled(false);
				choiceTopic.setEnabled(false);
				choiceTopic.addItemListener(this);
				textTitle.setText(mProjectName);			
			}
        }
		else if (actionCommand.equals(CLOSE_COMMAND))
		{
			// Close the project
			try
			{				
				// Update the GUI
				menuFileNew.setEnabled(true);
				menuFileClose.setEnabled(false);
				buttonRecord.setEnabled(false);
				buttonPause.setEnabled(false);
				buttonStop.setEnabled(false);
				buttonRewind.setEnabled(false);
				buttonPrevious.setEnabled(false);
				buttonNext.setEnabled(false);
				buttonFF.setEnabled(false);
				choiceTopic.removeItemListener(this);
				choiceTopic.removeAllItems();
				choiceTopic.setEnabled(false);
				textTopic.setEnabled(false);
				buttonSetTopic.setEnabled(false);
				textTitle.setText("");	
					
				// Reset client
				mWizard.closeProject();
			}
			catch (WizardException e)
			{
				showErrorDialog("Error closing the project: " + e.getMessage());
			}	
		}
		else if (actionCommand.equals(EXIT_COMMAND)) 
		{
			// Cleanup...
			exitApplication();
        }
		else if (actionCommand.equals(RECORD_COMMAND))
		{	
			// If the presentation is paused, resume
			if (mPresentationPaused)
			{
				mWizard.unpauseRecording();
				
				mPresentationPaused = false;
				buttonRecord.setEnabled(false);
					
				return;
			}
			
			// Start the recording
			try
			{
				mWizard.openPPTPresentation(500, 667, 179, 0);
				mWizard.startRecording();
			}
			catch (Exception e)
			{
				showErrorDialog("Error starting presentation recording: " + e.getMessage());
				return;
			}
			
			// Update GUI
			buttonRecord.setEnabled(false);
			buttonPause.setEnabled(true);
			buttonStop.setEnabled(true);
			buttonRewind.setEnabled(true);
			buttonPrevious.setEnabled(true);
			buttonNext.setEnabled(true);
			buttonFF.setEnabled(true);
			choiceTopic.removeItemListener(this);
			choiceTopic.removeAllItems();
			choiceTopic.addItem(EMPTY_ITEM);
			choiceTopic.addItemListener(this);
			choiceTopic.setEnabled(true);
			textTopic.setEnabled(true);
			buttonSetTopic.setEnabled(true);			
		}
		else if (actionCommand.equals(PAUSE_COMMAND))
		{
			// Pause / resume presentation
			if (!mPresentationPaused)
			{
				mWizard.pauseRecording();
				
				mPresentationPaused = true;
				buttonRecord.setEnabled(true);
				buttonSetTopic.setEnabled(false);
			}
			else
			{
				mWizard.unpauseRecording();
				
				mPresentationPaused = false;
				buttonRecord.setEnabled(false);
				buttonSetTopic.setEnabled(true);
			}
		}
		else if (actionCommand.equals(STOP_COMMAND))
		{
			// Stop the presentation
			try
			{
				mWizard.stopRecording();
				mWizard.closePPTPresentation();
			}
			catch (WizardException e)
			{
				showErrorDialog("Error stopping recording: " + e.getMessage());
			}
			
			// Update GUI
			buttonRecord.setEnabled(true);
			buttonPause.setEnabled(false);
			buttonStop.setEnabled(false);
			buttonRewind.setEnabled(false);
			buttonPrevious.setEnabled(false);
			buttonNext.setEnabled(false);
			buttonFF.setEnabled(false);
			choiceTopic.setEnabled(false);
			textTopic.setEnabled(false);
			buttonSetTopic.setEnabled(false);			
		}
		else if (actionCommand.equals(REWIND_COMMAND))
		{
			// Rewind presentation
			try
			{
				mWizard.gotoFirstPPTSlide();
				resetTopic();
			}
			catch (PowerPointControlException e)
			{
				showErrorDialog("PowerPoint exception occured: " + e.getMessage());
			}
		}
		else if (actionCommand.equals(PREVIOUS_COMMAND))
		{
			// Goto previous slide
			try
			{
				mWizard.gotoPreviousPPTSlide();
				resetTopic();
			}
			catch (PowerPointControlException e)
			{
				showErrorDialog("PowerPoint exception occured: " + e.getMessage());
			}	
		}
		else if (actionCommand.equals(NEXT_COMMAND))
		{
			// Rewind presentation
			try
			{
				mWizard.gotoNextPPTSlide();
				resetTopic();
			}
			catch (PowerPointControlException e)
			{
				showErrorDialog("PowerPoint exception occured: " + e.getMessage());
			}		
		}
		else if (actionCommand.equals(FF_COMMAND))
		{
			// Rewind presentation
			try
			{
				mWizard.gotoLastPPTSlide();
				resetTopic();
			}
			catch (PowerPointControlException e)
			{
				showErrorDialog("PowerPoint exception occured: " + e.getMessage());
			}				
		}
		else if (actionCommand.equals(SET_TOPIC_COMMAND))
		{					
			String newTopic;
			int numTopics;

			// Set the topic
			newTopic = textTopic.getText();
			if (!newTopic.equals(""))
			{
				numTopics = choiceTopic.getItemCount();
				if (!mWizard.setTopic(newTopic))
				{
					choiceTopic.removeItemListener(this);
					choiceTopic.removeItemAt(numTopics - 1);
					choiceTopic.addItemListener(this);
					textTopic.setText("");	
				}
				choiceTopic.removeItemListener(this);
				choiceTopic.addItem(newTopic);
				choiceTopic.setSelectedItem(newTopic);
				choiceTopic.addItemListener(this);
				textTopic.setText("");				
			}
		}
    }
	
	/**
	 * Handles SLIDE_COMMAND or TOPIC_COMMANDS events (fired when
	 * the user selects a different topic or slide).
	 * 
	 * @param e event to handle
	 */
	public void itemStateChanged(ItemEvent event)
	{	
		// Only respond to item selected events
		if (event.getStateChange() == ItemEvent.SELECTED)
		{
			// Get the action command associated with the source
			JComboBox comboBox = (JComboBox)event.getSource();
			String actionCommand = comboBox.getActionCommand();
			
			if (actionCommand.equals(TOPIC_COMMAND))
			{
				try
				{
					mWizard.gotoTopicPPTSlide((String)comboBox.getSelectedItem());
				}
				catch (WizardException e)
				{
					return;
				}
				catch (PowerPointControlException e)
				{
					return;
				}
			}
			else if (actionCommand.equals(SLIDE_COMMAND))
			{
			}
		}
	}
	
	/**
	 * Show an error dialog.
	 */
	public static void showErrorDialog(String error)
	{
		JOptionPane.showMessageDialog(null, error, "SPOT Error", JOptionPane.ERROR_MESSAGE); 
	}
	
	/**
	 * Show a message dialog
	 */
	public static void showMessageDialog(String message)
	{
		JOptionPane.showMessageDialog(null,message, "SPOT Message", JOptionPane.INFORMATION_MESSAGE);
	}	
	
	/**
	 * Performs all application exit duties.
	 */
	private void exitApplication()
	{	
		// Remember to reset the wizard...
		try
		{
			mWizard.closeProject();
		}
		catch (WizardException e)
		{
		}		
		
		dispose();
		System.exit(0);
	}
	
	/**
	 * Resets the topic selection
	 */
	private void resetTopic()
	{
		choiceTopic.removeItemListener(this);
		choiceTopic.setSelectedIndex(0);
		choiceTopic.addItemListener(this);		
	}	
	
	/**
	 * Get a Wizard project name from the associated presentation file name
	 */
	private static String getProjectName(String presentationName)
	{
		String returnString = new String(presentationName);
		
		// Is the name a valid presentation name?
		if (returnString.length() < SPOTDefinitions.PRESENTATION_FILE_SUFFIX.length() - 1)
		{
			return returnString;
		}
		
		return returnString.substring(0, 
			returnString.length() - SPOTDefinitions.PRESENTATION_FILE_SUFFIX.length());
	}
}

/**
 * SPOT directory filter:
 */
class SPOTDirectoryFilter extends FileFilter
{	
	/**
	 * Whether the given file is accepted by this filter.
	 */
	public boolean accept(File f)
	{	
		// Only accept directories
		if (f.isDirectory())
		{
			return true;
		}
		String filename = f.getName();		
		
		return (SPOTDefinitions.isPPTFile(filename));
	}
	
	/**
	 * The description of this filter.
	 */
	public String getDescription()
	{
		return "PowerPoint Presentations";
	}
}