/*
 * Created on 05.01.2004 17:47:48
 *
 * Multimediale Algorithmen und Datenstrukturen Assessments
 */
package mauda.plugin;

import mauda.Exercise;
import mauda.SimpleExercise;
import mauda.operation.*;

import jedas.*;
import java.io.*;
import java.util.*;
import java.awt.event.MouseListener;
/**
 * Loads all Plug-in-specific parameters and classes.<br>
 * - setting the data-directory<br>
 * - generates an empty data-structure<br>
 * - loads a class that implements Analysable<br>
 * - loads a class that extends OperationExecuter<br>
 * - loads suboperation-ratings<br>
 * - prepares the interacive access to the data-structure<br>
 * - inserts available operations for access<br>
 * 
 * @author Markus Krebs
 */
public class PlugInHandler {
	private static java.util.Properties piprop;	// PlugIn-Properties
	
	// TRUE = Status ausgeben
	private boolean print = false;
	
	private boolean isGUI = false;
	
	private String type = null;
	
	private Scheduler scheduler;
	private SimpleExercise exercise;
	
	private String[] availablePlugIns;
	
	/**
	 * Creates a PlugInHandler
	 * @param exercise SimpleExercise
	 */
	public PlugInHandler(SimpleExercise exercise) {
		if(exercise instanceof Exercise) isGUI = true;
		else isGUI = false;
		
		scheduler = null;
		if(isGUI) scheduler = Exercise.scheduler;
		//this.compPanel = exercise.compPanel;
		this.exercise = exercise;
		
		piprop = new java.util.Properties();
		try {
			// Im Nachfolgenden: Irgendeine Klasse in mauda.plugin angeben
			// --> Habe GeneralAnalyst gewählt
			Class c = Class.forName("mauda.plugin.GeneralAnalyst");
			InputStream is = c.getResourceAsStream("plugin-properties");
			piprop.load(is);

		} catch(Exception ex) {
			System.err.println("Error while loading PlugIn-Properties!");
			ex.printStackTrace();
			System.exit(0); 
		}
		
		// Verfügbare Plug-Ins ausgeben
		StringTokenizer st = new StringTokenizer((String)piprop.get("AvailablePlugIns"));
		int size = st.countTokens();
		availablePlugIns = new String[size];
		if(print) System.out.println("Available Plug-Ins:");
		int i = 0;
		while(st.hasMoreTokens()) {
			availablePlugIns[i] = st.nextToken();
			if(print) System.out.println("  - "+availablePlugIns[i]);
			i++;
		}
	}
	/**
	 * Gets a list of the available Plug-In-IDs
	 * @return Array of Plug-In-IDs
	 */
	// Rückgabe: Liste der PlugInNamen (IDs!)
	// z.B.: FibHeap, BinQueue
	public String[] getAvailablePlugIns() {
		return availablePlugIns;
	}
	/**
	 * Converts a PlugIn-ID into a PlugIn-Name.
	 * E.g.: Fibonacci-Heap => FibHeap
	 * @param name plug-in-ID
	 * @return plug-in-name
	 */
	// Rückgabe: Zu einem ID den gehörigen PlugInNamen
	// z.B.:	Fibonacci-Heap -> FibHeap
	//			Binomial-Queue -> BinQueue
	public String getPlugInID(String name) {
		String[] plugInNames = getAvailablePlugIns();
		for(int i=0; i<plugInNames.length; i++) {
			String found = (String)piprop.get(plugInNames[i]);
			if(found.equals(name)) return plugInNames[i];
		}
		return null;
	}
	/**
	 * Gets the plug-in-name from an plug-in-id from the plug-in-
	 * properies-file
	 * @param id plug-in-ID
	 * @return plug-in-Name
	 */
	public String getPlugInString(String id) {
		return (String)piprop.get(id);
	}
	
