/*
 * Created on 26.10.2004 14:52:20
 *
 * Multimediale Algorithmen und Datenstrukturen Assessments
 */
package mauda.undoredo;

import java.util.Vector;
/**
 * Stores several UndoRedoUnits in an undo/redo-vector. Therefore this class can hold the
 * whole undo/redo-information for specific objects like operations, fibheaps, etc.
 * 
 * @author Markus Krebs
 */
public class UndoRedoInfo {
	
	public boolean DEBUG = false;
	
	private int position;
	private Vector units;
	
	/**
	 * Creates a new UndoRedoInfo.
	 */
	public UndoRedoInfo() {
		position = -1;
		units = new Vector();
	}
	
	/**
	 * Performs a change on the vector.
	 * @param p The position of the change
	 * @param v The vector to perform the change on
	 * @param newObject The object to append.
	 */
	public void storeChange(int p, Vector v, Object newObject) {
		UndoRedoUnit uru = new UndoRedoUnit();
		UndoRedoElement ure;
		for(int i=v.size()-1; i>=p; i--) {
			//while (v.size() > p) {
			Object o = v.elementAt(i);
			ure = new UndoRedoElement(i,o,UndoRedoElement.DELETE);
			uru.addElement(ure);
			v.removeElementAt(i);
		}
		ure = new UndoRedoElement(p,newObject,UndoRedoElement.APPEND);
		uru.addElement(ure);
		v.add(newObject);
		addUnit(uru);
		if(DEBUG) {
			System.out.println("UndoRedoInfo.storeChange(..): LOGGED: (units.size()="+units.size()+")");
			System.out.println(uru);
		}
	}
	/**
	 * Adds an UndoRedoUnit to the undo/redo-vector
	 * @param uru A UndoRedoUnit
	 */
	public void addUnit(UndoRedoUnit uru) {
		units.add(uru);
		position = units.size()-1;
		//position++;
	}
	
	/**
	 * Undos this unit
	 * @param v The object-vector
	 * @return The performed UndoRedoUnit
	 */
	public UndoRedoUnit undo(Vector v) {
		if(DEBUG) System.out.println("UndoRedoInfo.undo(..): position="+position);
		UndoRedoUnit uru = (UndoRedoUnit)units.elementAt(position);
		position--;
		uru = uru.invert();
		//if(DEBUG) System.out.println("UndoRedoInfo.undo(..): position="+position+"\n"+uru);
		uru.perform(v);
		units.add(uru);	// nicht addUnit verwenden!
		return uru;
	}
	/**
	 * Redos this unit
	 * @param v The object-vector
	 * @return The performed UndoRedoUnit
	 */
	public UndoRedoUnit redo(Vector v) {
		if(DEBUG) System.out.println("UndoRedoInfo.redo(..): position="+position);
		boolean addUnit = true;
		if(position!=units.size()-1) {
			addUnit = false;
			units.removeElementAt(units.size()-1);
			//units.remove(units.lastElement());
		}
		position++;
		UndoRedoUnit uru = (UndoRedoUnit)units.elementAt(position);
		//if(DEBUG) System.out.println("UndoRedoInfo.redo(..): position="+position+"\n"+uru);
		uru.perform(v);
		if(addUnit) units.add(uru);	// nicht addUnit verwenden!
		return uru;
	}
	/**
	 * Returns the maximum possible position after an undo.
	 * @return maximum possible position
	 */
	public int getUndoJumpPosition() {
		UndoRedoUnit uru = (UndoRedoUnit)units.elementAt(position);
		UndoRedoUnit uru2 = uru.invert();
		return uru2.getMaxAppendPos();
	}
	/**
	 * Returns the maximum possible position after a redo
	 * @return maximum possible position
	 */
	public int getRedoJumpPosition() {
		UndoRedoUnit uru = (UndoRedoUnit)units.elementAt(position+1);
		return uru.getMaxAppendPos()+1;
	}
	/**
	 * Checks if an undo is possible
	 * @return true if undo is possible, false otherwise
	 */
	public boolean canUndo() {
		//System.out.println("UndoRedoInfo.canUndo(): = "+(units.size()>0&&position>0&&units.elementAt(position)!=null));
		return units.size()>0&&position>0&&units.elementAt(position)!=null;
	}
	/**
	 * Checks if a redo is possible
	 * @return true if redo is possible, false otherwise
	 */
	public boolean canRedo() {
		return position+1<units.size();
	}
	
	// fill gibt an wieviel und was am anfang aufgefüllt werden soll
	/**
	 * Clears the object-vector, and adds fill to it.
	 * @param fill the new object-vector
	 */
	public void clear(Vector fill) {
		position=-1+fill.size();
		units.removeAllElements();
		for(int i=0; i<fill.size(); i++) {
			if(fill.elementAt(i) != null) {
				UndoRedoUnit uru = new UndoRedoUnit();
				uru.addElement(new UndoRedoElement(i, fill.elementAt(i), UndoRedoElement.APPEND));
				units.add(uru);
			} else units.add(null);
		}
	}
	/**
	 * Removes all following objects from the object-vector after the position p
	 * @param p clear-position
	 * @param v the object-vector
	 */
	public void clearFollowing(int p, Vector v) {
		UndoRedoUnit uru = new UndoRedoUnit();
		UndoRedoElement ure;
		for(int i=v.size()-1; i>=p; i--) {
		//while (v.size() > p) {
			Object o = v.elementAt(i);
			ure = new UndoRedoElement(i,o,UndoRedoElement.DELETE);
			uru.addElement(ure);
			v.removeElementAt(i);
		}
		addUnit(uru);
		//while (v.size() > p)
		//	v.removeElementAt(p);				
	}
	/*
	// Wird nicht benötigt, da dieses Event nur im WorkEditor verwendet wird und dort die
	// Datenstrukturen unter Anderem auch durch finishedLoading gesteuert (beschnitten)
	// werden.
	public void clearPreceding(Vector v, Vector newv) {
		// Alles aus v löschen, und dann newv anhängen (Elemente entsprechend generieren)
		UndoRedoUnit uru = new UndoRedoUnit();
		UndoRedoElement ure;
		while (v.size() > 0) {
			Object o = v.elementAt(p);
			ure = new UndoRedoElement(p,o,UndoRedoElement.DELETE);
			uru.addElement(ure);
			v.removeElementAt(p);
		}
		addUnit(uru);
	}*/
}
