task4/solution07/src/org/apidesign/apifest08/currency/anothervendor/ZigZaggingBidirectionalConvertor.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 11 Oct 2008 23:38:46 +0200
changeset 61 58ec6da75f6f
parent 57 task3/solution07/src/org/apidesign/apifest08/currency/anothervendor/ZigZaggingBidirectionalConvertor.java@be49855c7fa2
permissions -rw-r--r--
Copying structure for task4
japod@57
     1
/*
japod@57
     2
 * To change this template, choose Tools | Templates
japod@57
     3
 * and open the template in the editor.
japod@57
     4
 */
japod@57
     5
japod@57
     6
package org.apidesign.apifest08.currency.anothervendor;
japod@57
     7
japod@57
     8
import java.math.BigDecimal;
japod@57
     9
import java.util.Currency;
japod@57
    10
import java.util.Iterator;
japod@57
    11
import org.apidesign.apifest08.currency.Convertor;
japod@57
    12
import org.apidesign.apifest08.currency.IllegalRequestSubtypeException;
japod@57
    13
import org.apidesign.apifest08.currency.MonetaryAmount;
japod@57
    14
japod@57
    15
japod@57
    16
/**
japod@57
    17
 * A convertor that changes the rate by a step amount on every conversion it performs.
japod@57
    18
 * @author jdvorak
japod@57
    19
 */
japod@57
    20
public class ZigZaggingBidirectionalConvertor implements Convertor {
japod@57
    21
japod@57
    22
    private final MonetaryAmount srcRateAmount;
japod@57
    23
    
japod@57
    24
    private final Currency tgtCurrency;
japod@57
    25
    
japod@57
    26
    private final Iterator<BigDecimal> rateIterator;
japod@57
    27
japod@57
    28
    /**
japod@57
    29
     * Costructor with the precise amounts.
japod@57
    30
     * @param srcRateAmount
japod@57
    31
     * @param tgtCurrency
japod@57
    32
     * @param startAmount
japod@57
    33
     * @param endAmount
japod@57
    34
     * @param stepAmount
japod@57
    35
     */
japod@57
    36
    public ZigZaggingBidirectionalConvertor( final MonetaryAmount srcRateAmount, final Currency tgtCurrency, final BigDecimal startAmount, final BigDecimal endAmount, final BigDecimal stepAmount ) {
japod@57
    37
        this.srcRateAmount = srcRateAmount;
japod@57
    38
        this.tgtCurrency = tgtCurrency;
japod@57
    39
        this.rateIterator = new ZigZaggingBigDecimalIterator( startAmount, endAmount, stepAmount );
japod@57
    40
    }
japod@57
    41
japod@57
    42
    /**
japod@57
    43
     * Do the conversion; updates the rate.
japod@57
    44
     * @param req
japod@57
    45
     * @return
japod@57
    46
     * @throws org.apidesign.apifest08.currency.IllegalRequestSubtypeException
japod@57
    47
     */
japod@57
    48
    public synchronized ConversionResult convert( ConversionRequest req ) throws IllegalRequestSubtypeException {
japod@57
    49
        if ( tgtCurrency.equals( req.getTgtCurrency() ) ) {
japod@57
    50
            if ( srcRateAmount.getCurrency().equals( req.getSrcAmount().getCurrency() ) ) {
japod@57
    51
                final BigDecimal tgtRateAmount = rateIterator.next();
japod@57
    52
                final BigDecimal tgtAmount = req.getSrcAmount().getAmount().multiply( tgtRateAmount ).divide( srcRateAmount.getAmount() );
japod@57
    53
                return new ConversionResult( new MonetaryAmount( tgtAmount, tgtCurrency ) );
japod@57
    54
            }
japod@57
    55
        }
japod@57
    56
        if ( srcRateAmount.getCurrency().equals( req.getTgtCurrency() ) ) {
japod@57
    57
            if ( tgtCurrency.equals( req.getSrcAmount().getCurrency() ) ) {
japod@57
    58
                final BigDecimal tgtRateAmount = rateIterator.next();
japod@57
    59
                final BigDecimal tgtAmount = req.getSrcAmount().getAmount().multiply( srcRateAmount.getAmount() ).divide( tgtRateAmount );
japod@57
    60
                return new ConversionResult( new MonetaryAmount( tgtAmount, srcRateAmount.getCurrency() ) );
japod@57
    61
            }
japod@57
    62
        }
japod@57
    63
        return new ConversionResult( null );
japod@57
    64
    }
japod@57
    65
japod@57
    66
}
japod@57
    67
japod@57
    68
/**
japod@57
    69
 * An iterator that goes zig first, then zag, then zig again, then zag again, ad libitum.
japod@57
    70
 * @author jdvorak
japod@57
    71
 */
japod@57
    72
class ZigZaggingBigDecimalIterator implements Iterator<BigDecimal> {
japod@57
    73
japod@57
    74
    private BigDecimal zigBounce;
japod@57
    75
    
japod@57
    76
    private BigDecimal zagBounce;
japod@57
    77
    
japod@57
    78
    private BigDecimal step;
japod@57
    79
    
japod@57
    80
    private BigDecimal currentValue;
japod@57
    81
    
japod@57
    82
    protected ZigZaggingBigDecimalIterator( final BigDecimal zagBounce, final BigDecimal zigBounce, final BigDecimal step ) {
japod@57
    83
        this. zigBounce = zigBounce;
japod@57
    84
        this.zagBounce = zagBounce;
japod@57
    85
        this.currentValue = zagBounce;
japod@57
    86
        this.step = step;
japod@57
    87
        
japod@57
    88
        if (  zigBounce == null ) {
japod@57
    89
            throw new NullPointerException( "zigAmount" );
japod@57
    90
        }
japod@57
    91
        if ( zagBounce == null ) {
japod@57
    92
            throw new NullPointerException( "zagAmount" );
japod@57
    93
        }
japod@57
    94
        if ( step == null ) {
japod@57
    95
            throw new NullPointerException( "stepAmount" );
japod@57
    96
        }
japod@57
    97
        final int stepSign = step.signum();
japod@57
    98
        if ( stepSign == 0 ) {
japod@57
    99
            throw new IllegalArgumentException( "stepAmount can't be zero" );
japod@57
   100
        }
japod@57
   101
        if ( stepSign * zigBounce.compareTo( zagBounce ) < 0 ) {
japod@57
   102
            throw new IllegalArgumentException( "stepAmount shall have the same sign as endAmount - startAmount" );
japod@57
   103
        }
japod@57
   104
    }
japod@57
   105
    
japod@57
   106
    public boolean hasNext() {
japod@57
   107
        return true;
japod@57
   108
    }
japod@57
   109
japod@57
   110
    public BigDecimal next() {
japod@57
   111
        final BigDecimal result = currentValue;
japod@57
   112
        
japod@57
   113
        currentValue = currentValue.add( step );
japod@57
   114
        final int stepSign = step.signum();
japod@57
   115
        final int currentMinusZigSign = currentValue.compareTo( zigBounce );
japod@57
   116
        if ( stepSign * currentMinusZigSign >= 0 ) {
japod@57
   117
            final BigDecimal temp = zigBounce;
japod@57
   118
            zigBounce = zagBounce;
japod@57
   119
            zagBounce = temp;
japod@57
   120
            step = step.negate();
japod@57
   121
        }
japod@57
   122
        
japod@57
   123
        return result;
japod@57
   124
    }
japod@57
   125
japod@57
   126
    public void remove() {
japod@57
   127
        throw new UnsupportedOperationException("Removal is not supported.");
japod@57
   128
    }
japod@57
   129
    
japod@57
   130
}