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 */ 021package csheets.core.formula.lang; 022 023import java.util.LinkedList; 024import java.util.List; 025 026import csheets.core.IllegalValueTypeException; 027import csheets.core.Value; 028import csheets.core.formula.BinaryOperator; 029import csheets.core.formula.Expression; 030import csheets.core.formula.Function; 031import csheets.core.formula.FunctionParameter; 032import 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 */ 040public 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}