/*
 * Created on 10.11.2003 20:01:17
 *
 * Multimediale Algorithmen und Datenstrukturen Assessments
 */
package mauda.operation;

import java.util.*;
/**
 * Storage of a base operation (e.g. FibHeap -> decrease-key)
 * with at most 2 parameters.
 * 
 * @author Markus Krebs
 */
public class Operation extends SimpleOperation implements Comparable {

	/**
	 * Identify that a sorting-algorithm should compare operations
	 * by its ratings.
	 * @see mauda.operation.Operation#compareTo(Object)
	 */
	public static final int SORT_BY_RATING = 0;
	/**
	 * Identify that a sorting-algorithm should compare operations
	 * by its IDs
	 * @see mauda.operation.Operation#compareTo(Object)
	 */
	public static final int SORT_BY_NAME = 1;
	
	private static int sortmode = SORT_BY_RATING;

	private int rating;		// Bewertung der Operation
	private int effect;	// für delete-min
	
	private boolean execute = true;
	
	private SubOperationQueue subOperations;

	/**
	 * Creates a Operation
	 */
	public Operation() {
		super(null, NULL, NULL);
		rating = NULL;
		effect = NULL;
		execute = true;
	}

	/**
	 * Creates a operation from the delivered ID
	 * @param id operation-ID
	 */
	public Operation(String id) {
		super(id, NULL, NULL);
		this.rating = NULL;
		this.effect = NULL;
		execute = true;
		subOperations = new SubOperationQueue();
	}
	
	/**
	 * Creates a operation from the delivered parameters
	 * @param id operation-ID
	 * @param param1 1st Parameter
	 * @param param2 2nd Parameter
	 * @param rating Rating of the operation
	 */
	public Operation(String id, int param1, int param2, int rating) {
		super(id, param1, param2);
		this.rating = rating;
		this.effect = NULL;
		execute = true;
		subOperations = new SubOperationQueue();
	}
	
	/**
	 * Sets if the operation should completely executed on the
	 * data-structure. If not, the data-structure stays unchanged,
	 * but in the SubOperationQueue of this operation there are now
	 * the correct suboperations to perform this operation.
	 * @param execute
	 */
	public void setExecution(boolean execute) {
		this.execute = execute;
	}
	/**
	 * Gets the execute-state
	 * @return true if operation executed, false otherwise
	 * @see mauda.operation.Operation#setExecution(boolean)
	 */
	public boolean isExecuted() {
		return execute;
	}

	/**
	 * Sets an effect of an operation, if one exists. E.g. for
	 * delete-min there is entered whats the minimum is, because
	 * that information is not stored in the parameters.
	 * @param effect
	 */
	// Effect bei z.B. delete-min (Knoten der entfernt werden würde)
	public void setEffect(int effect) {
		this.effect = effect;
	}

	/**
	 * Sets the sorting-mode
	 * @param mode sorting-mode
	 * @see mauda.operation.Operation#SORT_BY_RATING
	 * @see mauda.operation.Operation#SORT_BY_NAME
	 */
	public static void setSort(int mode) {
		sortmode = mode;
	}

	/* (non-Javadoc)
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	public int compareTo(Object o) {
		if(sortmode == SORT_BY_RATING)
			return rating - ((Operation)o).getRating();	// aufsteigend
		else if(sortmode == SORT_BY_NAME) 
			return this.toString().compareTo(((Operation)o).toString());
		else return 0;
		//return ((Operation)o).getRating() - rating;	// absteigend
	}

	/**
	 * Gets the rating
	 * @return rating
	 */
	public int getRating()  { return rating; }
	/**
	 * Sets the rating
	 * @param r rating
	 */
	public void setRating(int r) { rating = r; }
	
