001/**
002 * Copyright (c) 2012, 2014, Credit Suisse (Anatole Tresch), Werner Keil and others by the @author tag.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005 * use this file except in compliance with the License. You may obtain a copy of
006 * 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, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations under
014 * the License.
015 */
016package org.javamoney.moneta.spi;
017
018import java.math.BigDecimal;
019import java.math.MathContext;
020import java.util.Objects;
021
022import javax.money.MonetaryAmount;
023import javax.money.NumberValue;
024
025/**
026 * Default implementation of {@link NumberValue} based on {@link BigDecimal}.
027 * 
028 * @author Anatole Tresch
029 * @author Werner Keil
030 */
031public final class DefaultNumberValue extends NumberValue {
032        
033        /**
034         * serialVersionUID.
035         */
036        private static final long serialVersionUID = 1L;
037        /** The numeric value. */
038        private final Number number;
039
040    /**
041     * The value 1, with a scale of 0.<br>
042     * Backed by {@link BigDecimal#ONE}
043     *
044     * @since  0.8
045     */
046        public static final NumberValue ONE = new DefaultNumberValue(BigDecimal.ONE);
047        
048        public DefaultNumberValue(Number number) {
049        this.number = Objects.requireNonNull(number, "Number required");
050    }
051        
052        /**
053         * Creates a new instance of {@link NumberValue}, using the given number.
054         * 
055         * @param number
056         *            The numeric part, not null.
057         * @return A new instance of {@link NumberValue}.
058         */
059        public static NumberValue of(Number number) {
060                return new DefaultNumberValue(number);
061        }
062
063        /*
064         * (non-Javadoc)
065         * @see javax.money.NumberValue#getNumberType()
066         */
067        @Override
068        public Class<?> getNumberType() {
069                return this.number.getClass();
070        }
071
072        /*
073         * (non-Javadoc)
074         * @see javax.money.NumberValue#getPrecision()
075         */
076        @Override
077        public int getPrecision() {
078                return numberValue(BigDecimal.class).precision();
079        }
080
081        /*
082         * (non-Javadoc)
083         * @see javax.money.NumberValue#getScale()
084         */
085        @Override
086        public int getScale() {
087                return getBigDecimal(number).scale();
088        }
089
090        /*
091         * (non-Javadoc)
092         * @see javax.money.NumberValue#getIntValue()
093         */
094        @Override
095        public int intValue() {
096                return this.number.intValue();
097        }
098
099        /*
100         * (non-Javadoc)
101         * @see javax.money.NumberValue#getIntValueExact()
102         */
103        @Override
104        public int intValueExact() {
105                return getBigDecimal(number).intValueExact();
106        }
107
108        /*
109         * (non-Javadoc)
110         * @see javax.money.NumberValue#getLongValue()
111         */
112        @Override
113        public long longValue() {
114                return this.number.longValue();
115        }
116
117        /*
118         * (non-Javadoc)
119         * @see javax.money.NumberValue#getLongValueExact()
120         */
121        @Override
122        public long longValueExact() {
123                return getBigDecimal(number).longValueExact();
124        }
125
126        /*
127         * (non-Javadoc)
128         * @see javax.money.NumberValue#getFloatValue()
129         */
130        @Override
131        public float floatValue() {
132                return this.number.floatValue();
133        }
134
135        /*
136         * (non-Javadoc)
137         * @see javax.money.NumberValue#getDoubleValue()
138         */
139        @Override
140        public double doubleValue() {
141                return this.number.doubleValue();
142        }
143
144        /*
145         * (non-Javadoc)
146         * @see javax.money.NumberValue#getDoubleValueExact()
147         */
148        @Override
149        public double doubleValueExact() {
150                double d = this.number.doubleValue();
151                if (d == Double.NEGATIVE_INFINITY || d == Double.POSITIVE_INFINITY) {
152                        throw new ArithmeticException("Unable to convert to double: "
153                                        + this.number);
154                }
155                return d;
156        }
157
158    /*
159     * (non-Javadoc)
160         * @see javax.money.NumberValue#getAmountFractionNumerator()
161     */
162    @Override
163    public long getAmountFractionNumerator(){
164        BigDecimal bd = getBigDecimal(number).remainder(BigDecimal.ONE);
165        return bd.movePointRight(getScale()).longValueExact();
166    }
167
168    /*
169     * (non-Javadoc)
170         * @see javax.money.NumberValue#getAmountFractionDenominator()
171     */
172    @Override
173    public long getAmountFractionDenominator(){
174        return BigDecimal.valueOf(10).pow(getScale()).longValueExact();
175    }
176
177        /*
178         * (non-Javadoc)
179         * @see javax.money.NumberValue#getNumberValue(java.lang.Class)
180         */
181        @Override
182        public <T extends Number> T numberValue(Class<T> numberType) {
183                return ConvertNumberValue.of(numberType, number);
184        }
185
186    /*
187     * (non-Javadoc)
188         * @see javax.money.NumberValue#round(java.math.MathContext)
189         */
190    @Override
191    public NumberValue round(MathContext mathContext) {
192        if (this.number instanceof BigDecimal) {
193            return new DefaultNumberValue(((BigDecimal) this.number).round(mathContext));
194        }
195        return new DefaultNumberValue(new BigDecimal(this.number.toString()).round(mathContext));
196    }
197
198    /*
199     * (non-Javadoc)
200     * @see javax.money.NumberValue#numberValueExact(java.lang.Class)
201     */
202    @Override
203        public <T extends Number> T numberValueExact(Class<T> numberType) {
204                return ConvertNumberValue.ofExact(numberType, number);
205        }
206
207        /*
208         * (non-Javadoc)
209         * @see java.lang.Object#toString()
210         */
211        @Override
212        public String toString() {
213                return String.valueOf(number);
214        }
215
216        /**
217         * Creates a {@link BigDecimal} from the given {@link Number} doing the valid conversion
218         * depending the type given.
219         * 
220         * @param num
221         *            the number type
222         * @return the corresponding {@link BigDecimal}
223         */
224        protected static BigDecimal getBigDecimal(Number num) {
225                return ConvertBigDecimal.of(num);
226        }
227
228}