/*
 * FavoritesExplorer.java
 *
 * Copyright (c) 2003, Oracle Corporation. 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.
 *
 *
 * This is a specialized Catalog Explorer.  It will automatically handle
 * a double click event and updae a query based on the user selection.
 */
package samples.javaclient.analyzer;
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.naming.directory.BasicAttributes;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.tree.TreePath;

import oracle.dss.dataSource.client.QueryClient;
import oracle.dss.metadataManager.client.MetadataManager;
import oracle.dss.metadataManager.common.MDRoot;
import oracle.dss.persistence.PSRConstants;
import oracle.dss.selection.Selection;
import oracle.dss.selection.step.FavoriteStep;
import oracle.dss.selection.step.SavedSelectionStep;

/**
 * The Saved Selections tab in the Sidebar.
 * This Explorer is a CatalogExplorer that presents only saved selection
 * objects that are stored in the Catalog.
 * Users can apply a selection to a query in an open crosstab or graph.
 * They can replace the current selection with the saved selection, or
 * they can add the saved selection step to the current selection. 
 * The members in the saved selection can be added to the current selection,
 * removed from the current selection, or kept (all others removed) in the
 * current selection.
 * <p>
 * To apply the selection, the user can drag the selection to the worksheet,
 * double-click the saved selection, or click the Go button.
 * <p>
 * The {@link #setQuery} method specifies the query whose selections will be changed
 * by user actions in this Explorer.
 * The Analyzer application calls setQuery whenever the user selects a 
 * worksheet to make it the active worksheet.
 * <p>
 * The {@link #applySelection} method applies the saved selection
 * to the active query.
 */
public class FavoritesExplorer extends CatalogExplorer implements ActionListener  {


  /**
   * The active query, which is modified when the user clicks Go or drags
   * a selection to a worksheet.
   */
  private QueryClient m_query;
  /**
   * Text for the Go button.
   */
  private static final String APPLY_BUTTON_TEXT = "Go";  
  /**
   * Instruction text.
   * Currently not displayed.
   */
  private static final String FAVORITES_DESCRIPTION =
                    "Double-click on a saved selection to update a worksheet's query.";
  /**
   * "Replace with saved selection" text for the actions combo box.
   */
  private static final String REPLACE = "Replace with saved selection";  
  /**
   * "Add saved selection" text for the actions combo box.
   */
  private static final String ADD = "Add saved selection";
  /**
   * "Keep saved selection" text for the actions combo box.
   */
  private static final String KEEP = "Keep saved selection";  
  /**
   * "Remove saved selection" text for the actions combo box.
   */
  private static final String REMOVE = "Remove saved selection";    
  /**
   * Label for the actions combo box: "Update selected document:"
   */
  private static final String OPTION_TITLE = "Update selected worksheet:";  
  /**
   * Text to display when no worksheets are open.
   */
  private static final String FAVORITES_NOT_AVAILABLE = 
                    "Saved selection list is only available when a worksheet is open.";                    
  /**
   * Text to display when user tries to apply a selection to the wrong dimension.
   */
  private static final String FAVORITE_INVALID = "Unable to apply the saved selection.  The saved selection is based on a dimension that is not displayed in the worksheet.";                    
  /**
   * Mouse listener for double-clicks in the tree.
   */
  private MouseAdapter m_listener;
  /**
   * Drop-down list for what to do with the selected members.
   * Users can add, keep, or remove saved selections, or
   * replace the current selection with the saved selection.
   */
  private JComboBox actions = new JComboBox();
  /**
   * Go button.
   */
  private JButton m_applyButton = new JButton();

