package coreservlets.tags;

import java.io.*;
import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import coreservlets.beans.*;

/** Query tag to scroll through a result set and return a block
 *  of rows from the result set as an HTML table. The result set
 *  is obtained from a ScrollableQueryBean located in the
 *  SESSION scope. The ScrollableQueryBean is identified by the
 *  "id" custom tag attribute.
 *  <P>
 *  Use a scrollTo value of "next", "prev", "first", and "last"
 *  to scroll through the result set. If the scrollTo value
 *  is null or empty, "", then the SQL statement is read from
 *  the body of the tag and a new query is performed.
 *  <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 class ScrollableQueryTag extends BodyTagSupport {
  protected String headingColor = "CYAN";
  protected String connectionName;
  protected int scrollSize;
  protected String scrollTo;
  protected ScrollableQueryBean scroller;

  /** Set the name of the ConnectionInfoBean located in
   *  the servlet context. If a query must be executed, a
   *  connection to the database is obtained from the
   *  ConnectionInfoBean.
   */

  public void setConnectionName(String connectionName) {
    this.connectionName = connectionName.toUpperCase();
  }

  /** Set the scroll size of the ScrollableQueryBean. The
   *  scroll size represents the number of rows returned
   *  from the result set.
   */

  public void setScrollSize(int scrollSize) {
    if (scrollSize > 0) {
      this.scrollSize = scrollSize;
    } else {
      this.scrollSize = ScrollableQueryBean.DEFAULT_SCROLL_SIZE;
    }
  }

  /** Set the direction to scroll through the result set.
   *  Legal values include: "next", "prev", "first", and "last".
   */

  public void setScrollTo(String scrollTo) {
    this.scrollTo = scrollTo;
  }

  public void setHeadingColor(String headingColor) {
    this.headingColor = headingColor;
  }

  /** Scroll to the appropriate starting row in the result set
   *  and return the next block of rows as an HTML table. If
   *  scrollTo is undefined (null or an empty string), then
   *  the query statement is read from the tag body and a
   *  new query is performed.
   */

  public int doAfterBody() throws JspException {
    // Look up the ScrollableQueryBean from the SESSION
    // scope. If not found, produce no results.
    if ((scroller = getScrollerFromSessionScope()) == null) {
      System.err.println(
        "Unable to locate ScollableQueryBean: " + getId());
      return(SKIP_BODY);
    }
    try {
      // If the ScrollableQueryBean does not have a valid
      // result set (some previous action) or if no
      // scrollTo direction is specified, then reissue the
      // query.
      if (scroller.getResultSet() == null ||
          scrollTo == null || scrollTo.length() == 0) {
        executeQuery();
      }
      JspWriter out = bodyContent.getEnclosingWriter();
      out.println(scroller.getHTMLTable(scrollTo, headingColor));
    } catch(SQLException sqle) {
      System.err.println("Error accessing data: " + sqle);
    } catch(IOException ioe) {
      System.err.println("Error generating table: " + ioe);
    } finally {
      scroller.close();
    }
    return(SKIP_BODY);
  }

  /** Obtain the ScrollableQueryBean from the SESSION scope.
   *  The key for looking up the bean is based on the value
   *  for the custom tag "id" attribute.
   */

  protected ScrollableQueryBean getScrollerFromSessionScope() {
    // The id attribute is defined in superclass, BodyTagSupport,
    // and set by the custom tag attribute.
    Object bean = pageContext.getAttribute(getId(),
                                PageContext.SESSION_SCOPE);
    return((ScrollableQueryBean)bean);
  }

  /** Obtain the query from the tag body and send the
   *  query to the scroller for execution.
   */

  protected void executeQuery() throws SQLException {
    String query = bodyContent.getString().trim();
    scroller.setConnection(getConnection());
    scroller.setScrollSize(scrollSize);
    scroller.executeQuery(query);
  }

  /** Obtain connection to database. The desired connection
   *  is specified by the tag attribute, connectionName.
   *  Information to create the Connection object is obtained
   *  from the corresponding ConnectionInfoBean stored in the
   *  servlet context. The connection information is stored
   *  during startup of the engine through the specified
   *  ConnectionContextListener.
   */

  protected Connection getConnection() {
    ServletContext context = pageContext.getServletContext();
    ConnectionInfoBean info =
      (ConnectionInfoBean)context.getAttribute(connectionName);
    if (info == null) {
      return(null);
    } else {
      return(info.getConnection());
    }
  }

  /** Since custom tags can be pooled, set variables to their
   *  default values.
   */

  public void release() {
    headingColor = "CYAN";
    scrollSize = ScrollableQueryBean.DEFAULT_SCROLL_SIZE;
    scrollTo = null;
    scroller = null;
  }
}