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 csheets.core.Cell;
024    import csheets.core.Spreadsheet;
025    import csheets.core.Value;
026    import csheets.core.formula.BinaryOperator;
027    import csheets.core.formula.Expression;
028    import csheets.core.formula.Reference;
029    
030    /**
031     * A reference to a range of cells in a spreadsheet.
032     * @author Einar Pehrson
033     */
034    public 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    }