/**
 * A utility class that demonstrates the use of dynamic formatting
 * (i.e., the creation of format specifiers at "run time").
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */ 
public class DynamicFormatting {
    /**
     * The entry point of the application (which includes
     * some examples of use).
     *
     * @param args  The comand-line arguments (which are ignored)
     */
    @SuppressWarnings("checkstyle:needbraces")
    public static void main(String[] args) {
        System.out.println("0        1         2         3         4");
        System.out.println("1234567890123456789012345678901234567890");
        System.out.println(center("Fred", 20) + "|");
        System.out.println(centerl("Fred", 20) + "|");
        System.out.println(center("Flintstone!", 20) + "|");
        System.out.println(centerl("Flintstone!", 20) + "|");
        System.out.println(center("Fred", 25) + "|");
        System.out.println(centerl("Fred", 25) + "|");
        System.out.println(center("Flintstone!", 25) + "|");
        System.out.println(centerl("Flintstone!", 25) + "|");

        

        double  amount;
        int     precision;
        String  fs;

//[pi
        for (int digits = 1; digits <= 10; digits++) {
            fs = "%" + (digits + 2) + "." + digits + "f\n";
            System.out.printf(fs, Math.PI);
        }
//]pi

        amount    = 999.99;
        precision = 2;
        fs    = "%5." + precision + "f";
        System.out.printf(fs, amount);


        int max, width;        
        int[] data = {1, 10, 5, 321, 17, 2};

//[hardcodedsimple
        for (int i = 0; i < data.length; i++) {
            System.out.printf("%10d\n", data[i]);
        }
//]hardcodedsimple

//[hardcodedvariable
        fs = "%10d\n";
        
        for (int i = 0; i < data.length; i++) {
            System.out.printf(fs, data[i]);
        }
//]hardcodedvariable
        

        String   flags, conversion;
        flags = "";
        width = 0;
        precision = 0;
        conversion = "";
//[pattern
        fs = "%";
        if (flags != null) fs += flags;
        if (width > 0)     fs += width;
        if (precision > 0) fs += "." + precision;
        fs += conversion;
//]pattern

//[2
//[max
        max = -1;
        for (int i = 0; i < data.length; i++) {
            if (data[i] > max) max = data[i];
        }
//]max        
//[digits
        width = (int) (Math.log10(max)) + 1;
//]digits       
        for (int i = 0; i < data.length; i++) {
            System.out.printf(buildFormatSpecifier(null, width, 'd') + "\n",
                              data[i]);
        }
//]2
    }

//[0    
    /**
     * Build a format string.
     * 
     * @param flags       The flags (or null to ignore)
     * @param width       The width (or 0 to ignore)
     * @param precision   The precision (or -1 to ignore)
     * @param conversion  The conversion
     * @return            The format string
     */
    public static String buildFormatSpecifier(String flags, 
                                              int width, int precision, 
                                              char conversion) {
        String   result;
        
        result = "%";
        if (flags != null)  result += flags;
        if (width > 0)      result += width;
        if ((conversion == 'f') && (precision >= 0)) result += precision;
        result += conversion;
        
        return result;
    }
//]0    
    
//[1
    /**
     * Build a format string.
     * 
     * @param flags       The flags (or null to ignore)
     * @param width       The width (or 0 to ignore)
     * @param conversion  The conversion
     * @return            The format string
     */
    public static String buildFormatSpecifier(String flags, 
                                              int width, char conversion) {
        String   result;
        
        result = "%";
        if (flags != null)  result += flags;
        if (width > 0)      result += width;
        result += conversion;
        
        return result;
    }
//]1
    

    
//[center
    /**
     * Use dynamic formatting to center a String in a field of a given width.
     * 
     * @param source The String to center
     * @param width  The width of the resulting String
     * @return       The centered String
     */
    public static String center(String source, int width) {
        int      field, n, append;
        String   fs, result;
        
        // Calculate the number of spaces in the resulting String
        n = width - source.length();        
        if (n <= 0) return source;
        
        // Calculate the width of the field for source (it will be
        // right-justified in this field)
        field = (width + source.length()) / 2;
        
        // Calculate the number of spaces to append to the right
        append = width - field;
        
        // Build the format specifier
        fs = "%" + field + "s%" + append + "s";
        
        result = String.format(fs, source, " ");
        return result;
    }
//]center    

    
//[loop
    /**
     * Use a loop to center a String in a field of a given width.
     * 
     * @param source The String to center
     * @param width  The width of the resulting String
     * @return       The centered String
     */
    public static String centerl(String source, int width) {
        int      append, n, prepend;
        String   result;
        
        // Calculate the number of spaces in the result
        n = width - source.length();
        if (n <= 0) return source;
        
        // Calculate the number of spaces to prepend to the left
        prepend = n / 2;
        
        // Calculate the number of spaces to append to the right
        append   = n / 2;
        if (n % 2 == 1) append++;
        
        result = "";        
        // Prepend with spaces to the left
        for (int i = 0; i < prepend; i++) result += " ";

        result += source;
        
        // Prepend with spaces to the left
        for (int i = 0; i < append; i++) result += " ";
        
        return result;
    }
//]loop
}
