// ModuleBrowser v1998.11.2

import java.applet.*;
import java.awt.*;
import java.awt.event.*;      // interface ItemListener(), interface DrawPanel(), interface MouseListener()
import java.util.Vector;      // class Vector()

public class ModuleBrowser extends Applet implements ItemListener {
	int sizew, sizeh;            // max width and height of entire applet
	List list;                   // listbox with choice of modules
	Label title;                 // title of module on top of screen
	TextArea info;               // info about module on bottom of screen
	Applet applet;               // pointer to module applet
	ModuleInterface module;      // pointer to module
	int numberOfModules;         // number of modules (get from parameterlist)
	int numberOfModulesLoaded;   // (how many modules actually found) - 1
	Vector moduleNameList;       // store the names of successfully found modules
	boolean modulesLoaded;       // true if modules are accessed

	public void init() {
		sizew = getSize().width;
		sizeh = getSize().height;

		list = new List();
		list.setBackground(Color.white);
		list.addItemListener(this);

		title = new Label("ModuleBrowser v1998.11.2");
		title.setBackground(Color.lightGray);

		info = new TextArea("", 10, 80, TextArea.SCROLLBARS_VERTICAL_ONLY);
		info.setBackground(Color.white);
		info.setEditable(false);

		applet = new Applet();                 // this is just a dummy, to generalize code
		applet.setBackground(Color.lightGray);

		module = null;
		numberOfModules = java.lang.Integer.parseInt(getParameter("NumberOfModules"));
		numberOfModulesLoaded=-1;
		moduleNameList = new Vector();

		setLayout(new BorderLayout(2,2));      // 2,2 = Gaps between components
		this.setBackground(Color.lightGray);   // Color of applet background

		modulesLoaded = false;

		add("North", title);
		add("East", list);
		add("South", info);
		add("Center", applet);
	}

	public void start() {
		super.start();
		applet.start();
	}

	public void stop() {
		super.stop();
		applet.stop();
	}

	public void destroy() {
		super.destroy();
		applet.destroy();
	}

	public Insets getInsets() { return new Insets(3,3,3,3); }

	public String unknownErrorMessage() { return "This is a strange bug. If you know how to reproduce it, please notify the author: jotro@grm.hia.no\n\n"; }

	public void paint(Graphics g) {
		// draw edge around main applet
		g.setColor(Color.white);
		g.drawLine(0,0,sizew-2,0);
		g.drawLine(0,0,0,sizeh-2);
		g.setColor(Color.black);
		g.drawLine(1,sizeh-1,sizew-1,sizeh-1);
		g.drawLine(sizew-1,1,sizew-1,sizeh-1);

	if (!modulesLoaded) {
			// Add Listnames and write something to info
			String moduleName;
			info.append("HTML claims there are " + numberOfModules + " modules available. Attempting to load:\n");
			for(int n=1; n<=numberOfModules; n++) {
				moduleName = getParameter("NameOfModule"+n);

				// If we use compareTo with a "null" string, we get a NullPointerException. Possibly a bug in Java.
				// Therefore, we will do something else;
				// hope that no one calls their module for nulldummy396430687764
				if ((moduleName + "dummy396430687764").compareTo("nulldummy396430687764") == 0) {
					info.append(moduleName + "... failure; No Class Found! --Maybe the NumberOfModules parameter has the wrong value?,\n                                                  or the NameOfModule parameter has the wrong index?\n");
					continue;
				}

				// Try to load the class
				try { module = (ModuleInterface)Class.forName(moduleName).newInstance(); }
				catch (ClassNotFoundException a) { // Thrown by forName
					info.append(moduleName + "... failure; ClassNotFoundException! --Maybe the module name is misspelled?\n");
					continue;
				}
				catch (IllegalAccessException a) { // Thrown by newInstance
					info.append(moduleName + "... failure; IllegalAccessException!\n");
					info.append(unknownErrorMessage());
					continue;
				}
				catch (InstantiationException a) { // Thrown by newInstance
					info.append(moduleName + "... failure; InstantiationException! --Maybe the module is abstract?\n");
					continue;
				}
				catch (ClassCastException a) { // Thrown by Java itself (java.lang ?). The ModuleInterface cast will not work if the module does not implement ModuleInterface
					info.append(moduleName + "... failure; ClassCastException! --Maybe the module does not implement ModuleInterface?\n");
					continue;
				}

				// if no exception happened, we assume all is okay
				numberOfModulesLoaded++;
				moduleNameList.addElement(moduleName);
				list.addItem(module.getListname());
				info.append(moduleName + "... success\n");
			}
			modulesLoaded = true;
		} // if (!modulesLoaded)
	}

	// Interface ItemListener implementation...
	public void itemStateChanged(ItemEvent e) {
		int choice = list.getSelectedIndex();
		boolean error = false;

		if (choice > -1) { // sometimes choice is -1, WHY?
			// null out text
			title.setText("");
			info.setText("");

			// Try to load the module (this should almost always work, since we have already established which modules work, and which dont)
			try { module = (ModuleInterface)Class.forName((String)moduleNameList.elementAt(choice)).newInstance(); }
			catch (ClassNotFoundException b) { // Thrown by forName
				info.setText(moduleNameList.elementAt(choice) + "... failure; ClassNotFoundException! --What the heck happened to this module? It was here before...\n");
				info.append(unknownErrorMessage());
				error = true;
			}
			catch (IllegalAccessException b) { // Thrown by newInstance
				info.setText(moduleNameList.elementAt(choice) + "... failure; IllegalAccessException! --What the heck happened to this module? It was here before...\n");
				info.append(unknownErrorMessage());
				error = true;
			}
			catch (InstantiationException b) { // Thrown by newInstance
				info.setText(moduleNameList.elementAt(choice) + "... failure; InstantiationException! --What the heck happened to this module? It was here before...\n");
				info.append(unknownErrorMessage());
				error = true;
			}
			catch (ClassCastException b) { // Thrown by Java itself (java.lang ?). The ModuleInterface cast will not work if the module does not implement ModuleInterface
				info.setText(moduleNameList.elementAt(choice) + "... failure; ClassCastException! --What the heck happened to this module? It was here before...\n");
				info.append(unknownErrorMessage());
				error = true;
			}

			if (!error) {
				applet.stop();                    // run active applet.stop()
				applet.destroy();                 // run active applet.destroy()
				remove(applet);                   // Remove active applet from this.applet
				applet = module.getApplet();      // get new applet pointer
				add("Center", applet);            // add new applet to this.applet
				title.setText(module.getTitle()); // update title
				info.setText(module.getInfo());   // update info
				applet.init();                    // run new applet.init()
				applet.start();                   // run new applet.start()
				validate();                       // get this.applet to re-layout its members
			}
		}
	} // itenStateChanged
} // ModuleBrowser

