001/*
002 * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
003 * Copyright (C) 2006 - JScience (http://jscience.org/)
004 * All rights reserved.
005 * 
006 * Permission to use, copy, modify, and distribute this software is
007 * freely granted, provided that this notice is preserved.
008 */
009package javax.measure.unit;
010
011import javax.measure.converter.UnitConverter;
012import javax.measure.quantity.Quantity;
013
014/**
015 * <p> This class represents the units used in expressions to distinguish
016 *     between quantities of a different nature but of the same dimensions.</p>
017 *     
018 * <p> Instances of this class are created through the 
019 *     {@link Unit#alternate(String)} method.</p>
020 *
021 * @author  <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
022 * @version 4.2, August 26, 2007
023 */
024public final class AlternateUnit<Q extends Quantity> extends DerivedUnit<Q> {
025
026    /**
027     * Holds the symbol.
028     */
029    private final String _symbol;
030
031    /**
032     * Holds the parent unit (a system unit).
033     */
034    private final Unit<?> _parent;
035
036    /**
037     * Creates an alternate unit for the specified unit identified by the 
038     * specified symbol. 
039     *
040     * @param symbol the symbol for this alternate unit.
041     * @param parent the system unit from which this alternate unit is
042     *        derived.
043     * @throws UnsupportedOperationException if the source is not 
044     *         a standard unit.
045     * @throws IllegalArgumentException if the specified symbol is 
046     *         associated to a different unit.
047     */
048    AlternateUnit(String symbol, Unit<?> parent) {
049        if (!parent.isStandardUnit())
050            throw new UnsupportedOperationException(this
051                    + " is not a standard unit");
052        _symbol = symbol;
053        _parent = parent;
054        // Checks if the symbol is associated to a different unit.
055        synchronized (Unit.SYMBOL_TO_UNIT) {
056            Unit<?> unit = Unit.SYMBOL_TO_UNIT.get(symbol);
057            if (unit == null) {
058                Unit.SYMBOL_TO_UNIT.put(symbol, this);
059                return;
060            }
061            if (unit instanceof AlternateUnit) {
062                AlternateUnit<?> existingUnit = (AlternateUnit<?>) unit;
063                if (symbol.equals(existingUnit._symbol)
064                        && _parent.equals(existingUnit._parent))
065                    return; // OK, same unit.
066            }
067            throw new IllegalArgumentException("Symbol " + symbol
068                    + " is associated to a different unit");
069        }
070    }
071
072    /**
073     * Returns the symbol for this alternate unit.
074     *
075     * @return this alternate unit symbol.
076     */
077    public final String getSymbol() {
078        return _symbol;
079    }
080
081    /**
082     * Returns the parent unit from which this alternate unit is derived 
083     * (a system unit itself).
084     *
085     * @return the parent of the alternate unit.
086     */
087    @SuppressWarnings("unchecked")
088    public final Unit<? super Q> getParent() {
089        return (Unit<? super Q>) _parent;
090    }
091
092    @Override
093    public final Unit<? super Q> getStandardUnit() {
094        return this;
095    }
096
097    @Override
098    public final UnitConverter toStandardUnit() {
099        return UnitConverter.IDENTITY;
100    }
101
102    /**
103     * Indicates if this alternate unit is considered equals to the specified 
104     * object (both are alternate units with equal symbol, equal base units
105     * and equal converter to base units).
106     *
107     * @param  that the object to compare for equality.
108     * @return <code>true</code> if <code>this</code> and <code>that</code>
109     *         are considered equals; <code>false</code>otherwise. 
110     */
111    public boolean equals(Object that) {
112        if (this == that)
113            return true;
114        if (!(that instanceof AlternateUnit))
115            return false;
116        AlternateUnit<?> thatUnit = (AlternateUnit<?>) that;
117        return this._symbol.equals(thatUnit._symbol); // Symbols are unique.
118    }
119
120    // Implements abstract method.
121    public int hashCode() {
122        return _symbol.hashCode();
123    }
124
125    private static final long serialVersionUID = 1L;
126}