import java.awt.*;
import java.io.*;
import java.util.*;
import java.awt.event.*;

/**
* core class for JPE, works like a hub to all the handlers that do
* most of the work. Also can be started as a java application because
* it implements the main interface.
*/
public class JPE extends Object {

	// Vector that holds the loadable program parts
	private Vector handlers=new Vector();

	// Text handler, loadable part that handles the edit window	
	private TextHandler texthandler;

	// Titlebar handler, loadable part that handles the input/output in
	// the title bar
	private TitleBarHandler titlebarhandler;

	// Config handler, loads/maintains/stores the settings of JPE
	private ConfigHandler confighandler;


	// Menu bar of this application
	private MenuBar bar;

	// If we get a System.exit() this boolean is checked if its a wanted
	// exit by the Security Manager
	public boolean wantexit=false;

	// New Classloader (unused in this release) 
	private static JPEClassloader loader;

	// JPE homedir as detected by classpath
	private String jpehome;

	/**
	* Main JPE constructor starts JPE, all the handler and reads
	* the config.xml. Can be created by a other class or from the 
	* commandline by the Main method.
	*/
	public JPE()	{

		// setup the new security manager
		try	{	
			SecManager sm = new SecManager(this);
			System.setSecurityManager(sm);
		} catch (SecurityException se)	{
			System.out.println("JPE -> SecurityManager already loaded");
		}

		// create the config handler (read condig.xml)		
		confighandler=new ConfigHandler(this);

		// startup the needed Handler (will change in future release)
		handlers.addElement(new FileHandler(this));
		handlers.addElement(new EditHandler(this));
		handlers.addElement(new LogHandler(this));
		handlers.addElement(new ExtraHandler(this));

		// create the menu bar of JPE
		bar = new MenuBar();

		// create all the menu's (done by the handlers)
		createMenus(bar);

		// create the titlebar handler
		titlebarhandler = new TitleBarHandler(this);

		// create the edit window and init it.
		texthandler = new TextHandler(bar,this);
		texthandler.init();

		// read if we had opened files in the last run of JPE if we did
		// then restart them again.
		Vector vec=getProperties("openfile");
		if (vec!=null) {

			// we had opened file so start the openfile handler
			OpenFileHandler ofh=(OpenFileHandler)getHandler("Opened");	
			if (ofh==null) {
				// add the openfile handler to the menu
				ofh=(OpenFileHandler)addHandler(new OpenFileHandler(this));
				getMenuBar().add(ofh.createMenu());
			}

			// now we have the handler open the files
			ofh.openFiles();

			// was one of the files active in the editor ?
			String selfile=getProperty("setup","selectedfile");
			if (selfile!=null) {
				// yes then lets make it active again.
				ofh.switchOpenFile(selfile);
			}
		}

	}

	/**
	* main method needed to start the application
	*/
	public static void main(String[] args)
	{
		// create a instance of JPE to start the app
		JPE p = new JPE();	
	}

	/**
	* create all the needed menu's by calling on al the handlers who
	* will add their menu's to the menu bar.
	*/
	private void createMenus(MenuBar bar) {
		// Enum all the handles
		for (Enumeration e = handlers.elements();e.hasMoreElements();) {
			// get next one and cast to its core interface
			handlerInterface h=(handlerInterface)e.nextElement();

			// call the handler to add its menu to the menubar
			bar.add(h.createMenu());
		}
	}

	/**
	* return the text handler
	*/
	public TextHandler getTextHandler() {
		return(texthandler);
	}

	/**
	* return the config handler
	*/
	public ConfigHandler getConfigHandler() {
		return(confighandler);
	}

	/**
	* return the requested handler
	*/
	public handlerInterface getHandler(String name) {
		// search and return the handler not really a nice way
		// needs to be a hash or something
		for (Enumeration e = handlers.elements();e.hasMoreElements();) {
			handlerInterface h=(handlerInterface)e.nextElement();
			if (h.getName().equals(name)) {
				return(h);
			}
		}
		return(null);
	}

	/**
	* add a new Handler to the application, the must follow the
	* handler interface to be accepted
	*/
	public handlerInterface addHandler(handlerInterface handler) {
		// add it to the list of running handlers
		handlers.addElement(handler);
		// return the handler again, caller might wanne use it
		return(handler);
	}

