/*
 * Created on 31.01.2004 14:33:25
 *
 * Multimediale Algorithmen und Datenstrukturen Assessments
 */
package mauda.feedback;

import mauda.plugin.KBFormulaEvaluator;

import java.util.*;
import java.io.*;
/**
 * Knowledge-Base for Feedback-Information.
 * 
 * @author Markus Krebs
 */
public class FeedbackKB {
	
	private Vector kbObjects;

	/**
	 * Creates a FeedbackKB
	 */
	public FeedbackKB() {
		kbObjects = new Vector();
	}
	
	/**
	 * Loads a knowledge-base from disc.<br>
	 * The conventions for the knowledge-base-file:
	 * <ul>
	 * <li>Must be a normal txt-file</li>
	 * <li><i>FORMULA:</i> followed by the formula that have to evaluated</li>
	 * <li>The next line after <i>FORMULA:</i> must start with <i>MESSAGE:</i> followed by the feedback-message</li>
	 * <li>It's possible to write several FORMULA-lines one after another. This describes that the following MESSAGE will be displayed when one of the formulas is true</li>
	 * <li>It's possible to write several MESSAGE-lines one after another. This means that the messages will be displayed with a link to the next message</li>
	 * <li>The possible formulas are partly plug-in-dependent.</li>
	 * </ul>
	 * Conventions for formulas:
	 * <ul>
	 * <li>correct: will be replace by TRUE or FALSE, depends on whether the actual suboperation matches the correct suboperation</li>
	 * <li>firstincorrect: will be replaced by TRUE or FALSE, depends whether the actual failure is the first failure inside an operation (like INSERT)</li>
	 * <li>missingsubop: will be replaced by TRUE or FALSE, if there are missing suboperations</li>
	 * <li>All operators like =, !=, AND, etc. must enclosed in spaces.
	 * <li>subop[position]: Represents the SubOperation-Object, where different further access allowed like:
	 *     <ul>
	 *       <li>id: will be replaced by the ID of the suboperation</li>
	 *       <li>param1: will be replaced by the 1st parameter of the suboperation</li>
	 *       <li>param2: will be replaced by the 2nd parameter of the suboperation</li>
	 *     </ul>
	 *   </li>
	 * <li>on param1 and param2 is further access allowed, but this is plugin-dependent.</li>
	 * </ul>
	 * Example for an entry:<br>
	 * <code>
	 * FORMULA: correct AND subop[current].id = newfheapmeld<br>
	 * MESSAGE: A OPERATION causes to create a new Fibonacci-Heap with a node of the value OPPARAM1 and meld it with the current Fibonacci-Heap.<br>
	 * MESSAGE: A SUBOPERATION is the correct operation.<br>
	 * </code>
	 * <br>
	 * For further information see the dissertation.
	 * 
	 * @param filename Filename of the knowledge-base-file
	 * @return true if loading was successful, false otherwise
	 */
	// Momentane Konventionen für KB
	// FORMULA: formula
	//   .. (beliebig viele FORMULA's --> ODER-Verknüpfung, intern werden mehrere KBObjecte erzeugt, die alle die nachfolgenden Messages enthalten)
	// MESSAGE: msg		(muss direkt auf FORMULA folgen)
	//   .. (beliebig viele MESSAGE's)
	public boolean load(String filename) {
		//System.out.println("Loading: "+filename);
		BufferedReader br;
		try { br = new BufferedReader(new FileReader(filename)); }
		catch(Exception ex) {
			ex.printStackTrace();
			return false;
		}
		kbObjects = new Vector();
		Vector formulas = new Vector();
		Vector messages = new Vector();
		try{
			while(br.ready()) {
				String line = br.readLine();
				// NEUER CODE
				formulas.removeAllElements();
				messages.removeAllElements();
				if(!line.startsWith("FORMULA: ")) continue;
				while(line.startsWith("FORMULA: ")) {
					String formula = line.substring(9);
					formulas.add(formula);
					line = br.readLine();
					if(!br.ready()) break;
				}
				while(line.startsWith("MESSAGE: ")) {
					String message = line.substring(9);
					messages.add(message);
					line = br.readLine();
					if(!br.ready()) break;
				}
				if(messages.size() == 0) {
					System.err.println("Error in KB. Loading of KB canceled!");
					System.err.println("1. Formula: "+formulas.elementAt(0));
					return false;
				}
				Enumeration en = formulas.elements();
				while(en.hasMoreElements()) {
					String formula = (String)en.nextElement();
					FeedbackKBObject fkbo = new FeedbackKBObject();
					fkbo.setFormula(formula);
					fkbo.setMessages((Vector)messages.clone());
					kbObjects.add(fkbo);
				}
			}
		}
		catch(IOException e) {
			// End of file
		}
		try {
			br.close();
		} catch(IOException e) {
			// close file
		}
		return true;
	}
	
	/**
	 * Make a call to the knowledge-base for the current-position
	 * inside the exercise, and returns all FeedbackKB-Objects its
	 * formulas are <code>true</code>.
	 * @param evaluator
	 * @return A Vector of FeedbackKBObject's
	 */
	// liefert alle Feedback-Objekte für die die Formel=TRUE ist
	public Vector call(KBFormulaEvaluator evaluator) {
		if(kbObjects.size() == 0) return null;
		Vector v = new Vector();
		Enumeration en = kbObjects.elements();
		while(en.hasMoreElements()) {
			FeedbackKBObject fkbo = (FeedbackKBObject)en.nextElement();
			boolean result = evaluator.evaluate(fkbo.getFormula());
			if(result) {
				//System.out.println("Following Formula is TRUE! ---------------------------------");
				//System.out.println("--> Formula: "+fkbo.getFormula());
				//System.out.println(" -> Filled:  "+evaluator.filledFormula);
				//System.out.println(" -> Message: "+fkbo.getMessage());
				v.add(fkbo);
			} 
		}
		return v;
	}

}
