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
012
013import javax.money.*;
014import javax.money.spi.RoundingProviderSpi;
015import java.math.BigDecimal;
016import java.math.RoundingMode;
017import java.time.LocalDate;
018import java.util.HashMap;
019import java.util.Map;
020import java.util.Optional;
021import java.util.Set;
022
023/**
024 * Test ExchangeProvider. Created by Anatole on 26.04.2014.
025 */
026public class TestRoundingProvider implements RoundingProviderSpi {
027
028    private static final RoundingContext CONTEXT =
029            RoundingContextBuilder.of(TestRoundingProvider.class.getSimpleName(), "NOSCALE").build();
030    private static final RoundingContext CONTEXT_CASH =
031            RoundingContextBuilder.of(TestRoundingProvider.class.getSimpleName(), "cashRounding").build();
032
033    private Map<String, MonetaryRounding> customRoundings = new HashMap<>();
034
035    public TestRoundingProvider() {
036        customRoundings.put("NOSCALE", new MonetaryRounding() {
037            @Override
038            public RoundingContext getRoundingContext() {
039                return CONTEXT;
040            }
041
042            @Override
043            public MonetaryAmount apply(MonetaryAmount value) {
044                return value.getFactory()
045                        .setNumber(value.getNumber().numberValue(BigDecimal.class).setScale(0, RoundingMode.HALF_EVEN))
046                        .create();
047            }
048        });
049    }
050
051    @Override
052    public MonetaryRounding getRounding(RoundingQuery context) {
053        MonetaryRounding customRounding = customRoundings.get(context.getRoundingName());
054        if (customRounding != null) {
055            return customRounding;
056        }
057        if (context.getCurrency() == null) {
058            return null;
059        }
060        Boolean cashRounding = Optional.ofNullable(context.getBoolean("cashRounding")).orElse(Boolean.FALSE);
061        LocalDate timestamp = context.get(LocalDate.class);
062        if (cashRounding) {
063            if (timestamp != null) {
064                return getCashRounding(context.getCurrency(), timestamp);
065            }
066            return getCashRounding(context.getCurrency());
067        } else {
068            if ("XAU".equals(context.getCurrency().getCurrencyCode())) {
069                if (timestamp != null) {
070                    return new MonetaryRounding() {
071                        @Override
072                        public RoundingContext getRoundingContext() {
073                            return CONTEXT;
074                        }
075
076                        @Override
077                        public MonetaryAmount apply(MonetaryAmount value) {
078                            return value.getFactory().setNumber(
079                                    value.getNumber().numberValue(BigDecimal.class).setScale(2, RoundingMode.UP))
080                                    .create();
081                        }
082                    };
083                }
084                return new MonetaryRounding() {
085                    @Override
086                    public RoundingContext getRoundingContext() {
087                        return CONTEXT;
088                    }
089
090                    @Override
091                    public MonetaryAmount apply(MonetaryAmount value) {
092                        return value.getFactory()
093                                .setNumber(value.getNumber().numberValue(BigDecimal.class).setScale(4, RoundingMode.UP))
094                                .create();
095                    }
096                };
097            }
098        }
099        return null;
100    }
101
102
103    private MonetaryRounding getCashRounding(CurrencyUnit currency) {
104        if ("XAU".equals(currency.getCurrencyCode())) {
105            return new MonetaryRounding() {
106                @Override
107                public RoundingContext getRoundingContext() {
108                    return CONTEXT_CASH;
109                }
110
111                @Override
112                public MonetaryAmount apply(MonetaryAmount value) {
113                    return value.getFactory()
114                            .setNumber(value.getNumber().numberValue(BigDecimal.class).setScale(1, RoundingMode.DOWN))
115                            .create();
116                }
117            };
118        }
119        return null;
120    }
121
122    private MonetaryRounding getCashRounding(CurrencyUnit currency, LocalDate timestamp) {
123        if ("XAU".equals(currency.getCurrencyCode()) && timestamp.getYear() < 1972) {
124            return new MonetaryRounding() {
125                @Override
126                public RoundingContext getRoundingContext() {
127                    return CONTEXT_CASH;
128                }
129
130                @Override
131                public MonetaryAmount apply(MonetaryAmount value) {
132                    return value.getFactory()
133                            .setNumber(value.getNumber().numberValue(BigDecimal.class).setScale(2, RoundingMode.DOWN))
134                            .create();
135                }
136            };
137        }
138        return null;
139    }
140
141    @Override
142    public Set<String> getRoundingNames() {
143        return customRoundings.keySet();
144    }
145}