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
     1 /*
     2  * To change this template, choose Tools | Templates
     3  * and open the template in the editor.
     4  */
     5 
     6 package org.apidesign.apifest08.currency.anothervendor;
     7 
     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;
    14 
    15 
    16 /**
    17  * A convertor that changes the rate by a step amount on every conversion it performs.
    18  * @author jdvorak
    19  */
    20 public class ZigZaggingBidirectionalConvertor implements Convertor {
    21 
    22     private final MonetaryAmount srcRateAmount;
    23     
    24     private final Currency tgtCurrency;
    25     
    26     private final Iterator<BigDecimal> rateIterator;
    27 
    28     /**
    29      * Costructor with the precise amounts.
    30      * @param srcRateAmount
    31      * @param tgtCurrency
    32      * @param startAmount
    33      * @param endAmount
    34      * @param stepAmount
    35      */
    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 );
    40     }
    41 
    42     /**
    43      * Do the conversion; updates the rate.
    44      * @param req
    45      * @return
    46      * @throws org.apidesign.apifest08.currency.IllegalRequestSubtypeException
    47      */
    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 ) );
    54             }
    55         }
    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() ) );
    61             }
    62         }
    63         return new ConversionResult( null );
    64     }
    65 
    66 }
    67 
    68 /**
    69  * An iterator that goes zig first, then zag, then zig again, then zag again, ad libitum.
    70  * @author jdvorak
    71  */
    72 class ZigZaggingBigDecimalIterator implements Iterator<BigDecimal> {
    73 
    74     private BigDecimal zigBounce;
    75     
    76     private BigDecimal zagBounce;
    77     
    78     private BigDecimal step;
    79     
    80     private BigDecimal currentValue;
    81     
    82     protected ZigZaggingBigDecimalIterator( final BigDecimal zagBounce, final BigDecimal zigBounce, final BigDecimal step ) {
    83         this. zigBounce = zigBounce;
    84         this.zagBounce = zagBounce;
    85         this.currentValue = zagBounce;
    86         this.step = step;
    87         
    88         if (  zigBounce == null ) {
    89             throw new NullPointerException( "zigAmount" );
    90         }
    91         if ( zagBounce == null ) {
    92             throw new NullPointerException( "zagAmount" );
    93         }
    94         if ( step == null ) {
    95             throw new NullPointerException( "stepAmount" );
    96         }
    97         final int stepSign = step.signum();
    98         if ( stepSign == 0 ) {
    99             throw new IllegalArgumentException( "stepAmount can't be zero" );
   100         }
   101         if ( stepSign * zigBounce.compareTo( zagBounce ) < 0 ) {
   102             throw new IllegalArgumentException( "stepAmount shall have the same sign as endAmount - startAmount" );
   103         }
   104     }
   105     
   106     public boolean hasNext() {
   107         return true;
   108     }
   109 
   110     public BigDecimal next() {
   111         final BigDecimal result = currentValue;
   112         
   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;
   119             zagBounce = temp;
   120             step = step.negate();
   121         }
   122         
   123         return result;
   124     }
   125 
   126     public void remove() {
   127         throw new UnsupportedOperationException("Removal is not supported.");
   128     }
   129     
   130 }