task4/solution07/src/org/apidesign/apifest08/currency/anothervendor/ZigZaggingBidirectionalConvertor.java
2 * To change this template, choose Tools | Templates
3 * and open the template in the editor.
6 package org.apidesign.apifest08.currency.anothervendor;
8 import java.math.BigDecimal;
9 import java.util.Currency;
10 import java.util.Iterator;
11 import org.apidesign.apifest08.currency.Convertor;
12 import org.apidesign.apifest08.currency.IllegalRequestSubtypeException;
13 import org.apidesign.apifest08.currency.MonetaryAmount;
17 * A convertor that changes the rate by a step amount on every conversion it performs.
20 public class ZigZaggingBidirectionalConvertor implements Convertor {
22 private final MonetaryAmount srcRateAmount;
24 private final Currency tgtCurrency;
26 private final Iterator<BigDecimal> rateIterator;
29 * Costructor with the precise amounts.
30 * @param srcRateAmount
36 public ZigZaggingBidirectionalConvertor( final MonetaryAmount srcRateAmount, final Currency tgtCurrency, final BigDecimal startAmount, final BigDecimal endAmount, final BigDecimal stepAmount ) {
37 this.srcRateAmount = srcRateAmount;
38 this.tgtCurrency = tgtCurrency;
39 this.rateIterator = new ZigZaggingBigDecimalIterator( startAmount, endAmount, stepAmount );
43 * Do the conversion; updates the rate.
46 * @throws org.apidesign.apifest08.currency.IllegalRequestSubtypeException
48 public synchronized ConversionResult convert( ConversionRequest req ) throws IllegalRequestSubtypeException {
49 if ( tgtCurrency.equals( req.getTgtCurrency() ) ) {
50 if ( srcRateAmount.getCurrency().equals( req.getSrcAmount().getCurrency() ) ) {
51 final BigDecimal tgtRateAmount = rateIterator.next();
52 final BigDecimal tgtAmount = req.getSrcAmount().getAmount().multiply( tgtRateAmount ).divide( srcRateAmount.getAmount() );
53 return new ConversionResult( new MonetaryAmount( tgtAmount, tgtCurrency ) );
56 if ( srcRateAmount.getCurrency().equals( req.getTgtCurrency() ) ) {
57 if ( tgtCurrency.equals( req.getSrcAmount().getCurrency() ) ) {
58 final BigDecimal tgtRateAmount = rateIterator.next();
59 final BigDecimal tgtAmount = req.getSrcAmount().getAmount().multiply( srcRateAmount.getAmount() ).divide( tgtRateAmount );
60 return new ConversionResult( new MonetaryAmount( tgtAmount, srcRateAmount.getCurrency() ) );
63 return new ConversionResult( null );
69 * An iterator that goes zig first, then zag, then zig again, then zag again, ad libitum.
72 class ZigZaggingBigDecimalIterator implements Iterator<BigDecimal> {
74 private BigDecimal zigBounce;
76 private BigDecimal zagBounce;
78 private BigDecimal step;
80 private BigDecimal currentValue;
82 protected ZigZaggingBigDecimalIterator( final BigDecimal zagBounce, final BigDecimal zigBounce, final BigDecimal step ) {
83 this. zigBounce = zigBounce;
84 this.zagBounce = zagBounce;
85 this.currentValue = zagBounce;
88 if ( zigBounce == null ) {
89 throw new NullPointerException( "zigAmount" );
91 if ( zagBounce == null ) {
92 throw new NullPointerException( "zagAmount" );
95 throw new NullPointerException( "stepAmount" );
97 final int stepSign = step.signum();
98 if ( stepSign == 0 ) {
99 throw new IllegalArgumentException( "stepAmount can't be zero" );
101 if ( stepSign * zigBounce.compareTo( zagBounce ) < 0 ) {
102 throw new IllegalArgumentException( "stepAmount shall have the same sign as endAmount - startAmount" );
106 public boolean hasNext() {
110 public BigDecimal next() {
111 final BigDecimal result = currentValue;
113 currentValue = currentValue.add( step );
114 final int stepSign = step.signum();
115 final int currentMinusZigSign = currentValue.compareTo( zigBounce );
116 if ( stepSign * currentMinusZigSign >= 0 ) {
117 final BigDecimal temp = zigBounce;
118 zigBounce = zagBounce;
120 step = step.negate();
126 public void remove() {
127 throw new UnsupportedOperationException("Removal is not supported.");