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.function;
017
018import java.math.BigDecimal;
019import java.math.MathContext;
020import java.util.concurrent.atomic.AtomicLong;
021
022import javax.money.MonetaryOperator;
023import javax.money.MonetaryQuery;
024
025/**
026 * This singleton class provides access to the predefined monetary functions.
027 * <p>
028 * The class is thread-safe, which is also true for all functions returned by
029 * this class.
030 *
031 * @author Anatole Tresch
032 */
033public final class MonetaryUtil {
034    /**
035     * defaulkt Math context used.
036     */
037    private static final MathContext DEFAULT_MATH_CONTEXT = initDefaultMathContext();
038    /**
039     * Shared reciprocal instance.
040     */
041    private static final Reciprocal RECIPROCAL = new Reciprocal();
042
043    /**
044     * The shared instance of this class.
045     */
046    private static final MinorPart MINORPART = new MinorPart();
047    /**
048     * SHared minor units class.
049     */
050    private static final MinorUnits MINORUNITS = new MinorUnits();
051    /**
052     * Shared major part instance.
053     */
054    private static final MajorPart MAJORPART = new MajorPart();
055    /**
056     * Shared major units instance.
057     */
058    private static final MajorUnits MAJORUNITS = new MajorUnits();
059
060    /**
061     * Private singleton constructor.
062     */
063    private MonetaryUtil() {
064        // Singleton constructor
065    }
066
067    /**
068     * Get {@link MathContext} for {@link Permil} instances.
069     *
070     * @return the {@link MathContext} to be used, by default
071     * {@link MathContext#DECIMAL64}.
072     */
073    private static MathContext initDefaultMathContext() {
074        // TODO Initialize default, e.g. by system properties, or better:
075        // classpath properties!
076        return MathContext.DECIMAL64;
077    }
078
079    /**
080     * Return a {@link MonetaryOperator} realizing the reciprocal value of
081     * {@code f(R) = 1/R}.
082     *
083     * @return the reciprocal operator, never {@code null}
084     */
085    public static MonetaryOperator reciprocal() {
086        return RECIPROCAL;
087    }
088
089    /**
090     * Factory method creating a new instance with the given {@code BigDecimal} permil value.
091     *
092     * @param decimal the decimal value of the permil operator being created.
093     * @return a new  {@code Permil} operator
094     */
095    public static MonetaryOperator permil(BigDecimal decimal) {
096        return new Permil(decimal);
097    }
098
099    /**
100     * Factory method creating a new instance with the given {@code Number} permil value.
101     *
102     * @param number the number value of the permil operator being created.
103     * @return a new  {@code Permil} operator
104     */
105    public static MonetaryOperator permil(Number number) {
106        return permil(number, DEFAULT_MATH_CONTEXT);
107    }
108
109    /**
110     * Factory method creating a new instance with the given {@code Number} permil value.
111     *
112     * @param number the number value of the permil operator being created.
113     * @return a new  {@code Permil} operator
114     */
115    public static MonetaryOperator permil(Number number, MathContext mathContext) {
116        return new Permil(getBigDecimal(number, mathContext));
117    }
118
119    /**
120     * Factory method creating a new instance with the given {@code BigDecimal} percent value.
121     *
122     * @param decimal the decimal value of the percent operator being created.
123     * @return a new  {@code Percent} operator
124     */
125    public static MonetaryOperator percent(BigDecimal decimal) {
126        return new Percent(decimal); // TODO caching, e.g. array for 1-100 might
127        // work.
128    }
129
130    /**
131     * Factory method creating a new instance with the given {@code Number} percent value.
132     *
133     * @param number the number value of the percent operator being created.
134     * @return a new  {@code Percent} operator
135     */
136    public static MonetaryOperator percent(Number number) {
137        return percent(getBigDecimal(number, DEFAULT_MATH_CONTEXT));
138    }
139
140    /**
141     * Access the shared instance of {@link MinorPart} for use.
142     *
143     * @return the shared instance, never {@code null}.
144     */
145    public static MonetaryOperator minorPart() {
146        return MINORPART;
147    }
148
149    /**
150     * Access the shared instance of {@link MajorPart} for use.
151     *
152     * @return the shared instance, never {@code null}.
153     */
154    public static MonetaryOperator majorPart() {
155        return MAJORPART;
156    }
157
158    /**
159     * Access the shared instance of {@link MinorUnits} for use.
160     *
161     * @return the shared instance, never {@code null}.
162     */
163    public static MonetaryQuery<Long> minorUnits() {
164        return MINORUNITS;
165    }
166
167    /**
168     * Access the shared instance of {@link MajorUnits} for use.
169     *
170     * @return the shared instance, never {@code null}.
171     */
172    public static MonetaryQuery<Long> majorUnits() {
173        return MAJORUNITS;
174    }
175
176    /**
177     * Converts to {@link BigDecimal}, if necessary, or casts, if possible.
178     *
179     * @param num         The {@link Number}
180     * @param mathContext the {@link MathContext}
181     * @return the {@code number} as {@link BigDecimal}
182     */
183    private static BigDecimal getBigDecimal(Number num,
184                                            MathContext mathContext) {
185        if (num instanceof BigDecimal) {
186            return (BigDecimal) num;
187        }
188        if (num instanceof Long || num instanceof Integer
189                || num instanceof Byte || num instanceof AtomicLong) {
190            return BigDecimal.valueOf(num.longValue());
191        }
192        if (num instanceof Float || num instanceof Double) {
193            return new BigDecimal(num.toString());
194        }
195        try {
196            // Avoid imprecise conversion to double value if at all possible
197            return new BigDecimal(num.toString(), mathContext);
198        } catch (NumberFormatException ignored) {
199        }
200        return BigDecimal.valueOf(num.doubleValue());
201    }
202}