/*
 * Created on 02.12.2003 14:01:39
 *
 * Multimediale Algorithmen und Datenstrukturen Assessments
 */
package mauda;

import mauda.operation.*;
import mauda.undoredo.UndoRedoInfo;
import java.util.*;

/**
 * Detects and sets the modified-state of the exercise by listening to exercise-changes.
 * 
 * @author Markus Krebs
 */
public class ModifiedDetector implements ExerciseUpdateListener {
	
	private Exercise exercise;
	
	private UndoRedoInfo undoRedoInfo;
	
	private Vector operations;
	private int position = -1;
	private int minPosition = 0;	// untere Abgrenzung für Undo
	
	/**
	 * Creates a ModifiedDetector
	 */
	public ModifiedDetector(Exercise ex) {
		this.exercise = ex;
		undoRedoInfo = new UndoRedoInfo();
		operations = new Vector();
	}
	
	/* (non-Javadoc)
	 * @see mauda.ExerciseUpdateListener#exerciseUpdate(mauda.ExerciseUpdateEvent)
	 */
	public void exerciseUpdate(ExerciseUpdateEvent e) {
		//System.out.println("OperationRecorder.exerciseUpdate(..): "+e);
		if(e.getID() == ExerciseUpdateEvent.BACK) back();
		else if(e.getID() == ExerciseUpdateEvent.FORWARD) forward();
		else if(e.getID() == ExerciseUpdateEvent.UNDO) undo();
		else if(e.getID() == ExerciseUpdateEvent.REDO) redo();
		else if(e.getID() == ExerciseUpdateEvent.OPERATION_EXECUTED) {
			add(e.getOperation());
		} else if(e.getID() == ExerciseUpdateEvent.RESET) {
			clear();
		} else if(e.getID() == ExerciseUpdateEvent.CLEAR_PRECEDING) {
			clearPreceding();
		} else if(e.getID() == ExerciseUpdateEvent.CLEAR_FOLLOWING) {
			clearFollowing();
		} else if(e.getID() == ExerciseUpdateEvent.JUMP) {
			position += e.getValue();
		} else if(e.getID() == ExerciseUpdateEvent.FULL_LOADED) {
			exercise.setModified(false);
		}
	}
		
	/**
	 * Adds an operation to the recorded operations. Normally this method is
	 * called, when an operation was executed in the 
	 * <code>JedasPanel</code>
	 * @param obj The executed operation
	 */
	// Aktuelle Operation vermerken
	private void add(Object obj) {
		SimpleOperation op = (SimpleOperation)obj;
		// Testen ob gleiche Operation gemacht wird
		// siehe auch UndoRedo
		if(op!=null&&position<operations.size()-1) {
			Object o = operations.elementAt(position+1);
			if(o!=null && o instanceof SimpleOperation) {
				SimpleOperation undoRedoOp = (SimpleOperation)o;
				if(undoRedoOp.equals(op)) {
					position++;
					return;
				}
			} 
		}		
		// Undo-Information:
		position++;
		Object o = null;
		if(op!=null) o = op.clone();
		undoRedoInfo.storeChange(position, operations, o);
		//while (operations.size() > position)
		//	operations.removeElementAt(position);
		//operations.add(o);
		//System.out.println("ModifiedDetector.add(..): setting modified to TRUE (op="+op+")");
		exercise.setModified(true);
	}
	/**
	 * Clears all entries
	 */
	private void clear() {
		if(operations.size()>1) exercise.setModified(true);
		minPosition = 0;
		position = 0;
		operations.removeAllElements();
		operations.add(null);
	}
	private void clearPreceding() {
		if(operations.size()>1) exercise.setModified(true);
		position = 0;
		Object o = operations.lastElement();
		operations.removeAllElements();
		operations.add(null);
		minPosition = 0;
		Vector newv = new Vector();
		newv.add(null);
		undoRedoInfo.clear(newv);
	}
	private void clearFollowing() {
		if(operations.size() > position+1) exercise.setModified(true);
		undoRedoInfo.clearFollowing(position+1, operations);
		//while (operations.size() > position+1)
		//	operations.removeElementAt(position+1);		
	}
	// UNDO
	private void back() {
		if (position <= minPosition)
			return;
		position--;
	}
	// REDO
	private void forward() {
		if (position >= operations.size() - 1)
			return;
		position++;
	}
	protected void undo() {
		undoRedoInfo.undo(operations);
	}
	protected void redo() {
		undoRedoInfo.redo(operations);
	}
}
