/*
 * @(#)com.ibm.vista.bi.common.OutputTable.java
 * ===========================================================================
 * Licensed Materials - Property of IBM 
 * "Restricted Materials of IBM" 
 * (C) Copyright IBM Corp. 2005 All rights reserved.
 * ===========================================================================
 * 
 * @(#)OutputTable.java  $Revision: $ $Date: $
 */
/*
 * Change Activity:
 *
 * Reason 	 Date   	Author    	Version		Description
 * ------  	 ----   	------    	-------		-------------------------------------- 
 * 
 */
package com.ibm.vista.bi.common;

import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

/**
 * Table to be output to console or the like for debugging purposes.
 */
public class OutputTable {
  private static final String EOL = System.getProperty("line.separator");

  private String title = null;

  private List columnNames = new ArrayList();

  private List columnMaxSizes = new ArrayList();

  private List nativeRows = new ArrayList();

  private List stringRows = new ArrayList();

  private List columnIndicesByPrintOrder = new ArrayList();

  public OutputTable(String pTitle) {
    this.title = pTitle;
  }

  public OutputTable() {
    this("");
  }

  public void setTitle(String pTitle) {
    this.title = pTitle;
  }

  public String getTitle() {
    return title;
  }

  public int addColumnName(String pColumnName) {
    columnNames.add(pColumnName);
    columnMaxSizes.add(new Integer(pColumnName.length()));
    int idx = columnNames.size() - 1;
    columnIndicesByPrintOrder.add(new Integer(idx));
    return idx;
  }

  public List getColumnNames() {
    return columnNames;
  }

  public int getColumnIndex(String pColumnName) {
    for (int i = 0; i < columnNames.size(); i++) {
      if (columnNames.get(i).equals(pColumnName)) {
        return i;
      }
    }
    return -1;
  }

  /*
   * Comma separated list of 0-based indices and column names. Can contain one
   * '*' for "all not explicitly listed columns".
   */
  public void setColumnPrintOrder(String pCommaSeparatedColumns) {
    int insertWildcardIndex = -1;

    columnIndicesByPrintOrder.clear();

    StringTokenizer st = new StringTokenizer(pCommaSeparatedColumns, ",");
    while (st.hasMoreTokens()) {
      String token = st.nextToken().trim();
      if (token.equals("*")) {
        insertWildcardIndex = columnIndicesByPrintOrder.size();
      } else {
        // Check if it's a name.
        int idx = getColumnIndex(token);
        if (idx != -1) {
          columnIndicesByPrintOrder.add(new Integer(idx));
        } else {
          // Check if its an index.
          try {
            idx = Integer.parseInt(token);
            if (idx >= 0 && idx < columnNames.size()) {
              columnIndicesByPrintOrder.add(new Integer(idx));
            }
          } catch (NumberFormatException e) {
            // Ignore (passing unknown column names is supported)!
            ignoredException();
          }
        }
      }
    }
    if (insertWildcardIndex != -1) {
      // Insert all missing column indices at wildcard position.
      Set added = new HashSet(columnIndicesByPrintOrder);
      for (int i = columnNames.size() - 1; i >= 0; i--) {
        Integer idx = new Integer(i);
        if (!added.contains(idx)) {
          columnIndicesByPrintOrder.add(insertWildcardIndex, idx);
        }
      }
    }
  }

  public List getNativeRows() {
    return nativeRows;
  }

  public List getStringRows() {
    return stringRows;
  }

  public boolean isEmpty() {
    return getStringRows().isEmpty();
  }

  public void addRow(List pRow) {
    nativeRows.add(pRow);
    List stringRow = new ArrayList();
    for (int i = 0; i < pRow.size(); i++) {
      Object objectValue = pRow.get(i);
      String stringValue = "";
      if (objectValue == null) {
        stringValue = "<null>";
      } else if (objectValue instanceof byte[]) {
        stringValue = toHexString((byte[]) objectValue);
      } else {
        stringValue = objectValue.toString();
      }
      stringRow.add(stringValue);
      int prevMaxSize = ((Integer) columnMaxSizes.get(i)).intValue();
      if (stringValue.length() > prevMaxSize) {
        columnMaxSizes.set(i, new Integer(stringValue.length()));
      }
    }
    stringRows.add(stringRow);
  }

  public void print(PrintStream pPrintStream) {
    PrintWriter printWriter = new PrintWriter(pPrintStream);
    print(printWriter);
    printWriter.flush();
  }

  public void print(Writer pWriter) {
    PrintWriter printWriter = new PrintWriter(pWriter);
    print(printWriter);
    printWriter.flush();
  }

  public void print(PrintWriter pWriter) {
    int spacing = 1;

    pWriter.println("-" + title);

    if (!stringRows.isEmpty()) {
      for (int i = 0; i < columnIndicesByPrintOrder.size(); i++) {
        int idx = ((Integer) columnIndicesByPrintOrder.get(i)).intValue();
        String colName = (String) columnNames.get(idx);
        int colSize = ((Integer) columnMaxSizes.get(idx)).intValue() + spacing;
        printPadded(pWriter, colName, colSize);
      }
      pWriter.println();

      for (int r = 0; r < stringRows.size(); r++) {
        List stringRow = (List) stringRows.get(r);

        for (int i = 0; i < columnIndicesByPrintOrder.size(); i++) {
          int idx = ((Integer) columnIndicesByPrintOrder.get(i)).intValue();
          String value = (String) stringRow.get(idx);
          int colSize = ((Integer) columnMaxSizes.get(idx)).intValue() + spacing;
          printPadded(pWriter, value, colSize);
        }
        pWriter.println();
      }
    }
  }

  private void printPadded(PrintWriter pWriter, String pLine, int pMinSize) {
    pWriter.print(pLine);
    int padding = pMinSize - pLine.length();
    for (int i = 0; i < padding; i++) {
      pWriter.print(' ');
    }
  }
  
  // Added for VistaSqlTrigger
  private static final Map fallbackMessageStrings = new HashMap();

  private static final char[] HEX_MAP = new char[] { '0', '1', '2', '3', '4',
      '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
  /**
   * Converts a byte[] to a hex String. Every byte is converted to two
   * characters.
   * 
   * @param pByteArray
   *          the byte[] to convert.
   * @return the hex String or null if pByteArray is null.
   */
  public static String toHexString(byte[] pByteArray) {
    if (pByteArray == null) {
      return null;
    }

    StringBuffer sb = new StringBuffer(pByteArray.length * 2);
    for (int i = 0; i < pByteArray.length; i++) {
      int b = pByteArray[i] & 0xFF;
      sb.append(HEX_MAP[b >> 4]);
      sb.append(HEX_MAP[b & 0x0F]);
    }
    return sb.toString();
  }
  
  /**
   * Dummy method doing nothing to make static code analysis happy.
   */
  public static void ignoredException() {
    // We do real hard work here...
  }
}
