001/*
002 * CREDIT SUISSE IS WILLING TO LICENSE THIS SPECIFICATION TO YOU ONLY UPON THE
003 * CONDITION THAT YOU ACCEPT ALL OF THE TERMS CONTAINED IN THIS AGREEMENT.
004 * PLEASE READ THE TERMS AND CONDITIONS OF THIS AGREEMENT CAREFULLY. BY
005 * DOWNLOADING THIS SPECIFICATION, YOU ACCEPT THE TERMS AND CONDITIONS OF THE
006 * AGREEMENT. IF YOU ARE NOT WILLING TO BE BOUND BY IT, SELECT THE "DECLINE"
007 * BUTTON AT THE BOTTOM OF THIS PAGE. Specification: JSR-354 Money and Currency
008 * API ("Specification") Copyright (c) 2012-2013, Credit Suisse All rights
009 * reserved.
010 */
011package org.javamoney.moneta.function;
012
013import java.math.BigDecimal;
014import java.math.MathContext;
015import java.util.concurrent.atomic.AtomicLong;
016
017import javax.money.MonetaryOperator;
018import javax.money.MonetaryQuery;
019
020/**
021 * This singleton class provides access to the predefined monetary functions.
022 * <p>
023 * The class is thread-safe, which is also true for all functions returned by
024 * this class.
025 * 
026 * @author Anatole Tresch
027 */
028public final class MonetaryFunctions {
029        /** defaulkt Math context used. */
030        private static final MathContext DEFAULT_MATH_CONTEXT = initDefaultMathContext();
031        /** Shared reciprocal instance. */
032        private static final Reciprocal RECIPROCAL = new Reciprocal();
033
034        /**
035         * The shared instance of this class.
036         */
037        private static final MinorPart MINORPART = new MinorPart();
038        /** SHared minor units class. */
039        private static final MinorUnits MINORUNITS = new MinorUnits();
040        /** Shared major part instance. */
041        private static final MajorPart MAJORPART = new MajorPart();
042        /** Shared major units instance. */
043        private static final MajorUnits MAJORUNITS = new MajorUnits();
044
045        /**
046         * Private singleton constructor.
047         */
048        private MonetaryFunctions() {
049                // Singleton constructor
050        }
051
052        /**
053         * Get {@link MathContext} for {@link Permil} instances.
054         * 
055         * @return the {@link MathContext} to be used, by default
056         *         {@link MathContext#DECIMAL64}.
057         */
058        private static MathContext initDefaultMathContext() {
059                // TODO Initialize default, e.g. by system properties, or better:
060                // classpath properties!
061                return MathContext.DECIMAL64;
062        }
063
064        /**
065         * Return a {@link MonetaryAdjuster} realizing the recorpocal value of
066         * {@code f(R) = 1/R}.
067         * 
068         * @return the reciprocal operator, never {@code null}
069         */
070        public static MonetaryOperator reciprocal() {
071                return RECIPROCAL;
072        }
073
074/**
075         * Factory method creating a new instance with the given {@code BigDecimal) permil value;
076         * @param decimal the decimal value of the permil operator being created.
077         * @return a new  {@code Permil} operator
078         */
079        public static MonetaryOperator permil(BigDecimal decimal) {
080                return new Permil(decimal);
081        }
082
083/**
084         * Factory method creating a new instance with the given {@code Number) permil value;
085         * @param decimal the decimal value of the permil operator being created.
086         * @return a new  {@code Permil} operator
087         */
088        public static MonetaryOperator permil(Number number) {
089                return permil(number, DEFAULT_MATH_CONTEXT);
090        }
091
092/**
093         * Factory method creating a new instance with the given {@code Number) permil value;
094         * @param decimal the decimal value of the permil operator being created.
095         * @return a new  {@code Permil} operator
096         */
097        public static MonetaryOperator permil(Number number, MathContext mathContext) {
098                return new Permil(getBigDecimal(number, mathContext));
099        }
100
101        /**
102         * Converts to {@link BigDecimal}, if necessary, or casts, if possible.
103         * 
104         * @param number
105         *            The {@link Number}
106         * @param mathContext
107         *            the {@link MathContext}
108         * @return the {@code number} as {@link BigDecimal}
109         */
110        private static final BigDecimal getBigDecimal(Number num,
111                        MathContext mathContext) {
112                if (num instanceof BigDecimal) {
113                        return (BigDecimal) num;
114                }
115                if (num instanceof Long || num instanceof Integer
116                                || num instanceof Byte || num instanceof AtomicLong) {
117                        return BigDecimal.valueOf(num.longValue());
118                }
119                if (num instanceof Float || num instanceof Double) {
120                        return new BigDecimal(num.toString());
121                }
122                try {
123                        // Avoid imprecise conversion to double value if at all possible
124                        return new BigDecimal(num.toString(), mathContext);
125                } catch (NumberFormatException e) {
126                }
127                return BigDecimal.valueOf(num.doubleValue());
128        }
129
130/**
131         * Factory method creating a new instance with the given {@code BigDecimal) percent value;
132         * @param decimal the decimal value of the percent operator being created.
133         * @return a new  {@code Percent} operator
134         */
135        public static MonetaryOperator percent(BigDecimal decimal) {
136                return new Percent(decimal); // TODO caching, e.g. array for 1-100 might
137                                                                                // work.
138        }
139
140/**
141         * Factory method creating a new instance with the given {@code Number) percent value;
142         * @param decimal the decimal value of the percent operator being created.
143         * 
144         * @return a new  {@code Percent} operator
145         */
146        public static MonetaryOperator percent(Number number) {
147                return percent(getBigDecimal(number, DEFAULT_MATH_CONTEXT));
148        }
149
150        /**
151         * Access the shared instance of {@link MinorPart} for use.
152         * 
153         * @return the shared instance, never {@code null}.
154         */
155        public static MonetaryOperator minorPart() {
156                return MINORPART;
157        }
158
159        /**
160         * Access the shared instance of {@link MajorPart} for use.
161         * 
162         * @return the shared instance, never {@code null}.
163         */
164        public static MonetaryOperator majorPart() {
165                return MAJORPART;
166        }
167
168        /**
169         * Access the shared instance of {@link MinorUnits} for use.
170         * 
171         * @return the shared instance, never {@code null}.
172         */
173        public static MonetaryQuery<Long> minorUnits() {
174                return MINORUNITS;
175        }
176
177        /**
178         * Access the shared instance of {@link MajorUnits} for use.
179         * 
180         * @return the shared instance, never {@code null}.
181         */
182        public static MonetaryQuery<Long> majorUnits() {
183                return MAJORUNITS;
184        }
185
186}