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.math.RoundingMode;
021import java.util.Objects;
022
023import javax.money.MonetaryAmount;
024import javax.money.MonetaryOperator;
025
026import org.javamoney.moneta.RoundedMoney;
027
028/**
029 * This implementation uses a scale and {@link RoundingMode} to does the rounding operations. The implementation will use the <b>scale</b>, in other words, the number of digits to the right of the decimal point
030 * The derived class will implements the {@link RoundedMoney} with this rounding monetary operator
031 *  <pre>
032 *   {@code
033 *
034 *     MonetaryOperator monetaryOperator = ScaleRoundedOperator.of(scale, RoundingMode.HALF_EVEN);
035 *     CurrencyUnit real = Monetary.getCurrency("BRL");
036 *     MonetaryAmount money = Money.of(BigDecimal.valueOf(35.34567), real);
037 *     MonetaryAmount result = monetaryOperator.apply(money); // BRL 35.3457
038 *
039 *    }
040* </pre>
041 * Case the parameter in {@link MonetaryOperator#apply(MonetaryAmount)} be null, the apply will return a {@link NullPointerException}
042 * @author Otavio Santana
043 * @see #ScaleRoundedOperator(int, RoundingMode)
044 * @see RoundedMoney
045 * @see MonetaryOperator
046 * @see BigDecimal#scale()
047 */
048public final class ScaleRoundedOperator implements MonetaryOperator {
049
050        private final int scale;
051
052        private final RoundingMode roundingMode;
053
054        private ScaleRoundedOperator(int scale, RoundingMode roundingMode) {
055                this.scale = scale;
056                this.roundingMode = roundingMode;
057        }
058
059        /**
060         * Creates the rounded Operator from scale and roundingMode
061         * @param scale the scale to be used
062         * @param roundingMode the rounding mode to be used
063         * @return the {@link MonetaryOperator} using the scale and {@link RoundingMode} used in parameter
064         * @throws NullPointerException when the {@link MathContext} is null
065         * @see RoundingMode
066         */
067        public static ScaleRoundedOperator of(int scale, RoundingMode roundingMode) {
068
069                Objects.requireNonNull(roundingMode);
070
071                if(RoundingMode.UNNECESSARY.equals(roundingMode)) {
072                   throw new IllegalStateException("To create the ScaleRoundedOperator you cannot use the RoundingMode.UNNECESSARY");
073                }
074                return new ScaleRoundedOperator(scale, roundingMode);
075        }
076
077        @Override
078        public MonetaryAmount apply(MonetaryAmount amount) {
079                RoundedMoney roundedMoney = RoundedMoney.from(Objects.requireNonNull(amount));
080                BigDecimal numberValue = roundedMoney.getNumber().numberValue(BigDecimal.class);
081                BigDecimal numberRounded = numberValue.setScale(scale, roundingMode);
082                return RoundedMoney.of(numberRounded, roundedMoney.getCurrency(), this);
083        }
084
085        public int getScale() {
086                return scale;
087        }
088
089        public RoundingMode getRoundingMode() {
090                return roundingMode;
091        }
092
093        @Override
094        public String toString() {
095                return ScaleRoundedOperator.class.getName() + '{' +
096                "scale:" + Integer.toString(scale) + ',' +
097                "roundingMode:" + roundingMode + '}';
098        }
099
100}