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 csheets.core.Cell;
024import csheets.core.Spreadsheet;
025import csheets.core.Value;
026import csheets.core.formula.BinaryOperator;
027import csheets.core.formula.Expression;
028import csheets.core.formula.Reference;
029
030/**
031 * A reference to a range of cells in a spreadsheet.
032 * @author Einar Pehrson
033 */
034public class RangeReference implements BinaryOperator {
035
036        /** The unique version identifier used for serialization */
037        private static final long serialVersionUID = 8527083457981256682L;
038
039        /**
040         * Creates a new range reference operator.
041         */
042        public RangeReference() {}
043
044        public Value applyTo(Expression leftOperand, Expression rightOperand) {
045                // Casts operands
046                if (!(leftOperand instanceof CellReference && rightOperand instanceof CellReference))
047                        return new Value(new IllegalArgumentException("#OPERAND!"));
048                CellReference ref1 = (CellReference)leftOperand;
049                CellReference ref2 = (CellReference)rightOperand;
050
051                // Fetches the cells
052                Cell[][] cells;
053                try {
054                        cells = getCells(ref1, ref2);
055                } catch (IllegalArgumentException e) {
056                        return new Value(e);
057                }
058
059                // Fetches the values
060                Value[][] values = new Value[cells.length][cells[0].length];
061                for (int row = 0; row < cells.length; row++)
062                        for (int column = 0; column < cells[row].length; column++)
063                                values[row][column] = cells[row][column].getValue();
064                return new Value(values);
065        }
066
067        /**
068         * Returns the range of cells formed by the two cell references.
069         * @param reference1 the first reference
070         * @param reference2 the other reference
071         * @return an array of the cells that constitute the range
072         */
073        public Cell[][] getCells(Reference reference1, Reference reference2) {
074                // Casts operands
075                if (!(reference1 instanceof CellReference && reference2 instanceof CellReference))
076                        throw new IllegalArgumentException("#OPERAND!");
077                CellReference ref1 = (CellReference)reference1;
078                CellReference ref2 = (CellReference)reference2;
079
080                // Checks that the references point to cells in the same spreadsheet
081                Spreadsheet spreadsheet = ref1.getCell().getSpreadsheet();
082                if (spreadsheet != ref2.getCell().getSpreadsheet())
083                        throw new IllegalArgumentException("#3DREF!");
084
085                // Fetches coordinates
086                int column1 = ref1.getCell().getAddress().getColumn();
087                int column2 = ref2.getCell().getAddress().getColumn();
088                int row1 = ref1.getCell().getAddress().getRow();
089                int row2 = ref2.getCell().getAddress().getRow();
090                int startColumn = column1 <= column2 ? column1 : column2;
091                int endColumn = column1 <= column2 ? column2 : column1;
092                int startRow = row1 <= row2 ? row1 : row2;
093                int endRow = row1 <= row2 ? row2 : row1;
094
095                // Builds the matrix
096                Cell[][] matrix = new Cell
097                        [endRow - startRow + 1]
098                        [endColumn - startColumn + 1];
099                for (int row = 0; row < matrix.length; row++)
100                        for (int column = 0; column < matrix[row].length; column++)
101                                matrix[row][column] = spreadsheet.getCell
102                                        (column + startColumn, row + startRow);
103                return matrix;
104        }
105
106        public String getIdentifier() {
107                return ":";
108        }
109
110        public Value.Type getOperandValueType() {
111                return Value.Type.NUMERIC;
112        }
113
114        public String toString() {
115                return getIdentifier();
116        }
117}