001/*
002 * Units of Measurement Reference Implementation
003 * Copyright (c) 2005-2016, Jean-Marie Dautelle, Werner Keil, V2COM.
004 *
005 * All rights reserved.
006 *
007 * Redistribution and use in source and binary forms, with or without modification,
008 * are permitted provided that the following conditions are met:
009 *
010 * 1. Redistributions of source code must retain the above copyright notice,
011 *    this list of conditions and the following disclaimer.
012 *
013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
014 *    and the following disclaimer in the documentation and/or other materials provided with the distribution.
015 *
016 * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products
017 *    derived from this software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package tec.units.ri;
031
032import java.util.ArrayList;
033import java.util.List;
034
035import javax.measure.UnitConverter;
036
037/**
038 * <p>
039 * The base class for our {@link UnitConverter} implementations.
040 * </p>
041 *
042 * @author <a href="mailto:units@catmedia.us">Werner Keil</a>
043 * @version 0.8.1, $Date: 2016-01-17 $
044 */
045public abstract class AbstractConverter implements UnitConverter {
046
047  /**
048   * 
049   */
050  // private static final long serialVersionUID = 5790242858468427131L;
051
052  /**
053   * The ratio of the circumference of a circle to its diameter.
054   **/
055  protected static final double PI = 3.1415926535897932384626433832795;
056
057  /**
058   * Holds identity converter.
059   */
060  public static final AbstractConverter IDENTITY = new Identity();
061
062  /**
063   * Default constructor.
064   */
065  protected AbstractConverter() {
066  }
067
068  /**
069   * Concatenates this physics converter with another unit converter. The resulting converter is equivalent to first converting by the specified
070   * converter (right converter), and then converting by this converter (left converter).
071   *
072   * @param that
073   *          the other converter.
074   * @return the concatenation of this converter with that converter.
075   */
076  public AbstractConverter concatenate(AbstractConverter that) {
077    return (that == IDENTITY) ? this : new Pair(this, that);
078  }
079
080  public boolean isIdentity() {
081    return false;
082  }
083
084  @Override
085  public abstract boolean equals(Object cvtr);
086
087  @Override
088  public abstract int hashCode();
089
090  @Override
091  public abstract AbstractConverter inverse();
092
093  @Override
094  public UnitConverter concatenate(UnitConverter converter) {
095    return (converter == IDENTITY) ? this : new Pair(this, converter);
096  }
097
098  @Override
099  public List<? extends UnitConverter> getConversionSteps() {
100    final List<AbstractConverter> steps = new ArrayList<AbstractConverter>();
101    steps.add(this);
102    return steps;
103  }
104
105  /**
106   * @throws IllegalArgumentException
107   *           if the value is </code>null</code>.
108   */
109  public Number convert(Number value) {
110    if (value != null) {
111      return convert(value.doubleValue());
112    } else {
113      throw new IllegalArgumentException("Value cannot be null");
114    }
115  }
116
117  public abstract double convert(double value);
118
119  /**
120   * This class represents the identity converter (singleton).
121   */
122  private static final class Identity extends AbstractConverter {
123
124    @Override
125    public boolean isIdentity() {
126      return true;
127    }
128
129    @Override
130    public Identity inverse() {
131      return this;
132    }
133
134    @Override
135    public double convert(double value) {
136      return value;
137    }
138
139    @Override
140    public UnitConverter concatenate(UnitConverter converter) {
141      return converter;
142    }
143
144    @Override
145    public boolean equals(Object cvtr) {
146      return (cvtr instanceof Identity);
147    }
148
149    @Override
150    public int hashCode() {
151      return 0;
152    }
153
154    public boolean isLinear() {
155      return true;
156    }
157  }
158
159  /**
160   * This class represents converters made up of two or more separate converters (in matrix notation <code>[pair] = [left] x [right]</code>).
161   */
162  public static final class Pair extends AbstractConverter {
163
164    /**
165     * Holds the first converter.
166     */
167    private final UnitConverter left;
168
169    /**
170     * Holds the second converter.
171     */
172    private final UnitConverter right;
173
174    /**
175     * Creates a compound converter resulting from the combined transformation of the specified converters.
176     *
177     * @param left
178     *          the left converter.
179     * @param right
180     *          the right converter.
181     * @throws IllegalArgumentException
182     *           if either the left or right converter are </code>null</code>
183     */
184    public Pair(UnitConverter left, UnitConverter right) {
185      this.left = left;
186      this.right = right;
187    }
188
189    public boolean isLinear() {
190      return left.isLinear() && right.isLinear();
191    }
192
193    @Override
194    public boolean isIdentity() {
195      return false;
196    }
197
198    @Override
199    public List<UnitConverter> getConversionSteps() {
200      final List<UnitConverter> steps = new ArrayList<UnitConverter>();
201      List<? extends UnitConverter> leftCompound = left.getConversionSteps();
202      List<? extends UnitConverter> rightCompound = right.getConversionSteps();
203      steps.addAll(leftCompound);
204      steps.addAll(rightCompound);
205      return steps;
206    }
207
208    @Override
209    public Pair inverse() {
210      return new Pair(right.inverse(), left.inverse());
211    }
212
213    @Override
214    public double convert(double value) {
215      return left.convert(right.convert(value));
216    }
217
218    @Override
219    public boolean equals(Object cvtr) {
220      if (this == cvtr)
221        return true;
222      if (!(cvtr instanceof Pair))
223        return false;
224      Pair that = (Pair) cvtr;
225      return (this.left.equals(that.left)) && (this.right.equals(that.right));
226    }
227
228    @Override
229    public int hashCode() {
230      return left.hashCode() + right.hashCode();
231    }
232
233    public UnitConverter getLeft() {
234      return left;
235    }
236
237    public UnitConverter getRight() {
238      return right;
239    }
240  }
241}