001/*
002 * ModeShape (http://www.modeshape.org)
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.modeshape.common.math;
017
018import java.math.BigDecimal;
019import java.util.Comparator;
020import java.util.Random;
021import java.util.concurrent.TimeUnit;
022import org.modeshape.common.annotation.Immutable;
023
024/**
025 * The {@link MathOperations math operations} for {@link Duration}s.
026 */
027@Immutable
028public class DurationOperations implements MathOperations<Duration>, Comparator<Duration> {
029
030    @Override
031    public Class<Duration> getOperandClass() {
032        return Duration.class;
033    }
034
035    @Override
036    public Duration add( Duration value1,
037                         Duration value2 ) {
038        if (value1 == null) return value2 != null ? value2 : createZeroValue();
039        if (value2 == null) return value1;
040        return value1.add(value2);
041    }
042
043    @Override
044    public Duration subtract( Duration value1,
045                              Duration value2 ) {
046        if (value1 == null) return negate(value2);
047        if (value2 == null) return value1;
048        return value1.subtract(value2);
049    }
050
051    @Override
052    public Duration multiply( Duration value1,
053                              Duration value2 ) {
054        if (value1 == null || value2 == null) return createZeroValue();
055        return value1.multiply(value2.longValue());
056    }
057
058    @Override
059    public double divide( Duration value1,
060                          Duration value2 ) {
061        if (value1 == null || value2 == null) throw new IllegalArgumentException();
062        return value1.divide(value2);
063    }
064
065    @Override
066    public Duration negate( Duration value ) {
067        if (value == null) return createZeroValue();
068        return value.multiply(value.longValue() * -1);
069    }
070
071    @Override
072    public Duration increment( Duration value ) {
073        if (value == null) return createZeroValue();
074        return value.add(1l, TimeUnit.NANOSECONDS);
075    }
076
077    @Override
078    public Duration maximum( Duration value1,
079                             Duration value2 ) {
080        if (value1 == null) return value2;
081        if (value2 == null) return value1;
082        return new Duration(Math.max(value1.longValue(), value2.longValue()));
083    }
084
085    @Override
086    public Duration minimum( Duration value1,
087                             Duration value2 ) {
088        if (value1 == null) return value2;
089        if (value2 == null) return value1;
090        return new Duration(Math.min(value1.longValue(), value2.longValue()));
091    }
092
093    @Override
094    public int compare( Duration value1,
095                        Duration value2 ) {
096        if (value1 == null) return value2 != null ? -1 : 0;
097        if (value2 == null) return 1;
098        return value1.compareTo(value2);
099    }
100
101    @Override
102    public BigDecimal asBigDecimal( Duration value ) {
103        return value != null ? value.toBigDecimal() : null;
104    }
105
106    @Override
107    public Duration fromBigDecimal( BigDecimal value ) {
108        return value != null ? new Duration(value.longValue()) : null;
109    }
110
111    @Override
112    public Duration createZeroValue() {
113        return new Duration(0l);
114    }
115
116    @Override
117    public Duration create( int value ) {
118        return new Duration(value);
119    }
120
121    @Override
122    public Duration create( long value ) {
123        return new Duration(value);
124    }
125
126    @Override
127    public Duration create( double value ) {
128        return new Duration((long)value);
129    }
130
131    @Override
132    public double sqrt( Duration value ) {
133        return Math.sqrt(value.longValue());
134    }
135
136    @Override
137    public Comparator<Duration> getComparator() {
138        return this;
139    }
140
141    @Override
142    public Duration random( Duration minimum,
143                            Duration maximum,
144                            Random rng ) {
145        Duration difference = subtract(maximum, minimum);
146        return new Duration(minimum.getDuratinInNanoseconds() + rng.nextInt(difference.intValue()));
147    }
148
149    @Override
150    public double doubleValue( Duration value ) {
151        return value.doubleValue();
152    }
153
154    @Override
155    public float floatValue( Duration value ) {
156        return value.floatValue();
157    }
158
159    @Override
160    public int intValue( Duration value ) {
161        return value.intValue();
162    }
163
164    @Override
165    public long longValue( Duration value ) {
166        return value.longValue();
167    }
168
169    @Override
170    public short shortValue( Duration value ) {
171        return value.shortValue();
172    }
173
174    @Override
175    public int getExponentInScientificNotation( Duration value ) {
176        long v = Math.abs(value.getDuratinInNanoseconds());
177        int exp = 0;
178        if (v > 1l) {
179            while (v >= 10l) {
180                v /= 10l;
181                ++exp;
182            }
183        }
184        return exp;
185    }
186
187    @Override
188    public Duration roundUp( Duration durationValue,
189                             int decimalShift ) {
190        long value = durationValue.longValue();
191        if (value == 0) return new Duration(0l);
192        if (decimalShift >= 0) return durationValue;
193        long shiftedValueP5 = Math.abs(value);
194        for (int i = 0; i != (-decimalShift - 1); ++i)
195            shiftedValueP5 /= 10l;
196        shiftedValueP5 += 5l;
197        long shiftedValue = shiftedValueP5 / 10l;
198        if (shiftedValue * 10l - shiftedValueP5 >= 5) ++shiftedValue;
199        shiftedValue *= Long.signum(value);
200        for (int i = 0; i != -decimalShift; ++i)
201            shiftedValue *= 10l;
202        return new Duration(shiftedValue);
203    }
204
205    @Override
206    public Duration roundDown( Duration durationValue,
207                               int decimalShift ) {
208        long value = durationValue.longValue();
209        if (value == 0) return new Duration(0l);
210        if (decimalShift >= 0) return durationValue;
211        long shiftedValue = Math.abs(value);
212        for (int i = 0; i != -decimalShift; ++i)
213            shiftedValue /= 10l;
214        shiftedValue *= Long.signum(value);
215        for (int i = 0; i != -decimalShift; ++i)
216            shiftedValue *= 10l;
217        return new Duration(shiftedValue);
218    }
219
220    @Override
221    public Duration keepSignificantFigures( Duration value,
222                                            int numSigFigs ) {
223        if (numSigFigs < 0) return value;
224        if (numSigFigs == 0) return new Duration(0l);
225        int currentExp = getExponentInScientificNotation(value);
226        int decimalShift = -currentExp + numSigFigs - 1;
227        return roundUp(value, decimalShift);
228    }
229}