import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import java.util.Vector;
import java.net.URL;

/**
 *  jTFlashManager is a GUI interface for turning on and off the flash plugin for multiple
 *  browsers. There's not a whole lot of magic -- It simply renames the current plugin to a
 *  backup name to turn it off, and vice versa to turn it on.
 *
 * Version 1.1 is now packaged in an installer (nullsoft), and has fix the bug that happens
 * when a new version of the plugin is downloaded while the plugin has been renamed to the
 * backup name.
 *
   @version 1.1
 * @author     jTMetzger
 * @created    April 25, 2002
 */
class jTFlashManager extends JFrame {
	private static jTFlashManager frame;
	private static ResourceBundle resources;
	private JMenu managemenu, filemenu;
	private PrintWriter out;
	private JPanel panel0, panel1, panel2;
	private JMenuItem about, find, auto, delete;
	private JDialog aboutBox = null;
	private Image jt;
	private ImageIcon startIcon, stopIcon, onIcon, offIcon;
	private String aboutTx;
	private ActionListener theListener;
	private PlayButton startButton, stopButton;
	private JLabel onOrOff, pluginName;
	private String path, backupPath, flashPlugin, flashBackupPlugin, fileSeparator, dataPath, currentManagedPath;
	private File theFile, backup;
	private Font aboutFont, displayFont;
	private Properties dataProperties;
	private Vector manageVector;
	private boolean dataFileExists;


	/**
	 *  Constructor for the jTFlashManager object. creates the fonts to be used,
	 *  checks for the data file, attaches actionlisteners to the buttons, etc
	 *  and loads the default plugin.
	 */
	private jTFlashManager() {
		aboutFont = new Font("Arial", 1, 10);
		displayFont = new Font("Tahoma", 1, 12);
		dataFileExists = readDataFile();
		jt = Toolkit.getDefaultToolkit().getImage(getResource("jtIcon"));
		this.setIconImage(jt);
		this.setTitle(resources.getString("Title"));
		buildGUI();
		setToDefaultPlugin();
		hookupEvents();

	}


	/**
	 *  The main program for the jTFlashManager class
	 *
	 * 
	 */
	public static void main(String[] args) {

		frame = new jTFlashManager();
		WindowListener l =
			new WindowAdapter() {
				public void windowClosing(WindowEvent e) {
					System.exit(0);
				}
			};
		frame.addWindowListener(l);
		frame.setVisible(true);
		frame.setResizable(false);
		frame.pack();
	}


	/**
	 *  Toggles the "Flash: on/off" message in the GUI.
	 */
	public void setIsRunning() {
		if (theFile.exists()) {
			onOrOff.setIcon(onIcon);
		} else if (backup.exists()) {
			onOrOff.setIcon(offIcon);
		}
		this.pack();
	}


	/**
	 *  When a new Plugin is added through the "Auto-Detect" or "Find Plugin"
	 *  options in the GUI, this controls what happens, adding that plugin to
	 *the Manage Menu, and setting the currently controlled plugin to the
	 * new plugin.
	 *
	 * @param  tPath        The path for the real plugin file
	 * @param  tBackupPath  The path for the backup plugin.
	 * @param  tName        The name of the new plugin
	 */
	public void setPluginData(String tPath, String tBackupPath, String tName) {

		path = tPath;
		backupPath = tBackupPath;
		if (path == null || backupPath == null) {
			managemenu.setVisible(true);
			path = "";
			backupPath = "";
			filemenu.remove(delete);
			onOrOff.setIcon(null);
		} else {
			filemenu.add(delete);
		}
		currentManagedPath = path;
		theFile = new File(path);
		backup = new File(backupPath);
		pluginName.setText(tName);
		this.pack();
	}


	/**
	 *  Returns the frame instance
	 *
	 * @return    The frame value
	 */
	public JFrame getFrame() {
		return frame;
	}


	/**
	 *  Gets the path to the plugin from the data file.
	 *
	 * @param  whichPath     the paths are in a comma-delimited String
	 * of data. this int tells which segment to use to get the path.
	 *
	 * @param  dataVariable  which property to read in.
	 * @return               The pluginData value
	 */
	public String getPluginData(int whichPath, String dataVariable) {
		String thePath = dataProperties.getProperty(dataVariable);
		StringTokenizer eachPath = new StringTokenizer(thePath, "|");
		int i = 0;
		while (i <= whichPath) {
			thePath = eachPath.nextToken();
			i++;
		}

		return thePath;
	}


