001    /*
002     * Copyright (c) 2005 Peter Palotas, Fredrik Johansson, Einar Pehrson,
003     * Sebastian Kekkonen, Lars Magnus Lång, 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     */
023    package csheets.ext.assertion;
024    
025    import java.io.Serializable;
026    import java.util.Iterator;
027    
028    import csheets.core.IllegalValueTypeException;
029    import 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    */
035    public 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    }