001/**
002 * Copyright (c) 2012, 2015, 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.math.RoundingMode;
021import java.util.Objects;
022
023import javax.money.CurrencyUnit;
024import javax.money.MonetaryAmount;
025import javax.money.MonetaryOperator;
026
027import org.javamoney.moneta.spi.DefaultNumberValue;
028
029/**
030 * This singleton class provides access to the predefined monetary functions.
031 * <p>
032 * The class is thread-safe, which is also true for all functions returned by
033 * this class.
034 * <pre>
035 * {@code
036 *      MonetaryAmount money = Money.parse("EUR 2.35");
037 *  MonetaryAmount result = operator.apply(money);
038 * }
039 * </pre>
040 * <p>Or using: </p>
041 * <pre>
042 * {@code
043 *      MonetaryAmount money = Money.parse("EUR 2.35");
044 *  MonetaryAmount result = money.with(operator);
045 * }
046 * </pre>
047 * @see {@link MonetaryAmount#with(MonetaryOperator)}
048 * @see {@link MonetaryOperator}
049 * @see {@link MonetaryOperator#apply(MonetaryAmount)}
050 * @author Anatole Tresch
051 * @author Otavio Santana
052 * @since 1.0.1
053 */
054public final class MonetaryOperators {
055
056    private static final MathContext DEFAULT_MATH_CONTEXT = MathContext.DECIMAL64;
057
058    private static final ReciprocalOperator RECIPROCAL = new ReciprocalOperator();
059
060    private static final ExtractorMinorPartOperator EXTRACTOR_MINOR_PART = new ExtractorMinorPartOperator();
061
062    private static final ExtractorMajorPartOperator EXTRACTOR_MAJOR_PART = new ExtractorMajorPartOperator();
063
064    private static final RoudingMonetaryAmountOperator ROUNDING_MONETARY_AMOUNT = new RoudingMonetaryAmountOperator();
065
066    private MonetaryOperators() {
067    }
068
069    /**
070         * Gets the reciprocal of {@link MonetaryAmount}
071         * <p>
072         * Gets the amount as reciprocal, multiplicative inverse value (1/n).
073         * <p>
074         *<pre>
075         *{@code
076         *MonetaryAmount money = Money.parse("EUR 2.0");
077         *MonetaryAmount result = ConversionOperators.reciprocal().apply(money);//EUR 0.5
078         *}
079         *</pre>
080         * @return the reciprocal part as {@link MonetaryOperator}
081         */
082    public static MonetaryOperator reciprocal() {
083        return RECIPROCAL;
084    }
085
086    /**
087         * Gets the permil of the amount.
088         * <p>
089         * This returns the monetary amount in permil. For example, for 10% 'EUR
090         * 2.35' will return 0.235.
091         * <p>
092         *<pre>
093         *{@code
094         *MonetaryAmount money = Money.parse("EUR EUR 2.35");
095         *MonetaryAmount result = ConversionOperators.permil(BigDecimal.TEN).apply(money);//EUR 0.0235
096         *}
097         *</pre>
098         * @return the permil as {@link MonetaryOperator}
099         */
100    public static MonetaryOperator permil(BigDecimal decimal) {
101        return new PermilOperator(decimal);
102    }
103
104    /**
105     * Returns the {@link #percent(BigDecimal)} converting
106     * this number to {@link BigDecimal} and using the {@link org.javamoney.moneta.convert.ConversionOperators#DEFAULT_MATH_CONTEXT}
107     * @param number to be converted to {@link BigDecimal}
108     * @see {@link #permil(BigDecimal)}
109     * @return the permil {@link MonetaryOperator}
110     */
111    public static MonetaryOperator permil(Number number) {
112        return permil(number, DEFAULT_MATH_CONTEXT);
113    }
114
115
116    /**
117     * Returns the {@link #percent(BigDecimal)} converting
118     * this number to {@link BigDecimal} and using the {@link MathContext} in parameters
119     * @param number to be converted to {@link BigDecimal}
120     * @param mathContext the mathContext to be used
121     * @see {@link #permil(BigDecimal)}
122     * @return the permil {@link MonetaryOperator}
123     */
124    public static MonetaryOperator permil(Number number, MathContext mathContext) {
125        return new PermilOperator(new DefaultNumberValue(number).numberValue(BigDecimal.class));
126    }
127
128        /**
129         * Gets the percentage of the amount.
130         * <p>
131         * This returns the monetary amount in percent. For example, for 10% 'EUR
132         * 2.35' will return 0.235.
133         * <p>
134         *<pre>
135         *{@code
136         *MonetaryAmount money = Money.parse("EUR 200.0");
137         *MonetaryAmount result = ConversionOperators.percent(BigDecimal.TEN).apply(money);//EUR 20.0
138         *}
139         *</pre>
140         * @param decimal the value to percent
141         * @return the percent of {@link MonetaryOperator}
142         */
143    public static MonetaryOperator percent(BigDecimal decimal) {
144        return new PercentOperator(decimal);
145    }
146
147    /**
148     * Gets the percentage of the amount.
149     * @param number to be used in percent
150     * @see {@link #percent(BigDecimal)}
151     * @return the percent of {@link MonetaryOperator}
152     */
153    public static MonetaryOperator percent(Number number) {
154        return percent(new DefaultNumberValue(number).numberValue(BigDecimal.class));
155    }
156
157        /**
158         * Extract minor part of {@link MonetaryAmount}
159         * <p>
160         * This returns the monetary amount in terms of the minor units of the
161         * currency, truncating the whole part if necessary. For example, 'EUR 2.35'
162         * will return 'EUR 0.35', and 'BHD -1.345' will return 'BHD -0.345'.
163         * <p>
164         *<pre>
165         *{@code
166         *MonetaryAmount money = Money.parse("EUR 2.35");
167         *MonetaryAmount result = ConversionOperators.minorPart().apply(money);//EUR 0.35
168         *}
169         *</pre>
170         * @return the minor part as {@link MonetaryOperator}
171         */
172    public static MonetaryOperator minorPart() {
173        return EXTRACTOR_MINOR_PART;
174    }
175
176        /**
177         * Extract major part of {@link MonetaryAmount}
178         * <p>
179         * This returns the monetary amount in terms of the minor units of the
180         * currency, truncating the whole part if necessary. For example, 'EUR 2.35'
181         * will return 'EUR 0.35', and 'BHD -1.345' will return 'BHD -0.345'.
182         * <p>
183         *<pre>
184         *{@code
185         *MonetaryAmount money = Money.parse("EUR 2.35");
186         *MonetaryAmount result = ConversionOperators.majorPart().apply(money);//EUR 2.0
187         *}
188         *</pre>
189         * @return the major part as {@link MonetaryOperator}
190         */
191        public static MonetaryOperator majorPart() {
192                return EXTRACTOR_MAJOR_PART;
193        }
194
195        /**
196         * Rounding the {@link MonetaryAmount} using {@link CurrencyUnit#getDefaultFractionDigits()}
197         * and {@link RoundingMode#HALF_EVEN}.
198         * <p>
199         * For example, 'EUR 2.3523' will return 'EUR 2.35',
200         * and 'BHD -1.34534432' will return 'BHD -1.345'.
201         * <p>
202         *<pre>
203         *{@code
204         *MonetaryAmount money = Money.parse("EUR 2.355432");
205         *MonetaryAmount result = ConversionOperators.rounding().apply(money);//EUR 2.36
206         *}
207         *</pre>
208         * @return the major part as {@link MonetaryOperator}
209         */
210        public static MonetaryOperator rounding() {
211                return ROUNDING_MONETARY_AMOUNT;
212        }
213
214        /**
215         * Rounding the {@link MonetaryAmount} using {@link CurrencyUnit#getDefaultFractionDigits()}
216         * and {@link RoundingMode}.
217         * <p>
218         * For example, 'EUR 2.3523' will return 'EUR 2.35',
219         * and 'BHD -1.34534432' will return 'BHD -1.345'.
220         * <p>
221         *<pre>
222         *{@code
223         *MonetaryAmount money = Money.parse("EUR 2.355432");
224         *MonetaryAmount result = ConversionOperators.rounding(RoundingMode.HALF_EVEN).apply(money);//EUR 2.35
225         *}
226         *</pre>
227         * @param roundingMode rounding to be used
228         * @return the major part as {@link MonetaryOperator}
229         */
230        public static MonetaryOperator rounding(RoundingMode roundingMode) {
231                return new RoudingMonetaryAmountOperator(Objects.requireNonNull(roundingMode));
232        }
233
234        /**
235         * Rounding the {@link MonetaryAmount} using {@link CurrencyUnit#getDefaultFractionDigits()}
236         * and {@link RoundingMode}.
237         * <p>
238         * For example, 'EUR 2.3523' will return 'EUR 2.35',
239         * and 'BHD -1.34534432' will return 'BHD -1.345'.
240         * <p>
241         *<pre>
242         *{@code
243         *MonetaryAmount money = Money.parse("EUR 2.355432");
244         *MonetaryAmount result = ConversionOperators.rounding(RoundingMode.HALF_EVEN, 3).apply(money);//EUR 2.352
245         *}
246         *</pre>
247         * @param roundingMode rounding to be used
248         * @param scale to be used
249         * @return the major part as {@link MonetaryOperator}
250         */
251        public static MonetaryOperator rounding(RoundingMode roundingMode, int scale) {
252                return new RoudingMonetaryAmountOperator(Objects.requireNonNull(roundingMode), scale);
253        }
254
255        /**
256         * Rounding the {@link MonetaryAmount} using the scale informed
257         * and {@link RoundingMode#HALF_EVEN}.
258         * <p>
259         * For example, 'EUR 2.3523' will return 'EUR 2.35',
260         * and 'BHD -1.34534432' will return 'BHD -1.345'.
261         * <p>
262         *<pre>
263         *{@code
264         *MonetaryAmount money = Money.parse("EUR 2.355432");
265         *MonetaryAmount result = ConversionOperators.rounding(2).apply(money);//EUR 2.35
266         *}
267         *</pre>
268         * @param scale scale to be used
269         * @return the major part as {@link MonetaryOperator}
270         */
271        public static MonetaryOperator rounding(int scale) {
272                return new RoudingMonetaryAmountOperator(RoudingMonetaryAmountOperator.DEFAULT_ROUDING_MONETARY_AMOUNT, scale);
273        }
274
275        /**
276         * Do exchange of currency, in other words, create the monetary amount with the
277         * same value but with currency different.
278         * <p>
279         * For example, 'EUR 2.35', using the currency 'USD' as exchange parameter, will return 'USD 2.35',
280         * and 'BHD -1.345', using the currency 'USD' as exchange parameter, will return 'BHD -1.345'.
281         * <p>
282         *<pre>
283         *{@code
284         *Currency real = Monetary.getCurrency("BRL");
285         *MonetaryAmount money = Money.parse("EUR 2.355");
286         *MonetaryAmount result = MonetaryOperators.exchangeCurrency(real).apply(money);//BRL 2.355
287         *}
288         *</pre>
289         * @param currencyUnit currency to be used
290         * @return the major part as {@link MonetaryOperator}
291         * @deprecated
292         */
293        @Deprecated
294        public static MonetaryOperator exchangeCurrency(CurrencyUnit currencyUnit){
295                return new ExchangeCurrencyOperator(Objects.requireNonNull(currencyUnit));
296        }
297}