<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">/*
 * ConvertedValue.java
 *
 * Created on December 28, 2005, 4:59 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.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.text.*;
import java.util.*;

/**
 * Stores a double value and maintains the measurement units the value may be 
 * displayed in.  A hashtable creates ties between systems of measurement such as SI
 * or US and their respective units as they apply to the stored value.
 * @author Joseph Levin
 */
public class ConvertedValue {

    /**
     * The base units the value is stored in.
     */
    private ConversionUnit c_baseUnits;
    /**
     * The currently active display units.  This variable is assigned as unit systems are set.
     */
    private ConversionUnit c_displayUnits;
    /**
     * Hashtable with system name / unit pairs.  Used to tie a system, such as "SI" or "US" to a measurement unit.
     */
    private Map&lt;String, ConversionUnit&gt; c_displayUnitsTable;

    /**
     *
     */
    public static final String PROP_VALUE = "value";

    /**
     *
     */
    public static final String PROP_DISPLAY_VALUE = "displayValue";

    /**
     *
     */
    public static final String PROP_DISPLAY_UNIT = "displayUnits";

    private PropertyChangeSupport c_changes;

    /**
     * Cached conversion factor.  This will probally need to be moved to the 
     * ConversionCalculator class.
     */
    private double c_factor;
    /**
     * Value being stored in base units.
     */
    private double c_value;
    /**
     * Number format for toStringValue and toStringDisplayValue methods.
     */
    private String c_valueOutputFormat = "#.##";

    /**
     * Prepares variables and objects.
     */
    private void init() {
        c_displayUnitsTable = new HashMap&lt;String, ConversionUnit&gt;();
        c_changes = new PropertyChangeSupport(this);
    }

    /**
     * Default constructor.  Uses a conversion factor of 1, and no units.
     */
    public ConvertedValue() {
        init();
        c_factor = 1;
    }