	/**
	 *  Renames the file to a backup name to turn off, vice-versa to turn on.
	 *  This is the part that's been updated to check for a newly downloaded plugin
	 *  while switching. It always defaults to the current real plugin if both
	 *  the real plugin and the backup file exist.
	 *
	 * @param  command  Description of Parameter
	 */
	public void togglePlugin(String command) {

		if (command.equals("on")) {
			if (backup.exists()) {
				if(theFile.exists()){
				backup.delete();
				}else{
				backup.renameTo(theFile);
				}
			}
		}
		if (command.equals("off")) {
			if (theFile.exists()) {
				if(backup.exists()){
					backup.delete();
				}
				theFile.renameTo(backup);
			}
		}
	}


	/**
	 *  The dialog which requests a name for newly detected plugins. It uses the
	 *  name to write data about that plugin to the data file.
	 *
	 * @param  pluginsFound  Array of data about the plugins found.
	 */
	public void doPluginNamingDialog(String[] pluginsFound) {
		int i;
		String tempOutput = new String();
		String pathString = new String();
		String backupString = new String();
		String pluginString = new String();
		String currentPaths = new String();
		String currentBackups = new String();
		String currentPlugins = new String();
		int pluginsCounter = 0;
		if (dataFileExists) {
			currentPaths = dataProperties.getProperty("path");
			currentBackups = dataProperties.getProperty("backupPath");
			currentPlugins = dataProperties.getProperty("plugins");
		}

		for (i = 0; i < pluginsFound.length; i++) {
			if (pluginsFound[i] != null) {
				pluginsFound[i] = pluginsFound[i].replace('\\', '/');
				if (currentPaths.indexOf(pluginsFound[i]) == -1 && currentBackups.lastIndexOf(pluginsFound[i]) == -1) {

					String name = JOptionPane.showInputDialog("Enter name for : " + pluginsFound[i]);
					if (name != null) {
						if (name.length() > 12) {
							name = name.substring(0, 12) + "...";
						}
						name = name.replace('|', '~');
						name = name.replace('\\', '~');
						name = name.replace('/', '~');
						name = name.replace(':', '~');
						name = name.trim();
						if (name.equals("")) {
							name = "Plugin " + String.valueOf(i + 1);
						}
						pathString += pluginsFound[i] + "|";
						backupString += pluginsFound[i] + ".jTFMBackup|";
						pluginString += name + "|";
						pathString = pathString.replace('\\', '/');
						backupString = backupString.replace('\\', '/');
						pluginsCounter += 1;
					}
				}
			}
		}
		if (pluginsCounter > 0) {
			pathString += currentPaths;
			backupString += currentBackups;
			pluginString += currentPlugins;
			writeData(pathString, backupString, pluginString, false);
		} else {
			JOptionPane.showMessageDialog(
					frame, "I didn't load any new plugins. If you know the \nlocation of the plugin, choose File > Find Plugin."
					);
		}

	}


	/**
	 *  handles the file i/o for writing the plugin data to the data file.
	 *
	 * @param  pathString    path to the real plugin
	 * @param  backupString  path to the backup plugin file
	 * @param  pluginString  Description of name of the plugin.
	 * @param  deleteOption  this can also delete the current plugin (when true) and rewrite 
	 *                        the data file.
	 */
	public void writeData(String pathString, String backupString, String pluginString, boolean deleteOption) {

		if (deleteOption = true && pathString.length() == 0) {
			File killFile = new File(dataPath);
			killFile.delete();
			dataFileExists = readDataFile();
			setPluginData(null, null, null);
			filemenu.remove(delete);
			onOrOff.setText("");
		} else {
			try {

				out = new PrintWriter(new FileWriter(dataPath));
			} catch (IOException ioe) {
				JOptionPane.showMessageDialog(
						frame, "Could not write to the data file at " + dataPath
						);
				throw new RuntimeException("Could not write to output.txt");
			}
			out.println("#pluginData.properties contains path to plugin and backup file.");
			out.println("#This is a generated file.");
			out.println("#Do not edit.");
			out.println("#If you believe you have corrupted this file, delete it.");
			out.println("path=" + pathString);
			out.println("backupPath=" + backupString);
			out.println("plugins=" + pluginString);
			out.close();
		}
	}


