001/*
002 * Copyright (c) 2012, 2013, Werner Keil, Credit Suisse (Anatole Tresch). Licensed under the Apache
003 * License, Version 2.0 (the "License"); you may not use this file except in compliance with the
004 * License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
005 * Unless required by applicable law or agreed to in writing, software distributed under the License
006 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
007 * or implied. See the License for the specific language governing permissions and limitations under
008 * the License. Contributors: Anatole Tresch - initial version.
009 */
010package org.javamoney.tck.tests.internal;
011
012import javax.money.CurrencyUnit;
013import javax.money.MonetaryAmount;
014import javax.money.MonetaryRounding;
015import javax.money.RoundingContext;
016import javax.money.RoundingContextBuilder;
017import javax.money.RoundingQuery;
018import javax.money.spi.RoundingProviderSpi;
019import java.math.BigDecimal;
020import java.math.RoundingMode;
021import java.util.Calendar;
022import java.util.HashMap;
023import java.util.Map;
024import java.util.Set;
025
026/**
027 * Test ExchangeProvider. Created by Anatole on 26.04.2014.
028 */
029public class TestRoundingProvider implements RoundingProviderSpi {
030
031    private static final RoundingContext CONTEXT =
032            RoundingContextBuilder.of(TestRoundingProvider.class.getSimpleName(), "NOSCALE").build();
033    private static final RoundingContext CONTEXT_CASH =
034            RoundingContextBuilder.of(TestRoundingProvider.class.getSimpleName(), "cashRounding").build();
035
036    private Map<String, MonetaryRounding> customRoundings = new HashMap<>();
037
038    public TestRoundingProvider() {
039        customRoundings.put("NOSCALE", new MonetaryRounding() {
040            @Override
041            public RoundingContext getRoundingContext() {
042                return CONTEXT;
043            }
044
045            @Override
046            public MonetaryAmount apply(MonetaryAmount value) {
047                return value.getFactory()
048                        .setNumber(value.getNumber().numberValue(BigDecimal.class).setScale(0, RoundingMode.HALF_EVEN))
049                        .create();
050            }
051        });
052    }
053
054    @Override
055    public MonetaryRounding getRounding(RoundingQuery context) {
056        MonetaryRounding customRounding = customRoundings.get(context.getRoundingName());
057        if (customRounding != null) {
058            return customRounding;
059        }
060        if (context.getCurrency() == null) {
061            return null;
062        }
063        Boolean cashRounding = context.getBoolean("cashRounding");
064        if(cashRounding==null) {
065            cashRounding = Boolean.FALSE;
066        }
067        Calendar timestamp = context.get(Calendar.class);
068        if (cashRounding) {
069            if (timestamp != null) {
070                return getCashRounding(context.getCurrency(), timestamp);
071            }
072            return getCashRounding(context.getCurrency());
073        } else {
074            if ("XAU".equals(context.getCurrency().getCurrencyCode())) {
075                if (timestamp != null) {
076                    return new MonetaryRounding() {
077                        @Override
078                        public RoundingContext getRoundingContext() {
079                            return CONTEXT;
080                        }
081
082                        @Override
083                        public MonetaryAmount apply(MonetaryAmount value) {
084                            return value.getFactory().setNumber(
085                                    value.getNumber().numberValue(BigDecimal.class).setScale(2, RoundingMode.UP))
086                                    .create();
087                        }
088                    };
089                }
090                return new MonetaryRounding() {
091                    @Override
092                    public RoundingContext getRoundingContext() {
093                        return CONTEXT;
094                    }
095
096                    @Override
097                    public MonetaryAmount apply(MonetaryAmount value) {
098                        return value.getFactory()
099                                .setNumber(value.getNumber().numberValue(BigDecimal.class).setScale(4, RoundingMode.UP))
100                                .create();
101                    }
102                };
103            }
104        }
105        return null;
106    }
107
108
109    private MonetaryRounding getCashRounding(CurrencyUnit currency) {
110        if ("XAU".equals(currency.getCurrencyCode())) {
111            return new MonetaryRounding() {
112                @Override
113                public RoundingContext getRoundingContext() {
114                    return CONTEXT_CASH;
115                }
116
117                @Override
118                public MonetaryAmount apply(MonetaryAmount value) {
119                    return value.getFactory()
120                            .setNumber(value.getNumber().numberValue(BigDecimal.class).setScale(1, RoundingMode.DOWN))
121                            .create();
122                }
123            };
124        }
125        return null;
126    }
127
128    private MonetaryRounding getCashRounding(CurrencyUnit currency, Calendar timestamp) {
129        if ("XAU".equals(currency.getCurrencyCode()) && timestamp.get(Calendar.YEAR) < 1972) {
130            return new MonetaryRounding() {
131                @Override
132                public RoundingContext getRoundingContext() {
133                    return CONTEXT_CASH;
134                }
135
136                @Override
137                public MonetaryAmount apply(MonetaryAmount value) {
138                    return value.getFactory()
139                            .setNumber(value.getNumber().numberValue(BigDecimal.class).setScale(2, RoundingMode.DOWN))
140                            .create();
141                }
142            };
143        }
144        return null;
145    }
146
147    @Override
148    public Set<String> getRoundingNames() {
149        return customRoundings.keySet();
150    }
151
152    @Override
153    public String getProviderName() {
154        return getClass().getSimpleName();
155    }
156}