  /**
   * Constuctor.
   * This constructor:
   * <ol><li>Calls the CatalogExplorer's constructor.</li>
   * <li>Sets attributes so that it displays only saved selections.</li>
   * <li>Specifies "not available" text and sets the Explorer as not available.</li>
   * <li>Adds this class as an action listener to the Go button.</li>
   * </ol>
   */
  public FavoritesExplorer() {
    super();

    // Set the ExplorerType
    setExplorerType("FAVORITES");
    
    // Only display favorites in the Explorer
    setBasicAttributes(new BasicAttributes(PSRConstants.Attributes.OBJECT_TYPE, 
                      PSRConstants.SELECTION));
    setNotAvailableText(FAVORITES_NOT_AVAILABLE);

    // Favorites are only available if a dataview is open
    setNotAvailable();

    // Add listener to button that updates the query
    m_applyButton.addActionListener(this);

  }

  /**
   * Sets the root folder for this Explorer, without populating the JTree.
   * The tree is populated after the query is set.
   * 
   * @param root The root folder.
   */
  public void setMDRoot(MDRoot root) {
    // Set the root but do not populate the tree.  The tree will be populated
    // after the query is set
    setMDRoot(root, false);

    // Add listener to process event
    addFavoritesListener();
    
  }

  /**
   * Sets the MetadataManager for this Explorer.
   * Analyzer.initializeUI calls this method to set the application's
   * MetadataManager on this Explorer.
   * This Explorer uses the MetadataManager to get information about
   * the dimensions in the query.
   * 
   * @param metadataManager The MetadataManager that the application uses.
   * 
   * @see Analyzer#initializeUI
   */
  public void setMetadataManager(MetadataManager mm) {
    super.setMetadataManager(mm);
    setQuery(null);
  }
  /**
   * Sets the active query for this Explorer.
   * Saved selections that the user chooses in this Explorer will be applied to 
   * this query.
   * If the query is null, then the panel is disabled.
   * If the query changes from null to a non-null query, then this method
   * initializes the Explorer tree.
   * <p>
   * The Analyzer.setActiveWorksheet method calls this method when the user
   * selects a worksheet.
   * The Analyzerz.disconnectCleanUp method calls this method to set the query
   * to null.
   * 
   * @param query The query for this Explorer.
   * 
   * @see Analyzer#disconnectCleanUp
   * @see Analyzer#setActiveWorksheet
   */
  public void setQuery(QueryClient query) {
    if (query == null)  {
      setNotAvailable();
    }
    else if (m_query == null)  {
      populateTree();
      initializeExplorer();      
    }    
    m_query = query;
  }

  /**
   * Initializes the user interface for this Explorer.
   * This method:
   * <ol>
   * <li>Sets the text on the Go button.</li>
   * <li>Sets the choices in the Add, Replace, Keep, or Remove combo box.</li>
   * <li>Adds the combo box and the Go button to the panel.</li></ol>
   */
  public void initializeExplorer() {
      this.removeAll();

      /*
       * Create the objects in the Explorer
       */

      // Set up apply button
      m_applyButton.setText(APPLY_BUTTON_TEXT);
      
      // First, create options for Add and Replace...
      JLabel actionLabel = new JLabel(OPTION_TITLE);
      actions.removeAllItems();
      actions.addItem(REPLACE);
      actions.addItem(ADD);
      actions.addItem(KEEP);
      actions.addItem(REMOVE);      
      actions.setSelectedIndex(0);

      /*
       * Add the objects to the panels
       */
      JPanel options = new JPanel(new GridBagLayout());
      options.add(actionLabel, new GridBagConstraints(0,0,2,1,1,1,
                        GridBagConstraints.WEST, GridBagConstraints.NONE, 
                        new Insets(4, 4, 4, 4), 0,0));
      options.add(actions, new GridBagConstraints(0,1,1,1,1,1,
                      GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, 
                      new Insets(0,4, 0, 4), 0,0));                    
      options.add(m_applyButton, new GridBagConstraints(1,1,1,1,0,0,
                      GridBagConstraints.EAST, GridBagConstraints.NONE, 
                      new Insets(0,4, 0, 4), 0,0));                                        

      this.add(getJTree(), BorderLayout.CENTER);
      this.add(options, BorderLayout.SOUTH);
      
      this.validate();
    
  }

