
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.net.URL;

import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;

import dirk_krause.jtools.ApplicationFrame;
import dirk_krause.jtools.DirectoryFilter;
import dirk_krause.jtools.GbcMaker;
import dirk_krause.jtools.GuiController;
import dirk_krause.jtools.GuiDialog;
import dirk_krause.jtools.HelpWindow;
import dirk_krause.jtools.LogContents;
import dirk_krause.jtools.LogContentsForCommand;
import dirk_krause.jtools.LogWindow;
import dirk_krause.jtools.OneDirectoryDropTransferHandler;
import dirk_krause.jtools.SizeTracker;
import dirk_krause.jtools.StringTool;
import dirk_krause.jtools.StatusChanger;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class Png2PdfWindow extends ApplicationFrame
	implements ActionListener
{
	/**
	 * Dialog to set up GUI.
	 */
	protected GuiDialog guid = null;
	
	/**
	 * Controller keeping options for png2pdf.
	 */
	protected Png2PdfController tc = null;
	
	/**
	 * Dialog to set up options to png2pdf.
	 */
	protected Png2PdfDialog tod = null;
	
	/**
	 * Window to show log text (command output).
	 */
	protected LogWindow lw = null;
	
	/**
	 * Window to show version information and help.
	 */
	protected HelpWindow hw = null;
	
	/**
	 * Flag to indicate whether or not a background
	 * thread is running
	 */
	protected boolean isRunning = false;
	
	/**
	 * Menu item to choose directory.
	 */
	protected JMenuItem miDir =  null;
	
	/**
	 * Menu item to set options.
	 */
	protected JMenuItem miOpt  = null;
	
	/**
	 * Menu item to run the png2pdf command.
	 */
	protected JMenuItem miRun  = null;
	
	/**
	 * Menu item to exit the application.
	 */
	protected JMenuItem miExit = null;
	
	/**
	 * Menu item to set up GUI.
	 */
	protected JMenuItem miGui  = null;
	
	/**
	 * Menu item to pack window.
	 */
	protected JMenuItem miPck = null;
	
	/**
	 * Menu item to show version and license information.
	 */
	protected JMenuItem miLic  = null;
	
	/**
	 * Menu item to show help text.
	 */
	protected JMenuItem miHlp  = null;
	
	/**
	 * Button to change directory.
	 */
	protected JButton bDir = null;
	
	/**
	 * Button to change options to png2pdf.
	 */
	protected JButton bOpt = null;
	
	/**
	 * Button to run the png2pdf command.
	 */
	protected JButton bRun = null;
	
	/**
	 * Button to exit the application.
	 */
	protected JButton bExit = null;
	
	/**
	 * Label to show the current working directory.
	 */
	protected JLabel  lDir = null;
	
	/**
	 * Label to show the program status.
	 */
	protected JLabel  lSta = null;
	
	/**
	 * Color to show the program status in red while
	 * the application is busy.
	 */
	protected Color  myR = null;
	
	/**
	 * Color to show the program status in green
	 * while the application is idle.
	 */
	protected Color  myG = null;
	
	/**
	 * Size tracker for directory label.
	 */
	protected SizeTracker stDir = null;
	
	/**
	 * Size tracker for status messages.
	 */
	protected SizeTracker stSta = null;
	
	/**
	 * Allow the controller to print file names.
	 */
	protected ControllerStatusChanger csc = null;
	
	/**
	 * License terms.
	 */
	public static final String licenseTerms =
		"<html>\n"
		+ "<head>\n"
		+ "</head>\n"
		+ "<body>\n"
		+ "<p>This is Png2PdfGUI, version 1.1.0</p>"
		+ "<p>\n"
		+ "Copyright (c) 2006, Dirk Krause<br>\n"
		+ "All rights reserved.\n"
		+ "</p>\n"
		+ "<p>\n"
		+ "Redistribution and use in source and binary forms,\n"
		+ "with or without modification, are permitted provided\n"
		+ "that the following conditions are met:\n"
		+ "<ul>\n"
		+ "<li>Redistributions of source code must retain the above\n"
		+ "copyright notice, this list of conditions and the\n"
		+ "following disclaimer.</li>\n"
		+ "<li>Redistributions in binary form must reproduce the above \n"
		+ "opyright notice, this list of conditions and the following\n"
		+ "disclaimer in the documentation and/or other materials\n"
		+ "provided with the distribution.</li>\n"
		+ "<li>Neither the name of the Dirk Krause nor the names of\n"
		+ "its contributors may be used to endorse or promote\n"
		+ "products derived from this software without specific\n"
		+ "prior written permission.</li>\n"
		+ "</ul>\n"
		+ "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n"
		+ "CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n"
		+ "INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
		+ "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n"
		+ "DISCLAIMED.<br>\n"
		+ "IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n"
		+ "LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n"
		+ "EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
		+ "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n"
		+ "LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n"
		+ "HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
		+ "CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n"
		+ "OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n"
		+ "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n"
		+ "DAMAGE.\n"
		+ "</p>\n"
		+ "</body>\n"
		+ "</html>\n";

	/**
	 * Keywords to set up GUI elements
	 */
	public static final String[] theTexts = {
		"Png2pdf-GUI",				//  0
		"Png2pdf",				//  1
		"Setup",				//	2
		"<html><body><b>Png2pdfGUI - a GUI to the png2pdf program</b></body></html>",	// 3
		"Directory:",			//  4
		"Status:",				//  5
		"Ready",				//  6
		"Running",				//  7
		"Initializing",			//  8
		"Saving Options",		//  9
		"Exiting",				// 10
		"Retrieving defaults",	// 11
		"Saving defaults",		// 12
		"Help",					// 13
	};
	
	/**
	 * Keyword to set up buttons and menu items
	 */
	public static final String[] actionCmd = {
		"GUI",					//  0
		"Directory",			//  1
		"Options",				//  2
		"Run",					//  3
		"Exit",					//  4
		"Save Options",			//  5
		"About",				//  6
		"Help",					//  7
		"Pack window",			//  8
		"Retrieve Options",		//  9
	};
	
	/**
	 * File names for icons in the button bar.
	 */
	public static final String[] iconFileNames = {
		"ChooseDirectory.png",
		"Options.png",
		"Run.png",
		"Exit.png"
	};
	
	/**
	 * Texts for tooltips.
	 */
	public static final String[] toolTipTexts = {
		"<html><body>Choose <b>Directory</b></body></html>",
		"<html><body>Set <b>Options</b></body></html>",
		"<html><body><b>Run</b> png2pdf</body></html>",
		"<html><body><b>Exit</b> the GUI</body></html>",
		"<html><body><b>Setup</b> the <b>GUI</b></body></html>",
		"<html><body><b>Pack window</b> to optimized size</body></html>"
	};
	
	/**
	 * File name for online help.
	 */
	public static final String helpFileName = "ppgui.html";
	
	/**
	 * Change status label.
	 *
	 */
	class PpStatusChanger implements Runnable
	{
		private int newText = 0;
		private Color newColor = Color.BLACK;
		public PpStatusChanger(int t, Color c)
		{
			newText = t; newColor = c;
		}
		public void run()
		{
			setStatus(newText, newColor, true);
		}
	}
	
	/**
	 * Change directory label.
	 *
	 */
	class DirectoryChanger implements Runnable
	{
		String newDirectory;
		public DirectoryChanger(String s)
		{
			newDirectory = s;
		}
		public void run()
		{
			lDir.setText(newDirectory);
			if(stDir.mustPackAgain(lDir)) {
				pack();
			}
			lDir.repaint();
		}
	}
	
	/**
	 * Transfer handler for drop operations.
	 *
	 */
	class DropHandler extends OneDirectoryDropTransferHandler
	{
		protected boolean processFilename(String s)
		{
			boolean back = false;
			File f = new File(s);
			if(f.isDirectory()) {
				getTc().setCwd(s);
				getTc().writeCwd();
				back = true; 
				SwingUtilities.invokeLater(new DirectoryChanger(s));
			}
			return back;
		}
	}
	
	/**
	 * Show the log window.
	 *
	 */
	class LogWindowShower implements Runnable
	{
		private LogContents lc = null;
		public void run()
		{
			getLogWindow().setVisible(false);
			// getLogWindow().chooseNonmodalPosition(this);
			positionLogWindow();
			getLogWindow().showTextIfNecessary(lc);
		}
		public LogWindowShower(LogContents l)
		{
			lc = l;
		}
	}
	
	/**
	 * Retrieve options.
	 *
	 */
	class OptionRetriever implements Runnable
	{
		public void run()
		{
			setStatus(11, myR, false);
			LogContentsForCommand lcfc = getTc().restoreOptions();
			setRunning(false);
			setStatus(6, myG, false);
			if(!(lcfc.getSuccess())) {
				SwingUtilities.invokeLater(new LogWindowShower(lcfc));
			}
		}
		public OptionRetriever()
		{
		}
	}
	
	/**
	 * Save options.
	 *
	 */
	class OptionSaver implements Runnable
	{
		public void run()
		{
			setStatus(12, myR, false);
			LogContentsForCommand lcfc = getTc().saveOptions();
			setRunning(false);
			setStatus(6, myG, false);
			if(!(lcfc.getSuccess())) {
				SwingUtilities.invokeLater(new LogWindowShower(lcfc));
			}
		}
		public OptionSaver()
		{
			
		}
	}
	
	/**
	 * Run png2pdf.
	 *
	 */
	class ProgramRunner implements Runnable
	{
		public void run()
		{
			setStatus(7, myR, false);
			LogContentsForCommand lcfc = getTc().runTheProgram();
			setRunning(false);
			setStatus(6, myG, false);
			if(!(lcfc.getSuccess())) {
				SwingUtilities.invokeLater(new LogWindowShower(lcfc));
			}
		}
		public ProgramRunner() 
		{
			
		}
	}
	
	class ControllerStatusChanger implements StatusChanger
	{
		class MyRunner implements Runnable
		{
			String myText = null;
			public void run()
			{
				lSta.setText(myText);
				if(stSta.mustPackAgain(lSta)) {
					pack();
				}
				lSta.repaint();
			}
			public MyRunner(String s)
			{
				myText = s;
			}
		}
		public void setStatus(String s)
		{
			SwingUtilities.invokeLater(new MyRunner(s));
		}
	}
	
	/**
	 * DropHandler instance.
	 */
	protected DropHandler dh = null;
	
	/**
	 * Get the dialog to set png2pdf options. Create new dialog
	 * if necessary.
	 * 
	 * @param p
	 * The parent frame.
	 * 
	 * @param g
	 * A GuiController providing the border settings.
	 * 
	 * @param tc
	 * The Png2PdfController to set up.
	 * 
	 * @return
	 * The png2pdf options dialog.
	 */
	protected synchronized Png2PdfDialog internalGetTod()
	{
		return tod;
	}
	
	protected synchronized void internalSetTod(Png2PdfDialog d)
	{
		tod = d;
	}
	
	/**
	 * Get the dialog to set png2pdf options. Create new dialog
	 * if necessary.
	 */
	protected  Png2PdfDialog getTod()
	{
		Png2PdfController tc = getTc();
		Png2PdfDialog back = internalGetTod();
		if(back == null) {
			back = new Png2PdfDialog(this, getGuic(), tc, this);
			internalSetTod(back);
			// back.chooseNonmodalPosition(this);
		}
		return back;
	}
	
	/**
	 * Mark existing png2pdf options dialog as not longer being used.
	 *
	 */
	protected synchronized void resetTod()
	{
		tod = null;
	}
	
	/**
	 * Check whether or not there already is a png2pdf options dialog.
	 * 
	 * @return
	 * The test result.
	 */
	protected synchronized boolean haveTod()
	{
		boolean back = false;
		if(tod != null) {
			back = true;
		}
		return back;
	}
	
	/**
	 * Get the png2pdf controller.
	 * 
	 * @return
	 * The controller.
	 */
	protected synchronized Png2PdfController getTc()
	{
		if(tc == null) {
			tc = new Png2PdfController();
		}
		return tc;
	}
	
	/**
	 * Get the log window.
	 * 
	 * @return
	 * The log window.
	 */
	protected synchronized LogWindow internalGetLogWindow() { return lw; }
	
	/**
	 * Set the log window.
	 * 
	 * @param l
	 * The log window.
	 */
	protected synchronized void internalSetLogWindow(LogWindow l) { lw = l; }
	
	/**
	 * Get the log window.
	 * 
	 * @return
	 * The log window.
	 */
	protected LogWindow getLogWindow()
	{
		LogWindow back = internalGetLogWindow();
		if(back == null) {
			back = new LogWindow(this, getGuic());
			internalSetLogWindow(back);
			// back.chooseNonmodalPosition(this);
		}
		return back;
	}
	
	/**
	 * Mark the log window as not longer being used.
	 *
	 */
	protected synchronized void resetLogWindow()
	{
		lw = null;
	}
	
	/**
	 * Check whether or not we already have a log window.
	 * 
	 * @return
	 * The test result.
	 */
	protected synchronized boolean haveLogWindow()
	{
		boolean back = false;
		if(lw != null) back = true;
		return back;
	}
	
	/**
	 * Get the help window.
	 * 
	 * @return
	 * The help window.
	 */
	protected synchronized HelpWindow internalGetHelpWindow() { return hw; }
	
	/**
	 * Set the help window.
	 * 
	 * @param h
	 * The help window.
	 */
	protected synchronized void internalSetHelpWindow(HelpWindow h) { hw = h; }
	
	/**
	 * Get the help window.
	 * 
	 * @return
	 * The help window.
	 */
	protected HelpWindow getHelpWindow()
	{
		HelpWindow back = internalGetHelpWindow();
		if(back == null) {
			back = new HelpWindow(this, getGuic());
			// back.chooseNonmodalPosition(this);
			internalSetHelpWindow(back);
		}
		return back;
	}
	
	/**
	 * Mark the help window as not longer being used.
	 *
	 */
	protected synchronized void resetHelpWindow()
	{
		hw = null;
	}
	
	/**
	 * Check whether or not there already is a help window.
	 * 
	 * @return
	 * The test result.
	 */
	protected synchronized boolean haveHelpWindow()
	{
		boolean back = false;
		if(hw != null) back = true;
		return back;
	}
	
	/**
	 * Set a new status.
	 * 
	 * @param t
	 * The index of the text in the theTexts array.
	 * 
	 * @param c
	 * The color to use.
	 * 
	 * @param fromAwtThread
	 * Flag indicating whether or not we are in the
	 * AWT/event thread.
	 */
	protected void setStatus(int t, Color c, boolean fromAwtThread)
	{
		if(fromAwtThread) {
			lSta.setText(theTexts[t]);
			lSta.setForeground(c);
			lSta.repaint();
		} else {
			SwingUtilities.invokeLater(new PpStatusChanger(t, c));
		}
	}
	
	/**
	 * Set up the menu bar.
	 */
	protected void setupMenuBar()
	{
		JMenuBar mb = new JMenuBar();
		JMenu m1 = new JMenu(theTexts[1]);
		mb.add(m1);
		miDir = new JMenuItem(actionCmd[1]);
		miDir.addActionListener(this);
		miDir.setToolTipText(toolTipTexts[0]);
		m1.add(miDir);
		miOpt = new JMenuItem(actionCmd[2]);
		miOpt.addActionListener(this);
		miOpt.setToolTipText(toolTipTexts[1]);
		m1.add(miOpt);
		miRun = new JMenuItem(actionCmd[3]);
		miRun.addActionListener(this);
		miRun.setToolTipText(toolTipTexts[2]);
		m1.add(miRun);
		miExit = new JMenuItem(actionCmd[4]);
		miExit.addActionListener(this);
		miExit.setToolTipText(toolTipTexts[3]);
		m1.add(miExit);
		
		JMenu m2 = new JMenu(theTexts[2]);
		miGui = new JMenuItem(actionCmd[0]);
		miGui.addActionListener(this);
		miGui.setToolTipText(toolTipTexts[4]);
		m2.add(miGui);
		miPck = new JMenuItem(actionCmd[8]);
		miPck.addActionListener(this);
		miPck.setToolTipText(toolTipTexts[5]);
		m2.add(miPck);
		mb.add(m2);
		JMenu m3 = new JMenu(theTexts[13]);
		miHlp = new JMenuItem(actionCmd[7]);
		miHlp.addActionListener(this);
		m3.add(miHlp);
		miLic = new JMenuItem(actionCmd[6]);
		miLic.addActionListener(this);
		m3.add(miLic);
		mb.add(Box.createHorizontalGlue());
		mb.add(m3);
		setJMenuBar(mb);
	}
	
	/**
	 * Set up the button bar.
	 * 
	 * @return
	 * The new button bar.
	 */
	protected JToolBar setupButtonBar()
	{
		JToolBar back = new JToolBar();
		bDir = new JButton(findImageForName(iconFileNames[0]));
		bDir.setActionCommand(actionCmd[1]);
		bDir.addActionListener(this);
		bDir.setToolTipText(toolTipTexts[0]);
		bOpt = new JButton(findImageForName(iconFileNames[1]));
		bOpt.setActionCommand(actionCmd[2]);
		bOpt.addActionListener(this);
		bOpt.setToolTipText(toolTipTexts[1]);
		bRun = new JButton(findImageForName(iconFileNames[2]));
		bRun.setActionCommand(actionCmd[3]);
		bRun.addActionListener(this);
		bRun.setToolTipText(toolTipTexts[2]);
		bExit = new JButton(findImageForName(iconFileNames[3]));
		bExit.setActionCommand(actionCmd[4]);
		bExit.addActionListener(this);
		bExit.setToolTipText(toolTipTexts[3]);
		back.add(bDir);
		back.add(bOpt);
		back.add(bRun);
		back.add(bExit);
		return back;
	}
	
	/**
	 * Create the inner panel (real window panel).
	 * 
	 * @return
	 * The new panel.
	 */
	protected JPanel createInnerPanel()
	{
		JPanel back = new JPanel();
		int b = getGuic().getBorder();
		GridBagLayout gbl = new GridBagLayout();
		back.setLayout(gbl);
		GbcMaker gbcm = new GbcMaker(5, 4, b);
		GridBagConstraints gbc = null;
		JLabel l = null;
		JPanel d = null;
		d = gbcm.createDummyPanel();
		gbc = gbcm.createDummyGbc(0, 0, 1, 1);
		gbl.setConstraints(d, gbc);
		back.add(d);
		l = new JLabel(theTexts[3]);
		gbc = gbcm.create(1, 1, 1, 2);
		gbl.setConstraints(l, gbc);
		back.add(l);
		l = new JLabel(theTexts[4]);
		l.setHorizontalAlignment(JLabel.RIGHT);
		gbc = gbcm.create(2, 1, 1, 1);
		gbc.anchor = GridBagConstraints.EAST;
		gbl.setConstraints(l, gbc);
		back.add(l);
		lDir = new JLabel(tc.getCwd());
		gbc = gbcm.create(2, 2, 1, 1);
		gbc.anchor = GridBagConstraints.WEST;
		lDir.setHorizontalAlignment(JLabel.LEFT);
		gbl.setConstraints(lDir, gbc);
		back.add(lDir);
		l = new JLabel(theTexts[5]);
		l.setHorizontalAlignment(JLabel.RIGHT);
		gbc = gbcm.create(3, 1, 1, 1);
		gbc.anchor = GridBagConstraints.EAST;
		gbl.setConstraints(l, gbc);
		back.add(l);
		lSta = new JLabel(theTexts[6]);
		gbc = gbcm.create(3, 2, 1, 1);
		gbc.anchor = GridBagConstraints.WEST;
		lSta.setHorizontalAlignment(JLabel.LEFT);
		gbl.setConstraints(lSta, gbc);
		lSta.setForeground(myG);
		back.add(lSta);
		d = gbcm.createDummyPanel();
		gbc = gbcm.createDummyGbc(4, 3, 1, 1);
		gbl.setConstraints(d, gbc);
		back.add(d);
		return back;
	}
	
	/**
	 * Constructor.
	 * 
	 * @param c
	 * A GuiController providing the border setting.
	 * 
	 * @param t
	 * A controller for png2pdf options.
	 */
	public Png2PdfWindow(GuiController c, Png2PdfController t)
	{
		super(Png2PdfGUI.appName, c);
		setTitle(theTexts[0]);
		tc = t;
		myR = new Color(128, 0, 0);
		myG = new Color(0, 128, 0);
		Container cp = getContentPane();
		cp.setLayout(new BorderLayout());
		setupMenuBar();
		JPanel ip;
		cp.add(setupButtonBar(), BorderLayout.PAGE_START);
		ip = createInnerPanel();
		cp.add(ip, BorderLayout.CENTER);
		pack();
		restorePosition();
		// setResizable(false);
		dh = new DropHandler();
		ip.setTransferHandler(dh);
		stDir = new SizeTracker();
		stDir.mustPackAgain(lDir);
		stSta = new SizeTracker();
		stSta.mustPackAgain(lSta);
		csc = new ControllerStatusChanger();
		t.setStatusChanger(csc);
	}
	
	/**
	 * Cleanup procedure.
	 */
	public void cleanup(boolean isLast)
	{
		if(isLast) {
			// guic.writeProperties(false);
			if(haveGuid()) {
				GuiDialog g = getGuid();
				g.cleanup(); g.dispose(); g = null;
			}
			if(haveHelpWindow()) {
				HelpWindow h = getHelpWindow();
				h.cleanup(); h.dispose(); h = null;
			}
			if(haveLogWindow()) {
				LogWindow l = getLogWindow();
				l.cleanup(); l.dispose(); l = null;
			}
			if(haveTod()) {
				Png2PdfDialog t = getTod();
				t.cleanup(); t.dispose(); t = null;
			}
		}
		if(haveGuid()) {
			resetGuid();
		}
		if(haveHelpWindow()) {
			resetHelpWindow();
		}
		if(haveLogWindow()) {
			resetLogWindow();
		}
		if(haveTod()) {
			resetTod();
		}
		miDir.removeActionListener(this); miDir = null;
		miOpt.removeActionListener(this); miOpt = null;
		miRun.removeActionListener(this); miRun = null;
		miExit.removeActionListener(this); miExit = null;
		miGui.removeActionListener(this); miGui = null;
		miPck.removeActionListener(this); miPck = null;
		bDir.removeActionListener(this); bDir = null;
		bOpt.removeActionListener(this); bOpt = null;
		bRun.removeActionListener(this); bRun = null;
		bExit.removeActionListener(this); bExit = null;
		tc.setStatusChanger(null); csc = null;
		tc = null;
	}
	
	/**
	 * Check whether or not there already is a GUI options dialog.
	 * 
	 * @return
	 * The test result.
	 */
	protected synchronized boolean haveGuid()
	{
		boolean back = false;
		if(guid != null) { back = true; }
		return back;
	}
	
	/**
	 * Synchronized request for GUI dialog.
	 * 
	 * @return
	 * Reference to current GUI dialog (may be null).
	 */
	protected synchronized GuiDialog internalGetGuid() { return guid; }
	
	/**
	 * Synchronized set GUI dialog.
	 * 
	 * @param d
	 * The new GUI dialog.
	 */
	protected synchronized void internalSetGuid(GuiDialog d) { guid = d; }
	
	/**
	 * Get the GUI options dialog.
	 * 
	 * @return
	 * The GUI options dialog.
	 */
	protected GuiDialog getGuid()
	{
		GuiDialog back = internalGetGuid();
		if(back == null) {
			back = new GuiDialog(this,  getGuic());
			internalSetGuid(back);
			// guid.chooseNonmodalPosition(this);
		}
		return back;
	}
	
	/**
	 * Mark the current GUI options dialog as not longer being used.
	 *
	 */
	protected synchronized void resetGuid()
	{
		guid = null;
	}
	
	/**
	 * Show the GUI options dialog.
	 *
	 */
	protected void showGuiSetupDialog()
	{
		getGuid().controller_to_dialog();
		getGuid().setVisible(true);
	}
	
	/**
	 * Check whether or not a background task is running.
	 * 
	 * @return
	 * The test result.
	 */
	protected synchronized boolean getRunning()
	{
		return isRunning;
	}
	
	/**
	 * Set the flag to indicate whether or not a background
	 * task is running.
	 * 
	 * @param b
	 * The new flag value.
	 */
	protected synchronized void setRunning(boolean b)
	{
		isRunning = b;
	}
	
	/**
	 * Search for an icon image.
	 * 
	 * @param n
	 * The file name.
	 * 
	 * @return
	 * The icon image or null.
	 */
	protected ImageIcon findImageForName(String n)
	{
		ImageIcon back = null;
		try {
			back = new ImageIcon(getClass().getResource(n));
		}
		catch(NullPointerException e) {
			back = new ImageIcon(n);
		}
		return back;
	}
	
	/**
	 * Choose a new directory for png2pdf.
	 *
	 */
	protected void chooseDirectory()
	{
		String workingDirectory;
		JFileChooser c = new JFileChooser(getTc().getCwd());
		c.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		c.setFileFilter(new DirectoryFilter());
		int result = c.showOpenDialog(this);
		if(result == JFileChooser.APPROVE_OPTION) {
			workingDirectory = c.getSelectedFile().getAbsolutePath();
			lDir.setText(workingDirectory);
			if(stDir.mustPackAgain(lDir)) {
				pack();
			}
			repaint();
			getTc().setCwd(workingDirectory);
			getTc().writeCwd();
		}
	}
	
	/**
	 * Retrieve default settings.
	 *
	 */
	public void retrieveDefaults()
	{
		Thread thr = new Thread(new OptionRetriever());
		setRunning(true);
		thr.start();
	}
	
	/**
	 * Save default settings.
	 *
	 */
	public void saveDefaults()
	{
		Thread thr = new Thread(new OptionSaver());
		setRunning(true);
		thr.start();
	}
	
	/**
	 * Run png2pdf.
	 *
	 */
	public void runProgram()
	{
		Thread thr = new Thread(new ProgramRunner());
		setRunning(true);
		thr.start();
	}
	
	public void positionLogWindow()
	{
		getLogWindow().chooseNonmodalPosition(this);
	}
	
	
	/**
	 * Reaction on mouseclicks
	 * 
	 */
	public void actionPerformed(ActionEvent e)
	{
		switch(StringTool.getArrayIndex(actionCmd, e.getActionCommand())) {
		case 0: {
			showGuiSetupDialog();
		} break;
		case 1: {	// directory
			if(!getRunning()) {
				chooseDirectory();
			}
		} break;
		case 2: {	// options
			if(!getRunning()) {
				getTod().chooseNonmodalPosition(this);
				getTod().controller_to_dialog();
				getTod().correct_dialog();
				getTod().setVisible(true);
			}
		} break;
		case 3: {	// run
			if(!getRunning()) {
				setRunning(true);
				runProgram();
			}
		} break;
		case 4: {	// exit
			if(!getRunning()) {
				WindowEvent we = new WindowEvent(
					this,
					WindowEvent.WINDOW_CLOSING
				);
				processWindowEvent(we);
			}
		} break;
		case 5: {	// save options
			getTc().writeCwd();
			if(!getRunning()) {
				setRunning(true);
				saveDefaults();
			}
		} break;
		case 6: {	// license terms
			getHelpWindow().chooseNonmodalPosition(this);
			getHelpWindow().setVisible(false);
			getHelpWindow().setPurpose(2);
			getHelpWindow().setContentType(1);
			getHelpWindow().setText(licenseTerms);
			getHelpWindow().setVisible(true);
		} break;
		case 7: {	// help
			URL helpUrl;
			getHelpWindow().chooseNonmodalPosition(this);
			getHelpWindow().setVisible(false);
			getHelpWindow().setPurpose(1);
			getHelpWindow().setContentType(0);
			getHelpWindow().setText(LogWindow.theTexts[1]);
			
			getHelpWindow().setContentType(1);
			helpUrl = Png2PdfGUI.class.getResource(helpFileName);
			if(helpUrl != null) {
				try {
					getHelpWindow().setPage(helpUrl);
				}
				catch(IOException ioe) {
					getHelpWindow().setText(LogWindow.theTexts[1]);
				}
			} else {
			}
			getHelpWindow().setVisible(true);
		} break;
		case 8: {
			pack(); repaint();
		} break;
		}
	}	

	/**
	 * Let the controller retrieve the settings from
	 * png2pdf -C
	 *
	 */
	public void retrievePng2pdfSettings()
	{
		retrieveDefaults();
	}
}
