package org.geogebra.common.kernel.scripting;
import java.util.Iterator;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.SetRandomValue;
import org.geogebra.common.kernel.algos.AlgoDependentNumber;
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.MyList;
import org.geogebra.common.kernel.arithmetic.NumberValue;
import org.geogebra.common.kernel.commands.CmdScripting;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoFunction;
import org.geogebra.common.kernel.geos.GeoFunctionable;
import org.geogebra.common.kernel.geos.GeoList;
import org.geogebra.common.kernel.geos.GeoNumeric;
import org.geogebra.common.main.MyError;
import org.geogebra.common.plugin.Operation;
import org.geogebra.common.util.debug.Log;
/**
* SetValue
*/
public class CmdSetValue extends CmdScripting {
/**
* Create new command processor
*
* @param kernel
* kernel
*/
public CmdSetValue(Kernel kernel) {
super(kernel);
}
@Override
protected final GeoElement[] perform(Command c) throws MyError {
int n = c.getArgumentNumber();
GeoElement[] arg = resArgs(c);
boolean ok;
switch (n) {
case 2:
setValue2(arg[0], arg[1]);
return arg;
case 3:
if ((ok = (arg[0].isGeoList() && arg[0].isIndependent()))
&& arg[1] instanceof NumberValue) {
boolean success = setValue3(kernelA, (GeoList) arg[0],
(int) ((NumberValue) arg[1]).getDouble(), arg[2]);
if (!success) {
throw argErr(app, c, arg[1]);
}
} else {
throw argErr(app, c, ok ? arg[1] : arg[0]);
}
return arg;
default:
throw argNumErr(app, c, n);
}
}
/**
* sets a value of a list (or extends the list if you set element n+1)
*
* @param kernel
* kernel
* @param list
* list
* @param nn
* index (1 based)
* @param arg2
* value
* @return success
*/
public static boolean setValue3(Kernel kernel, GeoList list, int nn,
GeoElement arg2) {
if (nn < 1 || nn > list.size() + 1) {
return false;
}
if (nn > list.size()) {
list.add((GeoElement) arg2.deepCopy(kernel));
if (list.getDefinition() != null) {
ExpressionValue root = list.getDefinition().unwrap();
if (root instanceof MyList && arg2.getDefinition() != null
&& arg2.isIndependent()) {
((MyList) root).addListElement(arg2.getDefinition());
} else {
list.setDefinition(null);
}
}
list.updateRepaint();
return true;
}
GeoElement geo = list.get(nn - 1);
if (geo.isIndependent()) {
if (geo.isGeoNumeric() && arg2 instanceof NumberValue) {
NumberValue num = (NumberValue) arg2;
((GeoNumeric) geo).setValue(num.getDouble());
} else {
geo.set(arg2);
}
if (list.getDefinition() != null) {
ExpressionValue root = list.getDefinition().unwrap();
// sizes different == something went wrong
if (root instanceof MyList && arg2.getDefinition() != null
&& ((MyList) root).size() == list.size()
&& arg2.isIndependent()) {
((MyList) root).setListElement(nn - 1,
arg2.getDefinition());
} else {
list.setDefinition(null);
}
}
} else {
Log.debug(geo.getParentAlgorithm());
}
geo.updateRepaint();
// update the list too if necessary
if (!geo.isLabelSet()) { // eg like first element of {1,2,a}
Iterator<GeoElement> it = kernel.getConstruction()
.getGeoSetConstructionOrder().iterator();
while (it.hasNext()) {
GeoElement geo2 = it.next();
if (geo2.isGeoList()) {
final GeoList gl = (GeoList) geo2;
for (int i = 0; i < gl.size(); i++) {
if (gl.get(i) == geo) {
// avoid ConcurrentModificationException in desktop
kernel.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
gl.updateRepaint();
}
});
}
}
}
}
}
return true;
}
/**
* sets arg[0] to arg[1]
*
* @param arg0
* target
* @param arg1
* value
*/
public static void setValue2(GeoElement arg0, GeoElement arg1) {
if (arg0.isGeoFunction() && arg1.isGeoFunctionable()) {
// eg f(x)=x^2
// SetValue[f,1]
GeoFunction fun = (GeoFunction) arg0;
GeoFunctionable val = (GeoFunctionable) arg1;
fun.set(val.getGeoFunction());
if (!fun.validate(true)) {
fun.set(arg0);
fun.setUndefined();
}
fun.updateRepaint();
} else if (arg0.isGeoList() && arg1.isNumberValue()) {
((GeoList) arg0).setSelectedIndex(
(int) Math.round(arg1.evaluateDouble()) - 1, true);
} else if (arg0.isIndependent() || arg0.isMoveable()) {
if (arg0.isGeoNumeric() && arg1 instanceof NumberValue) {
NumberValue num = (NumberValue) arg1;
((GeoNumeric) arg0).setValue(num.getDouble());
} else {
if (arg1.isGeoNumeric()
&& Double.isNaN(arg1.evaluateDouble())) {
// eg SetValue[a,?] for line
arg0.setUndefined();
} else {
arg0.set(arg1);
if (arg1.isChildOf(arg0)) {
arg0.resetDefinition();
}
}
}
arg0.updateRepaint();
} else if (arg1 instanceof NumberValue && arg0.isGeoNumeric()
&& arg0.getParentAlgorithm() instanceof SetRandomValue) {
// eg a = RandomBetween[0,10]
SetRandomValue algo = (SetRandomValue) arg0.getParentAlgorithm();
algo.setRandomValue(((NumberValue) arg1).getDouble());
} else if (arg1 instanceof NumberValue
&& arg0.getParentAlgorithm() instanceof AlgoDependentNumber) {
// eg a = random()
double val = ((NumberValue) arg1).getDouble();
if (val >= 0 && val <= 1) {
AlgoDependentNumber al = (AlgoDependentNumber) arg0
.getParentAlgorithm();
ExpressionNode en = al.getExpression();
if (en.getOperation().equals(Operation.RANDOM)) {
GeoNumeric num = ((GeoNumeric) al.getOutput()[0]);
ExpressionNode def = num.getDefinition();
num.setValue(val);
num.setDefinition(def);
num.updateRepaint();
}
}
}
}
}