	/**
	 *  read in data from the data file. If there is no data file,
	 *  it gives advice on what to do and how to use the autodetect.
	 *
	 * @return    Description of the Returned Value
	 */
	public boolean readDataFile() {
		dataPath = System.getProperty("user.dir");
		dataPath = dataPath.replace('\\', '/') + "/";
		dataPath = dataPath + "data/pluginData.properties";
		dataProperties = null;
		dataProperties = new Properties();
		try {
			FileInputStream in = new FileInputStream(dataPath);
			dataProperties.load(in);
			in.close();
			return true;
		} catch (java.io.FileNotFoundException fnfe) {
			File dataDir = new File(System.getProperty("user.dir") + "/data");
			if (!dataDir.exists()) {
				dataDir.mkdir();
				JOptionPane.showMessageDialog(
						frame, "It looks like this is your first time using jTFlashManager.\n Choosing File > Auto-Detect will automatically load the most common broswers."
						);
			}
			return false;
		} catch (java.io.IOException ioe) {
			return false;
		}

	}


	/**
	 *  Returns paths to graphics from jTFlashManager.properties.
	 *
	 * @param  key  Description of Parameter
	 * @return      The resource value
	 */
	protected URL getResource(String key) {
		String name = resources.getString(key);
		if (name != null) {
			URL url = this.getClass().getResource(name);
			return url;
		}
		return null;
	}


	/**
	 *  adds graphics, buttons, menus, etc
	 */
	private void buildGUI() {

		JMenuBar menubar = new JMenuBar();
		setJMenuBar(menubar);
		filemenu = new JMenu("File", false);
		managemenu = new JMenu("Manage", false);
		menubar.add(filemenu);
		menubar.add(managemenu);
		about = new JMenuItem("About");
		auto = new JMenuItem("Auto-Detect");
		find = new JMenuItem("Find Plugin");
		delete = new JMenuItem("Delete");
		buildManageMenu();
		filemenu.add(auto);
		filemenu.add(find);
		filemenu.add(about);
		getContentPane().setLayout(new BorderLayout());
		panel0 = new JPanel();
		panel1 = new JPanel();
		panel2 = new JPanel();
		getContentPane().add(panel0, "North");
		getContentPane().add(panel1, "Center");
		getContentPane().add(panel2, "South");
		startIcon = new ImageIcon(getResource("startIcon"));
		stopIcon = new ImageIcon(getResource("stopIcon"));
		onIcon = new ImageIcon(getResource("onIcon"));
		offIcon = new ImageIcon(getResource("offIcon"));
		stopButton = new PlayButton("off", stopIcon);
		startButton = new PlayButton("on", startIcon);
		onOrOff = new JLabel();
		pluginName = new JLabel();
		pluginName.setText("");
		panel0.add(pluginName);
		panel1.add(startButton);
		panel1.add(stopButton);
		panel2.add(onOrOff);
	}


	/**
	 *  uses the data in the datafile to generate the manage menu, a list
	 *  of plugins currently being managed by jtflashmanager.
	 */
	private void buildManageMenu() {

		managemenu.removeAll();
		if (dataFileExists) {
			String plugins = dataProperties.getProperty("plugins");
			StringTokenizer eachPlugin = new StringTokenizer(plugins, "|");
			manageVector = new Vector();
			int i = 0;
			while (eachPlugin.hasMoreTokens()) {
				String theToken = eachPlugin.nextToken();
				manageVector.add(new JMenuItem(theToken));
				JMenuItem tempItem = (JMenuItem) manageVector.get(i);
				tempItem.setActionCommand(String.valueOf(i));
				tempItem.addActionListener(new ManageAction());
				managemenu.add((JMenuItem) manageVector.get(i));
				i++;
			}
		}
	}


	/**
	 *  adds actionlisteners to the menuitems and buttons
	 */
	private void hookupEvents() {
		auto.addActionListener(new AutoAction());
		about.addActionListener(new AboutAction(this));
		find.addActionListener(new FindPluginAction(this));
		delete.addActionListener(new DeleteAction());

	}


	/**
	 *  Opens the "About" window (new frame)
	 *
	 * @author     tmetzger
	 * @created    April 25, 2002
	 */
	class AboutAction extends AbstractAction {
		jTFlashManager jtflashmanager;


		/**
		 *  Constructor for the AboutAction object
		 *
		 * @param  jtflashmanager  Description of Parameter
		 */
		protected AboutAction(jTFlashManager jtflashmanager) {
			super("AboutAction");
			this.jtflashmanager = jtflashmanager;
		}


