
// still need to implement format(long)
// still need to add support for group seperators

public class NumFmt extends Object {
    private static int  DEFAULTPLACES = 6;

    private     int     minLen          = 0; //no max, string grows as needed
    private     int     decPlaces       = DEFAULTPLACES; //only used for reals

    private     boolean padIt           = true;
    private     char    padCharLeading  = ' ';
    private     char    padCharTrailing = ' ';

    private     boolean roundIt         = true; //only used for real nums
    private     boolean alignRight      = true;

    private     boolean useThouSep      = false;
    private     char    thousandCharSep = ',';


    public NumFmt() {
        // need no-op constructor with all default values
    }

    public NumFmt(int minLen) {
        this();
        setMinLen(minLen);
    }

    public NumFmt(int minLen, int decPlaces) {
        this(minLen);
        setDecPlaces(decPlaces);
    }

    public NumFmt(int minLen, int decPlaces, char padCharLeading) {
        this(minLen, decPlaces);
        setPadIt(true);
        setPadCharLeading(padCharLeading);
    }

    public NumFmt(int minLen, char padCharLeading) {
        // for use with integer types, so decimal places value does not matter
        this(minLen, DEFAULTPLACES, padCharLeading); 
    }

    public void setMinLen(int minLen) {
        // make sure that vals are valid, else use curr val (initally default)
        this.minLen = ( minLen >= 0 ? minLen : this.minLen );
    }

    public void setDecPlaces(int decPlaces) {
        // make sure that vals are valid, else use curr val (initally default)
        this.decPlaces = ( decPlaces >= 0 ? decPlaces : this.decPlaces );
    }

    public void setPadIt(boolean padIt) {
        this.padIt = padIt;
    }

    public void setPadCharLeading(char padCharLeading) {
        this.padCharLeading = padCharLeading;
    }

    public void setPadCharTrailing(char padCharTrailing) {
        this.padCharTrailing = padCharTrailing;
    }

    public void setRoundIt(boolean roundIt) {
        this.roundIt = roundIt;
    }

    /**
      * If true, number is attempted to be aligned with the right side
      * of the field.  If false, the left side.
      */
    public void setAlignRight(boolean alignRight) {
        this.alignRight = alignRight;
    }

    public String format(double num) {
        long   digits;
        int    digitLen;
        String digitStr, wholeStr, fractStr;

        char rangeFlag;
        if ( 0.0 <= num && num < 1.0 ) {
            rangeFlag = 'P';
        } else if ( -1.0 < num && num < 0.0 ) {
            rangeFlag = 'N';
        } else {
            rangeFlag = 'O';
        }

        switch ( rangeFlag ) {
            case 'P':
                num += 1.0;
                break;
            case 'N':
                num -= 1.0;
                break;
            // only care about those two cases
        }

        digits = Math.round(num * Math.pow(10.0, decPlaces));
        digitStr = String.valueOf(digits);

        digitLen = (int)digitStr.length();
        wholeStr = digitStr.substring(0, digitLen - decPlaces);
        fractStr = digitStr.substring(digitLen - decPlaces, digitLen);

        switch ( rangeFlag ) {
            case 'P':
                wholeStr = "0";
                break;
            case 'N':
                wholeStr = "-0";
                break;
            // only care about those two cases
        }

        return formatCombine(wholeStr, fractStr);
    }

    private String formatCombine(String wholeStr, String fractStr) {
        String numStr;
        int    numStrLen;

        if ( fractStr.length() > 0 ) {
            numStr = wholeStr + "." + fractStr;
        }
        else {
            numStr = wholeStr;
        }

        numStrLen = (int)numStr.length();

        if ( padIt && ( numStrLen < minLen ) ) {
            // we need to do some padding 
            StringBuffer padBuff = new StringBuffer(minLen + 10);

            if ( alignRight ) {
                for ( int i = numStrLen; i < minLen; i++ ) {
                    padBuff.append(padCharLeading);
                }

                padBuff.append(numStr);
            }
            else {
                padBuff.append(numStr);
                for ( int i = numStrLen; i < minLen; i++ ) {
                    padBuff.append(padCharTrailing);
                }
            }

            numStr = padBuff.toString();
        }

        return numStr;
    }

