/*
GeoGebra - Dynamic Mathematics for Everyone
http://www.geogebra.org
This file is part of GeoGebra.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation.
*/
/*
* AlgoDependentNumber.java
*
* Created on 30. August 2001, 21:37
*/
package org.geogebra.common.kernel.algos;
import org.geogebra.common.euclidian.EuclidianConstants;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.StringTemplate;
import org.geogebra.common.kernel.arithmetic.Command;
import org.geogebra.common.kernel.arithmetic.ExpressionNode;
import org.geogebra.common.kernel.arithmetic.ExpressionValue;
import org.geogebra.common.kernel.arithmetic.MyStringBuffer;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoText;
/**
*
* @author Markus
*/
public class AlgoDependentText extends AlgoElement implements DependentAlgo {
private GeoText text; // output
// Curve[If[t>1,(t,t)],t,0,5]
/**
* @param cons
* construction
* @param root
* root element
* @param mayBeSpreadsheetTraceable
* whether this may contain spreadsheet tracable vars
*/
public AlgoDependentText(Construction cons, ExpressionNode root,
boolean mayBeSpreadsheetTraceable) {
super(cons);
text = new GeoText(cons);
text.setDefinition(root);
setInputOutput(); // for AlgoElement
if (mayBeSpreadsheetTraceable) {
text.initSpreadsheetTraceableCase();
}
// compute value of dependent number
compute();
}
@Override
public Algos getClassName() {
return Algos.Expression;
}
@Override
public int getRelatedModeID() {
return EuclidianConstants.MODE_TEXT;
}
/**
* @return root expression
*/
public ExpressionNode getRoot() {
return text.getDefinition();
}
// for AlgoElement
@Override
protected void setInputOutput() {
input = text.getDefinition().getGeoElementVariables();
for (int i = 0; i < input.length; i++) {
if (input[i].isGeoText()) {
((GeoText) input[i]).addTextDescendant(text);
}
}
super.setOutputLength(1);
super.setOutput(0, text);
setDependencies(); // done by AlgoElement
}
/**
* @return resulting text
*/
public GeoText getGeoText() {
return text;
}
private StringTemplate oldTpl;
// calc the current value of the arithmetic tree
@Override
public final void compute() {
StringTemplate tpl = text.getStringTemplate();
if (oldTpl != tpl) {
oldTpl = tpl;
for (int i = 0; i < input.length; i++) {
if (input[i].isGeoText() && !input[i].isLabelSet()
&& input[i].getParentAlgorithm() != null) {
input[i].setVisualStyle(text);
input[i].getParentAlgorithm().update();
}
}
}
nodeToGeoText(text.getDefinition(), text, tpl);
}
/**
* Converts expression node to geotext
*
* @param root
* expression
* @param text
* text
* @param tpl
* string template
*/
public final static void nodeToGeoText(ExpressionNode root, GeoText text,
StringTemplate tpl) {
try {
boolean latex = text.isLaTeX();
root.setHoldsLaTeXtext(latex);
String str;
if (latex) {
str = root.evaluate(tpl).toLaTeXString(false, tpl);
} else {
str = root.evaluate(tpl).toValueString(tpl);
}
text.setTextString(str);
} catch (Exception e) {
text.setUndefined();
}
}
@Override
final public String toString(StringTemplate tpl) {
// was defined as e.g. text0 = "Radius: " + r
if (text.getDefinition() == null) {
return "";
}
return text.getDefinition().toString(tpl);
}
/**
* Update spreadsheet traceable flag
*/
public void setSpreadsheetTraceableText() {
/*
* AbstractApplication.debug("\nroot: "+root+ "\nleft: "
* +root.getLeftTree()+ "\nright: "+root.getRightTree()+
* "\ngeos:"+root.getVariables()+ "\nright geos:"
* +root.getRightTree().getVariables() ); //
*/
// find first NumberValue in expression and replace
numToTraceSet = false;
ExpressionNode copy = getSpecialCopy(text.getDefinition());
// AbstractApplication.printStacktrace("XXX"+copy.evaluate(StringTemplate.defaultTemplate).toValueString(StringTemplate.defaultTemplate));
// if (numToTrace != null) {
// AbstractApplication.debug("YYY"+numToTrace.toOutputValueString(StringTemplate.defaultTemplate));
// }
text.setSpreadsheetTraceable(copy, numToTrace);
// AbstractApplication.debug("\nleft string :
// "+root.getLeftTree().evaluate(StringTemplate.defaultTemplate).toValueString(StringTemplate.defaultTemplate));
// AbstractApplication.debug("\nleft string latex :
// "+root.getLeftTree().evaluate(StringTemplate.defaultTemplate).toLaTeXString(false,
// StringTemplate.defaultTemplate));
}
private ExpressionValue numToTrace;
// adpated from ExpressionNode.getCopy()
private ExpressionNode getSpecialCopy(ExpressionNode en) {
// Application.debug("getCopy() input: " + this);
ExpressionNode newNode = null;
ExpressionValue lev = null, rev = null;
ExpressionValue left = en.getLeft();
ExpressionValue right = en.getRight();
if (left != null) {
lev = copy(left);
}
if (right != null) {
rev = copy(right);
}
if (lev != null) {
newNode = new ExpressionNode(kernel, lev, en.getOperation(), rev);
newNode.leaf = en.leaf;
} else {
// something went wrong
return null;
}
// set member vars that are not set by constructors
// newNode.forceVector = forceVector;
// newNode.forcePoint = forcePoint;
// newNode.forceFunction = forceFunction;
// Application.debug("getCopy() output: " + newNode);
return newNode;
}
// adpated from ExpressionNode
// finds first "+ NumberValue" and replaces with " x "
// eg "value = "+x(A)+"cm"
private ExpressionValue copy(ExpressionValue ev) {
if (ev == null) {
return null;
}
ExpressionValue ret = null;
// Application.debug("copy ExpressionValue input: " + ev);
if (ev.isNumberValue()) {
// ************
// replace first encountered NumberValue, eg x(A) with empty string
// and make note
// ************
setNumToTrace(ev);
ret = new MyStringBuffer(kernel, " ... ");
} else if (ev instanceof ExpressionNode) {
ExpressionNode en = (ExpressionNode) ev;
ret = getSpecialCopy(en);
// } else if (ev instanceof MyList) {
// MyList en = (MyList) ev;
// ret = getCopy(kernel, en);
}
// deep copy
else if (ev.isConstant() || (ev instanceof Command)) {
ret = ev.deepCopy(kernel);
} else if (ev.isGeoElement()) {
// eg FormulaText[x(A)]
GeoElement geo = (GeoElement) ev;
AlgoElement algo = geo.getParentAlgorithm();
if (algo != null && algo.getInput().length > 0) {
GeoElement geo2 = algo.getInput()[0];
if (geo2.isNumberValue()) {
setNumToTrace(geo2);
ret = new MyStringBuffer(kernel, " ... ");
} else {
ret = ev;
}
} else {
ret = ev;
}
} else {
ret = ev;
}
// Application.debug("copy ExpressionValue output: " + ev);
return ret;
}
private boolean numToTraceSet;
private void setNumToTrace(ExpressionValue ev) {
if (!numToTraceSet) {
numToTrace = ev;
numToTraceSet = true;
} else {
numToTrace = null;
}
}
@Override
public ExpressionNode getExpression() {
return text.getDefinition();
}
}