001/*
002 * Copyright (c) 2005 Peter Palotas, Fredrik Johansson, Einar Pehrson,
003 * Sebastian Kekkonen, Lars Magnus Lang, Malin Johansson and Sofia Nilsson
004 *
005 * This file is part of
006 * CleanSheets Extension for Assertions
007 *
008 * CleanSheets Extension for Assertions is free software; you can
009 * redistribute it and/or modify it under the terms of the GNU General Public
010 * License as published by the Free Software Foundation; either version 2 of
011 * the License, or (at your option) any later version.
012 *
013 * CleanSheets Extension for Assertions is distributed in the hope that
014 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
015 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016 * See the GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with CleanSheets Extension for Assertions; if not, write to the
020 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
021 * Boston, MA  02111-1307  USA
022 */
023package csheets.ext.assertion;
024
025import java.io.Serializable;
026import java.util.Iterator;
027
028import csheets.core.IllegalValueTypeException;
029import csheets.core.Value;
030
031/** Abstract class representing an assertion. This class contains the common
032        data and functionality for assertion (USAssertion and SGAssertion).
033        @author Peter Palotas
034*/
035public abstract class Assertion implements Serializable {
036
037        /** Represents the intervals of allowed values for this assertion. */
038        protected MultiInterval intervals = new MultiInterval();
039
040        /** Indicates wether only integer values are allowed */
041        protected boolean isInteger;
042
043        /** Enumeration indicating the result of a validation of a value. */
044        public enum Result {
045                /** Indicates the assertion succeeded. */
046                OK,
047                /** Indicates the assertion failed. */
048                FAILED,
049                /** Indicates there was no data to validate. */
050                NO_DATA,
051                /** Indicates the assertion failed because the data was not a number. */
052                NAN
053        };
054
055        /**
056         * The possible results when two assertions are compared.
057         * @see AssertableCell#assertAssertions()
058         */
059        public enum ComparisonResult {
060                /** Denotes that the assertions on this cell are okay */
061                OK,
062                /** Denotes that the user supplied assertion and the system generated assertion
063                    associated with this cell do <i>not</i> represent the same range(s) of values. */
064                NON_EQUAL,
065                /** Denotes that the system generated assertion for this cell can not be generated because the
066                    formula in this cell contains a possible illegal mathematic operation. Such as division by
067                    zero or calculations with an imaginary result. (Due to either an error in the formula
068                    itself or in the assertion(s) of its precedents. */
069                ILLEGAL_INTERVAL {
070                        /** A message describing the error */
071                        private String errorMsg;
072                        
073                        public void setErrorMsg(String msg) {
074                                errorMsg = msg;
075                        }
076                        
077                        public String getErrorMsg() {
078                                return errorMsg;
079                        }
080                };
081                public void setErrorMsg(String msg) {}
082
083                public String getErrorMsg() {
084                        return null;
085                }
086        };
087
088        /** Returns an iterator over the intervals representing all allowed values in
089            this assertion. Note that this iterator cannot be used to modify the underlying
090            collection.
091            @return Returns an iterator over the intervals representing all allowed values in
092            this assertion. */
093        public Iterator<Interval> getIntervalIterator() {
094                return intervals.iterator();
095        }
096
097        /** Returns the MultiInterval specifying the valid values for this assertion.
098                @return the MultiInterval specifying the valid values for this assertion.*/
099        public MultiInterval getMultiInterval() {
100                return intervals;
101        }
102
103        /** Checks if this assertion allows only integer values.
104                @return <code>true</code> if this assertion will validate only integer values
105                            successfully, and <code>false</code> otherwise. */
106        public boolean allowsIntegersOnly() {
107                return isInteger;
108        }
109
110        /**
111         * Checks if the current assertion holds for the given value. The value
112         * may be any object.
113         * @param value An arbritrary object. The value the assertion will be verified
114         *                              against will be retrieved from the object using its <code>toString()</code> method.
115         * @return <ul>
116                                <li><code>Result.NO_DATA</code> if <code>value</code> is <code>null</code> or
117                                        <code>value.toString()</code> returns an empty string.
118                                <li><code>Result.NAN</code> if the string returned by <code>value.toString()</code>
119                                        does not represent a number parsable by <code>Double.parseDouble()</code>.
120                                <li><code>Result.OK</code> if assertion holds for the value.
121                                <li><code>Result.FAILED</code> if the assertion failed for the value, unless
122                                        one of the reasons above.
123                        </ul>
124         */
125        public Result validate(Value value) {
126                if (value.toAny() == null)
127                        return Result.NO_DATA;
128                try {
129                        return validate(value.toDouble());
130                } catch (IllegalValueTypeException e) {
131                        return Result.NAN;
132                }
133
134        }
135        /**
136         * Checks if the current assertion holds for the given value
137         * @return <ul>
138                           <li><code>Result.OK</code> if the assertion holds for the value,
139         *                 <li><code>Result.NAN</code> if <code>value == Double.NaN</code>
140         *                 <li><code>Result.FAILED</code> otherwise.
141                           </ul>
142         */
143        public Result validate(double value) {
144                if (Double.isNaN(value))
145                        return Result.NAN;
146
147                // Check if the isInteger criterion holds
148                if (isInteger && (Math.ceil(value) != Math.floor(value)))
149                {
150                        return Result.FAILED;
151                }
152
153                return intervals.contains(value) ? Result.OK : Result.FAILED;
154
155        }
156
157        public boolean equals(Object o) {
158                if (o == null)
159                        return false;
160
161                if (!(o instanceof Assertion))
162                        return false;
163
164                Assertion a = (Assertion)o;
165
166                return intervals.equals(a.intervals);
167        }
168
169        public String toString() {
170                String s = "";
171                for (Iterator<Interval> iter = intervals.iterator(); iter.hasNext(); ) {
172                        Interval i = iter.next();
173                        s += i.toString();
174                        if (iter.hasNext())
175                                s += " or ";
176                }
177                return s;
178        }
179
180}