001/*
002 *  Copyright 2001-2005 Stephen Colebourne
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.joda.time.field;
017
018import org.joda.time.DateTimeField;
019import org.joda.time.DateTimeFieldType;
020import org.joda.time.IllegalFieldValueException;
021
022/**
023 * General utilities that don't fit elsewhere.
024 * <p>
025 * FieldUtils is thread-safe and immutable.
026 *
027 * @author Stephen Colebourne
028 * @since 1.0
029 */
030public class FieldUtils {
031
032    /**
033     * Restricted constructor.
034     */
035    private FieldUtils() {
036        super();
037    }
038    
039    //------------------------------------------------------------------------
040    /**
041     * Negates the input throwing an exception if it can't negate it.
042     * 
043     * @param value  the value to negate
044     * @return the negated value
045     * @throws ArithmeticException if the value is Integer.MIN_VALUE
046     * @since 1.1
047     */
048    public static int safeNegate(int value) {
049        if (value == Integer.MIN_VALUE) {
050            throw new ArithmeticException("Integer.MIN_VALUE cannot be negated");
051        }
052        return -value;
053    }
054    
055    /**
056     * Add two values throwing an exception if overflow occurs.
057     * 
058     * @param val1  the first value
059     * @param val2  the second value
060     * @return the new total
061     * @throws ArithmeticException if the value is too big or too small
062     */
063    public static int safeAdd(int val1, int val2) {
064        int sum = val1 + val2;
065        // If there is a sign change, but the two values have the same sign...
066        if ((val1 ^ sum) < 0 && (val1 ^ val2) >= 0) {
067            throw new ArithmeticException
068                ("The calculation caused an overflow: " + val1 + " + " + val2);
069        }
070        return sum;
071    }
072    
073    /**
074     * Add two values throwing an exception if overflow occurs.
075     * 
076     * @param val1  the first value
077     * @param val2  the second value
078     * @return the new total
079     * @throws ArithmeticException if the value is too big or too small
080     */
081    public static long safeAdd(long val1, long val2) {
082        long sum = val1 + val2;
083        // If there is a sign change, but the two values have the same sign...
084        if ((val1 ^ sum) < 0 && (val1 ^ val2) >= 0) {
085            throw new ArithmeticException
086                ("The calculation caused an overflow: " + val1 + " + " + val2);
087        }
088        return sum;
089    }
090    
091    /**
092     * Subtracts two values throwing an exception if overflow occurs.
093     * 
094     * @param val1  the first value, to be taken away from
095     * @param val2  the second value, the amount to take away
096     * @return the new total
097     * @throws ArithmeticException if the value is too big or too small
098     */
099    public static long safeSubtract(long val1, long val2) {
100        long diff = val1 - val2;
101        // If there is a sign change, but the two values have different signs...
102        if ((val1 ^ diff) < 0 && (val1 ^ val2) < 0) {
103            throw new ArithmeticException
104                ("The calculation caused an overflow: " + val1 + " - " + val2);
105        }
106        return diff;
107    }
108    
109    /**
110     * Multiply two values throwing an exception if overflow occurs.
111     * 
112     * @param val1  the first value
113     * @param val2  the second value
114     * @return the new total
115     * @throws ArithmeticException if the value is too big or too small
116     * @since 1.2
117     */
118    public static int safeMultiply(int val1, int val2) {
119        long total = (long) val1 * (long) val2;
120        if (total < Integer.MIN_VALUE || total > Integer.MAX_VALUE) {
121            throw new ArithmeticException
122                ("The calculation caused an overflow: " + val1 + " * " + val2);
123        }
124        return (int) total;
125    }
126
127    /**
128     * Multiply two values throwing an exception if overflow occurs.
129     * 
130     * @param val1  the first value
131     * @param scalar  the second value
132     * @return the new total
133     * @throws ArithmeticException if the value is too big or too small
134     * @since 1.2
135     */
136    public static long safeMultiply(long val1, int scalar) {
137        switch (scalar) {
138        case -1:
139            return -val1;
140        case 0:
141            return 0L;
142        case 1:
143            return val1;
144        }
145        long total = val1 * scalar;
146        if (total / scalar != val1) {
147            throw new ArithmeticException
148                ("The calculation caused an overflow: " + val1 + " * " + scalar);
149        }
150        return total;
151    }
152
153    /**
154     * Multiply two values throwing an exception if overflow occurs.
155     * 
156     * @param val1  the first value
157     * @param val2  the second value
158     * @return the new total
159     * @throws ArithmeticException if the value is too big or too small
160     */
161    public static long safeMultiply(long val1, long val2) {
162        if (val2 == 1) {
163            return val1;
164        }
165        if (val2 == 0) {
166            return 0;
167        }
168        long total = val1 * val2;
169        if (total / val2 != val1) {
170            throw new ArithmeticException
171                ("The calculation caused an overflow: " + val1 + " * " + val2);
172        }
173        return total;
174    }
175    
176    /**
177     * Casts to an int throwing an exception if overflow occurs.
178     * 
179     * @param value  the value
180     * @return the value as an int
181     * @throws ArithmeticException if the value is too big or too small
182     */
183    public static int safeToInt(long value) {
184        if (Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE) {
185            return (int) value;
186        }
187        throw new ArithmeticException("Value cannot fit in an int: " + value);
188    }
189    
190    /**
191     * Multiply two values to return an int throwing an exception if overflow occurs.
192     * 
193     * @param val1  the first value
194     * @param val2  the second value
195     * @return the new total
196     * @throws ArithmeticException if the value is too big or too small
197     */
198    public static int safeMultiplyToInt(long val1, long val2) {
199        long val = FieldUtils.safeMultiply(val1, val2);
200        return FieldUtils.safeToInt(val);
201    }
202
203    //-----------------------------------------------------------------------
204    /**
205     * Verify that input values are within specified bounds.
206     * 
207     * @param value  the value to check
208     * @param lowerBound  the lower bound allowed for value
209     * @param upperBound  the upper bound allowed for value
210     * @throws IllegalFieldValueException if value is not in the specified bounds
211     */
212    public static void verifyValueBounds(DateTimeField field, 
213                                         int value, int lowerBound, int upperBound) {
214        if ((value < lowerBound) || (value > upperBound)) {
215            throw new IllegalFieldValueException
216                (field.getType(), new Integer(value),
217                 new Integer(lowerBound), new Integer(upperBound));
218        }
219    }
220
221    /**
222     * Verify that input values are within specified bounds.
223     * 
224     * @param value  the value to check
225     * @param lowerBound  the lower bound allowed for value
226     * @param upperBound  the upper bound allowed for value
227     * @throws IllegalFieldValueException if value is not in the specified bounds
228     * @since 1.1
229     */
230    public static void verifyValueBounds(DateTimeFieldType fieldType, 
231                                         int value, int lowerBound, int upperBound) {
232        if ((value < lowerBound) || (value > upperBound)) {
233            throw new IllegalFieldValueException
234                (fieldType, new Integer(value),
235                 new Integer(lowerBound), new Integer(upperBound));
236        }
237    }
238
239    /**
240     * Verify that input values are within specified bounds.
241     * 
242     * @param value  the value to check
243     * @param lowerBound  the lower bound allowed for value
244     * @param upperBound  the upper bound allowed for value
245     * @throws IllegalFieldValueException if value is not in the specified bounds
246     */
247    public static void verifyValueBounds(String fieldName,
248                                         int value, int lowerBound, int upperBound) {
249        if ((value < lowerBound) || (value > upperBound)) {
250            throw new IllegalFieldValueException
251                (fieldName, new Integer(value),
252                 new Integer(lowerBound), new Integer(upperBound));
253        }
254    }
255
256    /**
257     * Utility method used by addWrapField implementations to ensure the new
258     * value lies within the field's legal value range.
259     *
260     * @param currentValue the current value of the data, which may lie outside
261     * the wrapped value range
262     * @param wrapValue  the value to add to current value before
263     *  wrapping.  This may be negative.
264     * @param minValue the wrap range minimum value.
265     * @param maxValue the wrap range maximum value.  This must be
266     *  greater than minValue (checked by the method).
267     * @return the wrapped value
268     * @throws IllegalArgumentException if minValue is greater
269     *  than or equal to maxValue
270     */
271    public static int getWrappedValue(int currentValue, int wrapValue,
272                                      int minValue, int maxValue) {
273        return getWrappedValue(currentValue + wrapValue, minValue, maxValue);
274    }
275
276    /**
277     * Utility method that ensures the given value lies within the field's
278     * legal value range.
279     * 
280     * @param value  the value to fit into the wrapped value range
281     * @param minValue the wrap range minimum value.
282     * @param maxValue the wrap range maximum value.  This must be
283     *  greater than minValue (checked by the method).
284     * @return the wrapped value
285     * @throws IllegalArgumentException if minValue is greater
286     *  than or equal to maxValue
287     */
288    public static int getWrappedValue(int value, int minValue, int maxValue) {
289        if (minValue >= maxValue) {
290            throw new IllegalArgumentException("MIN > MAX");
291        }
292
293        int wrapRange = maxValue - minValue + 1;
294        value -= minValue;
295
296        if (value >= 0) {
297            return (value % wrapRange) + minValue;
298        }
299
300        int remByRange = (-value) % wrapRange;
301
302        if (remByRange == 0) {
303            return 0 + minValue;
304        }
305        return (wrapRange - remByRange) + minValue;
306    }
307
308    //-----------------------------------------------------------------------
309    /**
310     * Compares two objects as equals handling null.
311     * 
312     * @param object1  the first object
313     * @param object2  the second object
314     * @return true if equal
315     * @since 1.4
316     */
317    public static boolean equals(Object object1, Object object2) {
318        if (object1 == object2) {
319            return true;
320        }
321        if (object1 == null || object2 == null) {
322            return false;
323        }
324        return object1.equals(object2);
325    }
326
327}