task4/solution07/src/org/apidesign/apifest08/currency/anothervendor/ZigZaggingBidirectionalConvertor.java
changeset 61 58ec6da75f6f
parent 57 be49855c7fa2
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/task4/solution07/src/org/apidesign/apifest08/currency/anothervendor/ZigZaggingBidirectionalConvertor.java	Sat Oct 11 23:38:46 2008 +0200
     1.3 @@ -0,0 +1,130 @@
     1.4 +/*
     1.5 + * To change this template, choose Tools | Templates
     1.6 + * and open the template in the editor.
     1.7 + */
     1.8 +
     1.9 +package org.apidesign.apifest08.currency.anothervendor;
    1.10 +
    1.11 +import java.math.BigDecimal;
    1.12 +import java.util.Currency;
    1.13 +import java.util.Iterator;
    1.14 +import org.apidesign.apifest08.currency.Convertor;
    1.15 +import org.apidesign.apifest08.currency.IllegalRequestSubtypeException;
    1.16 +import org.apidesign.apifest08.currency.MonetaryAmount;
    1.17 +
    1.18 +
    1.19 +/**
    1.20 + * A convertor that changes the rate by a step amount on every conversion it performs.
    1.21 + * @author jdvorak
    1.22 + */
    1.23 +public class ZigZaggingBidirectionalConvertor implements Convertor {
    1.24 +
    1.25 +    private final MonetaryAmount srcRateAmount;
    1.26 +    
    1.27 +    private final Currency tgtCurrency;
    1.28 +    
    1.29 +    private final Iterator<BigDecimal> rateIterator;
    1.30 +
    1.31 +    /**
    1.32 +     * Costructor with the precise amounts.
    1.33 +     * @param srcRateAmount
    1.34 +     * @param tgtCurrency
    1.35 +     * @param startAmount
    1.36 +     * @param endAmount
    1.37 +     * @param stepAmount
    1.38 +     */
    1.39 +    public ZigZaggingBidirectionalConvertor( final MonetaryAmount srcRateAmount, final Currency tgtCurrency, final BigDecimal startAmount, final BigDecimal endAmount, final BigDecimal stepAmount ) {
    1.40 +        this.srcRateAmount = srcRateAmount;
    1.41 +        this.tgtCurrency = tgtCurrency;
    1.42 +        this.rateIterator = new ZigZaggingBigDecimalIterator( startAmount, endAmount, stepAmount );
    1.43 +    }
    1.44 +
    1.45 +    /**
    1.46 +     * Do the conversion; updates the rate.
    1.47 +     * @param req
    1.48 +     * @return
    1.49 +     * @throws org.apidesign.apifest08.currency.IllegalRequestSubtypeException
    1.50 +     */
    1.51 +    public synchronized ConversionResult convert( ConversionRequest req ) throws IllegalRequestSubtypeException {
    1.52 +        if ( tgtCurrency.equals( req.getTgtCurrency() ) ) {
    1.53 +            if ( srcRateAmount.getCurrency().equals( req.getSrcAmount().getCurrency() ) ) {
    1.54 +                final BigDecimal tgtRateAmount = rateIterator.next();
    1.55 +                final BigDecimal tgtAmount = req.getSrcAmount().getAmount().multiply( tgtRateAmount ).divide( srcRateAmount.getAmount() );
    1.56 +                return new ConversionResult( new MonetaryAmount( tgtAmount, tgtCurrency ) );
    1.57 +            }
    1.58 +        }
    1.59 +        if ( srcRateAmount.getCurrency().equals( req.getTgtCurrency() ) ) {
    1.60 +            if ( tgtCurrency.equals( req.getSrcAmount().getCurrency() ) ) {
    1.61 +                final BigDecimal tgtRateAmount = rateIterator.next();
    1.62 +                final BigDecimal tgtAmount = req.getSrcAmount().getAmount().multiply( srcRateAmount.getAmount() ).divide( tgtRateAmount );
    1.63 +                return new ConversionResult( new MonetaryAmount( tgtAmount, srcRateAmount.getCurrency() ) );
    1.64 +            }
    1.65 +        }
    1.66 +        return new ConversionResult( null );
    1.67 +    }
    1.68 +
    1.69 +}
    1.70 +
    1.71 +/**
    1.72 + * An iterator that goes zig first, then zag, then zig again, then zag again, ad libitum.
    1.73 + * @author jdvorak
    1.74 + */
    1.75 +class ZigZaggingBigDecimalIterator implements Iterator<BigDecimal> {
    1.76 +
    1.77 +    private BigDecimal zigBounce;
    1.78 +    
    1.79 +    private BigDecimal zagBounce;
    1.80 +    
    1.81 +    private BigDecimal step;
    1.82 +    
    1.83 +    private BigDecimal currentValue;
    1.84 +    
    1.85 +    protected ZigZaggingBigDecimalIterator( final BigDecimal zagBounce, final BigDecimal zigBounce, final BigDecimal step ) {
    1.86 +        this. zigBounce = zigBounce;
    1.87 +        this.zagBounce = zagBounce;
    1.88 +        this.currentValue = zagBounce;
    1.89 +        this.step = step;
    1.90 +        
    1.91 +        if (  zigBounce == null ) {
    1.92 +            throw new NullPointerException( "zigAmount" );
    1.93 +        }
    1.94 +        if ( zagBounce == null ) {
    1.95 +            throw new NullPointerException( "zagAmount" );
    1.96 +        }
    1.97 +        if ( step == null ) {
    1.98 +            throw new NullPointerException( "stepAmount" );
    1.99 +        }
   1.100 +        final int stepSign = step.signum();
   1.101 +        if ( stepSign == 0 ) {
   1.102 +            throw new IllegalArgumentException( "stepAmount can't be zero" );
   1.103 +        }
   1.104 +        if ( stepSign * zigBounce.compareTo( zagBounce ) < 0 ) {
   1.105 +            throw new IllegalArgumentException( "stepAmount shall have the same sign as endAmount - startAmount" );
   1.106 +        }
   1.107 +    }
   1.108 +    
   1.109 +    public boolean hasNext() {
   1.110 +        return true;
   1.111 +    }
   1.112 +
   1.113 +    public BigDecimal next() {
   1.114 +        final BigDecimal result = currentValue;
   1.115 +        
   1.116 +        currentValue = currentValue.add( step );
   1.117 +        final int stepSign = step.signum();
   1.118 +        final int currentMinusZigSign = currentValue.compareTo( zigBounce );
   1.119 +        if ( stepSign * currentMinusZigSign >= 0 ) {
   1.120 +            final BigDecimal temp = zigBounce;
   1.121 +            zigBounce = zagBounce;
   1.122 +            zagBounce = temp;
   1.123 +            step = step.negate();
   1.124 +        }
   1.125 +        
   1.126 +        return result;
   1.127 +    }
   1.128 +
   1.129 +    public void remove() {
   1.130 +        throw new UnsupportedOperationException("Removal is not supported.");
   1.131 +    }
   1.132 +    
   1.133 +}
   1.134 \ No newline at end of file