ConversionCalculator.java [src/usda/weru/util] Revision: default  Date:
/*
 * ConversionCalculator.java
 *
 * Created on January 30, 2006, 12:50 PM
 *
 * To change this template, choose Tools | Options and locate the template under
 * the Source Creation and Management node. Right-click the template and choose
 * Open. You can then make changes to the template in the Source Editor.
 */

package usda.weru.util;
import java.io.File;
import java.util.Hashtable;


/**
 * Stores a table of units and conversion to simplify unit conversions.
 * @author Joseph Levin
 */
public class ConversionCalculator {       
        
    /**
     * Stores the units avaliable to use in conversions.
     */
    private static Hashtable <String, ConversionUnit> c_unitCatalog;
    /**
     * Table of conversions.
     */
    private static Hashtable <ConversionUnit, Hashtable <ConversionUnit, Double>> c_table;
    
    
    static{
        c_unitCatalog = new Hashtable <String, ConversionUnit> ();
        c_table = new Hashtable <ConversionUnit, Hashtable <ConversionUnit, Double>> ();
        loadUnitCatalog(null);
    }           
    
    /**
     * Loads the unit catalog.  Currently the files are not read and only hardcoded 
     * units and conversions and uses.
     * @param file File to load
     */
    public static void loadUnitCatalog(File file){
        //LENGTH
        addUnit(new ConversionUnit("meter", "m"));
        addUnit(new ConversionUnit("centimeter", "cm"));
        addUnit(new ConversionUnit("milimeter", "mm"));



        addUnit(new ConversionUnit("foot","ft"));
        addUnit(new ConversionUnit("inch","in"));
        addUnit(new ConversionUnit("yard","yd"));
        addUnit(new ConversionUnit("mile","mi"));

        addUnit(new ConversionUnit("pound","lb"));
        addUnit(new ConversionUnit("ton","tn"));

        //AREA
        addUnit(new ConversionUnit("squaremeter", "m\u00B2", "m^2"));

        addUnit(new ConversionUnit("hectare","ha"));
        addUnit(new ConversionUnit("acre","acres", "ac"));

        //Special
        addUnit(new ConversionUnit("kilogrampermetersquared","kg/m\u00B2","kg/m^2"));
        addUnit(new ConversionUnit("tonperacre", "t/ac", "tn/ac", "tons/acre"));
        addUnit(new ConversionUnit("poundperacre", "lbs/acre", "lb/ac"));
        
        
        addUnit(new ConversionUnit("kilogrampermeter","kg/m"));
        addUnit(new ConversionUnit("tonperthousandfeet", "tons/1000ft","tn/1000ft"));
        
        addUnit(new ConversionUnit("percent","%"));
        addUnit(new ConversionUnit("ratio","ratio"));
        
        addUnit(new ConversionUnit("meterpermeter","m/m"));
        addUnit(new ConversionUnit("footperfoot","ft/ft"));
        
        addUnit(new ConversionUnit("fraction","fraction"));
        
        addUnit(new ConversionUnit("degree","degrees"));
        
        addUnit(new ConversionUnit("ln(J/m^2)","ln(J/m\u00B2)","ln(J/m^2)"));
        
        addUnit(new ConversionUnit("KJ/m^2/day","KJ/m\u00B2/day"));
        
        addUnit(new ConversionUnit("m^2/m^2", "m\u00B2/m\u00B2"));
        addUnit(new ConversionUnit("ft^2/ft^2", "ft\u00B2/ft\u00B2"));
        
        addUnit(new ConversionUnit("#/m^2", "#/m\u00B2"));
        addUnit(new ConversionUnit("#/ac", "#/ac"));
        
        addUnit(new ConversionUnit("liter/hectare", "L/ha"));
        addUnit(new ConversionUnit("gallon/acre", "gal/ac"));
        
        addUnit(new ConversionUnit("Mg/m^3", "Mg/m\u00B3"));
        addUnit(new ConversionUnit("lb/ft^3", "lb/ft\u00B3"));
        
        addUnit(new ConversionUnit("Mg/m^2", "Mg/m\u00B2"));
        addUnit(new ConversionUnit("lb/ft^2", "lb/ft\u00B2"));
        
        addUnit(new ConversionUnit("1/m", "1/m"));
        addUnit(new ConversionUnit("1/ft", "1/ft"));
        
        addUnit(new ConversionUnit("m^3/m^3", "m\u00B3/m\u00B3"));
        addUnit(new ConversionUnit("ft^3/ft^3", "ft\u00B3/ft\u00B3"));        
        //Lookup units for the conversions
        try{

            //LENGTH
            addConversion("m", "ft", 3.2808399, true);      
            addConversion("1/m", "1/ft", 3.2808399, true);
            addConversion("m", "in", 39.3700787, true);
            addConversion("mm", "in", 0.0393700787, true);      
                             

            //AREA
            addConversion("m^2", "ac", 0.000247105381, true);
            addConversion("m^2", "ha", 0.0001, true);
            addConversion("ha", "ac", 2.47105381, true);
            
            
            //Special
            addConversion("kg/m^2", "lb/ft^2", 0.204816144, true);
            addConversion("kg/m^2", "t/ac", 4.46089561, true);
            addConversion("kg/m^2", "lb/ac", 8921.79122, true);
            addConversion("ratio", "percent", 100, true);
            
            addConversion("m/m", "ft/ft", 1, true);
            
            addConversion("kg/m", "tn/1000ft", 0.335984488, true);
            addConversion("m^2/m^2", "ft^2/ft^2", 1, true);
            
            addConversion("#/m^2", "#/ac", 4046.85642, true);
            
            addConversion("L/ha", "gal/ac", 0.106906637, true);
            
            addConversion("Mg/m^3", "lb/ft^3", 62.4279606, true);
            addConversion("Mg/m^2", "lb/ft^2", 204.816144, true);
            
            addConversion("m^3/m^3", "ft^3/ft^3", 1, true);
            
            
            
            
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
    
    public static double convert(double value, String from, String to) throws ConversionNotFoundException, UnitNotFoundException{
        double factor = getConversionFactor(from, to);
        return value * factor;
    }
    
    public static double convert(double value, ConversionUnit from, ConversionUnit to) throws ConversionNotFoundException{
        double factor = getConversionFactor(from, to);
        return value * factor;
    }
    
    
    
    
    /**
     * Adds a ConversionUnit object to the catalog.
     * @param unit ConversionUnit to add.
     */
    public static void addUnit(ConversionUnit unit){
        c_unitCatalog.put(unit.getName(), unit);
    }
    
    /**
     * Helper method for adding conversions by string names of units.
     * @param from Name of the unit intial unit
     * @param to Name of the final unit
     * @param factor Conversion factor
     * @param reverse If true, a reverse conversion will be added.
     */
    public static void addConversion(String from, String to, double factor, boolean reverse){
        try{
            ConversionUnit fromUnit = getUnitFromTag(from);              
            ConversionUnit toUnit = getUnitFromTag(to); 
            addConversion(fromUnit, toUnit, factor, reverse);
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
    
    /**
     * Adds a converion to the table.
     * @param from intial ConversionUnit object 
     * @param to final ConversionUnit object 
     * @param factor conversion factor
     * @param reverse If true, a reverse conversion will be added.
     */
    public static void addConversion(ConversionUnit from, ConversionUnit to, double factor, boolean reverse){
        getFirstTable(from).put(to, factor);      
        if (reverse){
            addConversion(to, from, 1/factor, false);
        }
    }
    
    /**
     * Returns the conversion factor between two units.
     * @param from Unit to convert from.
     * @param to Unit to convert to.
     * @throws usda.weru.util.ConversionCalculator.ConversionNotFoundException If the conversion is not in the conversion table.
     * @throws usda.weru.util.ConversionCalculator.UnitNotFoundException If a unit is not found in the catalog
     * @return Conversion factor
     */
    public static double getConversionFactor(Object from, Object to) throws ConversionNotFoundException, UnitNotFoundException{
        ConversionUnit uFrom = getUnitFromTag(from.toString());
        ConversionUnit uTo = getUnitFromTag(to.toString());
        return getConversionFactor(uFrom, uTo);
    }
    
    /**
     * Returns the conversion factor between two units.
     * @param from Unit to convert from.
     * @param to Unit to convert to.
     * @throws usda.weru.util.ConversionCalculator.ConversionNotFoundException If the conversion is not in the table.
     * @return Conversino factor.
     */
    public static double getConversionFactor(ConversionUnit from, ConversionUnit to) throws ConversionNotFoundException{
        if (from.equals(to)) return 1;       //Easy factor
        
        Double factor = getFirstTable(from).get(to);
        if (factor != null){
            return factor.doubleValue();
        }
        else{
            throw new ConversionNotFoundException(from, to);
        }        
    }
    
    
    /**
     * Returns the inner table used to store conversions.
     * @param unit Unit to return the table for.
     * @return Table of conversinons from the unit.
     */
    private static Hashtable <ConversionUnit, Double> getFirstTable(ConversionUnit unit){
        Hashtable <ConversionUnit, Double> table = c_table.get(unit);
        if (table != null){
            return table;
        }
        else{
            table = new Hashtable <ConversionUnit, Double> ();
            c_table.put(unit, table);
            return table;
        }
    }
    
    /**
     * Looksup ConversionUnits from a string tag.  The tag can be the full name or
     * abbreviation as stored in the catalog.
     * @param tag Tag to lookup.
     * @throws usda.weru.util.ConversionCalculator.UnitNotFoundException If the tag does not represent a unit in the catalog.
     * @return ConversionUnit object
     */
    public static ConversionUnit getUnitFromTag(String tag) throws UnitNotFoundException{
        ConversionUnit result;
        result = c_unitCatalog.get(tag);
        if (result == null){
            for (ConversionUnit unit : c_unitCatalog.values()){
                if (unit.accept(tag)) return unit;
            }
        }
        if (result != null){
            return result;    
        }
        else{
            throw new UnitNotFoundException(tag);
        }
    }
     
 
    
    /**
     * Exception for trapping unknown unit tags
     */
    static public class UnitNotFoundException extends Exception{
        /**
         * ConversionUnit object
         */
        private String c_unit;
        /**
         * Constructor for the exception.
         * @param unit Tag not found
         */
        UnitNotFoundException(String unit){
            super("Unit Not Found In Table: " + unit);
            c_unit = unit;
        }
        /**
         * Getter method for the unknown unit tag.
         * @return Unknown unit tag
         */
        public String getUnitTag(){
            return c_unit;
        }
    }
    
   
    
    /**
     * Exception for trapping undefined conversions
     */
    static public class ConversionNotFoundException extends Exception{
        /**
         * ConversionUnit object
         */
        private ConversionUnit c_fromUnit;
        /**
         * ConversionUnit object
         */
        private ConversionUnit c_toUnit;
        /**
         * Constructor for the conversion not found exception.
         * @param from intial ConversionUnit 
         * @param to final ConversionUnit 
         */
        ConversionNotFoundException(ConversionUnit from, ConversionUnit to){
            super("Conversion Not Found In Table: from " + from.toString() + " to " + to.toString());
            c_fromUnit = from;
            c_toUnit = to;
        }
        /**
         * Getter method for the from unit
         * @return ConversionUnit object
         */
        public ConversionUnit getFromUnit(){
            return c_fromUnit;
        }
        /**
         * Getter method for the to ConversionUnit object
         * @return ConversionUnit object
         */
        public ConversionUnit getToUnit(){
            return c_toUnit;
        }
    }
    
    
    

}