package coreservlets.beans;

import java.sql.*;
import java.util.*;
import coreservlets.*;

/** An abstract class for scrolling through a result set
 *  and generating an HMTL table. The ResultSet, which
 *  could be cached or not cached, is defined by a concrete
 *  subclass. To walk through the result set, use the
 *  following directions when calling getHTMLTable:
 *  first, prev, next, and last.
 *  <P>
 *  Taken from Core Servlets and JavaServer Pages
 *  from Prentice Hall and Sun Microsystems Press,
 *  http://www.coreservlets.com/.
 *  &copy; 2004 Marty Hall and Larry Brown;
 *  may be freely used or adapted
 */

public abstract class ScrollableQueryBean {
  public static final int DEFAULT_SCROLL_SIZE = 20;
  public static final String FIRST = "first";
  public static final String PREV = "prev";
  public static final String NEXT = "next";
  public static final String LAST = "last";
  public static final int FIRST_DIR = 0;
  public static final int PREV_DIR = 1;
  public static final int NEXT_DIR = 2;
  public static final int LAST_DIR = 3;

  protected Connection connection;
  protected Statement statement;
  protected ResultSet resultSet;
  protected String[] columnNames;
  protected String scrollTo;
  protected int scrollSize = DEFAULT_SCROLL_SIZE;
  protected static Map directions;

  // Map of scroll directions to potentially use
  // in findStartRow.
  static {
    directions = new HashMap();
    directions.put(FIRST, new Integer(FIRST_DIR));
    directions.put(PREV, new Integer(PREV_DIR));
    directions.put(NEXT, new Integer(NEXT_DIR));
    directions.put(LAST, new Integer(LAST_DIR));
  }

  /** Set the connection to the database. */

  public void setConnection(Connection connection) {
    this.connection = connection;
  }

  /** Set the direction to scroll the cursor in the
   *  result set. Legal values include: "first", "prev",
   *  "next", and "last".
   */

  public void setScrollTo(String scrollTo) {
    this.scrollTo = scrollTo;
  }

  /** Set the scroll size of the cursor when
   *  stepping through blocks of rows in the result set.
   *  The default scroll size is 20.
   */

  public void setScrollSize(int scrollSize) {
    if (scrollSize > 0) {
      this.scrollSize = scrollSize;
    } else {
      this.scrollSize = DEFAULT_SCROLL_SIZE;
    }
  }

  public void setResultSet(ResultSet resultSet) {
    this.resultSet = resultSet;
  }

  public ResultSet getResultSet() {
    return(resultSet);
  }

  /** Execute the database query and store the result in
   *  a ResultSet. Typically, implementations might support
   *  cached and noncached result sets.
   */

  public abstract ResultSet executeQuery(String query)
    throws SQLException;

  /** Position the cursor in the result set before
   *  obtaining the next block of rows. The method should
   *  support scroll directions of "next", "prev",
   *  "first", and "last."
   */

  public abstract void findStartRow(String scrollTo)
    throws SQLException;

  /** Close the result set and supporting objects
   *  (Statement, Connection, if used).
   */

  public abstract void close();

  /** Generate an HTML table. Before generating the table,
   *  position the cursor in the result set according to
   *  the scrollTo direction. The next "scrollSize" rows
   *  are then returned as an HTML table.
   */

  public String getHTMLTable(String scrollTo, String headingColor)
      throws SQLException {
    StringBuffer buffer =
      new StringBuffer("<TABLE BORDER=1>\n");
    if (headingColor != null) {
      buffer.append("  <TR BGCOLOR=\"" + headingColor +
                    "\">\n    ");
    } else {
      buffer.append("  <TR>\n    ");
    }
    for(int col=0; col<columnNames.length; col++) {
      buffer.append("<TH>" + columnNames[col]);
    }
    // Position cursor at the first start row and return the
    // next block of rows, if available.
    findStartRow(scrollTo);
    int counter = 0;
    while((counter++ < scrollSize) && resultSet.next()) {
      buffer.append("\n  <TR>\n    ");
      for(int col=1; col<=columnNames.length; col++) {
        buffer.append("<TD>" +
          ServletUtilities.filter(resultSet.getString(col)));
      }
    }
    buffer.append("\n</TABLE>");
    return(buffer.toString());
  }

  protected void closeResultSet() {
    if (resultSet != null) {
      try {
        resultSet.close();
      } catch(SQLException sqle) {
        System.err.println(
          "Failed to close result set: " + sqle);
      } finally {
        resultSet = null;
      }
    }
  }

  protected void closeStatement() {
    if (statement != null) {
      try {
        statement.close();
      } catch(SQLException sqle) {
        System.err.println(
          "Failed to close statement: " + sqle);
      } finally {
        statement = null;
      }
    }
  }

  protected void closeConnection() {
    if (connection != null) {
      try {
        connection.close();
      } catch(SQLException sqle) {
        System.err.println(
          "Failed to close connection: " + sqle);
      } finally {
        connection = null;
      }
    }
  }
}