src/java/isac/bridge/CalcTree.java
author wneuper
Fri, 04 Feb 2005 14:22:17 +0100
changeset 2051 6e1037f45945
parent 2047 b94a07202d28
child 2062 6a6ab062700b
permissions -rw-r--r--
java: CalcFormula extends Formula with Position
repeated after cvs reported an error ?!?
     1 /*
     2  * Created on Sep 11, 2003
     3  * @author rgradisc
     4  */
     5 package isac.bridge;
     6 
     7 import isac.util.CalcChanged;
     8 import isac.util.CalcChangedEvent;
     9 import isac.util.formulae.CalcHead;
    10 import isac.util.formulae.CalcFormula;
    11 import isac.util.formulae.Position;
    12 import isac.util.interfaces.ICalcIterator;
    13 import isac.util.interfaces.IToCalc;
    14 import isac.util.interfaces.IToUser;
    15 import isac.util.tactics.Tactic;
    16 import isac.wsdialog.DialogGuide;
    17 
    18 import java.io.Serializable;
    19 import java.rmi.RemoteException;
    20 import java.util.Iterator;
    21 import java.util.Vector;
    22 
    23 import org.apache.log4j.Logger;
    24 
    25 /**
    26  * A CalcTree represents a Calculation: It is a tree which consists of one
    27  * CalcHead at the top and abitrarily many Formulas and SubCalculations (with
    28  * separate CalcHeads). This is the main interface between the Bridge and the
    29  * Dialog. The CalcTree calls methods of the Math Engine, which in turn are
    30  * delegated to the BridgeRMI object on the other side of the RMI connection
    31  * ??????WN0409. The communication with the SML Kernel is completly hided from
    32  * the Dialog and the Frontend.
    33  * 
    34  * @author Richard Gradischnegg
    35  */
    36 
    37 public class CalcTree implements IToCalc, Serializable {
    38 
    39 	private int id_;
    40 
    41 	private Vector listeners_;
    42 
    43 	private MathEngine mathEngine_;
    44 
    45 	private ICalcIterator hot_spot_;//WN040924 ..delete: control hotSpot --> DG
    46 
    47 	private IBridgeRMI bridgeRMI_;//WN040924 added for completeCalcHead & Co.
    48 
    49 	static Logger logger_ = Logger.getLogger(CalcTree.class.getName());
    50 
    51 	/**
    52 	 * Start a new calculation. In case of failure, the constructor may change
    53 	 * the formalization object to hint at incomplete or contradictory
    54 	 * specifications. <br>
    55 	 * Only complete calcHeads should be passed. <br>
    56 	 * Check every CalcHead for completeness (with the static method
    57 	 * checkcalcHead() before constructing a CalcTree ..TODO WN040824 shift to
    58 	 * authoring-tools
    59 	 * 
    60 	 * @param identification
    61 	 *            for the CalcTree as delivered by the SML-kernel
    62 	 */
    63 	CalcTree(MathEngine me, int id) {
    64 		this.id_ = id;
    65 		this.mathEngine_ = me;
    66 		this.bridgeRMI_ = me.getBridgeRMI();//WN040924
    67 		listeners_ = new Vector();
    68 	}
    69 
    70 	/**
    71 	 * Attach another dialog to the existing calculation tree.
    72 	 * 
    73 	 * @param dlg
    74 	 *            The new Dialog to be attached to this CalcTree
    75 	 */
    76 	public void attach(DialogGuide dg) {
    77 		listeners_.add(dg);
    78 	}
    79 
    80 	/**
    81 	 * Get a new iterator referencing the root element of the calculation tree.
    82 	 * <p>
    83 	 * The functionality for navigating the calculation is implemented in the
    84 	 * CalcIterator object.
    85 	 * 
    86 	 * @return new instance of CalcIterator
    87 	 */
    88 	public ICalcIterator iterator() {
    89 		return new CalcIterator(this);
    90 	}
    91 
    92 	/**
    93 	 * Makes the passed formula the active formula, i.e. the formula the next
    94 	 * tactic is applied to.
    95 	 * 
    96 	 * @param newActiveFormula
    97 	 */
    98 	public void moveActiveFormula(ICalcIterator cit) {
    99 		try {
   100 			Position p = mathEngine_.moveActiveFormula(id_, cit.getPosition());
   101 			//			if (p == null)//WN0412 message ?!
   102 			//				return false;
   103 			//			else
   104 			//				return true;
   105 		} catch (RemoteException e) {
   106 			// TODO Auto-generated catch block
   107 			e.printStackTrace();
   108 		}
   109 	}
   110 
   111 	/**
   112 	 * WN040924 copied + updated from MathEngine
   113 	 * 
   114 	 * @see isac.util.interfaces.IToCalc#startSolving()
   115 	 */
   116 	public void startSolving() throws Exception {
   117 		// TODO Auto-generated method stub
   118 	}
   119 
   120 	/*
   121 	 * @see isac.util.interfaces.IToCalc#startSolving(isac.util.formulae.CalcHead)
   122 	 *      WN040924 copied + updated from MathEngine
   123 	 * 
   124 	 * public void startSolving() throws Exception {
   125 	 * logger.warn("startSolving"); int id = calcHead.getCalcTreeID();//WN040922
   126 	 * TODO simplify CalcHead CalcTree calcTree = (CalcTree) calcTrees.get(new
   127 	 * Integer(id));//WN040922 TODO simplify
   128 	 * 
   129 	 * if (calcHead.getCalcHeadStatus() != CalcHead.CALCHEAD_CORRECT) { throw
   130 	 * new Exception("Startsolving with incorrect CalcHead"); } Tactic t =
   131 	 * calcTree.fetchProposedTactic(); if (t.getName().compareTo("Apply_Method") !=
   132 	 * 0) { throw new Exception("Startsolving fetches " + t.getName()); } //Next
   133 	 * Tactic must always be Apply_Method calcTree.setNextTactic(t); //return
   134 	 * calcTree; }
   135 	 */
   136 
   137 	/*
   138 	 * TODO WN040924 redesign COMPLETE_PROBLEM, COMPLETE_GIVEN ... public static
   139 	 * final int COMPLETE_METHOD = 1; public static final int COMPLETE_THEORY =
   140 	 * 2; public static final int COMPLETE_PROBLEM = 3; public static final int
   141 	 * COMPLETE_GIVEN = 4; public static final int COMPLETE_FIND = 5; public
   142 	 * static final int COMPLETE_RELATE = 6; //FIXME WN040820 complete a
   143 	 * particular model-item is not included into this design
   144 	 */
   145 
   146 	/**
   147 	 * @see isac.util.interfaces.IToCalc#modifyCalcHead(isac.util.formulae.CalcHead)
   148 	 */
   149 	public void modifyCalcHead(CalcHead calcHead) {
   150 		logger_.fatal(" DG->BR: modifyCalcHead(" + calcHead.toSMLString());
   151 		CalcHead newCalcHead = null;
   152 		try {
   153 			//WN040924 newCalcHead = bridgeRMI.modifyCalcHead(calcHead);
   154 			bridgeRMI_.modifyCalcHead(calcHead);
   155 			//WN040924 calcHead.fillValuesfrom(newCalcHead);
   156 		} catch (RemoteException e) {
   157 			e.printStackTrace();
   158 		}
   159 	}
   160 
   161 	/**
   162 	 * @see isac.util.interfaces.IToCalc#completeCalcHead(isac.util.formulae.CalcHead)
   163 	 */
   164 	public void completeCalcHead() {
   165 		logger_.fatal(" DG->BR: completeCalcHead()");
   166 		try {
   167 			//WN040924 newCalcHead = bridgeRMI.completeCalcHead(calcHead);
   168 			bridgeRMI_.completeCalcHead(this.id_);
   169 			//WN040924 calcHead.fillValuesfrom(newCalcHead);
   170 		} catch (RemoteException e) {
   171 			e.printStackTrace();
   172 		}
   173 	}
   174 
   175 	/**
   176 	 * @see isac.util.interfaces.IToCalc#completeCalcHead(isac.util.formulae.CalcHead,
   177 	 *      int)
   178 	 * @param calcHead
   179 	 *            eventually updated by the user
   180 	 * @param completeItem
   181 	 *            requested by the DialogGuide
   182 	 * 
   183 	 * WN040924 copied from MathEngine
   184 	 */
   185 	public void completeCalcHead(CalcHead calcHead, int completeItem) {
   186 		CalcHead newCalcHead;
   187 		try {
   188 			//WN040924 newCalcHead = bridgeRMI.completeCalcHead(calcHead,
   189 			// completeItem);
   190 			bridgeRMI_.completeCalcHead(this.id_, calcHead, completeItem);
   191 			//WN040924 calcHead.fillValuesfrom(newCalcHead);
   192 			//TODO: Remove the following line!!
   193 			calcHead.setCalcHeadStatus(CalcHead.CALCHEAD_CORRECT);
   194 
   195 		} catch (RemoteException e) {
   196 			e.printStackTrace();
   197 		}
   198 	}
   199 
   200 	/**
   201 	 * Calculate the next n steps starting from the active formula. The Tactic
   202 	 * to be applied in this step may be preset by setNextTactic
   203 	 * 
   204 	 * @param scope
   205 	 *            The scope parameter can have following values:
   206 	 *            <ul>
   207 	 *            <li>Stay in the current subproblem
   208 	 *            <li>Stay in the current subcalculation (e.g. repetitions)
   209 	 *            <li>Stay in the current calculation as a whole.
   210 	 *            </ul>
   211 	 *            Constants for this scopes are found in the IToCalc class
   212 	 * @param nSteps
   213 	 *            Specifies the count of steps to be autocalculated. Passing 0
   214 	 *            for nSteps will calculate until reaching a final result.
   215 	 * @return The method returns an unique id to identify the request when
   216 	 *         notifying about updates in the tree.
   217 	 */
   218 	public int autoCalculate(int scope, int nSteps) {
   219 		logger_.fatal(" DG->BR: autoCalculate(" + scope + ", " + nSteps + ")");
   220 		CalcChanged cc;
   221 		int transactionID = -1;
   222 		try {
   223 			cc = mathEngine_.autoCalculate(this.id_, scope, nSteps);
   224 			if (!(cc == null)) {
   225 				hot_spot_ = new CalcIterator(this, cc.getLastGenerated());
   226 				transactionID = generateTransactionID();
   227 				informListeners(new CalcIterator(this, cc.getLastUnchanged()),
   228 						new CalcIterator(this, cc.getLastDeleted()),
   229 						new CalcIterator(this, cc.getLastGenerated()),
   230 						transactionID);
   231 			}
   232 		} catch (RemoteException e) {
   233 			e.printStackTrace();
   234 		}
   235 		return transactionID;
   236 	}
   237 
   238 	/**
   239 	 * Tries to replaces the active formula in the calculation tree by the
   240 	 * passed formula. This could fail if no valid derivation from the preceding
   241 	 * formula to the (new) active formula can be found.
   242 	 * <p>
   243 	 * Parts of the calculation after the replaced formula are likely to become
   244 	 * invalid, listeners will be informed of this with the update message,
   245 	 * which contains the last unchanged formula.
   246 	 * 
   247 	 * @param newFormula
   248 	 * @return The method will return 0 on success or a nonzero value indicating
   249 	 *         the status otherwise.
   250 	 */
   251 	public int replaceFormula(CalcFormula f) throws RemoteException {
   252 		logger_.fatal(" DG->BR: replaceFormula(" + f.toSMLString() + ")");
   253 		CalcChanged cc;
   254 		int transactionID = -1;
   255 		try {
   256 			cc = mathEngine_.replaceFormula(this.id_, f);
   257 			if (!(cc == null)) {
   258 				hot_spot_ = new CalcIterator(this, cc.getLastGenerated());
   259 				transactionID = generateTransactionID();
   260 				informListeners(new CalcIterator(this, cc.getLastUnchanged()),
   261 						new CalcIterator(this, cc.getLastDeleted()),
   262 						new CalcIterator(this, cc.getLastGenerated()),
   263 						transactionID);
   264 			}
   265 		} catch (RemoteException e) {
   266 			e.printStackTrace();
   267 		}
   268 		return 0;
   269 	}
   270 
   271 	/**
   272 	 * Tries to append the passed formula after the active formula. This could
   273 	 * fail if no valid derivation from the preceding formula to the (new)
   274 	 * active formula can be found. The method will fail as well if the active
   275 	 * formula is not the last formula in the (sub)calculation. Parts of the
   276 	 * calculation might become invalid.
   277 	 * 
   278 	 * @param newFormula
   279 	 * @return The method will return 0 on success or a nonzero value indicating
   280 	 *         the status otherwise.
   281 	 */
   282 	public int appendFormula(CalcFormula f) throws RemoteException {
   283 		logger_.fatal(" DG->BR: appendFormula(" + f.toSMLString() + ")");
   284 		CalcChanged cc;
   285 		int transactionID = -1;
   286 		try {
   287 			cc = mathEngine_.appendFormula(this.id_, f);
   288 			if (!(cc == null)) {
   289 				hot_spot_ = new CalcIterator(this, cc.getLastGenerated());
   290 				transactionID = generateTransactionID();
   291 				informListeners(new CalcIterator(this, cc.getLastUnchanged()),
   292 						new CalcIterator(this, cc.getLastDeleted()),
   293 						new CalcIterator(this, cc.getLastGenerated()),
   294 						transactionID);
   295 			}
   296 		} catch (RemoteException e) {
   297 			e.printStackTrace();
   298 		}
   299 		return 0;
   300 	}
   301 
   302 	/**
   303 	 * Set a tactic for usage by autocalculate.
   304 	 * 
   305 	 * @param tactic
   306 	 *            the Tactic to be used in the the next step
   307 	 * @return The return value indicates success, failure or probable success
   308 	 *         at a later time.
   309 	 */
   310 	public int setNextTactic(Tactic tactic) {
   311 		logger_.fatal(" DG->BR: setNextTactic(" + tactic.toSMLString() + ")");
   312 		int result = -1;
   313 		try {
   314 			result = mathEngine_.setNextTactic(this.id_, tactic);
   315 			if (result == 0) {
   316 				hot_spot_.moveDown(); // move to the new formula/calcHead
   317 				// FIXXXME
   318 				informListeners((ICalcIterator) hot_spot_.clone(),
   319 				// FIXXXME: nothing changed, but if outcommented: subpbl shows
   320 						// Add_Given etc. ... discuss with LK !
   321 						(ICalcIterator) hot_spot_.clone(),
   322 						(ICalcIterator) hot_spot_.clone(),
   323 						generateTransactionID());
   324 			}
   325 		} catch (RemoteException e) {
   326 			// TODO Auto-generated catch block
   327 			e.printStackTrace();
   328 		}
   329 		return -1;
   330 	}
   331 //	public int setNextTactic(Tactic tactic) {
   332 //		logger_.fatal(" DG->BR: setNextTactic(" + tactic.toSMLString() + ")");
   333 //		int result = -1;
   334 //		ICalcIterator it;
   335 //		try {
   336 //			result = mathEngine_.setNextTactic(this.id_, tactic);
   337 //			//^^^^ should be CalcChanged !
   338 //			if (result == 0) {
   339 //				//hack before @@@ autoCalculate --->
   340 //				//               isac.wsdialog.DialogGuide#notifyUserAction
   341 //				//works only if nothing is deleted by use in <Next Step>
   342 //				it = (ICalcIterator) hot_spot_.clone();
   343 //				hot_spot_.moveDown();
   344 //				informListeners((ICalcIterator) it, it,//thus deleted nodes
   345 //													   // are not reported !!!
   346 //						(ICalcIterator) hot_spot_.clone(),
   347 //						generateTransactionID());
   348 //			}
   349 //		} catch (RemoteException e) {
   350 //			// TODO Auto-generated catch block
   351 //			e.printStackTrace();
   352 //		}
   353 //		return -1;
   354 //	}
   355 
   356 	
   357 	/**
   358 	 * Retrieve the tactic proposed by the SML-Kernel for the next step in the
   359 	 * calculation.
   360 	 * 
   361 	 * @return proposed tactic. Can be null, if the kernel does not know what to
   362 	 *         do next, or if the end of the calculation is reached
   363 	 */
   364 	public Tactic fetchProposedTactic() {
   365 		logger_.fatal(" DG->BR: fetchProposedTactic()");
   366 		try {
   367 			Tactic tac = mathEngine_.fetchProposedTactic(this.id_);
   368 			logger_.fatal(" DG<-BR: fetchProposedTactic <- "+tac.toSMLString());
   369 			return tac;
   370 		} catch (RemoteException e) {
   371 			// TODO Auto-generated catch block
   372 			e.printStackTrace();
   373 		}
   374 		logger_.fatal(" DG<-BR: fetchProposedTactic <- NULL helpless");
   375 		return null;
   376 	}
   377 
   378 	/**
   379 	 * Get a list of tactics applicable to the active formula.
   380 	 * 
   381 	 * @param scope
   382 	 *            The filter parameter selects the scope of search for
   383 	 *            applicable tactics: all tactics / all tactics from the current
   384 	 *            theory / all tactics from the (calculation) method being
   385 	 *            applied.
   386 	 * @return Array with applyable tactics
   387 	 */
   388 	public Tactic[] fetchApplicableTactics(int scope) {
   389 		logger_.fatal(" DG->BR: fetchApplicableTactics(" + scope + ")");
   390 		Tactic[] result = null;
   391 		try {
   392 			result = mathEngine_.fetchAppliableTactics(this.id_, scope);
   393 		} catch (RemoteException e) {
   394 			// TODO Auto-generated catch block
   395 			e.printStackTrace();
   396 		}
   397 		return result;
   398 	}
   399 
   400 	/**
   401 	 * Add a Listener to this CalcTree. Listeners will be informed about any
   402 	 * changes in the CalcTree.
   403 	 * 
   404 	 * @param listener
   405 	 *            the new Listener, has to implement the interface IToUser
   406 	 * @return true, if the listener has been added successfully
   407 	 */
   408 	public boolean addDataChangeListener(IToUser listener) {
   409 		logger_.fatal(" DG->BR: addDataChangeListener(" + listener + ")");
   410 		if (listeners_.contains(listener)) {
   411 			return false;
   412 		} else {
   413 			listeners_.add(listener);
   414 		}
   415 		return true;
   416 	}
   417 
   418 	/**
   419 	 * Retrieve the active formula in a CalcTree. This is the formula form where
   420 	 * the calculation will continue.
   421 	 * 
   422 	 * @return Iterator that marks the currently active formula
   423 	 */
   424 	public ICalcIterator getActiveFormula() {
   425 		logger_.fatal(" DG<>BR: getActiveFormula <- "+hot_spot_.toSMLString());
   426 		return (ICalcIterator) hot_spot_.clone();
   427 	}
   428 
   429 	/**
   430 	 * Destruct this CalcTree: the sml-Representation of the CalcTree is
   431 	 * disposed, the id can be used for a new CalcTree
   432 	 * 
   433 	 * @return boolean value: success of operation (complete/failed) TODO
   434 	 *         WN040824 call mathEngine.destruct when WS is closed TODO WN040824
   435 	 *         call mathEngine.destruct when session is closed
   436 	 */
   437 	public boolean destruct() {
   438 		try {
   439 			return mathEngine_.destruct(this.id_);
   440 		} catch (RemoteException e) {
   441 			// TODO Auto-generated catch block
   442 			e.printStackTrace();
   443 		}
   444 		return false;
   445 	}
   446 
   447 	// send an update event to the registered listeners
   448 	private void informListeners(ICalcIterator lastUnchangedFormula,
   449 			ICalcIterator lastDeletedFormula,
   450 			ICalcIterator lastGeneratedFormula, int transactionID)
   451 			throws RemoteException {
   452 		logger_.fatal(" . . <-BR: informListeners (unc="
   453 				+ lastUnchangedFormula.toSMLString() + ", del="
   454 				+ lastDeletedFormula.toSMLString() + ", gen="
   455 				+ lastGeneratedFormula.toSMLString());
   456 		Iterator listn_it = listeners_.iterator();
   457 		//DialogGuide dg;
   458 		IToUser dg;
   459 		CalcChangedEvent e = new CalcChangedEvent(transactionID, true, // completed
   460 				lastUnchangedFormula, lastDeletedFormula, lastGeneratedFormula);
   461 		while (listn_it.hasNext()) {
   462 			dg = (IToUser) listn_it.next();
   463 			dg.calcChanged(e);
   464 		}
   465 	}
   466 
   467 	MathEngine getMathEngine() {
   468 		return mathEngine_;
   469 	}
   470 
   471 	public int getId() {
   472 		return id_;
   473 	}
   474 
   475 	// Special iterator hotSpot: marks the currently active formula of
   476 	// the calcTree
   477 	void setHotSpot(ICalcIterator iterator) {
   478 		hot_spot_ = iterator;
   479 	}
   480 
   481 	//WN0411 reminiscence to Dinopolis, drop it !?
   482 	private int generateTransactionID() {
   483 		return (int) (Math.random() * 0xFFFF);
   484 	}
   485 
   486 	/* (non-Javadoc)
   487 	 * @see isac.util.interfaces.IToCalc#intermediateSteps()
   488 	 */
   489 	public int intermediateSteps() throws RemoteException {
   490 		// TODO Auto-generated method stub
   491 		return 0;
   492 	}
   493 
   494 }