/*
 * Copyright 1998, University Corporation for Atmospheric Research
 * See file LICENSE for copying and redistribution conditions.
 *
 * $Id: UnitTable.java,v 1.6 2009-04-21 20:15:10 steve Exp $
 */

package visad.data.units;


import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;
import visad.BaseUnit;
import visad.DerivedUnit;
import visad.OffsetUnit;
import visad.SI;
import visad.ScaledUnit;
import visad.Unit;


/**
 * Provides support for a table of units.
 *
 * @author Steven R. Emmerson
 */
public class
UnitTable
    implements  UnitsDB, java.io.Serializable
{

	private static final long serialVersionUID = 1L;

	/**
     * Name-to-unit map.
     * @serial
     */
    private final Hashtable nameMap;

    /**
     * Symbol-to-unit map.
     * @serial
     */
    private final Hashtable symbolMap;

    /**
     * The unit set.
     * @serial
     */
    private final SortedSet unitSet;


    /**
     * Construct.
     *
     * @param numNames      Anticipated minimum number of names in the
     *              database.
     * @throws IllegalArgumentException numNames < 0.
     */
    public
    UnitTable(int numNames)
    throws IllegalArgumentException
    {
    this(numNames, 0);
    }


    /**
     * Construct.
     *
     * @param numNames      Anticipated minimum number of names in the
     *              database.
     * @param numSymbols    Anticipated minimum number of symbols in the
     *              database.
     * @throws IllegalArgumentException numNames < 0 || numSymbols < 0
     *                  .
     */
    public
    UnitTable(int numNames, int numSymbols)
    throws IllegalArgumentException
    {
    if (numNames < 0 || numSymbols < 0)
        throw new IllegalArgumentException("Negative hashtable size");
    nameMap = new Hashtable(numNames);
    symbolMap = new Hashtable(numSymbols);
    unitSet =
        Collections.synchronizedSortedSet(
        new TreeSet(
            new Comparator()
            {
            public int
            compare(Object o1, Object o2)
            {
                return ((Unit)o1).toString().compareToIgnoreCase(
                ((Unit)o2).toString());
            }
            }));
    }


    /**
     * Get a unit.
     *
     * @param name  The exact name of the unit to be retrieved.  If it is
     *          the empty string, then the dimensionless, unity
     *          unit
     *          will be returned.
     * @return      The unit of the matching entry or null if not found.
     * @require     name is non-null.
     */
    public Unit
    get(String name)
    {
    Unit    unit = null;    // default
    if (name.length() == 0)
    {
        // Return a unity, dimensionless unit.
        unit = new DerivedUnit();
    }
    else
    {
        /*
         * Try the symbol table first because symbols are case-sensitive.
         */
        unit = getBySymbol(name);
        if (unit == null)
        unit = getByName(name);
    }
    return unit;
    }


    /**
     * Get a unit by name.
     *
     * @param name  The name of the unit to be retrieved.  If it is
     *          the empty string, then the dimensionless, unity
     *          unit
     *          will be returned.
     * @return      The unit of the matching entry or null if not found.
     * @require     name is non-null.
     */
    protected Unit
    getByName(String name)
    {
    return (Unit)nameMap.get(name.toLowerCase());
    }


    /**
     * Get a unit by symbol.
     *
     * @param symbol    The exact symbol of the unit to be retrieved.  If it is
     *          the empty string, then the dimensionless, unity
     *          unit
     *          will be returned.
     * @return      The unit of the matching entry or null if not found.
     * @require     name is non-null.
     */
    protected Unit
    getBySymbol(String symbol)
    {
    return (Unit)symbolMap.get(symbol);
    }


    /**
     * Adds a base unit.
     *
     * @param unit  The base unit to be added.
     * @throws IllegalArgumentException
     *          The base unit argument is invalid.
     */
    public void
    put(BaseUnit unit)
    throws IllegalArgumentException
    {
    String  name = unit.unitName();
    putName(name, unit);
    putName(makePlural(name), unit);
    putSymbol(unit.unitSymbol(), unit);
    }


    /**
     * Returns the plural form of a name.  Regular rules are used to generate
     * the plural form.
     * @param name      The name.
     * @return          The plural form of the name.
     */
    protected String
    makePlural(String name)
    {
    String  plural;
    int length = name.length();
    char    lastChar = name.charAt(length-1);
    if (lastChar != 'y')
    {
        plural = name +
        (lastChar == 's' || lastChar == 'x' ||
         lastChar == 'z' || name.endsWith("ch")
            ? "es"
            : "s");
    }
    else
    {
        if (length == 1)
        {
        plural = name + "s";
        }
        else
        {
        char    penultimateChar = name.charAt(length-2);
        plural =
            (penultimateChar == 'a' || penultimateChar == 'e' ||
             penultimateChar == 'i' || penultimateChar == 'o' ||
             penultimateChar == 'u')
            ? name + "s"
            : name.substring(0, length-1) + "ies";
        }
    }
    return plural;
    }


    /**
     * Adds a name and a unit to the name table.
     * @param name      The name to be added.
     * @param unit      The unit to be added.
     * @throws IllegalArgumentException Invalid argument.
     */
    public void
    putName(String name, Unit unit)
    {
    if (name == null)
        throw new IllegalArgumentException(this.getClass().getName() +
        ".putName(String,Unit):  unit name");
    if (unit == null)
        throw new IllegalArgumentException(this.getClass().getName() +
        ".putName(String,Unit):  unit");
    name = name.toLowerCase();
    String[]    names =
        (name.indexOf(' ') == -1 && name.indexOf('_') == -1)
        ? new String[] {name}
        : new String[] {
            name.replace('_', ' '),
            name.replace(' ', '_')};
    for (int i = 0; i < names.length; i++)
    {
        Unit    prevUnit = (Unit)nameMap.get(names[i]);
        if (prevUnit != null && !prevUnit.equals(unit))
        throw new IllegalArgumentException(
            "Attempt to replace unit \"" + prevUnit + " with unit \"" +
            unit + '"');
        nameMap.put(names[i], unit);
    }
    unitSet.add(unit);
    }


    /**
     * Adds a symbol and a unit to the symbol table.
     * @param symbol        The symbol to be added.
     * @param unit      The unit to be added.
     * @throws IllegalArgumentException Invalid argument.
     */
    public void
    putSymbol(String symbol, Unit unit)
    {
    if (symbol == null)
        throw new IllegalArgumentException(this.getClass().getName() +
        ".putName(String,Unit):  unit symbol");
    if (unit == null)
        throw new IllegalArgumentException(this.getClass().getName() +
        ".putName(String,Unit):  unit");
    Unit    prevUnit = (Unit)symbolMap.get(symbol);
    if (prevUnit != null && !prevUnit.equals(unit))
        throw new IllegalArgumentException(
        "Attempt to replace unit \"" + prevUnit + " with unit \"" +
        unit + '"');
    symbolMap.put(symbol, unit);
    unitSet.add(unit);
    }


    /**
     * Get an enumeration of the unit names in the table.  The Object returned
     * by nextElement() is a String.
     */
    public Enumeration
    getNameEnumeration()
    {
    return nameMap.keys();
    }


    /**
     * Get an enumeration of the unit symbols in the table.  The Object returned
     * by nextElement() is a String.
     */
    public Enumeration
    getSymbolEnumeration()
    {
    return symbolMap.keys();
    }


    /**
     * Get an enumeration of the units in the table.  The Object returned
     * by nextElement() is a Unit.
     */
    public Enumeration
    getUnitEnumeration()
    {
    return new Enumeration()
    {
        private final Iterator  iter = unitSet.iterator();
        public boolean hasMoreElements()
        {
        return iter.hasNext();
        }
        public Object nextElement()
        {
        return iter.next();
        }
    };
    }


    /**
     * Return a string representation of this instance.
     */
    public String
    toString()
    {
    return nameMap.toString() + symbolMap.toString();
    }


    /**
     * Test this class.
     * @exception java.lang.Exception   A problem occurred.
     */
    public static void main(String[] args)
    throws Exception
    {
    UnitTable   db = new UnitTable(13);
    db.put(SI.ampere);
    db.put(SI.candela);
    db.put(SI.kelvin);
    db.put(SI.kilogram);
    db.put(SI.meter);
    db.put(SI.mole);
    db.put(SI.second);
    db.put(SI.radian);
    db.putName("amp", SI.ampere);   // alias
    db.putName("celsius", new OffsetUnit(273.15, SI.kelvin));
    db.putName("newton",  
        SI.kilogram.multiply(SI.meter).divide(SI.second.pow(2)));
    db.putName("rankine", new ScaledUnit(1/1.8, SI.kelvin));
    db.putName("fahrenheit",
        new OffsetUnit(459.67, (ScaledUnit)db.get("rankine")));
    System.out.println("db:");
    System.out.println(db.toString());
    }


    /**
     * List the units in the database.
     */
    public void
    list()
    {
    Enumeration en = getUnitEnumeration();
    
    while (en.hasMoreElements())
    {
        Unit    unit = (Unit)en.nextElement();
        System.out.println(unit.getIdentifier() + " = " + 
        unit.getDefinition());
    }
    }
}

 

Ads help maintain this website.