package water.util;

public class TwoDimTable {
  String description;
  String[] colNames;
  String[] colFormatStrings; //optional
  String[] rowNames;
  Object[][] values;

  /**
   * Full two-dim table constructor
   * @param colNames
   * @param colFormatStrings
   * @param rowNames
   * @param values
   */
  public TwoDimTable(String description, String[] colNames, String[] colFormatStrings, String[] rowNames, Object[][] values) {
    this.description = description;
    this.colNames = colNames;
    this.colFormatStrings = colFormatStrings;
    this.rowNames = rowNames;
    this.values = values;
  }

  /**
   * Construct empty two-dim table from row/column names
   * @param colNames
   * @param rowNames
   */
  public TwoDimTable(String description, String[] colNames, String[] colFormatStrings, String[] rowNames) {
    this.description = description;
    this.colNames = colNames;
    this.colFormatStrings = colFormatStrings;
    this.rowNames = rowNames;
    values = new Object[colNames.length][];
    for (int i=0; i<values.length; ++i) {
      values[i] = new Object[rowNames.length];
    }
  }

  public String toString() {
    int pad = 2;

    StringBuilder sb = new StringBuilder();

    // First pass to figure out cell sizes
    int maxRowNameLen = rowNames[0].length();
    for (int r=1; r<rowNames.length; ++r) {
      maxRowNameLen = Math.max(maxRowNameLen, rowNames[r].length());
    }
    maxRowNameLen += pad;
    int[] colLen = new int[colNames.length];
    for (int c=0; c<colNames.length; ++c) {
      colLen[c] = colNames[c].length();
      for (int r=0; r<rowNames.length; ++r) {
        colLen[c] = Math.max(colLen[c], String.format(colFormatStrings[c], values[r][c]).length());
      }
      colLen[c] += pad;
    }

    // Print column header
    sb.append(description).append(":\n");
    for (int i=0; i<maxRowNameLen; ++i) sb.append(" ");
    for (int c=0; c<colNames.length; ++c)
      sb.append(String.format("%" + colLen[c] + "s", colNames[c]));
    sb.append("\n");

    // Print table entries row by row
    for (int r=0; r<rowNames.length; ++r) {
      sb.append(String.format("%" + maxRowNameLen + "s", rowNames[r]));
      for (int c=0; c<colNames.length; ++c)
        sb.append(String.format("%" + colLen[c] + "s", String.format(colFormatStrings[c], values[r][c])));
      sb.append("\n");
    }
    return sb.toString();
  }


}
@@ -428,37 +428,36 @@
 %5D values) %7B%0A    
-this.
+if (
 description = de
@@ -453,39 +453,95 @@
 iption =
- description
+= null) throw new IllegalArgumentException(%22description is missing.%22)
 ;%0A    
-this.
+if (
 colNames
@@ -542,36 +542,93 @@
 lNames =
- colNames
+= null) throw new IllegalArgumentException(%22colNames are missing.%22)
 ;%0A    
-this.
+if (
 colForma
@@ -629,33 +629,76 @@
 lFormatStrings =
- 
+= null) throw new IllegalArgumentException(%22
 colFormatStrings
@@ -693,35 +693,49 @@
 ormatStrings
+ are missing.%22)
 ;%0A    
-this.
+if (
 rowNames = r
@@ -736,36 +736,93 @@
 es =
- rowNames
+= null) throw new IllegalArgumentException(%22rowNames are missing.%22)
 ;%0A    
-this.
+if (
 values =
  val
@@ -821,240 +821,621 @@
 es =
- values;%0A  %7D%0A%0A  /**%0A   * Construct empty two-dim table from row/column names%0A   * @param colNames%0A   * @param rowNames%0A   */%0A  public TwoDimTable(String description, String%5B%5D colNames, String%5B%5D colFormatStrings, String%5B%5D rowNames) %7B
+= null) throw new IllegalArgumentException(%22values are missing.%22);%0A    if (values.length != rowNames.length)%0A      throw new IllegalArgumentException(%22values must have the same length as rowNames: %22 + rowNames.length);%0A    for (Object%5B%5D v : values)%0A      if (v.length != colNames.length)%0A        throw new IllegalArgumentException(%22Each entry in values must have the same length as colNames: %22 + colNames.length);%0A    if (colFormatStrings != null && colFormatStrings.length != colNames.length)%0A      throw new IllegalArgumentException(%22colFormatStrings must have the same length as colNames: %22 + colNames.length);
 %0A   
@@ -1581,142 +1581,29 @@
     
-values = new Object%5BcolNames.length%5D%5B%5D;%0A    for (int i=0; i%3Cvalues.length; ++i) %7B%0A      values%5Bi%5D = new Object%5BrowNames.length%5D;%0A    %7D
+this.values = values;
 %0A  %7D

Add checking of constructor arguments for TwoDimTable.