/*
 * BIMultiplePageServlet.java
 *
 * Copyright © 1994-2004, Oracle. All rights reserved. Oracle grants
 * you ("Licensee") a non-exclusive, royalty-free, worldwide license to use,
 * modify and redistribute this software in source and binary code form, provided
 * that (i) this copyright notice and license appear on all copies of the
 * software; (ii) Licensee does not utilize the software in a manner disparaging
 * to Oracle; and (iii) Licensee does not utilize the software in a manner that
 * violates the terms of any Licensee agreement with Oracle.
 */
package samples.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Locale;

import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import oracle.cabo.share.util.CaboHttpUtils;
import oracle.cabo.ui.ServletRenderingContext;
import oracle.cabo.ui.beans.StyleSheetBean;
import oracle.cabo.ui.beans.form.FormBean;
import oracle.cabo.ui.beans.form.FormValueBean;

import oracle.dss.dataView.Dataview;
import oracle.dss.dataSource.client.QueryClient;
import oracle.dss.dataSource.client.QueryManager;
import oracle.dss.dataSource.common.Query;
import oracle.dss.thin.beans.BIConstants;
import oracle.dss.thin.beans.ThinBean;
import oracle.dss.thin.beans.ThinBeanUI;
import oracle.dss.thin.beans.dataView.Presentation;
import oracle.dss.thin.beans.dataView.PresentationBean;
import oracle.dss.thin.beans.persistence.ExplorerDetail;
import oracle.dss.thin.beans.persistence.ExplorerDetailBean;
import oracle.dss.thin.beans.persistence.ExplorerEvent;
import oracle.dss.thin.beans.persistence.ExplorerListener;
import oracle.dss.thin.servlet.ServletQueryParameterProvider;
import oracle.dss.thin.servlet.ServletRequestHandler;
import oracle.dss.util.persistence.Persistable;
import oracle.dss.util.persistence.PersistableConstants;

/** 
 * The main class for the BIMultiplePageServlet sample. This sample extends the
 * BIServlet sample.
 * <P>
 * The BIMultiPageServlet sample shows an application with multiple pages.
 */
public class BIMultiplePageServlet extends BIServlet {

  // the key for storing the BIHttpSession object on the HTTP session
  private static final String BI_HTTP_SESSION_KEY = "BIMultiHttpSessionKey";

  // the name of the explorer detail
  private static final String EXPLORER_DETAIL_NAME = "explorerdetail";

  // the name of the current page parameter in the query string of the url
  private static final String CURRENT_PAGE_PARAM = "currentpage";
  // the name of the open report page
  private static final String PAGE_OPEN_REPORT = "openreport";
  // the name of the analyze page
  private static final String PAGE_ANALYZE = "analyze";
  
  /**
   * Process the request while connected to the OLAP Server and BI Beans Catalog.
   * 
   * @param request an HttpServletRequest object that contains the request the
   * client has made of the servlet.
   * @param response an HttpServletResponse object that contains the response
   * the servlet sends to the client
   *
   * @return <code>true</code> if the request was handled, <code>false</code>
   * otherwise.
   *
   * @throws Exception if the request for the GET could not be handled
   */
  protected boolean processRequest(HttpServletRequest request,
                                   HttpServletResponse response) throws Exception {
    BIHttpSession biHttpSession = getBIHttpSession(request);

    ServletQueryParameterProvider provider = new ServletQueryParameterProvider( 
                                             request, response);

    // retrieve the query parameter describing the current page
    String currentPage = provider.getApplicationQueryParameter(CURRENT_PAGE_PARAM);
    if (null == currentPage) {
      currentPage = PAGE_OPEN_REPORT;
    }
    // ensure that the thin beans on the current page are initialized
    initializeThinBeans(request, currentPage);

    // retrieve the request handler from the session
    ServletRequestHandler handler = biHttpSession.getServletRequestHandler ();

    // use locale retrieved from browser
    setLocale(CaboHttpUtils.determineLocale(request));
    handler.setLocale(getLocale());

    // process form fields of all registered ThinBeans
    handler.processInput(provider);    

    // Key Concept: handle thin bean events. The ServletRequestHandler object
    // determines the thin bean object that should handle a thin bean event using
    // the BIConstants.SOURCE parameter from the provider object. The thin beans
    // are registered with the handler object in the initializeThinBeans method.
    // The handleEvent method on the thin bean object is invoked to allow the
    // thin bean to handle the event. The thin bean returns the result of the
    // event handling
    int nRetVal = handler.handleEvent(provider);

    // test whether processing is completed for the request. The thin bean
    // will return ThinBeanUI.EVENT_RESPONSE_DONE if the
    // BIConstants.EXPORT_EVENT event is handled. No rendering is required
    // after the BIConstants.EXPORT_EVENT event is processed
    if (ThinBeanUI.EVENT_RESPONSE_DONE == nRetVal) {
        return true;
    }
    // begin generating HTML
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();

    // create rendering context for UIX Components (UINodes)
    ServletRenderingContext renderingContext = createRenderingContext(request, response);

    // prepare the ServletRenderingContext for output
    renderingContext.prepareOutput(out, null, "text/html", null);

    out.println("<HTML>");
    out.println("<HEAD>");
    out.println("<TITLE>BI Beans Sample - Multiple Page Application</TITLE>");

    // render the UIX style sheet
    StyleSheetBean.sharedInstance().render(renderingContext);
    
    out.println("</HEAD>");
    out.println("<BODY>");

    // render the page header      
    renderPageHeader(out, request, response);    

    // check the value of the current page parameter. It may have changed during 
    // event handling. 
    String newPage = (String)biHttpSession.getAttribute(CURRENT_PAGE_PARAM);
    if (newPage != null) {
      currentPage = newPage;
      // the current page is a request scope attribute only. Remove it from the
      // session.
      biHttpSession.removeAttribute(CURRENT_PAGE_PARAM);
    }

    if (PAGE_OPEN_REPORT.equals(currentPage)) {
      // render the UIX component (UINode) tree for the open report page
      renderOpenReportPageContent ( request, response, renderingContext );
    }
    else if (PAGE_ANALYZE.equals(currentPage)) {
      // render the UIX component (UINode) tree for the analyze page
      renderAnalyzePageContent(out, request, response, renderingContext);
    }
    
    // render the page footer    
    renderPageFooter(out, request, response);
    
    out.println("</BODY>");
    out.println("</HTML>");

    
    return true;
  }
  