  /**
   * Gets the query for this Explorer.
   * This is the query whose selections are altered by the user's interaction 
   * with this Explorer.
   * 
   * @return The query for this Explorer.
   */  
  public QueryClient getQuery() {
    return m_query;
  }

  /**
   * Adds a listener for mouse events in the JTree.
   * This listener processes double-clicks on a saved selection by
   * applying the selection.
   * 
   * @see #applySelection
   */
  public void addFavoritesListener() {
    m_listener = new MouseAdapter() {
       public void mousePressed(MouseEvent e) {
           // When user double clicks on a favorite to apply it to a query
           JTree tree = getJTree();
           int selRow = tree.getRowForLocation(e.getX(), e.getY());
           TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
           if((selRow != -1) && (e.getClickCount() == 2)) {
              CatalogTreeNode node = (CatalogTreeNode) selPath.getLastPathComponent();
              // open if leaf node (do not "open" folder)
              if (node.isLeaf()) {
                String strName = node.getFullPathName();
                applySelection(strName);
              }
            }
       }
     };
    
    getJTree().addMouseListener(m_listener);

  }

  /**
   * Applies the specified saved selection to the related query.
   * This method retrieves the saved selection from the Catalog.
   * It checks the actions JComboBox to see whether the user wants
   * to replace the current selection, add to the current selection,
   * remove from the current selection, keep members from the current selection.
   * <p>
   * If the user has selected replacing, then this method removes all steps
   * from the selection and adds the saved selection step to the selection.
   * <p>
   * If the user has selected adding, keeping, or removing, then this method adds 
   * the saved selection step to the current selection, with the selected 
   * action.
   * <p>
   * The actionPerformed method calls this method.
   * 
   * @param favoriteName The name of the favorite to apply on the dataview
   * @see #actions
   * @see #actionPerformed
   */
  public void applySelection(String favoriteName) {
    try {
      Selection favorite = (Selection) getMDRoot().lookup(favoriteName);

      // Which option did the user select?
      int selectedAction = actions.getSelectedIndex();

      // Map the user specified action into the step type
      int favoriteAction = 0;
      
      switch (selectedAction) {
        case 0:  favoriteAction = SavedSelectionStep.SELECT; break;
        case 1:  favoriteAction = SavedSelectionStep.ADD; break;  
        case 2:  favoriteAction = SavedSelectionStep.KEEP; break; 
        case 3:  favoriteAction = SavedSelectionStep.REMOVE; break;
      }

      /*
       * 1. Find the dimension 
       * 2. Create a new favorite step
       * 3. Add the favorite step to the list of steps using the appropriate 
       *    action (ADD, KEEP, REMOVE, SELECT)
       */
      String dimension = favorite.getDimension();
      Selection selection = getQuery().findSelection(dimension);

      if (selection == null) {
        AnalyzerUtilities au = new AnalyzerUtilities(null);
        au.showErrorMessage(FAVORITE_INVALID, null);
        return;
      }

      
      SavedSelectionStep step = new SavedSelectionStep (dimension, favorite);

      // Select = Replace.  Clean out the existing steps
      if (favoriteAction == SavedSelectionStep.SELECT) 
        selection.removeAllSteps();  
      
      step.setAction(favoriteAction);
      selection.addStep(step);

      getQuery().applySelection(selection);
            
    }

    catch (Exception e) {
      System.out.println("Error retrieving favorite " + favoriteName + ".");      
    }

  }

  /**
   * Responds to user clicks in this Explorer.
   * This method responds when a user clicks the Go button.
   * 
   * @param e Information about the user action.
   * 
   * @see #applySelection
   */
  public void actionPerformed(ActionEvent e) {
    // Apply the selection based     
    TreePath selPath = getJTree().getSelectionPath();
    CatalogTreeNode node = (CatalogTreeNode) selPath.getLastPathComponent();

    if (node != null) {
      String strName = node.getFullPathName();
      applySelection(strName);
    }

  }
}