/*
 * Created on 09.02.2004 21:55:06
 *
 * Multimediale Algorithmen und Datenstrukturen Assessments
 */
package work;

import mauda.*;
import mauda.operation.*;
import mauda.feedback.*;
import mauda.feedback.select.*;
import mauda.feedback.types.*;
import mauda.utils.*;

import generation.AutoGenerator;
import help.HelpFrame;
import help.HelpTree;
import jedas.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import java.io.*;
import java.beans.*;
import java.awt.*;

/**
 * The listener for menu- and toolbar-actions
 * 
 * @author Markus Krebs
 */
public class MenuToolBarListener implements ActionListener {

	private FeedbackExercise exercise;

	private Vector editTabs;

	private JFileChooser fileChooser;
	private PreviewPanel previewPanel = new PreviewPanel();
	
	private PlugInSelector plugInSelector;
	private DifficultySelector difficultySelector;
	private ModeSelector modeSelector;
	private FeedbackSelector feedbackSelector;
	
	/**
	 * Creates a listener for menu and toolbars
	 * @param exercise FeedbackExercise
	 */
	public MenuToolBarListener(FeedbackExercise exercise) {
		this.exercise = exercise;
		
		plugInSelector = new PlugInSelector(exercise.getPlugInHandler());
		difficultySelector = new DifficultySelector();
		modeSelector = new ModeSelector();		
		feedbackSelector = new FeedbackSelector();
		
		fileChooser = new JFileChooser(FileLocation.unworkedPath);
		fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
		fileChooser.addChoosableFileFilter(new XMLFilter());
		fileChooser.setMultiSelectionEnabled(false); // Mehrfachselektion AUS
		fileChooser.setAccessory(previewPanel);
		fileChooser.addPropertyChangeListener(new PropertyChangeListener() {
			public void propertyChange(PropertyChangeEvent e) {
				if(e.getPropertyName().equals(
									 JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
					File f = (File)e.getNewValue();
					if(f==null) return;
					String s = f.getPath(), suffix = null;
					int i = s.lastIndexOf('.');

					if(i > 0 && i < s.length() - 1)
						suffix = s.substring(i+1).toLowerCase();

					if(suffix!=null&&suffix.equals("xml"))
						previewPanel.configure(f);
				}
			}
		});
	}

	/*public void setEditTabs(Vector et) {
		this.editTabs = et;
	}*/
	
	/* (non-Javadoc)
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	public void actionPerformed(ActionEvent e) {
		if(!exercise.actionsAllowed()) return;
		String s = e.getActionCommand();
		//System.out.println("ActionCommand: "+s);
		if(s == ActionCommands.newFile) {
			MetaData.setDisplayMode(MetaData.CREATOR);
			fileChooser.setCurrentDirectory(new File(FileLocation.unworkedPath));
			openFile();
			MetaData.setDisplayMode(MetaData.EDITOR);
			// Filename auf default setzen, damit bei save nicht
			// die Aufgabe überspielt wird!!!
			exercise.setFilename(exercise.getDefaultFilename());
		} else if(s == ActionCommands.newAutoFile) {
			openAutoGeneratorFile();
		} else if(s == ActionCommands.openFile) {
			MetaData.setDisplayMode(MetaData.EDITOR);
			fileChooser.setCurrentDirectory(new File(FileLocation.inProcessPath));
			openFile();
		} else if(s == ActionCommands.saveFile) {
			if(!exerciseLoaded()) return;
			SimpleFeedback actFeedback = exercise.getFeedback();
			if(actFeedback.exerciseFinished()) return;
			saveFile(exercise.getFilename());
		} else if(s == ActionCommands.saveAsFile) {
			if(!exerciseLoaded()) return;
			SimpleFeedback actFeedback = exercise.getFeedback();
			if(actFeedback.exerciseFinished()) return;
			fileChooser.setCurrentDirectory(new File(FileLocation.inProcessPath));
			saveAsFile();
		} else if(s == ActionCommands.meta) {
			if(!exerciseLoaded()) return;
			boolean mod = exercise.getMetaData().inputDialog();
			if(mod) exercise.setModified(true);
		} else if(s == ActionCommands.exit) {
			if(dialogDiscardActiveExercise()) System.exit(0);
		} else if(s == ActionCommands.reloadKB) {
			exercise.getFeedback().getFeedbackGenerator().loadKB();
		} else if(s == ActionCommands.switchFeedback) {
			if(!exerciseLoaded()) return;
			SimpleFeedback actFeedback = exercise.getFeedback();
			if(actFeedback.exerciseFinished()) return;
			if(actFeedback instanceof FaultFeedback) {
				JOptionPane.showMessageDialog(MAUDA.getApplicationMainFrame(), "No Feedback-Switching for Fault-Mode-Exercises possible");
				return;
			}
			int actFeedbackType = feedbackSelector.getFeedbackType();
			if(actFeedbackType == FeedbackSelector.CHOOSE) {
				JOptionPane.showMessageDialog(MAUDA.getApplicationMainFrame(), "No exercise loaded!\n\n=> No Feedback-Type change possible!");
				return;
			}
			int feedbackType = showFeedbackSelector();
			//System.out.println(feedbackType+" ?= "+actFeedbackType);
			//if(feedbackType == actFeedbackType) return;	// kein anderes Feedback ausgewählt => nichts tun
			SimpleFeedback feedback = createFeedback(feedbackType);
			exercise.setFeedback(feedback);
			actFeedback.switchTo(feedback, true);
		} else if(s == ActionCommands.undo) {
			SimpleFeedback actFeedback = exercise.getFeedback();
			if(actFeedback.getFeedbackTypeID() == FeedbackSelector.FAULT_FEEDBACK) return;
			else if(actFeedback.exerciseFinished()) return;
			exercise.undo();
		} else if(s == ActionCommands.redo) {
			SimpleFeedback actFeedback = exercise.getFeedback();
			if(actFeedback.getFeedbackTypeID() == FeedbackSelector.FAULT_FEEDBACK) return;
			else if(actFeedback.exerciseFinished()) return;
			exercise.redo();
		} else if(s == ActionCommands.showAbout) {
			AboutFrame.createAndShowGUI();
		} else if(s == ActionCommands.showHelp) {
			HelpTree.setView(HelpTree.WORKEDITOR_VIEW);
			HelpFrame.createAndShowGUI();
		}
	}
	// Checkt ob bereits eine Aufgabe geladen wurde
	// Abfrage über ToDos des aktuellen Feedbacks
	private boolean exerciseLoaded() {
		if(exercise.getFeedback().getTodoOperationQueue() == null) {
			// Es wurde noch keine Aufgabe geladen
			JOptionPane.showMessageDialog(MAUDA.getApplicationMainFrame(), "Please load a exercise!");
			return false;
		}		
		return true;
	}
	// NEW FILE
	private boolean newFile() {
		if(!dialogDiscardActiveExercise()) return false;
		exercise.reset();
		Jedas.updateDisplay();
		exercise.setDefaultFilename();
		updateFilenameLabel();
		return true;
	}
	private void openAutoGeneratorFile() {
		if(!dialogDiscardActiveExercise()) return;
		// Einstellen der Parameter über Dialog
		JPanel p = new JPanel();
		GridBagLayout gbl = new GridBagLayout();
		GridBagConstraints c = new GridBagConstraints();
		p.setLayout(gbl);
		c.fill = GridBagConstraints.BOTH;
		c.anchor = GridBagConstraints.NORTHWEST;
		c.insets = new Insets(2,2,2,2);
		c.gridx = 0;
		c.gridy = 0;
		c.gridwidth = 1;
		c.gridheight = 1;

		c.gridwidth = 4;
		JLabel label = new JLabel("Please specify what kind of exercise you want to generate!"); 		
		p.add(label);
		gbl.setConstraints(label, c);
		c.gridwidth = 1;
		c.gridy = 1;

		p.add(plugInSelector);
		gbl.setConstraints(plugInSelector, c);

		c.gridx = 1;
		p.add(difficultySelector);
		gbl.setConstraints(difficultySelector, c);

		c.gridx = 2;
		p.add(modeSelector);
		gbl.setConstraints(modeSelector, c);

		c.gridx = 3;
		p.add(feedbackSelector);
		gbl.setConstraints(feedbackSelector, c);

		int result = JOptionPane.showConfirmDialog(MAUDA.getApplicationMainFrame(), p, "Select Properties", JOptionPane.OK_CANCEL_OPTION);
		if(result != JOptionPane.OK_OPTION) return;

		String type = plugInSelector.getPlugInName();
		String diff = Difficulties.getString(difficultySelector.getDifficulty());
		String mode = ExerciseMode.getString(modeSelector.getMode());
		int feedbackType = feedbackSelector.getFeedbackType();
		
		//System.out.println(type+" "+diff+" "+mode);
		
		// Jetzt Aufgabe generieren
		AutoGenerator ag = 
			new AutoGenerator(type, diff, mode, false);
		HashMap hm = ag.getExercise();
		boolean ok = exercise.loadConfig(hm);
		if(!ok) return;
		exercise.reset();
		exercise.removeExerciseUpdateListener(exercise.getFeedback());
		exercise.loadConfig(hm);
		openExercise(hm, feedbackType);
	}
	// OPEN FILE
	private void openFile() {
		if(!dialogDiscardActiveExercise()) return;
		int state = fileChooser.showOpenDialog(null);
		if(state == JFileChooser.APPROVE_OPTION) {
			File file = fileChooser.getSelectedFile();
			if(file.isFile()) {
				exercise.reset();
				exercise.removeExerciseUpdateListener(exercise.getFeedback());
				
				openFile(file);				
			}
		}
	}
	
	private void openFile(File file) {
		Vector opVector = null;
		
		exercise.setFilename(file.getAbsolutePath());
		
		HashMap hm = exercise.load(exercise.getFilename());
		// loadConfig bereits in exercise.load ausgeführt
		
		boolean ok = openExercise(hm, FeedbackSelector.CHOOSE);
	}
	
	// Aufgabe laden per HashMap. Der Editor muss zuvor aber durch
	// exercise.loadConfig konfiguriert werden
	// 2. Übergabe: FeedbackSelector.?
	private boolean openExercise(HashMap hm, int feedbackType) {
		
		if(hm==null) return false;	// <-- Sollte nie vorkommen (falls PlugIn nicht existiert)

		String editorState = exercise.getMetaData().getEditorState();
		
		if(editorState.equals("unworked")) {
			exercise.load(hm);			
		} else if(editorState.equals("in process")) {
			((mauda.feedback.FeedbackExercise)exercise).loadWork(hm);
			return true;
		} else {
			JOptionPane.showMessageDialog(MAUDA.getApplicationMainFrame(), "Cant load a completed exercise.");
			return true;
		}
			
		OperationRecorder or = exercise.getOperationRecorder();

		// ToDo-SubOperationen einzeln ausführen =======
		// So etwas unschön implementiert, aber es tuts
		Vector initOps = or.getInitOperationQueue().toVector();
		Vector todoOps = or.getTodoOperationQueue().toVector();

		Enumeration en = todoOps.elements();
		while(en.hasMoreElements()) {
			SimpleOperation so = (SimpleOperation)en.nextElement();
			if(so instanceof Operation) {
				Operation o = (Operation)so;
				if(o.isExecuted()) o.setExecution(false);
			}
		}
		
		// Folgendes wird benötigt, damit im OperationRecorder
		// die Datenstruktur auf die neuen Templates angepasst
		// wird. Ansonsten würden auf die Templates keine SubOps
		// ausgeführt werden.
		or.clear();
		or.addOperations(initOps);
		or.goInTodoMode();
		or.addOperations(todoOps);
		
		// Einstellen des Feedbacks
		MetaData metaData = exercise.getMetaData();
		int mode = metaData.getMode();
		SimpleFeedback feedback = null;		
		if(mode == ExerciseMode.NORMAL) {
			FeedbackSelector fbs;
			if(feedbackType == FeedbackSelector.CHOOSE)
				feedbackType = showFeedbackSelector();
			feedback = createFeedback(feedbackType);
			feedback.setInitOperationQueue(or.getInitOperationQueue());
			feedback.setTodoOperationQueue(or.getTodoOperationQueue());
		} else if(mode == ExerciseMode.FAULT){
			feedback = new FaultFeedback(exercise);
			feedback.setInitOperationQueue(or.getInitOperationQueue());
			feedback.setTodoOperationQueue(or.getTodoOperationQueue());
		} else {
			JOptionPane.showMessageDialog(MAUDA.getApplicationMainFrame(), "Unknown mode!");
			return false;
		}

		metaData.setEditorName("<Please enter your name!>");
		metaData.actualizeEditorDate();
		metaData.setEditorFeedback(FeedbackSelector.getFeedbackTypeNameFromID(feedback.getFeedbackTypeID()));
		metaData.setEditorState("in process");
		exercise.addExerciseUpdateListener(feedback);
		exercise.setFeedback(feedback);
		
		feedback.displayLoadingMessage();

		// Jetzt InitOps ausführen
		Vector exOps = new Vector();

		exOps.add(new ExerciseUpdateEvent(exercise, ExerciseUpdateEvent.DSOBJECT_HIDE));
		exOps.addAll((Vector)or.getInitOperations().clone());

		ExerciseUpdateEvent eue = new ExerciseUpdateEvent(exercise, ExerciseUpdateEvent.SPECIAL);
		eue.setMessage("GO_IN_TODO-MODE");
		exOps.add(eue);

		// Event für das Löschen der Init-Operationen
		exOps.add(new ExerciseUpdateEvent(exercise,ExerciseUpdateEvent.CLEAR_PRECEDING));
		exOps.add(new ExerciseUpdateEvent(exercise,ExerciseUpdateEvent.DSOBJECT_SHOW));
		exOps.add(new ExerciseUpdateEvent(exercise,ExerciseUpdateEvent.FINISHED_LOADING));

		exOps = exercise.addFullLoadedMessage(exOps);

		//System.out.println("EXOPS: "+exOps);

		exercise.getUndoRedo().clear();
		exercise.setDSObject(exercise.getUndoRedo().getDSObject());
		or.clear();

		// Jetzt Init-Operations ausführen
		exercise.commit(exOps);
		
		return true;
	}
	// Auswahl eines Feedback-Typen
	protected int showFeedbackSelector() {
		JPanel p = new JPanel();
		p.setLayout(new BorderLayout(0,10));
		JLabel label = new JLabel("Please select a Feedback-Type ...");
		p.add(label, BorderLayout.NORTH);
		p.add(feedbackSelector, BorderLayout.CENTER);
		JOptionPane.showMessageDialog(MAUDA.getApplicationMainFrame(), p);
		//feedbackSelector.showDialog();
		return feedbackSelector.getFeedbackType();		
	}
	private SimpleFeedback createFeedback(int feedbackType) {
		SimpleFeedback feedback = null;
		switch(feedbackType) {
			case FeedbackSelector.IFAEC :
				feedback = new ImmediateFeedbackAndErrorCorrection(exercise);
				break;
			case FeedbackSelector.ERROR_FLAGGING :
				feedback = new ErrorFlagging(exercise);
				break;
			case FeedbackSelector.DEMAND_FEEDBACK :
				feedback = new DemandFeedback(exercise);
				break;
			case FeedbackSelector.NO_TUTOR :
				feedback = new NoTutor(exercise);
				break;				
		}		
		return feedback;
	}
	// SAVE FILE
	private void saveFile(String fname) {
		if(fname.equals(exercise.getDefaultFilename())) {
			JOptionPane.showMessageDialog(MAUDA.getApplicationMainFrame(), Prop.get(this, "DialogChooseSaveAs"));
			return;
		}
		exercise.getMetaData().inputDialog();
		exercise.saveWork(fname);
		exercise.setFilename(fname);
		updateFilenameLabel();			
	}
	// SAVE AS FILE
	private void saveAsFile() {
		int state = fileChooser.showSaveDialog(null);
		if(state == JFileChooser.APPROVE_OPTION) {
			File file = fileChooser.getSelectedFile();
			if(file!=null) {
				String fname = file.getAbsolutePath();
				if(file.exists()&&!dialogExistsOverwrite(fname)) {
					JOptionPane.showMessageDialog(MAUDA.getApplicationMainFrame(), Prop.get(this,"FileNotSaved"));
					return;
				}
				if(!fname.toLowerCase().endsWith(".xml")) {
					fname = fname + ".xml";
				}
				exercise.getMetaData().inputDialog();
				exercise.saveWork(fname);
				exercise.setFilename(fname);
				updateFilenameLabel();
			}
		}
	}
	private void updateFilenameLabel() {
		/*
		String fn = filename.replace('\\','/');
		fn = fn.substring(fn.lastIndexOf("/")+1);
		filenameLabel.setText(fn);
		*/
	}

	// Datei überschreiben? - Dialog
	private boolean dialogExistsOverwrite(String filename) {
		String s = Prop.get(this,"DialogExistsOverwrite");
		s = s.replaceAll("FILENAME", filename);
		int result = JOptionPane.showConfirmDialog(MAUDA.getApplicationMainFrame(), s, Prop.get(this,"DialogExistsOverwriteTitle"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
		if(result == JOptionPane.YES_OPTION) { return true; }
		//else if(result == JOptionPane.NO_OPTION) { return false; }
		//else if(result == JOptionPane.CANCEL_OPTION) { return false; }
		return false;
	}
	// Aktive Aufgabe verwerfen? - Dialog
	private boolean dialogDiscardActiveExercise() {
		if(!exercise.isModified()) return true;
		String s = Prop.get(this,"DialogDiscardActiveExercise");
		int result = JOptionPane.showConfirmDialog(MAUDA.getApplicationMainFrame(), s, Prop.get(this,"DialogDiscardActiveExerciseTitle"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
		if(result == JOptionPane.YES_OPTION) { return true; }
		//else if(result == JOptionPane.NO_OPTION) { return false; }
		//else if(result == JOptionPane.CANCEL_OPTION) { return false; }
		return false;		
	}

}