	/**
	* return the active menu bar
	*/
	public MenuBar getMenuBar() {
		return(bar);
	}

	/**
	* the say commands allows the different parts to give feedback
	* to the user. This call reroutes to the handler that implements
	* it at the moment. no param means display what the app thinks
	* is best to display at this time.
	*/
	public void say() {
		// at the moment hardwired to titlebar handler so give it to
		// that handler
		titlebarhandler.say();
	}

	/**
	* the say commands allows the different parts to give feedback
	* to the user. This call reroutes to the handler that implements
	* it at the moment. 
	*/
	public void say(String msg) {
		// at the moment hardwired to titlebar handler so give it to
		// that handler
		titlebarhandler.say(msg);
	}

	/**
	* get a property from the config handler defined by its
	* nodename and key. Allways returns the value as a string.
	*/
	public String getProperty(String nodename,String key) {
		if (confighandler!=null) {
			// reroute this call to the current config hander
			return(confighandler.getProperty(nodename,key));
		}
		return(null);
	}

	/**
	* store a property in the defined node by its given key, replaces
	* the value if it was allready defined.
	*/
	public void putProperty(String nodename,String key,String value) {
		if (confighandler!=null) {
			// reroute this call to the loaded config handler
			confighandler.putProperty(nodename,key,value);
		}
	}

	/**
	* get a properties vector from the config handler defined by its
	* nodename. Allways returns the a vector with hashtables with
	* keys/values.
	*/
	public Vector getProperties(String nodename) {
		if (confighandler!=null) {
			return(confighandler.getProperties(nodename));
		}
		return(null);
	}


	public boolean getAskMode() {
		return(texthandler.getAskMode());
	}

	public void setAskMode(AskInterface askCaller,String command,String usermsg) {
		texthandler.setAskMode(askCaller,command,usermsg,false);
	}

	public void setAskMode(AskInterface askCaller,String command,String usermsg,boolean oneshot) {
		texthandler.setAskMode(askCaller,command,usermsg,oneshot);
	}

	/**
	* store a properties Vector, replaces the whole vector if it was
	* allready defined by its nodename so make sure you have merged
	* the nodes yourself if needed !
	*/
	public void putProperties(String nodename,Vector values) {
		if (confighandler!=null) {
			confighandler.putProperties(nodename,values);
		}
	}

	/**
	* return the file path to JPE itself, should be defined in env. variable
	* home.jpe and defaults to c:\JPE
	*/
	public String getMyPath() {
		if (jpehome!=null) return (jpehome);

		// get defined path
		String cp=System.getProperty("java.class.path");
		StringTokenizer tok=new StringTokenizer(cp,";\n\r");
	
		while (tok.hasMoreTokens()) {
			String tmp=tok.nextToken();
		
			if (tmp.indexOf('?')==-1 && tmp.indexOf(".jar")==-1) {
				try {
					File file=new File(tmp+"\\JPE.class");
					if (file.isFile()) {
						jpehome=tmp;
						return(tmp);
					}
					file=new File(tmp+"\\JPE.jar");
					if (file.isFile()) {
						jpehome=tmp;
						return(tmp);
					}
				} catch(Exception e) {}
			} else if (tmp.indexOf('?')==-1 && tmp.indexOf("JPE.jar")!=-1) {
				try {
					tmp=tmp.substring(0,tmp.length()-7);
					File file=new File(tmp+"\\JPE.class");
					if (file.isFile()) {
						jpehome=tmp;
						return(tmp);
					}
				} catch(Exception e) {}
			}
		}
		// keep this in just so people can still set it if they really want
		String tmp=System.getProperty("jpe.home");
		if (tmp!=null && !tmp.equals("")) {
			// path defined so return it
			return(tmp);
		} 
		// path not defined so return default, should never happen
		return("C:\\system\\apps\\jpe");
	}

	public void setCompileState(boolean state) {
		titlebarhandler.setCompileState(state);
	}

	public void setSaveState(boolean state) {
		titlebarhandler.setSaveState(state);
	}

	public void setLockState(boolean state) {
		titlebarhandler.setLockState(state);
		texthandler.setEditable(!state);
	}

}
