/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/wvcm/src/org/apache/wvcm/sample/util/ReportFormat.java,v 1.8 2004/07/30 06:52:26 ozeigermann Exp $
 * $Revision: 1.8 $
 * $Date: 2004/07/30 06:52:26 $
 *
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Slide", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * [Additional notices, if required by prior licensing conditions]
 *
 */
package org.apache.wvcm.sample.util;

/**
 ** ReportFormat
 ** Produces formatted of table-like reports.
 **
 ** Usage example:
 **
 **   ReportFormat r = new ReportFormat( new int[] {15, 3, 25}, 1 );
 **   System.out.println( r.toString() );
 **   System.out.println( "\n" );
 **   System.out.println( r.format("Name", "Age", "City") );
 **   System.out.println( r.separator('-') );
 **   System.out.println( r.format("Pooh", "10", "Pooh's Corner") );
 **   System.out.println( r.format("Piglet", "8", "Pooh's Corner") );
 **   System.out.println( r.format("Robin", "9", "London") );
 **   System.out.println( r.format("Goofy", "27", "Disneyland") );
 **   System.out.println( r.format("Dino", "123456789", "Jurassic Park") );
 **
 ** Output:
 **
 **   colNo: 3
 **   colSpace: 1
 **   fillChar:
 **   cutChar: >
 **   useCutChar: true
 **   colWidth: { 15, 3, 25 }
 **   colStart: { 0, 16, 20 }
 **   colEnd: { 15, 19, 45 }
 **   lineLength: 45
 **
 **
 **   Name            Age City
 **   --------------- --- -------------------------
 **   Pooh            10  Pooh's Corner
 **   Piglet          8   Pooh's Corner
 **   Robin           9   London
 **   Goofy           27  Disneyland
 **   Dino            12> Jurassic Park
 **   --------------- --- -------------------------
 **
 * @author <a href="mailto:peter.nevermann@softwareag.com">Peter Nevermann</a>
 * @version $Revision: 1.8 $
 **/
public class ReportFormat {

  private StringBuffer lineBuffer = null;

  private StringBuffer workBuffer = null;

  private int colNo = 0;

  private int colSpace = 1;

  private int[] colWidth = null;

  private int[] colStart = null;

  private int[] colEnd = null;

  private int lineLength = 0;

  private char fillChar = ' ';

  private boolean useCutChar = true;

  private char cutChar = '>'; // indicates field does not fit into colWidth

