// Pascal's triangle
// This program uses JLiveWIndow to test methods to calculate and
// print Pascal's triangle. You can type any positive number n (say)
// in the integer field of the GUI window and hit the ready button, and
// and the first n rows of Pascal's triangle will be printed.

// More complicated than calculating Pascal's triangle is
// printing it nicely. This program prints it nicely centered, with
// each integer taking only as much horizontal space as it needs.
// You might try rewriting the printing method so that it prints
// each integer in the same number of characters (center it in
// its field).
public class Pascal extends JLiveWindow{
   
   /** Constructor: a window with i int fields, d double fields,
                    and s String fields */
   public Pascal(int i, int d, int s) {
      super(i, d, s);
      }
      
   /** Main method to test Pascal's triangle methods */
   public static void main(String pars[]) {
      Pascal t= new Pascal(1,0,0);
      t.showWindow();
   }
   
   /** Read the number n in the first int field of the GUI
       and print the first n rows of Pascal's triangle */
   Object buttonPressed() {
      int n= getIntField(0);
      int[][] b= pascalTriangle(n);
      System.out.println();
      
      printPascal(b);
      return null;
   }
   
   /** = first n rows of Pascal's triangle */
   public static int[][] pascalTriangle(int n) {
      int[][] b= new int[n][];  // First n rows of Pascal's triangle
      // invariant: rows 0..i-1 have been created
      for (int i= 0; i != b.length; i++) {
         // Create row i of Pascal's triangle
            b[i]= new int[i+1];
            
         // Calculate row i of Pascal's triangle
            b[i][0]= 1; 
            // invariant b[i][0..j-1] have been created
            for (int j= 1; j < i; j++) {
               b[i][j]= b[i-1][j-1] + b[i-1][j];
            }
            b[i][i]= 1;
      }
      return b;
   }
   
   /** = b is Pascal's triangle. Return an array that contains the no.
         of the middle character of each row, with 1 blank between each */
   public static int[] pascalSizes(int[][] b) {
      int[] size= new int[b.length];   // The array of sizes
      // invariant: s[0..r-1] has been created
      for (int r= 0; r != size.length; r++) {
         // Calculate size[r].
            size[r]= 0;
            // inv: size[r] contains the sum of lengths of first c
            //      integers, with a blank after each
            for (int c= 0; c != (b[r].length) / 2; c++)
               size[r]= size[r] + 1 + len(b[r][c]);
            if ((b[r].length % 2) == 1)
               size[r]= size[r] + (1+len(b[r][(b[r].length)/2]))/2;
      }
      return size;
   }
   
   /** = number of characters in x */
   public static int len(int x) {
      // The length of x is calculated by first converting x to
      // class Integer, then using toString to get its character
      // representation, and then using function length.
      return new Integer(x).toString().length();
   }
   
   /** Print Pascal's triangle b, with one blank between integers
       and each integer taking only the number of characters that it needs */
   public static void printPascal(int[][] b) {
      // Store in each element size[i] the character number of the middle
      // character in row i. For example, for line 6:
      //    1 6 15 20 15 6 1
      // store 8 in b[6] because the middle character, "2", is
      // characater number 8.
         int[] size= pascalSizes(b);
      
      // The last row is the longest. Store in middle the position
      // of the middle element of the last row. Thus, middle is where
      // the middle character of each row show go, so each row is centered
         int middle= size[b.length-1];
      
      // Print out the rows, each on a new line
         // Invariant: Rows b[0..i-1] have been printed
         for (int i= 0; i != b.length; i++) {
            StringBuffer line= new StringBuffer();  // line to be printed
            // Append to line the blanks preceding the row of integers
               // invariant: j blanks have been appended 
               for (int j= 0; j != middle - size[i]; j++)
                  line.append(' ');
            // Append to line each integer, followed by a blank
               // invariant: the first k integers have been appended
               for (int k= 0; k != b[i].length; k++) {
                  line.append(b[i][k]); line.append(' ');
               }   
            System.out.println(line);
         }
   }
   
   
   /** Print array d, one row per line.
       Precede each row by the integer 1+(row number) */
   public static void printTable(int[][] d) {
      // invariant: rows 0, ..., r-1 have been printed
      for (int r= 0; r != d.length; r++) {
         // Print row d[r] on one line
            System.out.print((1 + r) + "  ");
            // inv: elements d[r, 0..c-1] have been printed
            for (int c= 0; c != d[r].length; c++) {
               System.out.print("   " + d[r][c]);
            }
            System.out.println();
      }
   }
   
}
