/*
 * Created on 26.02.2004 17:53:38
 *
 * Multimediale Algorithmen und Datenstrukturen Assessments
 */
package mauda.feedback.types;

import mauda.*;
import mauda.feedback.FeedbackExercise;
import mauda.feedback.FeedbackObject;
import mauda.feedback.SimpleFeedback;
import mauda.operation.*;
import mauda.feedback.select.*;

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

/**
 * Provides the logic for <i>Feedback on demand</i>
 * 
 * @author Markus Krebs
 */
public class DemandFeedback extends SimpleFeedback implements ActionListener {
	
	private static final int type = FeedbackSelector.DEMAND_FEEDBACK;

	private static final String specialGetNext = "Get next ...";
	private static final String specialFinishEx = "Finish ...";

	protected static final String requestFeedback = "Request ...";
			
	/**
	 * The ActionCommand for the TreeOperationView context-menu, to
	 * request feedback
	 */
	public static final String requestMenuItem = "Request Feedback";

	/**
	 * Creates a DemandFeedback
	 * @param exercise FeedbackExercise
	 */
	public DemandFeedback(FeedbackExercise exercise) {
		super(exercise);
		specialState = specialGetNext;
				
		exercise.getFeedbackPanel().showDemandButton();
		setDemandButtonText(requestFeedback);
		setDemandEnabled(false);
		//demandButton.setText(requestFeedback);
	}
	
	protected void jumpEvent(int delta) {
		super.jumpEvent(delta);
		updateBackForwardButtons();
		//System.out.println("IF&EC: opDelta = "+opCounter);
		//System.out.println("       todoPosition = "+todoPosition);
		String msg = "";
		if(counter>=0) {
			OperationRecorder or = exercise.getOperationRecorder();
			SimpleOperation so = (SimpleOperation)or.getCurrentOperation();
			msg = feedbackGenerator.genMessage(
							"information.gif",
							"<b>Jump</b> to "+so.out());
			exercise.setInteractiveMode(Exercise.SUBOPERATION);
		} else {
			msg = feedbackGenerator.genMessage(
							"information.gif",
							"<b>Jump</b> to beginning");			
			exercise.setInteractiveMode(Exercise.NOPOPUP);
		}
		displayMessage("FEEDBACK", msg); 
		if(todoPosition==todoOperationQueue.length()-1) {
			setSpecialButtonText(specialFinishEx);
			specialState = specialFinishEx;
		} else {
			setSpecialButtonText(specialGetNext);
			specialState = specialGetNext;
		}
		//System.out.println("todoPosition = "+todoPosition);
		updateTaskMessage(); 
	}
	
	protected void specialPressed() {
		//super.specialPressed();
		String msg = null;
		// EXERCISE-START
		if(specialState == specialGetNext) { // || specialState == specialFinishOp) {
			if(todoPosition>=0) {
				checkForFailure();
				// Fehler nur loggen, wenn MISSING_SUBOP
				FeedbackObject fo = (FeedbackObject)firstFailureFeedbackObjects.elementAt(todoPosition);
				if(fo!=null && fo.getCorrectness() == FeedbackObject.INCORRECT_MISSING)
					evaluator.log(currentFeedbackObject);
			} 
			exercise.getTreeOperationView().enableJumping();
			//todoPosition++;	// wird bei interactiveEvent erledigt
			//counter++;		// dito
			Operation op = (Operation)todoOperationQueue.get(todoPosition+1).clone();
			op.setExecution(false);
			msg = feedbackGenerator.genMessage(
						"explanation.gif",
						"Perform the SubOperations for:");
			msg +=	"<ul><li><b>"+op.out()+"</b></li></ul>"+
					"by pressing the right mouse button in the drawing-area, and selecting the correct suboperation."+
					"<br><br>";
			if(todoPosition+1==todoOperationQueue.length()-1) {
				msg += "When you have finished all suboperations, please click the <b><i>"+specialFinishEx+"</i></b> button to complete the exercise.";
				setSpecialButtonText(specialFinishEx);
				specialState = specialFinishEx;
			} else {
				msg += "When you have finished all suboperations, please click the <b><i>"+specialGetNext+"</i></b> button.";
				setSpecialButtonText(specialGetNext);
				//specialState = specialFinishOp;
			}
			displayMessage("FEEDBACK", msg);
			exercise.commit(op);	// <-- löst OPERATION_EXECUTED aus --> interactiveEvent
			exercise.setInteractiveMode(Exercise.SUBOPERATION);
			// -> WAIT_FOR_FIRST
			return;
		} else if(specialState == specialFinishEx) {
			if(todoPosition>=0) {
				checkForFailure();
				// Fehler nur loggen, wenn MISSING_SUBOP
				FeedbackObject fo = (FeedbackObject)firstFailureFeedbackObjects.elementAt(todoPosition);
				if(fo!=null && fo.getCorrectness() == FeedbackObject.INCORRECT_MISSING)
				evaluator.log(currentFeedbackObject);
			} 
			finishedExercise();
			return;			
		}
	}
	protected void forwardPressed() { exercise.forward(); }
	protected void backPressed() {
		exercise.back();
	}
	