  /*******************************************************************************
  *
  *******************************************************************************/
  public ReportFormat( int[] colWidth, int colSpace ) {

    if( colWidth == null || colWidth.length == 0 ) {
      throw new RuntimeException( "Invalid argument colWidth" + colWidth );
    }

    this.colSpace = colSpace;
    this.colWidth = colWidth;
    this.colNo = colWidth.length;

    init();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public void setFillChar( char fillChar ) {
    this.fillChar = fillChar;
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public void setCutChar( char cutChar ) {
    this.cutChar = cutChar;
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public void setUseCutChar( boolean useCutChar ) {
    this.useCutChar = useCutChar;
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  private void init() {
    colStart  = new int[ colNo ];
    colEnd    = new int[ colNo ];

    for( int i = 0; i < colNo; i++ ) {

      if( i > 0 ) {
        lineLength += colSpace;
      }
      colStart[ i ] = lineLength;
      lineLength += colWidth[ i ];
      colEnd[ i ] = lineLength;
    }

    this.lineBuffer = new StringBuffer();
    this.workBuffer = new StringBuffer();

    lineBuffer.setLength( lineLength );
    //resetLineNoFill();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  private void resetLine() {
    resetLine( false );
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  private void resetLineNoFill() {
    resetLine( true );
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  private void resetLine( boolean nofill ) {
    lineBuffer.setLength( lineLength );
    char f = ( nofill ? ' ' : fillChar );

    for( int i = 0; i < lineLength; i++ ) {
      lineBuffer.setCharAt( i, ' ' );
    }

    for( int i = 0; i < colNo; i++ ) {
      lineBuffer.replace( colStart[i], colEnd[i], fill(f, colWidth[i]) );
    }
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public String separator( char sepChar ) {
    resetLineNoFill();

    for( int i = 0; i < colNo; i++ ) {
      lineBuffer.replace( colStart[i], colEnd[i], fill(sepChar, colWidth[i]) );
    }
    return lineBuffer.toString();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public String format( String[] data ) {

    if( colNo != data.length ) {
      throw new RuntimeException(
        "Argument does not fit to number of columns " + colNo );
    }

    resetLine();

    for( int i = 0; i < colNo; i++ ) {
      lineBuffer.replace( colStart[i], colEnd[i], fit(data[i], colWidth[i]) );
    }
    return lineBuffer.toString();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public String format( String data0 ) {

    if( colNo != 1 ) {
      throw new RuntimeException(
        "Argument does not fit to number of columns " + colNo );
    }

    resetLine();

    lineBuffer.replace( colStart[0], colEnd[0], fit(data0, colWidth[0]) );
    return lineBuffer.toString();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public String format( String data0, String data1 ) {

    if( colNo != 2 ) {
      throw new RuntimeException(
        "Argument does not fit to number of columns " + colNo );
    }

    resetLine();

    lineBuffer.replace( colStart[0], colEnd[0], fit(data0, colWidth[0]) );
    lineBuffer.replace( colStart[1], colEnd[1], fit(data1, colWidth[1]) );
    return lineBuffer.toString();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public String format( String data0, String data1, String data2 ) {

    if( colNo != 3 ) {
      throw new RuntimeException(
        "Argument does not fit to number of columns " + colNo );
    }

    resetLine();

    lineBuffer.replace( colStart[0], colEnd[0], fit(data0, colWidth[0]) );
    lineBuffer.replace( colStart[1], colEnd[1], fit(data1, colWidth[1]) );
    lineBuffer.replace( colStart[2], colEnd[2], fit(data2, colWidth[2]) );
    return lineBuffer.toString();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public String format( String data0, String data1, String data2, String data3 ) {

    if( colNo != 4 ) {
      throw new RuntimeException(
        "Argument does not fit to number of columns " + colNo );
    }

    resetLine();

    lineBuffer.replace( colStart[0], colEnd[0], fit(data0, colWidth[0]) );
    lineBuffer.replace( colStart[1], colEnd[1], fit(data1, colWidth[1]) );
    lineBuffer.replace( colStart[2], colEnd[2], fit(data2, colWidth[2]) );
    lineBuffer.replace( colStart[3], colEnd[3], fit(data3, colWidth[3]) );
    return lineBuffer.toString();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public String format( String data0, String data1, String data2, String data3,
                        String data4 ) {

    if( colNo != 5 ) {
      throw new RuntimeException(
        "Argument does not fit to number of columns " + colNo );
    }

    resetLine();

    lineBuffer.replace( colStart[0], colEnd[0], fit(data0, colWidth[0]) );
    lineBuffer.replace( colStart[1], colEnd[1], fit(data1, colWidth[1]) );
    lineBuffer.replace( colStart[2], colEnd[2], fit(data2, colWidth[2]) );
    lineBuffer.replace( colStart[3], colEnd[3], fit(data3, colWidth[3]) );
    lineBuffer.replace( colStart[4], colEnd[4], fit(data4, colWidth[4]) );
    return lineBuffer.toString();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public String format( String data0, String data1, String data2, String data3,
                        String data4, String data5 ) {

    if( colNo != 6 ) {
      throw new RuntimeException(
        "Argument does not fit to number of columns " + colNo );
    }

    resetLine();

    lineBuffer.replace( colStart[0], colEnd[0], fit(data0, colWidth[0]) );
    lineBuffer.replace( colStart[1], colEnd[1], fit(data1, colWidth[1]) );
    lineBuffer.replace( colStart[2], colEnd[2], fit(data2, colWidth[2]) );
    lineBuffer.replace( colStart[3], colEnd[3], fit(data3, colWidth[3]) );
    lineBuffer.replace( colStart[4], colEnd[4], fit(data4, colWidth[4]) );
    lineBuffer.replace( colStart[5], colEnd[5], fit(data5, colWidth[5]) );
    return lineBuffer.toString();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public String format( String data0, String data1, String data2, String data3,
                        String data4, String data5, String data6 ) {

    if( colNo != 7 ) {
      throw new RuntimeException(
        "Argument does not fit to number of columns " + colNo );
    }

    resetLine();

    lineBuffer.replace( colStart[0], colEnd[0], fit(data0, colWidth[0]) );
    lineBuffer.replace( colStart[1], colEnd[1], fit(data1, colWidth[1]) );
    lineBuffer.replace( colStart[2], colEnd[2], fit(data2, colWidth[2]) );
    lineBuffer.replace( colStart[3], colEnd[3], fit(data3, colWidth[3]) );
    lineBuffer.replace( colStart[4], colEnd[4], fit(data4, colWidth[4]) );
    lineBuffer.replace( colStart[5], colEnd[5], fit(data5, colWidth[5]) );
    lineBuffer.replace( colStart[6], colEnd[6], fit(data6, colWidth[6]) );
    return lineBuffer.toString();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public String format( String data0, String data1, String data2, String data3,
                        String data4, String data5, String data6, String data7 ) {

    if( colNo != 8 ) {
      throw new RuntimeException(
        "Argument does not fit to number of columns " + colNo );
    }

    resetLine();

    lineBuffer.replace( colStart[0], colEnd[0], fit(data0, colWidth[0]) );
    lineBuffer.replace( colStart[1], colEnd[1], fit(data1, colWidth[1]) );
    lineBuffer.replace( colStart[2], colEnd[2], fit(data2, colWidth[2]) );
    lineBuffer.replace( colStart[3], colEnd[3], fit(data3, colWidth[3]) );
    lineBuffer.replace( colStart[4], colEnd[4], fit(data4, colWidth[4]) );
    lineBuffer.replace( colStart[5], colEnd[5], fit(data5, colWidth[5]) );
    lineBuffer.replace( colStart[6], colEnd[6], fit(data6, colWidth[6]) );
    lineBuffer.replace( colStart[7], colEnd[7], fit(data7, colWidth[7]) );
    return lineBuffer.toString();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public String format( String data0, String data1, String data2, String data3,
                        String data4, String data5, String data6, String data7,
                        String data8 ) {

    if( colNo != 9 ) {
      throw new RuntimeException(
        "Argument does not fit to number of columns " + colNo );
    }

    resetLine();

    lineBuffer.replace( colStart[0], colEnd[0], fit(data0, colWidth[0]) );
    lineBuffer.replace( colStart[1], colEnd[1], fit(data1, colWidth[1]) );
    lineBuffer.replace( colStart[2], colEnd[2], fit(data2, colWidth[2]) );
    lineBuffer.replace( colStart[3], colEnd[3], fit(data3, colWidth[3]) );
    lineBuffer.replace( colStart[4], colEnd[4], fit(data4, colWidth[4]) );
    lineBuffer.replace( colStart[5], colEnd[5], fit(data5, colWidth[5]) );
    lineBuffer.replace( colStart[6], colEnd[6], fit(data6, colWidth[6]) );
    lineBuffer.replace( colStart[7], colEnd[7], fit(data7, colWidth[7]) );
    lineBuffer.replace( colStart[8], colEnd[8], fit(data8, colWidth[8]) );
    return lineBuffer.toString();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public String format( String data0, String data1, String data2, String data3,
                        String data4, String data5, String data6, String data7,
                        String data8, String data9 ) {

    if( colNo != 10 ) {
      throw new RuntimeException(
        "Argument does not fit to number of columns " + colNo );
    }

    resetLine();

    lineBuffer.replace( colStart[0], colEnd[0], fit(data0, colWidth[0]) );
    lineBuffer.replace( colStart[1], colEnd[1], fit(data1, colWidth[1]) );
    lineBuffer.replace( colStart[2], colEnd[2], fit(data2, colWidth[2]) );
    lineBuffer.replace( colStart[3], colEnd[3], fit(data3, colWidth[3]) );
    lineBuffer.replace( colStart[4], colEnd[4], fit(data4, colWidth[4]) );
    lineBuffer.replace( colStart[5], colEnd[5], fit(data5, colWidth[5]) );
    lineBuffer.replace( colStart[6], colEnd[6], fit(data6, colWidth[6]) );
    lineBuffer.replace( colStart[7], colEnd[7], fit(data7, colWidth[7]) );
    lineBuffer.replace( colStart[8], colEnd[8], fit(data8, colWidth[8]) );
    lineBuffer.replace( colStart[9], colEnd[9], fit(data9, colWidth[9]) );
    return lineBuffer.toString();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  private String fill( char f, int width ) {
    workBuffer.setLength( 0 );

    for( int i = 0; i < width; i++ ) {
      workBuffer.append( f );
    }
    return workBuffer.toString();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  private String fit( String s, int width ) {
    workBuffer.setLength( 0 );
    s = String.valueOf( s );

    boolean doesFit = ( width < s.length()
      ? false
      : true
      );

    for( int i = 0; i < width; i++ ) {

      if( i < s.length() ) {

        if( useCutChar && i == width - 1 && ! doesFit ) {
          workBuffer.append( cutChar );
        }
        else {
          workBuffer.append( s.charAt(i) );
        }
      }
      else {
        workBuffer.append( fillChar );
      }
    }
    return workBuffer.toString();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public String toString() {
    workBuffer.setLength(0);

    workBuffer.append( "\ncolNo: " ).append( colNo );
    workBuffer.append( "\ncolSpace: " ).append( colSpace );
    workBuffer.append( "\nfillChar: " ).append( fillChar );
    workBuffer.append( "\ncutChar: " ).append( cutChar );
    workBuffer.append( "\nuseCutChar: " ).append( useCutChar );
    workBuffer.append( "\ncolWidth: " ).append( arrayToString(colWidth) );
    workBuffer.append( "\ncolStart: " ).append( arrayToString(colStart) );
    workBuffer.append( "\ncolEnd: " ).append( arrayToString(colEnd) );
    workBuffer.append( "\nlineLength: " ).append( lineLength );
    return workBuffer.toString();
  }

  private String arrayToString( int[] a ) {

    if( a == null ) {
      return "null";
    }
    StringBuffer b = new StringBuffer();
    b.append( "{" );

    for( int i = 0; i < a.length; i ++ ) {
      if( i > 0 ) {
        b.append( ", " );
      }
      b.append( a[i] );
    }
    b.append( "}" );
    return b.toString();
  }

  /*******************************************************************************
  *
  *******************************************************************************/
  public static void main( String[] args ) {

    ReportFormat r = null;

    System.out.println( "\n\n" );
    r = new ReportFormat( new int[] {6, 2, 30}, 1 );
    System.out.println( r.toString() );
    System.out.println( "\n" );
    System.out.println( r.format(new String[] {"Name", "Age", "City"}) );
    System.out.println( r.separator('-') );
    System.out.println( r.format(new String[] {"Pu", "27", "Darmstadt"}) );
    System.out.println( r.format(new String[] {"1234567", "1234567", "xxxxxxxxxxxxxxxxx"}) );
    System.out.println( r.format(new String[] {"Peter", "12", "Darmstadt-Eberstadt"}) );
    System.out.println( r.separator('.') );
    System.out.println( r.format(new String[] {"P", "27", "D"}) );
    System.out.println( r.format(new String[] {"Pu", "27", "Darmstadt"}) );
    System.out.println( r.format(new String[] {"1234567", "1234567", "xxxxxxxxxxxxxxxxx"}) );
    System.out.println( r.format(new String[] {"Daniel", "12", "Darmstadt-Eberstadt"}) );
    System.out.println( r.format(new String[] {"P", "27", "D"}) );
    System.out.println( r.format(new String[] {null, null, null}) );
    System.out.println( r.separator('-') );

    System.out.println( "\n\n" );
    r = new ReportFormat( new int[] {15, 3, 25}, 1 );
    System.out.println( r.toString() );
    System.out.println( "\n" );
    System.out.println( r.format(new String[] {"Name", "Age", "City"}) );
    System.out.println( r.separator('-') );
    System.out.println( r.format(new String[] {"Pooh", "10", "Pooh's Corner"}) );
    System.out.println( r.format(new String[] {"Piglet", "8", "Pooh's Corner"}) );
    System.out.println( r.format(new String[] {"Robin", "9", "London"}) );
    System.out.println( r.format(new String[] {"Goofy", "27", "Disneyland"}) );
    System.out.println( r.format(new String[] {"Dino", "123456789", "Jurassic Park"}) );
    System.out.println( r.separator('-') );

    System.out.println( "\n\n" );
    r = new ReportFormat( new int[] {15, 3, 25}, 1 );
    System.out.println( r.toString() );
    System.out.println( "\n" );
    System.out.println( r.format("Name", "Age", "City") );
    r.setFillChar( '_' );
    System.out.println( r.separator('-') );
    System.out.println( r.format("Pooh", "10", "Pooh's Corner") );
    System.out.println( r.format("Piglet", "8", "Pooh's Corner") );
    System.out.println( r.format("Robin", "9", "London") );
    System.out.println( r.format("Goofy", "27", "Disneyland") );
    System.out.println( r.format("Dino", "123456789", "Jurassic Park") );
    System.out.println( r.format(null, null, null) );
    System.out.println( r.separator('-') );
  }
}