  /**
   * This method returns the key for storing the BIHttpSession object on the HTTP session
   *
   * @return The key for storing the BIHttpSession object on the HTTP session
   */
  protected String getHttpSessionKey() {
    return BI_HTTP_SESSION_KEY;
  }

  /**
   * Retrieves the title of the sample. Derived classes should override to
   * provide custom titles.
   *
   * @return the title of the sample.
   */
  protected String getSampleTitle() {
    return "BI Beans Sample - Multiple Page Application";
  }

  /**
   * Retrieves the description of the sample. Derived classes should override to
   * provide custom descriptions.
   *
   * @return the description of the sample.
   */
  protected String getSampleDescription() {
    return "This sample shows a multiple-page application."; 
  }
  
  /**
   * Render the UIX component (UINode) tree for the Analyze page.
   *
   * @param request an HttpServletRequest object that contains the request the
   * client has made of the servlet.
   * @param response an HttpServletResponse object that contains the response
   * the servlet sends to the client
   * @param renderingContext context for a single rendering pass over a tree of 
   * UIX components (UINodes). RendererContexts do not last longer than a single 
   * rendering, so any state stored on the context will not be persistent. 
   */
  protected void renderAnalyzePageContent(PrintWriter out, 
                                          HttpServletRequest request, 
                                          HttpServletResponse response,
                                          ServletRenderingContext renderingContext) throws IOException {
    FormBean rootNode = new FormBean(PAGE_ANALYZE);

    BIHttpSession biHttpSession = getBIHttpSession(request);
    
    ServletRequestHandler handler = biHttpSession.getServletRequestHandler();
    
    // retrieve the data view from the servlet request handler
    Presentation dataView = (Presentation)handler.getThinBean(PRESENTATION_NAME);
    if (dataView != null)
      rootNode.addIndexedChild(new PresentationBean(dataView));

    rootNode.addIndexedChild(new FormValueBean(CURRENT_PAGE_PARAM, PAGE_ANALYZE));

    rootNode.render(renderingContext);    

    out.println("<P>");

    // Render the "Return to Open Report" link 
    String returnURI = request.getRequestURI ();
    returnURI += "?" + CURRENT_PAGE_PARAM + "=" + PAGE_OPEN_REPORT;

    out.println ("<a href=\"" + returnURI + "\">Return to Open Report</a>" );
  }