		/**
		 *  Description of the Method
		 *
		 * @param  e  Description of Parameter
		 */
		public void actionPerformed(ActionEvent e) {
			if (aboutBox == null) {
				JPanel panel = new JPanel();
				JPanel panelOK = new JPanel();
				panel.setLayout(new GridLayout(5, 1));
				aboutBox = new JDialog(jtflashmanager.getFrame(), "About jTFlashManager", false);
				aboutBox.getContentPane().add(panel, BorderLayout.NORTH);
				aboutBox.getContentPane().add(panelOK, BorderLayout.CENTER);
				JLabel releaseName = new JLabel(resources.getString("releaseName") + " " + resources.getString("releaseVersion"));
				JLabel releaseCompany = new JLabel(resources.getString("releaseCompany"));
				JLabel releaseCopyright = new JLabel(resources.getString("releaseCopyright"));
				JLabel releaseBy = new JLabel(resources.getString("releaseBy"));
				JLabel releaseContact = new JLabel(resources.getString("releaseContact"));
				releaseName.setFont(aboutFont);
				releaseCompany.setFont(aboutFont);
				releaseCopyright.setFont(aboutFont);
				releaseBy.setFont(aboutFont);
				releaseContact.setFont(aboutFont);
				panel.add(releaseName);
				panel.add(releaseCompany);
				panel.add(releaseCopyright);
				panel.add(releaseBy);
				panel.add(releaseContact);
				JButton button = new JButton("OK");
				panelOK.add(button);
				button.addActionListener(
					new ActionListener() {
						public void actionPerformed(ActionEvent e) {
							aboutBox.setVisible(false);
						}
					});
			}
			aboutBox.pack();
			Point p = jtflashmanager.getLocationOnScreen();
			aboutBox.setLocation(p.x + 10, p.y + 10);
			aboutBox.show();
		}
	}


	/**
	 *  Action for the "Find Plugin" menu option
	 *
	 * @author     tmetzger
	 * @created    April 25, 2002
	 */
	class FindPluginAction extends AbstractAction {
		jTFlashManager jtflashmanager;


		protected FindPluginAction(jTFlashManager jtflashmanager) {
			super("FindPluginAction");
			this.jtflashmanager = jtflashmanager;
		}


		/**
		 *  attempts to find the plugin at the path specified by the user.
		 *
		 * @param  e  the ActionEvent of the file chooser.
		 */
		public void actionPerformed(ActionEvent e) {
			JFileChooser chooser = new JFileChooser();
			int retval = chooser.showDialog(frame, null);
			if (retval == JFileChooser.APPROVE_OPTION) {
				File theFile = chooser.getSelectedFile();
				if (theFile != null) {
					String[] pluginsFound = new String[1];
					pluginsFound[0]
							 = chooser.getSelectedFile().getPath();
					doPluginNamingDialog(pluginsFound);
					dataFileExists = readDataFile();
					buildManageMenu();
					setToDefaultPlugin();
					return;
				}
			}
		}
	}


	/**
	 *  Action for the "Autodetect" option.
	 *
	 * @author     tmetzger
	 * @created    April 25, 2002
	 */
	class AutoAction extends AbstractAction {
		private String commonPaths;
		private String[] pluginsFound;
		private StringTokenizer eachPath;


		/**
		 *  uses a predefined list of common paths
		 *  for flash plugins in jTFlashManager.properties
		 *  to detect plugins on the user machine.
		 *
		 * @param  e  the ActionEvent of the file chooser.
		 */
		public void actionPerformed(ActionEvent e) {
			commonPaths = resources.getString("commonPaths");
			eachPath = new StringTokenizer(commonPaths, "|");
			int howMany = eachPath.countTokens();
			pluginsFound = new String[howMany];
			int i = 0;
			while (eachPath.hasMoreTokens()) {
				String theToken = eachPath.nextToken();
				File checkPlugin = new File(theToken);
				if (checkPlugin.exists()) {
					pluginsFound[i] = theToken;
					i++;
				}
			}

			doPluginNamingDialog(pluginsFound);
			dataFileExists = readDataFile();
			buildManageMenu();
			setToDefaultPlugin();
		}

	}


	/**
	 *  Acton for the delete option in the file menu
	 *
	 * @author     TMetzger
	 * @created    May 9, 2002
	 */
	class DeleteAction extends AbstractAction {
		private String paths;
		private String backupPaths;
		private String plugins;
		private StringTokenizer allPath;
		private StringTokenizer allBackupPath;
		private StringTokenizer allPlugin;


