001 /**
002 * =========================================
003 * LibFormula : a free Java formula library
004 * =========================================
005 *
006 * Project Info: http://reporting.pentaho.org/libformula/
007 *
008 * (C) Copyright 2006-2007, by Pentaho Corporation and Contributors.
009 *
010 * This library is free software; you can redistribute it and/or modify it under the terms
011 * of the GNU Lesser General Public License as published by the Free Software Foundation;
012 * either version 2.1 of the License, or (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016 * See the GNU Lesser General Public License for more details.
017 *
018 * You should have received a copy of the GNU Lesser General Public License along with this
019 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020 * Boston, MA 02111-1307, USA.
021 *
022 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023 * in the United States and other countries.]
024 *
025 *
026 * ------------
027 * $Id: DefaultComparator.java 3521 2007-10-16 10:55:14Z tmorgner $
028 * ------------
029 * (C) Copyright 2006-2007, by Pentaho Corporation.
030 */
031 package org.jfree.formula.typing;
032
033 import java.math.BigDecimal;
034
035 import org.jfree.formula.FormulaContext;
036 import org.jfree.util.ObjectUtilities;
037
038 /**
039 * Creation-Date: 03.11.2006, 16:15:28
040 *
041 * @author Thomas Morgner
042 */
043 public class DefaultComparator implements ExtendedComparator
044 {
045 private FormulaContext context;
046
047 public static final Integer LESS = new Integer(-1);
048
049 public static final Integer EQUAL = new Integer(0);
050
051 private static final Integer MORE = new Integer(1);
052
053 public DefaultComparator()
054 {
055 }
056
057 public void inititalize(final FormulaContext context)
058 {
059 this.context = context;
060 }
061
062 public boolean isEqual(final Type type1, final Object value1,
063 final Type type2, final Object value2)
064 {
065 // this is rather easy. If at least one of the types is a numeric,
066 // try to compare them as numbers. (And here it gets messy.)
067
068 final TypeRegistry typeRegistry = context.getTypeRegistry();
069 try
070 {
071 final Number number1 = typeRegistry.convertToNumber(type1, value1);
072 final Number number2 = typeRegistry.convertToNumber(type2, value2);
073 final BigDecimal bd1 = new BigDecimal(number1.toString());
074 final BigDecimal bd2 = new BigDecimal(number2.toString());
075 if (bd1.signum() != bd2.signum())
076 {
077 return false;
078 }
079
080 final BigDecimal result = bd1.subtract(bd2);
081 return (result.signum() == 0);
082 }
083 catch (TypeConversionException nfe)
084 {
085 // ignore ..
086 }
087
088 if (type1.isFlagSet(Type.TEXT_TYPE) || type2.isFlagSet(Type.TEXT_TYPE))
089 {
090 String text1 = null;
091 String text2 = null;
092 try
093 {
094 // Convert both values to text ..
095 text1 = typeRegistry.convertToText(type1, value1);
096 text2 = typeRegistry.convertToText(type2, value2);
097 }
098 catch (TypeConversionException nfe)
099 {
100 // ignore ..
101 }
102
103 if (text1 == null && text2 == null)
104 {
105 return true;
106 }
107 if (text1 == null || text2 == null)
108 {
109 return false;
110 }
111 return ObjectUtilities.equal(text1, text2);
112
113 }
114
115 // Fall back to Java's equals method and hope the best ..
116 return (ObjectUtilities.equal(value1, value2));
117 }
118
119 /**
120 * Returns null, if the types are not comparable and are not convertible at
121 * all.
122 *
123 * @param type1
124 * @param value1
125 * @param type2
126 * @param value2
127 * @return
128 */
129 public Integer compare(final Type type1, final Object value1,
130 final Type type2, final Object value2)
131 {
132 // this is rather easy. If at least one of the types is a numeric,
133 // try to compare them as numbers. (And here it gets messy.)
134 if (value1 == null && value2 == null)
135 {
136 return DefaultComparator.EQUAL;
137 }
138 if (value1 == null)
139 {
140 return DefaultComparator.LESS;
141 }
142 if (value2 == null)
143 {
144 return DefaultComparator.MORE;
145 }
146
147 // First, we try to compare both types directly. This is the least-expensive
148 // solution, as it does
149 // not include any conversion operations ..
150 if (type1.isFlagSet(Type.SCALAR_TYPE) && type2.isFlagSet(Type.SCALAR_TYPE))
151 {
152 // this is something else
153 if (value1 instanceof Comparable && value2 instanceof Comparable)
154 {
155 final Comparable c1 = (Comparable) value1;
156 try
157 {
158 final int result = c1.compareTo(value2);
159 if (result == 0)
160 {
161 return DefaultComparator.EQUAL;
162 }
163 else if (result > 0)
164 {
165 return DefaultComparator.MORE;
166 }
167 else
168 {
169 return DefaultComparator.LESS;
170 }
171 }
172 catch (Exception e)
173 {
174 // ignore any exception ..
175 }
176 }
177 }
178
179 // Next, we check the types on a numeric level.
180 final TypeRegistry typeRegistry = context.getTypeRegistry();
181 try
182 {
183 final Number number1 = typeRegistry.convertToNumber(type1, value1);
184 final Number number2 = typeRegistry.convertToNumber(type2, value2);
185 final BigDecimal bd1 = new BigDecimal(number1.toString());
186 final BigDecimal bd2 = new BigDecimal(number2.toString());
187
188 if (bd1.signum() != bd2.signum())
189 {
190 if (bd1.signum() < 0)
191 {
192 return DefaultComparator.LESS;
193 }
194 else if (bd1.signum() > 0)
195 {
196 return DefaultComparator.MORE;
197 }
198 }
199
200 final BigDecimal result = bd1.subtract(bd2);
201 if (result.signum() == 0)
202 {
203 return DefaultComparator.EQUAL;
204 }
205 if (result.signum() > 0)
206 {
207 return DefaultComparator.MORE;
208 }
209 return DefaultComparator.LESS;
210 }
211 catch (TypeConversionException nfe)
212 {
213 // Ignore ..
214 }
215
216 // And finally convert them to text and compare the text values ..
217 // Convert both values to text ..
218 String text1 = null;
219 String text2 = null;
220 try
221 {
222 text1 = typeRegistry.convertToText(type1, value1);
223 text2 = typeRegistry.convertToText(type2, value2);
224 }
225 catch (TypeConversionException e)
226 {
227 // failure here can be ignored.
228 }
229
230 if (text1 == null && text2 == null)
231 {
232 return DefaultComparator.EQUAL;
233 }
234 if (text1 == null)
235 {
236 return DefaultComparator.LESS;
237 }
238 if (text2 == null)
239 {
240 return DefaultComparator.MORE;
241 }
242
243 final int result = text1.compareTo(text2);
244 if (result == 0)
245 {
246 return DefaultComparator.EQUAL;
247 }
248 else if (result > 0)
249 {
250 return DefaultComparator.MORE;
251 }
252 else
253 {
254 return DefaultComparator.LESS;
255 }
256 }
257 }