001 /*
002 * Copyright (c) 2005 Einar Pehrson <einar@pehrson.nu>.
003 *
004 * This file is part of
005 * CleanSheets - a spreadsheet application for the Java platform.
006 *
007 * CleanSheets is free software; you can redistribute it and/or modify
008 * it under the terms of the GNU General Public License as published by
009 * the Free Software Foundation; either version 2 of the License, or
010 * (at your option) any later version.
011 *
012 * CleanSheets is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with CleanSheets; if not, write to the Free Software
019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020 */
021 package csheets.core.formula.lang;
022
023 import java.util.LinkedList;
024 import java.util.List;
025
026 import csheets.core.IllegalValueTypeException;
027 import csheets.core.Value;
028 import csheets.core.formula.BinaryOperator;
029 import csheets.core.formula.Expression;
030 import csheets.core.formula.Function;
031 import csheets.core.formula.FunctionParameter;
032 import csheets.core.formula.Literal;
033
034 /**
035 * A function that emulates a looping statement, where each cell in a given
036 * range that satisfy a given condition, or each corresponding cell in
037 * another range, are passed to a function.
038 * @author Einar Pehrson
039 */
040 public class Do implements Function {
041
042 /** Parameters: function, function range, condition and condition range */
043 public static final FunctionParameter[] parameters = new FunctionParameter[] {
044 new FunctionParameter(Value.Type.TEXT, "Function", false,
045 "The name of the function to which arguments are to be passed."),
046 new FunctionParameter(Value.Type.MATRIX, "Function Range", false,
047 "The range from which to select arguments"),
048 new FunctionParameter(Value.Type.TEXT, "Conditional Operator", false,
049 "The binary operator to use in the condition when selecting arguments."),
050 new FunctionParameter(Value.Type.UNDEFINED, "Conditional Argument", false,
051 "The right operand to use in the condition when selecting arguments."),
052 new FunctionParameter(Value.Type.MATRIX, "Condition Range", true,
053 "The range to use when checking conditions.")
054 };
055
056 /**
057 * Creates a new instance of the DO function.
058 */
059 public Do() {}
060
061 public String getIdentifier() {
062 return "DO";
063 }
064
065 public Value applyTo(Expression[] arguments) throws IllegalValueTypeException {
066 // Check that the function and conditional operator exist
067 Function function = null;
068 BinaryOperator condOp = null;
069 try {
070 function = Language.getInstance().getFunction(arguments[0].evaluate().toText());
071 condOp = Language.getInstance().getBinaryOperator(arguments[2].evaluate().toText());
072 } catch (UnknownElementException e) {
073 return new Value(e);
074 }
075
076 // Check that the range dimensions agree
077 Value[][] opRange = arguments[1].evaluate().toMatrix();
078 Value[][] condRange = opRange;
079 if (arguments.length == 5) {
080 condRange = arguments[4].evaluate().toMatrix();
081 if (opRange.length != condRange.length || opRange[0].length != condRange[0].length)
082 return new Value(new IllegalArgumentException("Range dimensions must be equal"));
083 }
084
085 // Collects arguments
086 Literal condArg = new Literal(arguments[3].evaluate());
087 List<Literal> accepted = new LinkedList<Literal>();
088 for (int row = 0; row < condRange.length; row++)
089 for (int column = 0; column < condRange[row].length; column++)
090 if (condOp.applyTo(new Literal(condRange[row][column]), condArg)
091 .toBoolean())
092 accepted.add(new Literal(opRange[row][column]));
093
094 // Evaluates function call and returns
095 if (accepted.size() > 0)
096 return function.applyTo(accepted.toArray(new Expression[accepted.size()]));
097 else
098 return new Value();
099 }
100
101 public FunctionParameter[] getParameters() {
102 return parameters;
103 }
104
105 public boolean isVarArg() {
106 return false;
107 }
108 }