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;
022
023import java.util.SortedSet;
024import java.util.TreeSet;
025
026import csheets.core.Cell;
027import csheets.core.IllegalValueTypeException;
028import csheets.core.Value;
029import csheets.core.formula.util.CircularReferenceException;
030import csheets.core.formula.util.CircularReferenceFinder;
031import csheets.core.formula.util.ExpressionVisitor;
032import csheets.core.formula.util.ExpressionVisitorException;
033import csheets.core.formula.util.ReferenceFetcher;
034
035/**
036 * A formula in a cell.
037 * @author Einar Pehrson
038 */
039public class Formula implements Expression {
040
041        /** The unique version identifier used for serialization */
042        private static final long serialVersionUID = 7127589370042533160L;
043
044        /** The cell to which the formula belongs */
045        private Cell cell;
046
047        /** The expression of the formula */
048        private Expression expression;
049
050        /** Returns the references in the expression */
051        private SortedSet<Reference> references;
052
053        /**
054         * Creates a new formula.
055         * @param cell the cell to which the formula belongs
056         * @param expression the expression in the formula
057         */
058        public Formula(Cell cell, Expression expression) {
059                // Stores members
060                this.cell = cell;
061                this.expression = expression;
062        }
063
064        public Value evaluate() throws IllegalValueTypeException {
065                if (!hasCircularReference())
066                        return expression.evaluate();
067                else
068                        return new Value(new CircularReferenceException(this));
069        }
070
071        public Object accept(ExpressionVisitor visitor) {
072                return expression.accept(visitor);
073        }
074
075        /**
076         * Returns the cell to which the formula belongs.
077         * @return the cell to which the formula belongs
078         */
079        public Cell getCell() {
080                return cell;
081        }
082
083        /**
084         * Returns the expression in the formula.
085         * @return the expression in the formula
086         */
087        public Expression getExpression() {
088                return expression;
089        }
090
091        /**
092         * Returns the references in the expression.
093         * @return the references in the expression
094         */
095        public SortedSet<Reference> getReferences() {
096                if (references == null)
097                        references = new ReferenceFetcher().getReferences(expression);
098                return new TreeSet<Reference>(references);
099        }
100
101        /**
102         * Checks if the given formula has any circular references.
103         * @throws CircularReferenceException if the formula contains any circular references
104         */
105        public boolean hasCircularReference() {
106                try {
107                        new CircularReferenceFinder().check(this);
108                } catch (ExpressionVisitorException e) {
109                        return true;
110                }
111                return false;
112        }
113
114        /**
115         * Returns a string representation of the formula.
116         * @return a string representation of the formula
117         */
118        public String toString() {
119                return expression.toString();
120        }
121}