	/**
	 * Loads an specific PlugIn
	 * @param type plug-in-name
	 */
	public void load(String type) {
		this.type = type;
		//System.out.println("LOAD PLUG-IN: "+type);
		
		boolean needData = 	!(exercise instanceof mauda.evaluation.PlayerExercise)&&
							!(exercise instanceof mauda.evaluation.EvalExercise);
		
		// Meta-Daten-Type setzen (z.B. Fibonacci-Heap)
		exercise.getMetaData().setType((String)piprop.get(type));		
		// Datenverzeichnis
		if(needData) {
			if(print) System.out.println("  - Datenverzeichnis setzen");
			loadDataDirectory();
		}
		// DSObject laden
		if(print) System.out.println("  - Datenstruktur-Objekt laden");
		loadDSObject();	
		// Analyzer
		if(print) System.out.println("  - Analyzer laden");
		loadAnalyzer();
		// OperationExecuter
		if(print) System.out.println("  - OperationExecuter laden");
		loadOperationExecuter();
		// KBFormulaEvaluator
		if(exercise instanceof Exercise) {
			if(print) System.out.println("  - KBFormulaEvaluator laden");
			loadKBFormulaEvaluator();
		}
		// Mögliche Operationen
		if(print) System.out.println("  - Verfügbare Operationen in Exercise eintragen");
		loadPossibleOperations();		
		// Ratings
		if(needData) {
			if(print) System.out.println("  - Ratings laden");
			loadRatings();
		}
		// PopUp-Menu
		if(isGUI) {
			if(print) System.out.println("  - Interactive laden");
			loadInteractive();				
			// Mode setzen (Default = Operation)
			((Exercise)exercise).setInteractiveMode(Exercise.OPERATION);
		}
		
		// Fertig
		if(print) System.out.println("  --> Plug-In ready.");
	}