		/**
		 *  Checks if the user really wants to remove the plugin from
		 *  jTFlashmanager's control, and then deletes the data from the data file
		 *  for that plugin.
		 *
		 * @param  e  the ActionEvent of the file chooser.
		 */
		public void actionPerformed(ActionEvent e) {
			int retval = JOptionPane.showConfirmDialog(
					frame, "Do you really want to remove the current plugin \"" + pluginName.getText() + "\" from jTFlashManager?");
			if (retval == JOptionPane.YES_OPTION) {
				String outPaths = new String();
				String outBackupPaths = new String();
				String outPlugins = new String();
				paths = dataProperties.getProperty("path");
				backupPaths = dataProperties.getProperty("backupPath");
				plugins = dataProperties.getProperty("plugins");
				allPath = new StringTokenizer(paths, "|");
				allBackupPath = new StringTokenizer(backupPaths, "|");
				allPlugin = new StringTokenizer(plugins, "|");
				togglePlugin("on");
				while (allPath.hasMoreTokens()) {

					String pathToken = allPath.nextToken();
					String backupPathToken = allBackupPath.nextToken();
					String pluginToken = allPlugin.nextToken();
					if (!currentManagedPath.equals(pathToken)) {
						outPaths += pathToken + "|";
						outBackupPaths += backupPathToken + "|";
						outPlugins += pluginToken + "|";

					}
				}
				writeData(outPaths, outBackupPaths, outPlugins, true);
				dataFileExists = readDataFile();
				buildManageMenu();
				setToDefaultPlugin();
			}
		}

	}


	/**
	 *  Set up characteristics of PlayButtons, the "Start" and "Stop" buttons.
	 *
	 * @author     jTMetzger
	 * @created    April 25, 2002
	 */
	class PlayButton extends JButton {
		/**
		 *  Constructor for the GameButton object
		 *
		 * @param  actionCommand  "on" for the on button, "off" for the off button.
		 * @param  icon           the Imaheicon representing the action of the button.
		 */
		public PlayButton(String actionCommand, ImageIcon icon) {
			theListener = new PlayButtonListener();
			addActionListener(theListener);
			setActionCommand(actionCommand);
			setIcon(icon);
			setRequestFocusEnabled(false);
			setBackground(Color.white);
			setMargin(new Insets(-2, -2, -2, -2));

		}

	}


	/**
	 *  Sets the toDefaultPlugin attribute of the jTFlashManager object
	 */
	public void setToDefaultPlugin() {

		if (dataFileExists) {
			String thePath = getPluginData(0, "path");
			String backupPath = getPluginData(0, "backupPath");
			String theName = getPluginData(0, "plugins");
			if (thePath.trim().length() > 0) {
				setPluginData(thePath, backupPath, theName);
			}
			managemenu.setVisible(true);
			setIsRunning();
		} else {
			managemenu.setVisible(false);
			onOrOff.setIcon(null);
			pluginName.setText("");
		}

	}


	/**
	 *  Action listener for the Start/Stop buttons
	 *
	 * @author     jTmetzger
	 * @created    April 25, 2002
	 */
	class PlayButtonListener implements ActionListener {

		/**
		 *  Fires events which toggle the state of the plugin.
		 *
		 * @param  e  Description of Parameter
		 */
		public void actionPerformed(ActionEvent e) {
			togglePlugin(e.getActionCommand());
			setIsRunning();
		}
	}


	/**
	 *  Action for the items in the "Manage" menu, which is a list of the current plugins
	 *  controlled by jTFlashManager. 
	 *
	 * @author     tmetzger
	 * @created    April 25, 2002
	 */
	class ManageAction extends AbstractAction {


		/**
		 *  Changes the plugin selected in the Manage menu to be
		 *  the current plugin controlled.
		 *
		 * @param  e  Description of the Parameter
		 */
		public void actionPerformed(ActionEvent e) {
			JMenuItem tempItem = (JMenuItem) e.getSource();
			int actionCommand = Integer.parseInt(e.getActionCommand());
			String thePath = getPluginData(actionCommand, "path");
			currentManagedPath = thePath;
			String theBackupPath = getPluginData(actionCommand, "backupPath");
			String theName = getPluginData(actionCommand, "plugins");
			setPluginData(thePath, theBackupPath, theName);
			setIsRunning();
		}

	}
	
	//read in the static data for jtfm at runtime ("About" data,  paths to images, common paths to
	// browser plugins.
	static {
		resources = ResourceBundle.getBundle("resources.jTFlashManager");
	}
}