src/java/isac/bridge/CalcTree.java
author wneuper
Tue, 08 Feb 2005 12:05:04 +0100
changeset 2069 fdca7e9e593a
parent 2065 603c0de1a9e3
child 2082 1f418b3acd49
permissions -rw-r--r--
all after getElementsFromTo
(after commiting sml on shell)
     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 
   332 	//	public int setNextTactic(Tactic tactic) {
   333 	//		logger_.fatal(" DG->BR: setNextTactic(" + tactic.toSMLString() + ")");
   334 	//		int result = -1;
   335 	//		ICalcIterator it;
   336 	//		try {
   337 	//			result = mathEngine_.setNextTactic(this.id_, tactic);
   338 	//			//^^^^ should be CalcChanged !
   339 	//			if (result == 0) {
   340 	//				//hack before @@@ autoCalculate --->
   341 	//				// isac.wsdialog.DialogGuide#notifyUserAction
   342 	//				//works only if nothing is deleted by use in <Next Step>
   343 	//				it = (ICalcIterator) hot_spot_.clone();
   344 	//				hot_spot_.moveDown();
   345 	//				informListeners((ICalcIterator) it, it,//thus deleted nodes
   346 	//													   // are not reported !!!
   347 	//						(ICalcIterator) hot_spot_.clone(),
   348 	//						generateTransactionID());
   349 	//			}
   350 	//		} catch (RemoteException e) {
   351 	//			// TODO Auto-generated catch block
   352 	//			e.printStackTrace();
   353 	//		}
   354 	//		return -1;
   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 <- "
   369 					+ tac.toSMLString());
   370 			return tac;
   371 		} catch (RemoteException e) {
   372 			// TODO Auto-generated catch block
   373 			e.printStackTrace();
   374 		}
   375 		logger_.fatal(" DG<-BR: fetchProposedTactic <- NULL helpless");
   376 		return null;
   377 	}
   378 
   379 	/**
   380 	 * Get a list of tactics applicable to the active formula.
   381 	 * 
   382 	 * @param scope
   383 	 *            The filter parameter selects the scope of search for
   384 	 *            applicable tactics: all tactics / all tactics from the current
   385 	 *            theory / all tactics from the (calculation) method being
   386 	 *            applied.
   387 	 * @return Array with applyable tactics
   388 	 */
   389 	public Tactic[] fetchApplicableTactics(int scope) {
   390 		logger_.fatal(" DG->BR: fetchApplicableTactics(" + scope + ")");
   391 		Tactic[] result = null;
   392 		try {
   393 			result = mathEngine_.fetchAppliableTactics(this.id_, scope);
   394 		} catch (RemoteException e) {
   395 			// TODO Auto-generated catch block
   396 			e.printStackTrace();
   397 		}
   398 		return result;
   399 	}
   400 
   401 	/**
   402 	 * Add a Listener to this CalcTree. Listeners will be informed about any
   403 	 * changes in the CalcTree.
   404 	 * 
   405 	 * @param listener
   406 	 *            the new Listener, has to implement the interface IToUser
   407 	 * @return true, if the listener has been added successfully
   408 	 */
   409 	public boolean addDataChangeListener(IToUser listener) {
   410 		logger_.fatal(" DG->BR: addDataChangeListener(" + listener + ")");
   411 		if (listeners_.contains(listener)) {
   412 			return false;
   413 		} else {
   414 			listeners_.add(listener);
   415 		}
   416 		return true;
   417 	}
   418 
   419 	/**
   420 	 * Retrieve the active formula in a CalcTree. This is the formula form where
   421 	 * the calculation will continue.
   422 	 * 
   423 	 * @return Iterator that marks the currently active formula
   424 	 */
   425 	public ICalcIterator getActiveFormula() {
   426 		logger_
   427 				.fatal(" DG<>BR: getActiveFormula <- "
   428 						+ hot_spot_.toSMLString());
   429 		return (ICalcIterator) hot_spot_.clone();
   430 	}
   431 
   432 	/**
   433 	 * Destruct this CalcTree: the sml-Representation of the CalcTree is
   434 	 * disposed, the id can be used for a new CalcTree
   435 	 * 
   436 	 * @return boolean value: success of operation (complete/failed) TODO
   437 	 *         WN040824 call mathEngine.destruct when WS is closed TODO WN040824
   438 	 *         call mathEngine.destruct when session is closed
   439 	 */
   440 	public boolean destruct() {
   441 		try {
   442 			return mathEngine_.destruct(this.id_);
   443 		} catch (RemoteException e) {
   444 			// TODO Auto-generated catch block
   445 			e.printStackTrace();
   446 		}
   447 		return false;
   448 	}
   449 
   450 	// send an update event to the registered listeners
   451 	private void informListeners(ICalcIterator lastUnchangedFormula,
   452 			ICalcIterator lastDeletedFormula,
   453 			ICalcIterator lastGeneratedFormula, int transactionID)
   454 			throws RemoteException {
   455 		logger_.fatal(" . . <-BR: informListeners (unc="
   456 				+ lastUnchangedFormula.toSMLString() + ", del="
   457 				+ lastDeletedFormula.toSMLString() + ", gen="
   458 				+ lastGeneratedFormula.toSMLString());
   459 		Iterator listn_it = listeners_.iterator();
   460 		//DialogGuide dg;
   461 		IToUser dg;
   462 		CalcChangedEvent e = new CalcChangedEvent(transactionID, true, // completed
   463 				lastUnchangedFormula, lastDeletedFormula, lastGeneratedFormula);
   464 		while (listn_it.hasNext()) {
   465 			dg = (IToUser) listn_it.next();
   466 			dg.calcChanged(e);
   467 		}
   468 	}
   469 
   470 	MathEngine getMathEngine() {
   471 		return mathEngine_;
   472 	}
   473 
   474 	public int getId() {
   475 		return id_;
   476 	}
   477 
   478 	// Special iterator hotSpot: marks the currently active formula of
   479 	// the calcTree
   480 	void setHotSpot(ICalcIterator iterator) {
   481 		hot_spot_ = iterator;
   482 	}
   483 
   484 	//WN0411 reminiscence to Dinopolis, drop it !?
   485 	//WN0501 ... _NO_: ... = return-value of autoCalculate,etc. =
   486 	// = CalcChangedEvent.transaction_id_
   487 	private int generateTransactionID() {
   488 		return (int) (Math.random() * 0xFFFF);
   489 	}
   490 
   491 	/*
   492 	 * (non-Javadoc)
   493 	 * 
   494 	 * @see isac.util.interfaces.IToCalc#intermediateSteps()
   495 	 */
   496 	public Vector intermediateSteps(ICalcIterator i) throws RemoteException {
   497 		// TODO Auto-generated method stub
   498 		return null;
   499 	}
   500 
   501 	/*
   502 	 * (non-Javadoc)
   503 	 * 
   504 	 * @see isac.util.interfaces.IToCalc#getElementsFromTo(isac.util.interfaces.ICalcIterator,
   505 	 *      isac.util.interfaces.ICalcIterator, java.lang.Integer, boolean)
   506 	 */
   507 	public Vector getElementsFromTo(ICalcIterator iterator_from,
   508 			ICalcIterator iterator_to, Integer level,
   509 			boolean result_includes_tactics) throws RemoteException {
   510 		logger_.fatal(" DG->BR: getElementsFromTo("
   511 				+ iterator_from.toSMLString() + ", "
   512 				+ iterator_to.toSMLString() + level + ")");
   513 		try {
   514 			return mathEngine_.getElementsFromTo(this.id_, iterator_from,
   515 					iterator_to, level,result_includes_tactics);
   516 			} catch (RemoteException e) {
   517 				e.printStackTrace();
   518 			}
   519 			return null;
   520 	}
   521 
   522 }