	public SubOperationQueue getSubOperationQueue() {
		return subOperations;
	}
	/**
	 * Sets the SubOperations that have to performed to execute
	 * this operation
	 * @param so suboperations
	 */
	public void setSubOperationQueue(SubOperationQueue so) {
		subOperations = so;
	}
	/**
	 * Adds a SubOperation to the SubOperationQueue
	 * @param so SubOperation
	 */
	public void add(SubOperation so) {
		subOperations.add(so);
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	// Operationen vergleichen
	public boolean equals(Object o) {
		SimpleOperation op = (SimpleOperation)o;
		if(op instanceof SubOperation) return super.equals(op);
		Operation operation = (Operation)op;
		return operation.isExecuted()==execute&&super.equals(op);
	}

	/* (non-Javadoc)
	 * @see mauda.operation.SimpleOperation#execute(java.lang.Object)
	 */
	/*
		Eine Aktion ausführen
		Vorerst nur für Fibonacci-Heaps
		==> Muss später generalisiert werden,
			oder mehrere Routinen für die unterschiedlichen Bäume (mit gleichem Namen)
	*/
	// Operation ausführen
	public void execute(Object o) {
		if(!execute) {
			mauda.SimpleExercise.getOperationExecuter().executeTemplate(this, o);
			return;
		} 
		mauda.SimpleExercise.getOperationExecuter().execute(this, o);
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#clone()
	 */
	// Kopieren des Objektes
	public Object clone() {
		Operation op = new Operation(id, param1, param2, rating);
		op.setEffect(effect);
		op.setExecution(execute);
		if(subOperations!=null)
			op.subOperations = (SubOperationQueue)subOperations.clone();
		else op.subOperations = null;
		return op;
	}
	/* (non-Javadoc)
	 * @see mauda.operation.SimpleOperation#save()
	 */
	// Generiert einen String der für die Speicherung verwendet wird
	public String save() {
		String s = id;
		if(param1!=NULL) s+=" "+param1;
		if(param2!=NULL) s+=" "+param2;
		if(execute) s += " EXECUTE";
		else s += " TEMPLATE";
		return s;
	}
	/* (non-Javadoc)
	 * @see mauda.operation.SimpleOperation#load(java.lang.String)
	 */
	public void load(String opString) {
		id = null;
		param1 = NULL;
		param2 = NULL;
		effect = NULL;
		rating = NULL;
		execute = true;
		StringTokenizer st = new StringTokenizer(opString);
		String s = st.nextToken();
		id = s;
		if(st.hasMoreTokens()) {
			s = st.nextToken();
			if(s.equals("EXECUTE")) { execute = true; return; }
			else if(s.equals("TEMPLATE")) { execute = false; return; }
			param1 = Integer.parseInt(s);
		}
		if(st.hasMoreTokens()) {
			s = st.nextToken();
			if(s.equals("EXECUTE")) { execute = true; return; }
			else if(s.equals("TEMPLATE")) { execute = false; return; }
			param2 = Integer.parseInt(s);
		}
		if(st.hasMoreTokens()) {
			s = st.nextToken();
			if(s.equals("EXECUTE")) { execute = true; return; }
			else if(s.equals("TEMPLATE")) { execute = false; return; }
			//param3 = Integer.parseInt(s);
		}
	}
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	// für Ausgabe-Zwecke
	public String toString() {
		//if(!execute) return operation + " (Template)";
		if(param1==NULL&&param2==NULL&&effect==NULL&&rating==NULL)
			return id;
		String s = id;
		if(param1!=NULL) s+=" "+(param1<10?" ":"")+param1;
		if(param2!=NULL) s+=" "+(param2<10?" ":"")+param2;
		if(effect!=NULL) s+=" ("+(effect<10?" ":"")+effect+")";
		if(!execute) return s+" (Template)";
		return s+" -> "+rating;
	}
	/* (non-Javadoc)
	 * @see mauda.operation.SimpleOperation#out()
	 */
	// Für schöne Ausgaben (z.B. beim Feedback)
	public String out() {
		String s = id;
		if(param1!=NULL) s+=" "+(param1<10?" ":"")+param1;
		if(param2!=NULL) s+=" "+(param2<10?" ":"")+param2;
		return s;		
	}
}
