001/*
002 * Units of Measurement Reference Implementation
003 * Copyright (c) 2005-2017, 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 static tec.units.ri.format.UnitStyle.*;
033
034import java.util.HashMap;
035import java.util.HashSet;
036import java.util.Map;
037import java.util.Set;
038import java.util.logging.Level;
039import java.util.logging.Logger;
040
041import javax.measure.Dimension;
042import javax.measure.Quantity;
043import javax.measure.Unit;
044import javax.measure.spi.SystemOfUnits;
045
046import tec.units.ri.format.SimpleUnitFormat;
047import tec.units.ri.format.UnitStyle;
048
049/**
050 * <p>
051 * An abstract base class for unit systems.
052 * </p>
053 *
054 * @author <a href="mailto:units@catmedia.us">Werner Keil</a>
055 * @version 1.0.4, October 7, 2016
056 */
057public abstract class AbstractSystemOfUnits implements SystemOfUnits {
058  protected static final Logger logger = Logger.getLogger(AbstractSystemOfUnits.class.getName());
059
060  /**
061   * Holds the units.
062   */
063  protected final Set<Unit<?>> units = new HashSet<Unit<?>>();
064
065  /**
066   * Holds the mapping quantity to unit.
067   */
068  @SuppressWarnings("rawtypes")
069  protected final Map<Class<? extends Quantity>, Unit> quantityToUnit = new HashMap<Class<? extends Quantity>, Unit>();
070
071  /**
072   * The natural logarithm.
073   */
074  protected static final double E = 2.71828182845904523536028747135266;
075
076  /*
077   * (non-Javadoc)
078   * 
079   * @see SystemOfUnits#getName()
080   */
081  public abstract String getName();
082
083  // ///////////////////
084  // Collection View //
085  // ///////////////////
086  public Set<Unit<?>> getUnits() {
087    if (logger.isLoggable(Level.FINEST)) {
088      for (Unit<?> u : units) {
089        logger.log(Level.FINEST, u + "; D: " + u.getDimension() + "; C: " + u.getClass());
090      }
091    }
092    return units;
093  }
094
095  @Override
096  public Set<? extends Unit<?>> getUnits(Dimension dimension) {
097    final Set<Unit<?>> set = new HashSet<Unit<?>>();
098    for (Unit<?> unit : this.getUnits()) {
099      if (dimension.equals(unit.getDimension())) {
100        set.add(unit);
101      }
102    }
103    return set;
104  }
105
106  @SuppressWarnings("unchecked")
107  public <Q extends Quantity<Q>> Unit<Q> getUnit(Class<Q> quantityType) {
108    return quantityToUnit.get(quantityType);
109  }
110
111  protected static final class Helper {
112    static Set<Unit<?>> getUnitsOfDimension(final Set<Unit<?>> units, Dimension dimension) {
113      if (dimension != null) {
114        Set<Unit<?>> dimSet = new HashSet<Unit<?>>();
115        for (Unit<?> u : units) {
116          if (dimension.equals(u.getDimension())) {
117            dimSet.add(u);
118          }
119        }
120        return dimSet;
121      }
122      return null;
123    }
124
125    /**
126     * Adds a new named unit to the collection.
127     * 
128     * @param unit
129     *          the unit being added.
130     * @param name
131     *          the name of the unit.
132     * @return <code>unit</code>.
133     * @since 1.0
134     */
135    public static <U extends Unit<?>> U addUnit(Set<Unit<?>> units, U unit, String name) {
136      return addUnit(units, unit, name, NAME);
137    }
138
139    /**
140     * Adds a new named unit to the collection.
141     * 
142     * @param unit
143     *          the unit being added.
144     * @param name
145     *          the name of the unit.
146     * @param name
147     *          the symbol of the unit.
148     * @param style
149     *          style of the unit.
150     * @return <code>unit</code>.
151     * @since 1.0.1
152     */
153    @SuppressWarnings("unchecked")
154    public static <U extends Unit<?>> U addUnit(Set<Unit<?>> units, U unit, final String name, final String symbol, UnitStyle style) {
155      switch (style) {
156        case NAME:
157        case SYMBOL:
158        case SYMBOL_AND_LABEL:
159          if (name != null && symbol != null && unit instanceof AbstractUnit) {
160            AbstractUnit<?> aUnit = (AbstractUnit<?>) unit;
161            aUnit.setName(name);
162            if (SYMBOL.equals(style) || SYMBOL_AND_LABEL.equals(style)) {
163              aUnit.setSymbol(symbol);
164            }
165            if (LABEL.equals(style) || SYMBOL_AND_LABEL.equals(style)) {
166              SimpleUnitFormat.getInstance().label(unit, symbol);
167            }
168            units.add(aUnit);
169            return (U) aUnit;
170          }
171          if (name != null && unit instanceof AbstractUnit) {
172            AbstractUnit<?> aUnit = (AbstractUnit<?>) unit;
173            aUnit.setName(name);
174            units.add(aUnit);
175            return (U) aUnit;
176          }
177          break;
178        default:
179          if (logger.isLoggable(Level.FINEST)) {
180            logger.log(Level.FINEST, "Unknown style " + style + "; unit " + unit + " can't be rendered with '" + symbol + "'.");
181          }
182          break;
183      }
184      if (LABEL.equals(style) || SYMBOL_AND_LABEL.equals(style)) {
185        SimpleUnitFormat.getInstance().label(unit, symbol);
186      }
187      units.add(unit);
188      return unit;
189    }
190
191    /**
192     * Adds a new labeled unit to the set.
193     * 
194     * @param units
195     *          the set to add to.
196     * 
197     * @param unit
198     *          the unit being added.
199     * @param text
200     *          the text for the unit.
201     * @param style
202     *          style of the unit.
203     * @return <code>unit</code>.
204     * @since 1.0.1
205     */
206    @SuppressWarnings("unchecked")
207    public static <U extends Unit<?>> U addUnit(Set<Unit<?>> units, U unit, String text, UnitStyle style) {
208      switch (style) {
209        case NAME:
210          if (text != null && unit instanceof AbstractUnit) {
211            AbstractUnit<?> aUnit = (AbstractUnit<?>) unit;
212            aUnit.setName(text);
213            units.add(aUnit);
214            return (U) aUnit;
215          }
216          break;
217        case SYMBOL:
218          if (text != null && unit instanceof AbstractUnit) {
219            AbstractUnit<?> aUnit = (AbstractUnit<?>) unit;
220            aUnit.setSymbol(text);
221            units.add(aUnit);
222            return (U) aUnit;
223          }
224          break;
225        case SYMBOL_AND_LABEL:
226          if (text != null && unit instanceof AbstractUnit) {
227            AbstractUnit<?> aUnit = (AbstractUnit<?>) unit;
228            aUnit.setSymbol(text);
229            units.add(aUnit);
230            SimpleUnitFormat.getInstance().label(aUnit, text);
231            return (U) aUnit;
232          } else { // label in any case, returning below
233            SimpleUnitFormat.getInstance().label(unit, text);
234          }
235          break;
236        case LABEL:
237          SimpleUnitFormat.getInstance().label(unit, text);
238          break;
239        default:
240          logger.log(Level.FINEST, "Unknown style " + style + "; unit " + unit + " can't be rendered with '" + text + "'.");
241          break;
242      }
243      units.add(unit);
244      return unit;
245    }
246
247    /**
248     * Adds a new named unit to the collection.
249     * 
250     * @param unit
251     *          the unit being added.
252     * @param name
253     *          the name of the unit.
254     * @param name
255     *          the symbol of the unit.
256     * @return <code>unit</code>.
257     * @since 1.0
258     */
259    @SuppressWarnings("unchecked")
260    public static <U extends Unit<?>> U addUnit(Set<Unit<?>> units, U unit, final String name, final String symbol) {
261      if (name != null && symbol != null && unit instanceof AbstractUnit) {
262        AbstractUnit<?> aUnit = (AbstractUnit<?>) unit;
263        aUnit.setName(name);
264        aUnit.setSymbol(symbol);
265        units.add(aUnit);
266        return (U) aUnit;
267      }
268      if (name != null && unit instanceof AbstractUnit) {
269        AbstractUnit<?> aUnit = (AbstractUnit<?>) unit;
270        aUnit.setName(name);
271        units.add(aUnit);
272        return (U) aUnit;
273      }
274      if (symbol != null && unit instanceof AbstractUnit) {
275        AbstractUnit<?> aUnit = (AbstractUnit<?>) unit;
276        aUnit.setSymbol(symbol);
277        units.add(aUnit);
278        return (U) aUnit;
279      }
280      units.add(unit);
281      return unit;
282    }
283  }
284}