/*
 * BIStateServlet.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.PrintWriter;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;

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

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.cabo.share.url.EncoderUtils;

import oracle.dss.dataSource.client.QueryClient;
import oracle.dss.thin.beans.BIConstants;
import oracle.dss.thin.beans.QueryParameterProvider;
import oracle.dss.thin.beans.ChildThinBeanUI;
import oracle.dss.thin.beans.ThinBean;
import oracle.dss.thin.beans.ThinBeanUI;
import oracle.dss.thin.beans.ThinException;
import oracle.dss.thin.beans.ThinUIExtension;
import oracle.dss.thin.beans.dataView.ThinDataviewCommon;
import oracle.dss.thin.beans.dataView.Presentation;
import oracle.dss.thin.beans.dataView.PresentationBean;
import oracle.dss.thin.servlet.ServletQueryParameterProvider;
import oracle.dss.thin.servlet.ServletRequestHandler;
import oracle.dss.thin.state.BIAdvancedStateManager;
import oracle.dss.util.DataSource;

import oracle.dss.thin.beans.tools.ViewTypeTool;


/** 
 * The main class for the state handling sample. This sample extends the
 * BIServlet class.
 * <P>
 * The BIStateServlet sample shows state handling.
 */
public class BIStateServlet extends BIServlet {

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

  // the name of the UIX FormBean component containing the thin bean components
  private static final String FORM_NAME = "FormState";
  private static final String STATE_NAME = "state";
  
  /**
   * 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 {
    // retrieve the BIHttpSession object. Create one, if one does not exist    
    BIHttpSession biHttpSession = getBIHttpSession(request);
    
    // Create an instance of the ServletQueryParameterProvider to retrieve
    // query parameters from a request
    ServletQueryParameterProvider provider = new ServletQueryParameterProvider(
                                             request, response);

    // ensure that the thin beans are initialized
    initializeThinBeans(provider);
        
    // retrieve the request handler from the session    
    ServletRequestHandler handler = biHttpSession.getServletRequestHandler();
    
    // use locale retrieved from browser
    setLocale(CaboHttpUtils.determineLocale(request));
    handler.setLocale(getLocale());

    // Key Concept: set the thin bean state. The BIAdvancedStateManager object
    // retrieves the state of each thin bean registered with it from the 
    // provider object by using the name of the thin bean. The state of each 
    // thin bean is set on the corresponding thin bean by using the setState
    // method on the thin bean object. The thin beans are registered with the
    // BIAdvancedStateManager object in the initializeThinBeans method.
    BIAdvancedStateManager stateManager = biHttpSession.getStateManager();
    if (stateManager != null)
      stateManager.setState(provider);

    // 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 (nRetVal == ThinBeanUI.EVENT_RESPONSE_DONE) {
      return false;
    }
    // begin generating HTML 
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();

    // create and configure the 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>");
    out.println(getSampleTitle());
    out.println("</TITLE>");

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

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

    // prepare UIX Component (UINodes) tree
    FormBean rootNode = new FormBean(FORM_NAME);
    
    // retrieve the presentation from the servlet request handler
    Presentation presentation = (Presentation)handler.getThinBean(PRESENTATION_NAME);
    if (presentation != null)
      rootNode.addIndexedChild(new PresentationBean(presentation));

    // Key Concept: add the thin bean state. The BIAdvancedStateManager object
    // updates the state of each thin bean registered with it. The state of each 
    // thin bean is then added to the UIX component tree as hidden form fields
    if (stateManager != null) {
      addStateToForm(rootNode, stateManager);
    }

    // render the UIX components (UINodes)    
    rootNode.render(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 - View State Handling";
  }

  /**
   * 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 state handling for a view."; 
  }
  
  /**
   * Initialize thin beans
   *
   * @param provider retrieve the query parameters from a request
   *
   * @throws Exception if an error is detected when the thin beans are initialized.
   */
  private void initializeThinBeans(QueryParameterProvider provider) throws Exception {
    HttpServletRequest request = provider.getHttpServletRequest();

    // retrieve the BIHttpSession object  
    BIHttpSession biHttpSession = getBIHttpSession(request);

    ServletRequestHandler handler = biHttpSession.getServletRequestHandler();

    Presentation presentation = (Presentation)handler.getThinBean(PRESENTATION_NAME);
    // if no presentation has been created, create one.
    if (null == presentation) {
      //retrieve default data source from the base class
      DataSource dataSource = getDefaultDataSource(request);

      // create a Crosstab by default
      presentation = new Presentation(ViewTypeTool.CROSSTAB);
      presentation.setThinBeanName(PRESENTATION_NAME);

      ThinDataviewCommon crosstab = presentation.getView();
      crosstab.setPagingControlVisible(true);
      crosstab.setDataSource(dataSource);

      // register the thin bean with the request handler
      handler.registerThinBean(presentation);

      // register the thin bean with the BIAdvancedStateManager object
      BIAdvancedStateManager stateManager = biHttpSession.getStateManager();
      stateManager.registerTransientStateBean(presentation);

      // Key Concept: Establish the base state from which state changes that
      // are included in the state string are tracked.  This call will clear the
      // thin-bean's  current state string. 
      presentation.setBaseState();
    }
  }


  /**
   * Add the state strings to Form before a new page is rendered
   *
   * @param form The root node of the UIX component tree
   * @param stateManager The advanced state manager for a servlet application
   *
   */
  protected void addStateToForm(FormBean form, BIAdvancedStateManager stateManager) {

    try {
      // Key Concept: Call computeCurrentState to update the state of each 
      // thin bean that is registered with the BIAdvancedStateManager object.
      stateManager.computeCurrentState();

      FormValueBean formValue = null;

      // Key Concept: 
      // Call getCurrentTransientStateID() to retrieve the transient state.
      // Add it to the URL through a hidden form field.
      // Use the default query parameter name, TRANSIENT_STATE_ID to eliminate
      // the call to setInputTransientStateId.
      String transientStateId = stateManager.getCurrentTransientStateID();
      if (transientStateId != null) {
        formValue = new FormValueBean(BIAdvancedStateManager.TRANSIENT_STATE_ID, transientStateId);
        form.addIndexedChild(formValue);
      }

      // Key Concept: 
      // Call getCurrentSavedStateID() to retrieve the saved state.
      // Add it to the URL through a hidden form field.
      // Use the default query parameter name, SAVED_STATE_ID to eliminate
      // the call to setInputSavedStateId.
      String savedStateId = stateManager.getCurrentSavedStateID();
      if (savedStateId != null) {
        formValue = new FormValueBean(BIAdvancedStateManager.SAVED_STATE_ID, savedStateId);
        form.addIndexedChild(formValue);
      }

      // Key Concept: 
      // Call getCurrentBeanStates() to retrieve the bean state.
      // Add it to the URL through a hidden form field.
      // Use the default query parameter name, STATE_ID to eliminate
      // the call to setInputBeansStates.
      String stateString = stateManager.getCurrentBeanStates();
      if (stateString != null) {
        formValue = new FormValueBean(BIAdvancedStateManager.STATE_ID, stateString);
        form.addIndexedChild(formValue);
      }
    }
    catch(ThinException e) {
    }
  }

}
