/*
 * BIQueryToolBean.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.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import oracle.cabo.ui.AttributeKey;
import oracle.cabo.ui.RenderingContext;
import oracle.cabo.ui.UIConstants;
import oracle.cabo.ui.UINode;

import oracle.cabo.ui.beans.BaseWebBean;
import oracle.cabo.ui.beans.StyledTextBean;

import oracle.cabo.ui.beans.form.ChoiceBean;
import oracle.cabo.ui.beans.form.OptionBean;
import oracle.cabo.ui.beans.form.TextInputBean;

import oracle.cabo.ui.beans.layout.SpacerBean;
import oracle.cabo.ui.beans.layout.RowLayoutBean;

import oracle.cabo.ui.beans.nav.ButtonBean;

import oracle.cabo.ui.data.BoundValue;

import oracle.cabo.ui.laf.base.xhtml.FormValueRenderer;

import oracle.cabo.ui.validate.DecimalValidater;

import oracle.dss.dataSource.common.Query;

import oracle.dss.metadataManager.common.MDObject;

import oracle.dss.selection.Selection;

import oracle.dss.thin.beans.BIConstants;
import oracle.dss.thin.beans.ThinRuntimeException;

import oracle.dss.thin.beans.dataView.ThinDataviewCommon;

import oracle.dss.util.DataAccess;
import oracle.dss.util.DataDirector;
import oracle.dss.util.DataSource;
import oracle.dss.util.LayerMetadataMap;

public class BIQueryToolBean extends BaseWebBean {
    
    /**
     * Default Constructor.
     */
    public BIQueryToolBean(String namespace) {
      super(namespace, BIQueryTool.QUERY_TOOL_NAME, null);
    }

    /**
     * Constructor, taking the <code>QueryTool</code> or BoundValue as a parameter.
     *
     * @param QueryTool the <code>QueryTool</code> or BoundValue
     */
    public BIQueryToolBean(String namespace, Object queryTool) {
      super(namespace, BIQueryTool.QUERY_TOOL_NAME, null);
      setAttributeValue(QUERY_TOOL_ATTR, queryTool);
    }

    /**
     * Convenience method to specify QUERY_TOOL_ATTR attribute
     *
     * @param QueryTool Instance of BoundValue interface that will provide <code>QueryTool</code> to the renderer.
     */
    final public void setQueryTool(BoundValue queryTool) {
      setAttributeValue(QUERY_TOOL_ATTR, queryTool);
    }

    /**
     * Convenience method to specify QUERY_TOOL_ATTR attribute
     * Note: it is a responsibility of the application to ensure
     * that the <code>BIQueryTool</code> instance is not accessed simultaneously by
     * multiple threads
     *
     * @param BIQueryTool Instance of BIQueryTool.
     */
    final public void setQueryTool(BIQueryTool queryTool) {
      setAttributeValue(QUERY_TOOL_ATTR, queryTool);
    }

    /**
     * Convenience method to retrieve a value of QUERY_TOOL_ATTR attribute
     *
     * @return  An instance of <code>QueryTool</code> object or BoundValue providing <code>QueryTool</code> object
     */
    final public Object getQueryTool() {
      return getAttributeValue(QUERY_TOOL_ATTR);
    }


    /**
     * Renders the UI for the QueryToolBean.
     * Please note that this sample does not use the pluggable renderer architecture.
     */
    public void render(RenderingContext context, UINode node) throws IOException {
      // Get the QueryTool
      BIQueryTool queryTool = (BIQueryTool)getAttributeValue(context, QUERY_TOOL_ATTR);

      // Get the parent form name to be used in submits
      String parentFormName = (String)context.getProperty(
        UIConstants.MARLIN_NAMESPACE, UIConstants.FORM_NAME_PROPERTY);

      // Layout the components in a horizontal row
      RowLayoutBean row = new RowLayoutBean();

      // Create the prompt label for dimension levels
      // Please note that this sample code has not been internationalized
      StyledTextBean levelLabel = new StyledTextBean("Select", "OraPromptText");

      // Get the View from the QueryTool
      ThinDataviewCommon view = queryTool.getView();

      String dimension = null;
      String dimensionLabel = null;
      String hierarchy = null;
      int rowLayerCount = 0;

      // Find the innermost dimension on the row edge
      if (view != null && view.getModel() != null && view.getModel().getDataAccess() != null) {

        try {
          DataAccess dataAccess = view.getModel().getDataAccess();
          rowLayerCount = dataAccess.getLayerCount(DataDirector.ROW_EDGE);

          if (rowLayerCount > 0) {
            // Get the dimension unique name
            dimension = (String)dataAccess.getLayerMetadata(
              DataDirector.ROW_EDGE, rowLayerCount-1, LayerMetadataMap.LAYER_METADATA_NAME);
            // Get the dimension long label
            dimensionLabel = (String)dataAccess.getLayerMetadata(
              DataDirector.ROW_EDGE, rowLayerCount-1, LayerMetadataMap.LAYER_METADATA_LONGLABEL);

            // Find the current hierarchy for the Selection for this dimension
            // If DataSource supports Query API, proceed
            if (view.getDataSource() != null && view.getDataSource() instanceof Query) {
              Query query = (Query)view.getDataSource();

              Selection selection = query.findSelection(dimension);
              hierarchy = selection.getHierarchy();
            }
          }

          // Create the ChoiceBean with all the available levels
          ChoiceBean levelChoice = new ChoiceBean(BIQueryTool.LEVEL_PARAMETER);
          // Add the option for any dimension member (across levels)
          // Please note that this sample code has not been internationalized
          levelChoice.addOption("Any " + dimensionLabel, "");
          // Get the levels for the current hierarchy
          MDObject[] levels = queryTool.getHierarchyLevels(hierarchy);
          addMDObjectsToChoice(levelChoice, levels, queryTool.getLevel());

          // Create the prompt label for the measures
          // Please note that this sample code has not been internationalized
          StyledTextBean measureLabel = new StyledTextBean("where", "OraPromptText");

          // Create the ChoiceBean with all the Query measures
          ChoiceBean measureChoice = new ChoiceBean(BIQueryTool.MEASURE_PARAMETER);
          MDObject[] measures = queryTool.getQueryMeasures();
          addMDObjectsToChoice(measureChoice, measures, queryTool.getMeasure());

          // Create the prompt label for the query operator
          // Please note that this sample code has not been internationalized
          StyledTextBean operatorLabel = new StyledTextBean("is", "OraPromptText");

          // Create the ChoiceBean with all the available query types
          String[] operatorKeys = new String[] {
            BIQueryTool.OPERATOR_GREATER,
            BIQueryTool.OPERATOR_LESS,
            BIQueryTool.OPERATOR_TOP,
            BIQueryTool.OPERATOR_BOTTOM};

          // Please note that this sample code has not been internationalized
          String[] operatorValues = new String[] {"greater than", "less than", "in the top", "in the bottom"};
          ChoiceBean operatorChoice = createChoice(BIQueryTool.OPERATOR_PARAMETER, operatorKeys, operatorValues, queryTool.getOperator());

          // Create the number input field with 5 columns and 1 row
          // Initialize the field to 10, if empty
          // Please note that this sample code has not been internationalized
          String number = queryTool.getNumber();
          if (number == null) {
            number = "10";
          }
          TextInputBean numberField = new TextInputBean(BIQueryTool.NUMBER_PARAMETER, number, 10, 1);
          // Ensure that only decimal numbers are allowed
          numberField.setOnBlurValidater(new DecimalValidater());

          // Create the "Go" button
          // Please note that this sample code has not been internationalized
          ButtonBean button = new ButtonBean("Go");

          // If the QueryTool is on the ViewToolbar, target the event to the ViewToolbar
          String source = queryTool.getThinBeanName();
          if (queryTool.getToolbarName() != null) {
            source = queryTool.getToolbarName();
          }

          // Generate the on-click submit form javascript for the "Go" button
          StringBuffer js = new StringBuffer(256);

          // Use the UIX utility function submitForm() available in MarlinCore.js
          // to submit the parent form with the additional parameters
          js.append("submitForm('");
          js.append(parentFormName);
          js.append("',1,{");
          // The origin of the event is the thin bean name of the QueryTool
          js.append(BIConstants.ORIGIN);
          js.append(":'");
          js.append(queryTool.getThinBeanName());
          js.append("',");
          // The Source (target) for the event is either the QueryTool,
          // or the toolbar if the QueryTool is in a ViewToolbar
          js.append(BIConstants.SOURCE);
          js.append(":'");
          js.append(source);
          js.append("',");
          // The name of the event is QueryTool.QUERY_EVENT
          js.append(BIConstants.EVENT);
          js.append(":'");
          js.append(BIQueryTool.QUERY_EVENT);
          js.append("',");
          // Submit the dimension name with the form
          js.append(BIQueryTool.DIMENSION_PARAMETER);
          js.append(":'");
          js.append(dimension);
          js.append("',");
          // Submit the hierarchy name with the form
          js.append(BIQueryTool.HIERARCHY_PARAMETER);
          js.append(":'");
          js.append(hierarchy);
          js.append("'});return false;");

          // Add all the hidden fields to the form
          FormValueRenderer.addNeededValue(context, parentFormName, BIConstants.ORIGIN);
          FormValueRenderer.addNeededValue(context, parentFormName, BIConstants.SOURCE);
          FormValueRenderer.addNeededValue(context, parentFormName, BIConstants.EVENT);
          FormValueRenderer.addNeededValue(context, parentFormName, BIQueryTool.DIMENSION_PARAMETER);
          FormValueRenderer.addNeededValue(context, parentFormName, BIQueryTool.HIERARCHY_PARAMETER);

          // Set the on-click submit form javascript on the ButtonBean
          button.setOnClick(js.toString());

          // Add level controls
          row.addIndexedChild(levelLabel);
          row.addIndexedChild(new SpacerBean(3, 1));
          row.addIndexedChild(levelChoice);
          row.addIndexedChild(new SpacerBean(3, 1));

          // Add measure controls
          row.addIndexedChild(measureLabel);
          row.addIndexedChild(new SpacerBean(3, 1));
          row.addIndexedChild(measureChoice);
          row.addIndexedChild(new SpacerBean(3, 1));

          // Add operator controls
          row.addIndexedChild(operatorLabel);
          row.addIndexedChild(new SpacerBean(3, 1));
          row.addIndexedChild(operatorChoice);
          row.addIndexedChild(new SpacerBean(3, 1));

          // Add number input field
          row.addIndexedChild(numberField);
          row.addIndexedChild(new SpacerBean(3, 1));

          row.addIndexedChild(button);

          row.render(context);
        }
        catch (Exception e) {
          throw new ThinRuntimeException("Render QueryToolBean failed", e);
        }
      }
    }

    // Creates a ChoiceBean with the given name and the given MDObjects as options
    private void addMDObjectsToChoice(ChoiceBean choice,
                                      MDObject[] mdObjects,
                                      String selectedOption) {
      if (mdObjects != null) {
        for (int i=0; i < mdObjects.length; i++) {
          String objectID = mdObjects[i].getUniqueID();
          OptionBean option = new OptionBean(mdObjects[i].getLongLabel(), objectID);
          if (objectID.equals(selectedOption)) {
            option.setSelected(true);
          }
          choice.addOption(option);
        }
      }
    }

    // Creates a ChoiceBean with the given name and the given data as the options
    private ChoiceBean createChoice(String choiceName, String[] keys,
                                    String[] values, String selectedOption) {
      ChoiceBean choice = new ChoiceBean(choiceName);

      if (keys != null && values != null) {
        for (int i=0; i<keys.length; i++) {
          if (i < values.length) {
            OptionBean option = new OptionBean(values[i], keys[i]);
            if (keys[i].equals(selectedOption)) {
              option.setSelected(true);
            }
            choice.addOption(option);
          }
        }
      }

      return choice;
    }

    // Constants
    public static final AttributeKey QUERY_TOOL_ATTR  = AttributeKey.getAttributeKey("query_tool_attr");

    protected static final String FORM_NAME = "QueryForm";
}