  /**
   * Render the UIX component (UINode) tree for the Open Report page.
   *
   * @param request an HttpServletRequest object that contains the request the
   * client has made of the servlet.
   * @param response an HttpServletResponse object that contains the response
   * the servlet sends to the client
   * @param renderingContext context for a single rendering pass over a tree of 
   * UIX components (UINodes). RendererContexts do not last longer than a single 
   * rendering, so any state stored on the context will not be persistent. 
   */
  protected void renderOpenReportPageContent(HttpServletRequest request, 
                                             HttpServletResponse response,
                                             ServletRenderingContext renderingContext) throws IOException {
    FormBean rootNode = new FormBean(PAGE_OPEN_REPORT);

    BIHttpSession biHttpSession = getBIHttpSession(request);

    ServletRequestHandler handler = biHttpSession.getServletRequestHandler();

    ExplorerDetail explorerDetail = (ExplorerDetail)handler.getThinBean(EXPLORER_DETAIL_NAME);
    if (explorerDetail != null) {
      ExplorerDetailBean explorerDetailBean = new ExplorerDetailBean(explorerDetail);
      rootNode.addIndexedChild(explorerDetailBean);
    } 

    rootNode.addIndexedChild(new FormValueBean(CURRENT_PAGE_PARAM, PAGE_OPEN_REPORT));    

    rootNode.render(renderingContext);
  }
      
  /**
   * Process the Explorer Event. 
   *
   * @param e the ExplorerEvent broadcast by the ExplorerDetail thin bean when
   * an action occurs on the client.
   * @param biHttpSession provides a way to identify a user across more than
   * one page request and to store information about that user.
   */
  protected void processExplorerEvent ( ExplorerEvent e, BIHttpSession biHttpSession ) {
    String action = e.getAction();
    if (null == action) {
      return;
    }
    String location = e.getObjectName();
    String type = e.getObjectType ( );
    
    if (null == location) {
      return;
    }
    
    if (!type.equals(PersistableConstants.CROSSTAB) &&
        !type.equals(PersistableConstants.GRAPH) &&
        ! type.equals(PersistableConstants.TABLE)) {
        return;
    }
    
    if (BIConstants.SELECT_OBJECT_EVENT.equalsIgnoreCase(action)) {
      ServletRequestHandler handler = biHttpSession.getServletRequestHandler();

      Presentation dataView = (Presentation) handler.getThinBean(PRESENTATION_NAME);
      if (null == dataView) {
        dataView = new Presentation();
        dataView.setBIContext(biHttpSession.getMetadataManager().getMDRoot());
        dataView.setQueryManager(biHttpSession.getQueryManager());
        dataView.setThinBeanName(PRESENTATION_NAME);
        handler.registerThinBean(dataView);
      }

      try {
        dataView.handleEvent(e.getQueryParameterProvider());
      }
      catch (Exception t) {
      }

      // the current page is a request scope attribute. It is temporarily stored
      // on the session and cleared afterwards.
      biHttpSession.setAttribute(CURRENT_PAGE_PARAM, PAGE_ANALYZE);

    }
    else if (BIConstants.DELETE_EVENT.equalsIgnoreCase(action)) {
      try {
        biHttpSession.getMetadataManager ( ).getMDRoot ( ).unbind ( location );
      }
      catch(Throwable t) {
        log(t.toString());
      }
    }
  }

  /**
   * Initialize thin beans based on the current page.
   *
   * @param request an HttpServletRequest object that contains the request the
   * client has made of the servlet.
   * @param currentPage the current page of the application.
   *
   * @throws Exception if an error is detected when the thin beans are being initialized.
   */
  private void initializeThinBeans(HttpServletRequest request,
                                   String currentPage) throws Exception {
    BIHttpSession biHttpSession = getBIHttpSession(request);

    ServletRequestHandler handler = biHttpSession.getServletRequestHandler();

    if (PAGE_OPEN_REPORT.equals(currentPage)) {
      ExplorerDetail explorerDetail = (ExplorerDetail)handler
                                      .getThinBean(EXPLORER_DETAIL_NAME);
      if (null == explorerDetail) {
        explorerDetail = new ExplorerDetail();
        explorerDetail.setThinBeanName(EXPLORER_DETAIL_NAME);
        explorerDetail.setBIContext(
                       biHttpSession.getMetadataManager().getMDRoot());
        explorerDetail.addExplorerListener(new OpenDeleteListener(biHttpSession));

        handler.registerThinBean(explorerDetail);
      }
    }
  }

  /**
   * The OpenDeleteListener implements the ExplorerListener. This listener is
   * registered with the ExplorerDetail thin bean to allow the application to
   * react to events such as open and delete of a view.
   */
  public class OpenDeleteListener implements ExplorerListener {
    protected BIHttpSession m_biHttpSession = null;

    /**
     * Creates an OpenDeleteListener object.
     *
     * @biHttpSession the object provides a way to identify a user across more
     * than one page request or visit to a Web site and to store information
     * about that user.
     */
    public OpenDeleteListener(BIHttpSession biHttpSession) {
      m_biHttpSession = biHttpSession;
    }

    /**
     * Called when an Explorer Action event occurs.
     *
     * @param e an ExplorerEvent.
     */
    public void explorerActionPerformed(ExplorerEvent e) {
      processExplorerEvent(e, m_biHttpSession);
    }
  }
}