	// DATENSTRUKTUR laden --------------------------------
	private void loadDSObject() {
		//Object dsObject = new FibHeapExt(scheduler);
		Object dsObject = null;
		String cname = (String)piprop.get(type+"DS");
		try {
			Class cl = Class.forName(cname);
			Class[] carr = new Class[0];
			//Class[] carr = new Class[1];
			//carr[0] = Class.forName("jedas.Scheduler");
			java.lang.reflect.Constructor con= cl.getConstructor(carr);
			Object[] objs = new Object[0];
			//Object[] objs = new Object[1];
			//objs[0] = scheduler;
			dsObject = con.newInstance(objs);
		} catch(Exception ex) {
			ex.printStackTrace();
			System.exit(0);
		}
		
		exercise.setDSObject(dsObject);
	}
	// ANALYZER laden -------------------------------------
	private void loadAnalyzer() {
		//GeneralAnalyst.setAnalyzer(new FibHeapAnalyse());
		String cname = (String)piprop.get(type+"Analyzer");
		try {
			Class cl = Class.forName(cname);
			GeneralAnalyst.setAnalyzer((Analysable)cl.newInstance());
		} catch(Exception ex) {
			ex.printStackTrace();
			System.exit(0);
		}		
	}
	// OPERATIONEXECUTER laden ----------------------------
	private void loadOperationExecuter() {
		//SimpleExercise.setOperationExecuter(new FibHeapOperationExecuter());
		String cname = (String)piprop.get(type+"OperationExecuter");
		try {
			Class cl = Class.forName(cname);
			SimpleExercise.setOperationExecuter((OperationExecuter)cl.newInstance());
		} catch(Exception ex) {
			ex.printStackTrace();
			System.exit(0);
		}
	}
	// OPERATIONEXECUTER laden ----------------------------
	private void loadKBFormulaEvaluator() {
		//SimpleExercise.setOperationExecuter(new FibHeapOperationExecuter());
		String cname = (String)piprop.get(type+"KBFormulaEvaluator");
		try {
			Class cl = Class.forName(cname);
			Class[] carr = new Class[1];
			carr[0] = Class.forName("mauda.Exercise");
			java.lang.reflect.Constructor con = cl.getConstructor(carr);
			Object[] objs = new Object[1];
			objs[0] = (Exercise)exercise;
			Object kbfe = con.newInstance(objs);
			mauda.feedback.FeedbackGenerator.setKBFormulaEvaluator((KBFormulaEvaluator)kbfe);
		} catch(Exception ex) {
			ex.printStackTrace();
			System.exit(0);
		}
	}
	// RATINGS laden --------------------------------------
	/**
	 * Loads the ratings for the suboperations from a xml-file 
	 */
	public void loadRatings() {
		OperationExecuter oe = SimpleExercise.getOperationExecuter();
		Ratings ratings = oe.getRatings();
		String dataFilename = exercise.getDataDirectory()+"rating.xml";
		Vector v = mauda.XMLFileAccess.load(dataFilename);
		if(v==null) {
			System.out.println("--> rating.xml not exists!");
			Vector aso = exercise.getAvailableSubOperations();
			v = new Vector();
			Enumeration en = aso.elements();
			while(en.hasMoreElements()) {
				SubOperation subop = (SubOperation)en.nextElement();
				v.add(subop.getID()+" 1");
			}
			ratings.load(v);
			Vector savevev = new Vector();
			savevev.add(ratings.save());
			boolean result = mauda.XMLFileAccess.save(dataFilename, savevev);			
			if(!result) {
				System.err.println("Cant create file: '"+dataFilename+"' !\n\n"+
						"--> File not created!");
				System.exit(0);
			}
			System.out.println("--> Automatically generated Rating-File ("+dataFilename+") with each of value 1 from PlugIn-Available-SubOperations.");
			return;
		} 
		ratings.load((Vector)v.firstElement());		
	}
	// POPUP-MENU laden -----------------------------------
	private void loadInteractive() {
		//FibHeapInteractive fhi = new FibHeapInteractive(exercise);
		String cname = (String)piprop.get(type+"PopupMenu");
		try {
			Class cl = Class.forName(cname);
			Class[] carr = new Class[1];
			carr[0] = Class.forName("mauda.Exercise");
			java.lang.reflect.Constructor con = cl.getConstructor(carr);
			Object[] objs = new Object[1];
			objs[0] = (Exercise)exercise;
			Object interactive = con.newInstance(objs);
			if(interactive instanceof MouseListener) {
				Exercise.interactive = (MouseListener)interactive;
			} else {
				System.err.println("Interactive must implement MouseListener!");
				System.exit(0);
			}
		} catch(Exception ex) {
			ex.printStackTrace();
			System.exit(0);
		}
		
	}
	// POSSIBLE OPERATIONS setzen -------------------------
	private void loadPossibleOperations() {
		// für Auswahl-Menus in OpTemplateTab (Add: Radio-Buttons)
		// Operation
		String ops = (String)piprop.get(type+"Operations");
		StringTokenizer st = new StringTokenizer(ops);
		Vector v = new Vector();
		while(st.hasMoreTokens()) {
			String opstr = st.nextToken();
			v.add(new Operation(opstr));
		}
		exercise.setAvailableOperations(v);
		// SubOperation
		ops = (String)piprop.get(type+"SubOperations");
		st = new StringTokenizer(ops);
		v = new Vector();
		while(st.hasMoreTokens()) {
			String opstr = st.nextToken();
			v.add(new SubOperation(opstr));
		}
		exercise.setAvailableSubOperations(v);
	}
	// CONFIG DIRECTORY setzen -----------------------------
	private void loadDataDirectory() {
		String directory = (String)piprop.get(type+"DataDirectory");
		exercise.setDataDirectory(directory);
		// Testen ob es das Verzeichnis gibt, ansonsten erzeugen
		// => Bei weiteren PlugIns werden die Verzeichnisse
		//    automatisch angelegt
		File file = new File(directory);
		if(!file.exists()) {
			System.out.println    ("    - Datenverzeichnis existiert nicht.");
			if(file.mkdirs()) {
				System.out.println("    -> Datenverzeichnis erfolgreich erzeugt.");
			} else {
				System.out.println("    -> Datenverzeichnis konnte nicht angelegt werden!");
				System.out.println("       => Programm-Abbruch.");
				System.exit(0);
			}
			
		}		
	}
}
