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