    /**
     * Recommended Constructor.  Sets the base units and adds the base units to 
     * the display table with the passed system.  The display units are set to the
     * base units.
     * @param system 
     * @param baseUnits 
     */
    public ConvertedValue(String system, String baseUnits) {
        init();
        try {
            c_baseUnits = ConversionCalculator.getUnitFromTag(baseUnits);
            if (system != null &amp;&amp; system.length() &gt; 0) {
                addDisplayUnits(system, c_baseUnits);
                setDisplaySystem(system);
            } else {
                c_displayUnits = c_baseUnits;
            }
            updateConversionFactor();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Returns the base value stored.
     * @return The double value stored.  This is an unconverted value.
     */
    public double getValue() {
        return c_value;
    }

    /**
     * Sets the base value.
     * @param value The double value to be stored.  
     */
    public void setValue(double value) {
        double oldValue = c_value;
        double oldDisplay = getDisplayValue();
        c_value = value;

        c_changes.firePropertyChange(PROP_VALUE, oldValue, value);
        c_changes.firePropertyChange(PROP_DISPLAY_VALUE, oldDisplay, getDisplayValue());
    }

    /**
     * Sets the measurement system to be used when the display value is requested.
     * Use the addDisplayUnits method first to assign units to a system.
     * @param system The measurement system to display the units in.
     */
    public void setDisplaySystem(String system) {

        ConversionUnit unit = c_displayUnitsTable.get(system);
        setDisplayUnits(unit);
//            if (unit != null){
//                double oldDisplay = getDisplayValue();
//                c_displayUnits = unit;
//                updateConversionFactor();
//                
//                c_changes.firePropertyChange(PROP_DISPLAY_VALUE, oldDisplay, getDisplayValue());
//            }
//            else{
//                //System.err.println("There are no units for the " + system + " system of measurement.");
//            }
    }

    /**
     * Assign units to systems.  Only one unit can be tied to a system.  For
     * example, assume the value represents area.  The base units could be
     * km^2 and then a unit could be added for SI and US display.
     * addDisplayUnits("US", "ft^2");
     * addDisplayUnits("SI", "m^2");
     *
     * Now the interface is only required to tell the ConvertedValue the 
     * desired display system.
     *
     * @param system The tag or name of the measurement system.
     * @param units The measurement units to be associated with the system 
     */
    public void addDisplayUnits(String system, ConversionUnit units) {
        if (system == null || units == null) {
            return;
        }
        c_displayUnitsTable.put(system, units);
    }

    /**
     * Assigns units to systems.  First looks up the unit from the conversion
     * calculator.
     * @param system The tag or name of the measurement system.
     * @param units The measurement units to be associated with the system 
     */
    public void addDisplayUnits(String system, String units) {
        try {
            ConversionUnit unit = ConversionCalculator.getUnitFromTag(units);
            addDisplayUnits(system, unit);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * If the current base and display units are not null then the conversion factor is calcuated and cached.
     */
    private void updateConversionFactor() {
        if (c_baseUnits == null || c_displayUnits == null) {
            c_factor = 1;
            return;
        }
        try {
            c_factor = ConversionCalculator.getConversionFactor(c_baseUnits, c_displayUnits);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Sets the display units to the given units.  This method does not add the units to the display table.  
     * This method is used without unit systems.
     * @param units The units the value should be displayed in.
     */
    public void setDisplayUnits(String units) {
        try {
            setDisplayUnits(ConversionCalculator.getUnitFromTag(units));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * @param units
     */
    public void setDisplayUnits(ConversionUnit units) {
        double oldDisplay = getDisplayValue();
        ConversionUnit old = c_displayUnits;
        c_displayUnits = units;
        updateConversionFactor();
        c_changes.firePropertyChange(PROP_DISPLAY_UNIT, old, c_displayUnits);
        c_changes.firePropertyChange(PROP_DISPLAY_VALUE, oldDisplay, getDisplayValue());
    }

    /**
     * Gets the units the value is being displayed in.  These may be the same as the base units if no conversion is being applied.
     * @return ConversionCalculator.Unit measurement unit
     */
    public ConversionUnit getDisplayUnits() {
        return c_displayUnits;
    }

    /**
     * Sets the base units to the given units.  This method does not affect the display table.  
     * This method is used without unit systems.  This method does not affect the stored value.
     * @param units The units the value should are stored in.
     */
    public void setBaseUnits(String units) {
        try {

            setBaseUnits(ConversionCalculator.getUnitFromTag(units));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * @param units
     */
    public void setBaseUnits(ConversionUnit units) {
        double oldValue = getValue();
        double oldDisplay = getDisplayValue();
        c_baseUnits = units;
        updateConversionFactor();
        c_changes.firePropertyChange(PROP_VALUE, oldValue, getValue());
        c_changes.firePropertyChange(PROP_DISPLAY_VALUE, oldDisplay, getDisplayValue());
    }

    /**
     * Gets the units the value is being stored in.
     * @return ConversionCalculator.Unit measurement unit
     */
    public ConversionUnit getBaseUnits() {
        return c_baseUnits;
    }

    /**
     * The value converted from the base units to the display units.
     * @return double Converted value
     */
    public double getDisplayValue() {
        return c_value * c_factor;
    }

    /**
     * This method converts the passed value from the display units to the base units and stores
     * the value.
     * @param value value in display units
     */
    public void setDisplayValue(double value) {
        setValue(value / c_factor);
    }

    /**
     * String representation of the display value.  Applies the output format if possible.  Default format is #.##.
     * @return String The value in display units.
     */
    public String toStringDisplayValue() {
        if (c_valueOutputFormat.length() &gt; 0) {
            try {
                return new DecimalFormat(c_valueOutputFormat).format(getDisplayValue());
            } catch (NumberFormatException nfe) {
                return Double.toString(getDisplayValue());
            }
        } else {
            return Double.toString(getDisplayValue());
        }
    }

    /**
     * String representation of the base value.  Applies the output format if possible.  Default format is #.##.
     * @return String The value in base units.
     */
    public String toStringValue() {
        if (c_valueOutputFormat.length() &gt; 0) {
            try {
                return new DecimalFormat(c_valueOutputFormat).format(getValue());
            } catch (NumberFormatException nfe) {
                return Double.toString(getValue());
            }
        } else {
            return Double.toString(getValue());
        }
    }

    /**
     * String representation of the base value.  Does not apply the output format.
     * @return String The value in base units.
     */
    @Override
    public String toString() {
        return Double.toString(getValue());
    }

    /**
     * Sets the output format used for the toStringValue and toStringDisplayValue methods.  This
     * format is intended to prevent too many digits after the decimal point when writing
     * @param format the number format to apply to output.
     */
    public void setOutputFormat(String format) {
        c_valueOutputFormat = format;
    }

    /**
     *
     * @param listener
     */
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        c_changes.addPropertyChangeListener(listener);
    }

    /**
     *
     * @param property
     * @param listener
     */
    public void addPropertyChangeListener(String property, PropertyChangeListener listener) {
        c_changes.addPropertyChangeListener(property, listener);
    }

    /**
     *
     * @param listener
     */
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        c_changes.removePropertyChangeListener(listener);
    }

    /**
     *
     * @param property
     * @param listener
     */
    public void removePropertyChangeListener(String property, PropertyChangeListener listener) {
        c_changes.removePropertyChangeListener(property, listener);
    }
}
</pre></body></html>