	// =========================================================================
	protected void forwardEvent() {
		counter++;
		super.forwardEvent();
		updateBackForwardButtons();
		FeedbackObject fo = callKB();
		Object o = exercise.getOperationRecorder().getCurrentOperation();
		if(o instanceof Operation) {
			todoPosition++;
			if(todoPosition == todoOperationQueue.length()-1) {
				setSpecialButtonText(specialFinishEx);
				specialState = specialFinishEx;
			}
		} 
		String msg = feedbackGenerator.genMessage(
				"information.gif",
				"<b>Forward</b> "+((SimpleOperation)o).out());
		displayMessage("FEEDBACK", msg);
	}
	
	// =========================================================================
	protected void backEvent() {
		counter--;
		String msg;
		super.backEvent();
		updateBackForwardButtons();
		FeedbackObject fo = callKB();
		Object o = exercise.getOperationRecorder().getNextOperation();
		if(o instanceof Operation) {
			todoPosition--;
			if(todoPosition<todoOperationQueue.length()-1) {
				setSpecialButtonText(specialGetNext);
				specialState = specialGetNext;
			}
		} 
		msg = feedbackGenerator.genMessage(
				"information.gif",
				"<b>Back</b> "+((SimpleOperation)o).out());
		displayMessage("FEEDBACK", msg);
	}
	
	// =========================================================================
	protected void interactiveEvent() {
		Object o = exercise.getOperationRecorder().getCurrentOperation();

		// Erhöhung des counters wird bereits bei specialPressed
		// erledigt.
		if(o instanceof Operation) {
			todoPosition++;
			updateTaskMessage();
			updateBackForwardButtons();
			return;
		} 
		
		updateBackForwardButtons();
		
		String msg = feedbackGenerator.genMessage(
				"information.gif",
				"<b>Execute</b> "+((SimpleOperation)o).out());
		displayMessage("FEEDBACK", msg);
		
		if(differentOperation) {
			cutFirstFailureFeedbackObjects();
			checkForFailure();
		}
	}
	
	// =========================================================================

	protected void finishedLoading() {
		super.finishedLoading();
		String msg = genOpToPerformMessage();		
		msg += getFeedbackDescription();
		msg += "<br>";
		msg += "To perform the first operation, please click the <b><i>'"+specialGetNext+"'</i></b> button below.";
		displayMessage("TASK", msg);
		
		setSpecialButtonText(specialGetNext);
		setSpecialEnabled(true);
		setDemandEnabled(true);
	}
	protected String getFeedbackDescription() {
		return "You will get feedback only on demand.";
	}
	
