/*
 * Nearest.java - provides helper functions to display numbers.
 * This class was written for
 * a) simple wrapper around java.text.NumberFormat for fractions
 * b) provide special formatting for "two significant figures" for any size number
 *
 * Created on October 12, 2003, 9:56 PM
 * @author  Barry (barry@coilgun.info)
 */
import java.text.*;

public class Nearest {
    /**
     * Helper function to convert small numbers into engineering units
     * @param d is number to convert (seconds, farads, henries, amps, etc)
     * @param sUnit is a unit to append ("s", "F", "H", "A", etc)
     */
    public String toStringEng(double d, int places, String sUnit) {
        String s;
        if (d < 0.999E-9)           // should show pico's?
            s = toStringSigFig(d*1E12, places) + " p";
        else if (d < 0.999E-6)      // should show nano's?
            s = toStringSigFig(d*1E9, places) + " n";
        else if (d < 0.999E-3)      // should show micro's?
            s = toStringSigFig(d*1E6, places) + " u";
        else if (d < 0.999E0)       // should show milli's?
            s = toStringSigFig(d*1E3, places) + " m";
        else if (d < 0.999E3)       // should show plain units?
            s = toStringSigFig(d*1E0, places) + " ";
        else if (d < 0.999E6)       // should show kilo's?
            s = toStringSigFig(d*1E-3, places) + " K";
        else if (d < 0.999E9)       // should show mega's?
            s = toStringSigFig(d*1E-6, places) + " M";
        else if (d < 0.999E12)      // should show giga's'?
            s = toStringSigFig(d*1E-9, places) + " G";
        else if (d < 0.999E15)      // should show tera's'?
            s = toStringSigFig(d*1E-12, places) + " T";
        else
            s = "no convert!";
        
        return s + sUnit;
    }
    
    /**
     * Nearest.toStringSigFig
     *
     * @param f double
     * @return string rep of a double rounded to TWO or THREE significant figures.
     * For example: 0.12 - 1.2 - 12 - 120 - 1,200 - 12,000
     */
    String toStringSigFig(double f, int places) {
        switch (places) {
        case 2:
            {
                if (f < 0.09999)
                    return Thousandth(f);
                if (f < 0.9999)
                    return Hundredth(f);
                else if (f < 9.999)
                    return Tenth(f);
                else if (f < 99.99)
                    return Unit(f);
                else if (f < 999.9)
                    return RoundTo(f,10);
                else if (f < 10000)
                    return RoundTo(f,100);
                else if (f < 100000)
                    return RoundTo(f,1000);
                else if (f < 1000000)
                    return RoundTo(f,10000);
                else if (f < 10000000)
                    return RoundTo(f,100000);
                else
                    return Double.toString(f);
            }
        case 3:
            {
                if (f < 0.09999)
                    return TenThousandth(f);
                if (f < 0.9999)
                    return Thousandth(f);
                else if (f < 9.999)
                    return Hundredth(f);
                else if (f < 99.99)
                    return Tenth(f);
                else if (f < 999.9)
                    return Unit(f);
                else if (f < 9999)
                    return RoundTo(f,10);
                else if (f < 99990)
                    return RoundTo(f,100);
                else if (f < 999900)
                    return RoundTo(f,1000);
                else if (f < 9999000)
                    return RoundTo(f,10000);
                else
                    return Double.toString(f);
            }
        default:
                return "error!";
        }
    }
    
    /**
     * Nearest.RoundTo
     * 
     * @param f - number to be rounded
     * @param place - use 0.1 to round to nearest tenth, 10 to round to nearest tens, etc.
     * @return string rep of a double rounded to specified place value
     * @see http://java.sun.com/j2se/1.4.1/docs/api/java/text/NumberFormat.html
     */
    String RoundTo(double f, double place) {
        String s;
        int nNearest = (int)(f / place + 0.5);
        int nRounded = (int)(nNearest * place);
        numbers.setMinimumFractionDigits(0);
        numbers.setMaximumFractionDigits(0);
        numbers.setGroupingUsed(true);      // insert comma for thousands
        s = numbers.format(nRounded);
        return s;
    }

    /**
     * Nearest.Unit
     * 
     * @param f double
     * @return string rep of a double rounded using ROUND_HALF_EVEN to nearest integer
     * @see java.text.DecimalFormat
     */
    String Unit(double f) {
        numbers.setMinimumFractionDigits(0);
        numbers.setMaximumFractionDigits(0);
        numbers.setGroupingUsed(true);
        String s = numbers.format(f);
        return s;
    }

    /**
     * Nearest.Tenth
     * 
     * @param f double
     * @return string rep of a double rounded to nearest tenth
     */
    String Tenth(double f) {
        numbers.setMinimumFractionDigits(1);
        numbers.setMaximumFractionDigits(1);
        return numbers.format(f);
    }

    /**
     * Nearest.Hundredth
     * 
     * @param f double
     * @return string representation of a double rounded to nearest hundredth
     */
    String Hundredth(double f) {
        numbers.setMinimumFractionDigits(2);
        numbers.setMaximumFractionDigits(2);
        return numbers.format(f);
    }

    /**
     * Nearest.Thousandth
     * 
     * @param f double
     * @return string representation of a double rounded to nearest thousandth
     */
    String Thousandth(double f) {
        numbers.setMinimumFractionDigits(3);
        numbers.setMaximumFractionDigits(3);
        return numbers.format(f);
    }
    
    /**
     * Nearest.TenThousandth
     * 
     * @param f double
     * @return string representation of a double rounded to nearest thousandth
     */
    String TenThousandth(double f) {
        numbers.setMinimumFractionDigits(4);
        numbers.setMaximumFractionDigits(4);
        return numbers.format(f);
    }
    
    // fields of class Nearest
    NumberFormat numbers = java.text.NumberFormat.getInstance();

}

