/*
 * Created on 13.01.2004 13:17:24
 *
 * Multimediale Algorithmen und Datenstrukturen Assessments
 */
package mauda;

import mauda.operation.*;

import java.util.*;
/**
 * Storage-class for failures, with important internal
 * attributes.
 * 
 * @author Markus Krebs
 */
public class Failure {
	
	/**
	 * No failure description associated to this failure
	 */
	public static final int NO_DESCRIPTION = -1;
	/**
	 * Correct and incorrect suboperations differ from each other
	 */
	public static final int DIFFERENT = 0;
	/**
	 * All suboperation are correct for a specific operation, but
	 * there are missing some suboperations.
	 */
	public static final int MISSING_SUBOP = 1;
	/**
	 * All suboperation are correct for a specific operation, but
	 * there additional false suboperations, which are unnecessary
	 * for that operation.
	 */
	public static final int ADDITIONAL_FALSE_SUBOP = 2;
	
	private Vector differentOps;	// bei MISSING_SUBOP + ADDITIONAL_FALSE_SUBOP
	
	private Operation superOp;

	private SimpleOperation correctOp;
	private SimpleOperation currentOp;
	
	private int recorderOffset;	// inclusive
	private int recorderMaxOffset;	// inclusive
	
	private int opNr;
	private int subOpNr;
	
	private int description;
	
	/**
	 * Creates a new Failure-Object
	 */
	public Failure() {
		superOp = null;
		differentOps = new Vector();
		correctOp = null;
		currentOp = null;
		recorderOffset = -1;
		opNr = -1;
		subOpNr = -1;
		description = NO_DESCRIPTION;
	}
	/**
	 * Sets the operation the failure coressponds to.
	 * @param op Operation
	 */
	public void setSuperOp(Operation op) { superOp = op; }
	/**
	 * Sets the correct operation for the position where failure
	 * occured.
	 * @param so
	 */
	public void setCorrectOp(SimpleOperation so) { correctOp = so; }
	/**
	 * Sets the current operation, the user executed.
	 * @param so
	 */
	public void setCurrentOp(SimpleOperation so) { currentOp = so; }

	/**
	 * Sets the offset inside the <code>OperationRecorder</code>
	 * the failure belongs to.
	 * @param p OperationRecorder-Offset
	 */
	public void setOffset(int p) { recorderOffset = p; }
	/**
	 * Gets the offset.
	 * @return OperationRecorder-Offset
	 * @see mauda.Failure#setOffset(int)
	 */
	public int getOffset() { return recorderOffset; }

	/**
	 * A failure have a specific range, and the maximal offset of
	 * the <code>OperationRecorder</code> that this failure belongs
	 * to, is set here.
	 * @param p OperationRecorder-Offset
	 */
	public void setMaxOffset(int p) { recorderMaxOffset = p; }
	/**
	 * Gets the maximum offset
	 * @return OperationRecorder-Offset
	 * @see mauda.Failure#setMaxOffset(int)
	 */
	public int getMaxOffset() { return recorderMaxOffset; }

	/**
	 * Operations like e.g. FibHeap: INSERT, are counted from the
	 * beginning of the exercise. So this method sets the number of
	 * the operation, the failure belongs to.
	 * @param n Operation-Number
	 */
	public void setOpNr(int n) { opNr = n; }
	/**
	 * Gets the Operation-Number
	 * @return Operation-Number
	 */
	public int getOpNr() { return opNr; }

	/**
	 * SubOperations like e.g. FibHeap: updatemin, are counted
	 * inside the corresponding operation (like INSERT). So this
	 * method sets the number of the suboperation inside the
	 * operation this failure belongs to, namely to the first
	 * incorrect suboperation inside operation.
	 * @param n SubOperation-Number
	 */
	public void setSubOpNr(int n) { subOpNr = n; }
	/**
	 * Gets the SubOperation-Number
	 * @return SubOperation-Number
	 */
	public int getSubOpNr() { return subOpNr; }

	/**
	 * Sets the description-ID of the Failure.
	 * @param d Values: NO_DESCRIPTION, ADDITIONAL_FALSE, DIFFERENT, MISSING_SUBOP
	 */
	public void setDescription(int d) { description = d; }
	/**
	 * Gets the description-ID
	 * @return Description-ID
	 * @see mauda.Failure#setDescription(int)
	 */
	public int getDescription() { return description; }
	
	/**
	 * If the current failure is of type MISSING_SUBOP or 
	 * ADDITION_FALSE this methods add one suboperation to the
	 * failure-suboperations.
	 * @param so SimpleOperation
	 */
	public void addDifferentOperation(SimpleOperation so) {
		differentOps.add(so);
	}
	
	/**
	 * Gets a string-representation of the failure
	 * @return string-representation of the failure
	 */
	public String getDescriptionString() {
		String diffOpStr = "";
		if(differentOps!=null&&differentOps.size()>0) {
			int counter = subOpNr+1;
			Enumeration en = differentOps.elements();
			while(en.hasMoreElements()) {
				diffOpStr += "    -> "+(counter<10?" ":"")+counter+". "+en.nextElement()+"\n";
				counter++;
			}
		}
		
		String msg = "Failure-Description:\n\n";
		msg += "Recorder-Position: "+recorderOffset+"    (internal)\n";
		msg += "Recorder-Max-Pos.: "+recorderMaxOffset+"    (internal)\n";
		msg += "Operation-Nr.:     "+(opNr+1)+"    ["+superOp+"]\n";
		msg += "SubOperation-Nr.:  "+(subOpNr+1)+"\n";
		msg += "Type:              ";
		if(description == DIFFERENT) {
			msg += 	"DIFFERENT SUBOPERATIONS\n";
			msg +=	"Description:\n"+
					"    The following SubOperations differ from each other:\n"+
					"    -> Correct: "+correctOp+"\n"+
					"    -> Present: "+currentOp+"\n";
		} else if(description == MISSING_SUBOP) {
			msg += "MISSING SUBOPERATION(S)\n";
			msg += 	"Description:\n"+
					"    Correct but missing following SubOperation(s):\n"+diffOpStr;
		} else if(description == ADDITIONAL_FALSE_SUBOP) {
			msg +=	"ADDTIONAL FALSE SUBOPERATIONS\n";
			msg += 	"Description:\n"+
					"    Correct but following additional false SubOperations:\n"+diffOpStr;
		}
		return msg;
	}

	/**
	 * Tests if a given offset lies inside this failure
	 * @param p The offset to test
	 * @return true if the given offset involved in this failure, false otherwise
	 */
	public boolean containsOffset(int p) {
		return p>=recorderOffset&&p<=recorderMaxOffset;
	}
}