	protected void linkClicked(String href) {
		super.linkClicked(href);
	}
	protected void demandPressed() {
		//super.demandPressed();
		if(counter<0) return;
		//String msg = null;
		//System.out.println("linkClicked: demand");
		exercise.getTreeOperationView().markCorrectness(true, true);
		OperationRecorder or = exercise.getOperationRecorder();
		SimpleOperation so = (SimpleOperation)or.getCurrentOperation();
		requestFeedback(counter);
	}
	// Feedback für ON_OPERATION anzeigen
	private void requestFeedbackOnOperation(int opnr) {
		String msgadd = null;
		FeedbackObject fo = null;
		if(firstFailureFeedbackObjects.size()>opnr)
			fo = (FeedbackObject)firstFailureFeedbackObjects.elementAt(opnr);
		if(fo!=null) {
			// Aktuelle Operation enthält Fehler
			fo.setMessagePosition(-1);
			currentFeedbackObject = fo;
			// Falls in vorherigen Fehler, dann Message anzeigen
			if(checkBefore(opnr)) msgadd = "There are errors in previous operations!";
		} else {
			if(opnr == 0) {
				// Wir befinden uns auf der 1. Operation, und ...
				Operation op = todoOperationQueue.get(opnr);
				if(counter<=0) {
					// ... haben sonst noch keine Teil-Operationen ausgeführt!
					String msg = feedbackGenerator.genMessage(
							"information.gif",
							"Start of exercise"); 
					displayMessage("FEEDBACK", msg);
				} else {
					// ... haben Operationen ausgeführt aber keine Fehler gemacht
					String msg = feedbackGenerator.genMessage(
							"correct_v.gif",
							"<b>Correct</b>",
							null,
							"No Failure in <i>"+op.out()+"</i>");
					displayMessage("FEEDBACK", msg);
				}
				return;
			} 
			// Wenn in aktueller kein Fehler ist, dann das vorherige prüfen
			fo = (FeedbackObject)firstFailureFeedbackObjects.elementAt(opnr-1);
			if(fo!=null) {
				// im vorherigen war ein Fehler => Anzeigen
				fo.setMessagePosition(-1);	// damit immer erste angezeigt wird
				currentFeedbackObject = fo;
				if(checkBefore(opnr-1))
					msgadd = "There are errors in previous operations!";
			} else {
				Operation op = todoOperationQueue.get(opnr-1);
				String msg = feedbackGenerator.genMessage(
						"correct_v.gif",
						"<b>Correct</b>",
						null,
						"No Failure in <i>"+op.out()+"</i>");
				if(checkBefore(opnr-1)) {
					// Falls Fehler in vor-vorhergehenden Operationen
					msg += "<br>But there are errors in previous operations!";
				} 
				displayMessage("FEEDBACK", msg);
				return;
			}
		}
		currentFeedbackObject.setLocationShow(true);
		String msg = currentFeedbackObject.getNextMessage();
		if(msgadd!=null) msg += "<br>"+msgadd;
		displayMessage("FEEDBACK", msg);
	}
	// Testen ob vor opnr ein Fehler existiert
	// dann TRUE zurückgeben
	private boolean checkBefore(int opnr) {
		for(int i=0; i<opnr; i++) {
			FeedbackObject fo = (FeedbackObject)firstFailureFeedbackObjects.elementAt(i);
			if(fo != null) return true;
		}
		return false;
	}
	/**
	 * Listener for MenuItem in TreeOperationView.
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 * @see mauda.feedback.types.DemandFeedback#requestMenuItem
	 */
	public void actionPerformed(ActionEvent e) {
		if(e.getActionCommand() == requestMenuItem) {
			if(finishedExercise) return;
			int index = exercise.getTreeOperationView().getActionIndex();
			requestFeedback(index);
		}
	}
	// Aufruf aus TreeOperationView
	protected void requestFeedback(int index) {
		if(index<0 || index>=feedbackObjects.size()) return;
		exercise.getTreeOperationView().markCorrectness(false, true);
		FeedbackObject fo = (FeedbackObject)feedbackObjects.elementAt(index);
		if(fo.getSubOpNr()<0) {
			// bei ON_OPERATION
			requestFeedbackOnOperation(fo.getOpNr());
			return;
		}
		String msgadd = null;
		if(checkBefore(fo.getOpNr())) msgadd = "There are errors in previous operations!";
		fo.setMessagePosition(-1);
		currentFeedbackObject = fo;
		String msg = fo.getNextMessage();
		if(msgadd!=null) msg += "<br>"+msgadd;
		displayMessage("FEEDBACK", msg);
		/*
		if(fo.getCorrectness() == FeedbackObject.CORRECT)
			exercise.getTreeOperationView().markAsCorrect(index);
		else
			exercise.getTreeOperationView().markAsIncorrect(index);
		*/
	}
	
	
	/* (non-Javadoc)
	 * @see mauda.feedback.SimpleFeedback#getFeedbackTypeID()
	 */
	public int getFeedbackTypeID() { return type; }
	
	/* (non-Javadoc)
	 * @see mauda.feedback.SimpleFeedback#save()
	 */
	public HashMap save() {
		HashMap hm = super.save();
		//hm.put("demandPosition", new Integer(demandPosition));
		return hm;
	}
	/* (non-Javadoc)
	 * @see mauda.feedback.SimpleFeedback#load(java.util.HashMap)
	 */
	public void load(HashMap hm) {
		super.load(hm);
		//demandPosition = ((Integer)hm.get("demandPosition")).intValue();
	}
}