    public void printAllValues() {
        System.err.println("minLen = " + minLen);
        System.err.println("decPlaces = " + decPlaces);
        System.err.println("padIt = " + padIt);
        System.err.println("padCharLeading = " + padCharLeading);
        System.err.println("padCharTrailing = " + padCharTrailing);
        System.err.println("roundIt = " + roundIt);
        System.err.println("alignRight = " + alignRight);
    }
    
    public static void main(String[] args) {
        NumFmt nf1 = new NumFmt();
        NumFmt nf2 = new NumFmt(13);
        NumFmt nf3 = new NumFmt(13, 4);
        NumFmt nf4 = new NumFmt(-3);
        NumFmt nf5 = new NumFmt(-2, -1);
        NumFmt nf6 = new NumFmt(2, -1);
        NumFmt nf7 = new NumFmt(-22, 3);

        /*
        nf1.printAllValues();
        nf2.printAllValues();
        nf3.printAllValues();
        nf4.printAllValues();
        nf5.printAllValues();
        nf6.printAllValues();
        nf7.printAllValues();
        */

        NumFmt nf;
        String str;
        nf = new NumFmt();
        str = nf.format(3.4F); 
        System.out.println(">" + str + "<");
        System.out.println(">" + nf.format(3.123456789F) + "<"); 

        nf = new NumFmt(12, 0);
        System.out.println(">" + nf.format(3.123456789F) + "<"); 

        nf = new NumFmt(14, 3, '0');
        System.out.println(">" + nf.format(3.123456789F) + "<"); 
        System.out.println(">" + nf.format(3.5555555) + "<"); 

        nf = new NumFmt(14, '0');
        System.out.println(">" + nf.format(3.123456789F) + "<"); 
        System.out.println(">" + nf.format(3.5555555) + "<"); 

        nf = new NumFmt(12, 4);
        System.out.println(">" + nf.format(1234567890.1234) + "<"); 
        System.out.println(">" + nf.format(.1234) + "<"); 
        System.out.println(">" + nf.format(123.0) + "<"); 
        System.out.println(">" + nf.format(4444.44444) + "<"); 

        nf = new NumFmt(12, 4);
        nf.setAlignRight(false);
        System.out.println(">" + nf.format(1234567890.1234) + "<"); 
        System.out.println(">" + nf.format(.1234) + "<"); 
        System.out.println(">" + nf.format(123.0) + "<"); 
        System.out.println(">" + nf.format(4444.44444) + "<"); 

        nf = new NumFmt(12, 4);
        nf.setAlignRight(false);
        nf.setPadIt(false);
        System.out.println(">" + nf.format(1234567890.1234) + "<"); 
        System.out.println(">" + nf.format(.1234) + "<"); 
        System.out.println(">" + nf.format(123.0) + "<"); 
        System.out.println(">" + nf.format(4444.44444) + "<"); 

        nf = new NumFmt(12, 4);
        nf.setAlignRight(false);
        nf.setPadCharTrailing('-');
        System.out.println(">" + nf.format(1234567890.1234) + "<"); 
        System.out.println(">" + nf.format(123.0) + "<"); 
        System.out.println(">" + nf.format(4444.44444) + "<"); 

        nf = new NumFmt(12, 4);
        System.out.println(">" + nf.format( 1.50008) + "<"); 
        System.out.println(">" + nf.format(-1.50008) + "<"); 
        System.out.println(">" + nf.format( 1.5    ) + "<"); 
        System.out.println(">" + nf.format(-1.5    ) + "<"); 
        System.out.println(">" + nf.format( 0.12348) + "<"); 
        System.out.println(">" + nf.format(-0.12348) + "<"); 
        System.out.println(">" + nf.format( 0.01208) + "<"); 
        System.out.println(">" + nf.format(-0.01208) + "<"); 
        System.out.println(">" + nf.format( 0.1234) + "<"); 
        System.out.println(">" + nf.format(-0.1234) + "<"); 
        System.out.println(">" + nf.format( 0.012 ) + "<"); 
        System.out.println(">" + nf.format(-0.012 ) + "<"); 
        System.out.println(">" + nf.format( 0.0   ) + "<"); 
        System.out.println(">" + nf.format( 1.0   ) + "<"); 
        System.out.println(">" + nf.format(-1.0   ) + "<"); 
    }
}
