/*
 * CatalogExplorer.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.
 */
package samples.javaclient.analyzer;

import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.datatransfer.StringSelection;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;

import javax.naming.directory.BasicAttributes;

import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeSelectionModel;
import javax.swing.JScrollPane;

import oracle.bali.ewt.text.MultiLineLabel;
import oracle.bali.ewt.text.WordWrapper;

import oracle.dss.bicontext.BIFilter;
import oracle.dss.bicontext.BISearchControls;
import oracle.dss.metadataManager.client.MetadataManager;
import oracle.dss.metadataManager.common.MDRoot;
import oracle.dss.metadataManager.common.MetadataManagerAdapter;
import oracle.dss.metadataManager.common.MetadataManagerEvent;
import oracle.dss.metadataManager.common.MetadataModifiedEvent;


/**
 * The Worksheets tab in the Sidebar.
 * This Explorer displays graphs and crosstabs that are in the BI Beans Catalog. 
 * Users can open a view by dragging it to the desktop or by double-clicking
 * it.
 * <p>
 * This class uses a JTree to display objects in the BI Beans Catalog.
 * To do this, it uses customized tree models for the JTree.
 * 
 * @see BITreeModel
 * @see BITreeMNode
 * @see CatalogTreeModel
 * @see CatalogTreeNode
 */
public class CatalogExplorer extends JPanel implements DragGestureListener, DragSourceListener  {

  /**
   * Text to display when there is no connection.
   */
  private String m_notAvailableText = "Connect to database for list of items.";
  /**
   * Instruction text.
   * Currently not displayed.
   */
  private static final String DOCUMENT_DESCRIPTION = "Double-click on a worksheet to open.";
  /**
   * Label for the root folder.
   */
  private static final String ROOT = "Catalog";
  /**
   * Label for m_notAvailableText.
   * This object makes it possible to set font attributes.
   */
  private MultiLineLabel notAvail = new MultiLineLabel();
  /**
   * Root folder.
   */
  private MDRoot m_MDRoot; // root folder for catalog
  /**
   * The MetadataManager for this Explorer.
   * This is the application's MetadataManager.
   */
  private MetadataManager m_metadataManager;
  /**
   * Attributes that specify the object type to look for to display in this Explorer.
   */
  private BasicAttributes m_basicAttributes = null;
  /**
   * Tree to display Catalog objects.
   */
  private JTree m_tree = new JTree();
  /**
   * Filter that specifies the object types to display in this Explorer.
   */
  private BIFilter m_filter;
  /**
   * Variable for instruction text.
   * Currently not used.
   */
  private String m_description;
  /**
   * DragSource object for drag-and-drop support.
   */
  private DragSource m_dragSource;
  /**
   * Scroll pane to put the tree in.
   */
  private JScrollPane m_scrollpane;
  /**
   * Type of this Explorer: "WORKSHEET" or "FAVORITES".
   */
  private String m_explorerType;

  /**
   * Constructor.
   */
  public CatalogExplorer() {
    try {
      jbInit();

      // Set the default explorer type
      m_explorerType = "WORKSHEET";
      
      // Make the JTree a drag source
      DragSource m_dragSource = DragSource.getDefaultDragSource();

      // creating the recognizer is all that's necessary - it
      // does not need to be manipulated after creation
      m_dragSource.createDefaultDragGestureRecognizer(
         m_tree, // component where drag originates
         DnDConstants.ACTION_COPY_OR_MOVE, // actions
         this); // drag gesture listener
         
    } catch(Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * Sets the type of Explorer this is.
   * The constructor calls the method to make this Explorer a 
   * CatalogExplorer.
   * The FavoritesExplorer subclass calls this method to make itself a
   * FavoritesExplorer.
   * 
   * @param type The type of Explorer.
   */
  public void setExplorerType (String type) {
    m_explorerType = type;
  }

  /**
   * Gets the type of Explorer this is.
   * The dragGestureRecognized method calls this method.
   * 
   * @return "WORKSHEET" for a CatalogExplorer, 
   *         "FAVORITES" for a FavoritesExplorer.
   */
  public String getExplorerType () {
    return m_explorerType;
  }

  /**
   * Initializes the user interface for this Explorer.
   * It sets a scroll pane for the contents.
   */
  private void jbInit() throws Exception {
    this.setLayout(new BorderLayout());
    this.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
    notAvail.setTextWrapper(WordWrapper.getTextWrapper());
    setNotAvailable();

    // Add scroll bar to the tree
    m_scrollpane = new JScrollPane(m_tree, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                                             JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

  }

  /**
   * Sets the root folder for this Explorer and populates the JTree with the
   * contents of the specified folder.
   * 
   * @param root The root folder.
   */
  public void setMDRoot(MDRoot root) {
    // After setting the root for the tree, the explorer is now initialized
    // Reset the UI to display the tree control
    m_MDRoot = root;
    populateTree();     

    this.removeAll();
    this.add(m_scrollpane, BorderLayout.CENTER);
    this.validate();
  }

  /**
   * Sets the root folder and optionally populates the tree that displays
   * the contents of the folder.
   * 
   * @param root The root folder.
   * @param populateTree <code>true</code> to populate the tree,
   *                     <code>false</code> to set the root without 
   *                     populating the tree.
   */
  public void setMDRoot(MDRoot root, boolean populateTree) {
    if (populateTree)
      setMDRoot(root);
    else
      m_MDRoot = root;
  }

  /**
   * Gets the root folder for this Explorer.
   * 
   * @return The root folder.
   */
  public MDRoot getMDRoot() {
    return m_MDRoot;
  }

  /**
   * Populates the tree of objects and folders.
   */
  public void populateTree() {
    if (m_MDRoot == null) 
      return;

    // Use BISearchControls to display only crosstabs and graphs
    BISearchControls controls = new BISearchControls();
    // Searches for folders and subfolders that have the target objects
    controls.setSearchScope(BISearchControls.SELECTIVE_ONELEVEL_SCOPE);     

    // Set a BIPresentationFilter so only crosstabs, graphs, and folders
    // are displayed
    if (m_filter != null)
      controls.setResultFilter(m_filter);

    // Set up a tree model that works with the Catalog
    CatalogTreeModel _model = new CatalogTreeModel(m_MDRoot, m_basicAttributes,
                                  controls, ROOT);
    CatalogTreeCellRenderer _renderer = new CatalogTreeCellRenderer();
    DefaultTreeSelectionModel _selModel = new DefaultTreeSelectionModel();
    _selModel.setSelectionMode(_selModel.SINGLE_TREE_SELECTION);

    m_tree.setModel(_model);
    m_tree.setSelectionModel(_selModel);
    m_tree.setCellRenderer(_renderer);
    m_tree.addTreeExpansionListener(_model);    
    m_tree.setRootVisible(true);
    
  }

  /**
   * Gets the JTree for this Explorer.
   * 
   * @return The JTree that this Explorer displays.
   */
  public JTree getJTree() {
    return m_tree;
  }

  /**
   * Sets the search control filter for this Explorer.
   * This filter determines the kinds of objects that appear in this
   * Explorer.
   * The Analyzer.jbInit method calls this method and passes a 
   * BIPresentationFilter to it when it instantiates the CatalogExplorer.
   * 
   * @param filter The filter that specifies the types of object that
   *               this Explorer displays.
   */
  public void setFilter(BIFilter filter) {
    m_filter = filter;
  }

  /**
   * Gets the filter that has been set on this Explorer.
   * 
   * @return The filter that specifies the types of objects that this
   *         Explorer displays.
   */
  public BIFilter getFilter() {
    return m_filter;
  }

  /**
   * Specifies the text that this Explorer displays when it is not available.
   * 
   * @param text The text to display.
   */
  public void setNotAvailableText (String text) {
    m_notAvailableText = text;
  }

  /**
   * Gets the text that this Explorer displays when it is not available.
   * 
   * @return The text to display.
   */
  public String getNotAvailableText() {
    return m_notAvailableText;    
  }

  /**
   * Sets this Explorer as not available.
   */
  public void setNotAvailable() {
    notAvail.setFont(new Font("Dialog", 0, 12));
    notAvail.setText(m_notAvailableText);
    this.removeAll();
    this.add(notAvail);       
    this.validate();
  }  

  /**
   * Updates the JTree in this Explorer when items have been added or removed.
   */
  public void refreshTree() {
    // Refresh the catalog tree when items have been added/removed
    populateTree();
    getJTree().validate();
  }

  /**
   * Sets the instruction text for this Explorer.
   * Currently not used.
   */
  public void setDescription(String description) {
    m_description = description;
  }

  /**
   * Gets the instruction text for this Explorer.
   * Currently not used.
   */
  public String getDescription() {
    return m_description;
  }

  /**
   * Attributes that specify the display objects.
   * The BasicAttributes is applied before the filter.  
   * The search operation returns a result set that this BasicAttributes
   * has filtered.
   * The filter is then applied on the result set.
   * <p>
   * The FavoritesExplorer calls this method to specify that it only
   * displays saved selections.
   */
  public void setBasicAttributes(BasicAttributes basicAttributes) {
    m_basicAttributes = basicAttributes;
  }

  /**
   * Gets the attributes that specify the display objects.
   * 
   * @return The attributes that specify the objects that are searched for
   *          in the Catalog.
   */
  public BasicAttributes getBasicAttributes() {
    return m_basicAttributes;
  }

  /**
   * Registers any listeners that this Explorer needs.
   * This method adds a listener to the MetadataManager, to listen for 
   * changes in the metadata.
   * If the metadata changes, then this listener updates the JTree.
   */
  public void addListeners() {
    // Add a listener to the metadata manager that will update the Explorer when 
    // the metadata manager is updated
    getMetadataManager().addListener(new MetadataManagerAdapter() {
      public void metadataModified(MetadataModifiedEvent evt) {
        refreshTree();        
      }
      public void metadataRefresh(MetadataManagerEvent evt) {
        System.out.println("refreshing metadata");
        
      }
    });

   }

  /**
   * Specifies the MetadataManager for this Explorer.
   * The MetadataManager manages access to the BI Beans Catalog and
   * to the OLAP Catalog.
   * If it is set to null, then the catalog objects are not available.
   * The Analyzer.initializeUI method sets the application MetadataManager
   * on this Explorer when the connection is made.
   *
   * @param mm MetadataManager that the application uses.
   *           
   * @see Analyzer#initializeUI          
   */
  public void setMetadataManager(MetadataManager mm) {
     if (mm == null) {
       m_metadataManager = null;
       m_MDRoot = null;
       setNotAvailable();
     }
     else {
        m_metadataManager = mm;

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

   }

   /**
    * Gets the MetadataManager for this Explorer.
    * The MetadataManager manages access to the objects that this 
    * Explorer displays.
    * 
    * @return The MetadataManager for this Explorer.
    */
   public MetadataManager getMetadataManager() {
     return m_metadataManager;
   }

  /**
   * Gets the drag source for this Explorer.
   * 
   * @return The drag source.
   */
   public DragSource getDragSource() {
     return m_dragSource;
   }

  /**
   * Sets the drag source for this Explorer.
   * 
   * @param dragSource The drag source.
   */
   public void setDragSource (DragSource dragSource) {
     m_dragSource = dragSource;
   }

  /**
   * Responds to dragging.
   * 
   * @param dge Information about the drag gesture.
   */
  public void dragGestureRecognized(DragGestureEvent dge) {
     // drag anything ...
     CatalogTreeNode node = (CatalogTreeNode) m_tree.getSelectionPath().getLastPathComponent();
     String transferableData = getExplorerType() + ":" + node.getFullPathName();
     
     dge.startDrag(DragSource.DefaultCopyDrop, 
        new StringSelection(transferableData), // transferable
        this); // drag source listener
      
  }

  /**
   * Null implementation for DragSourceListener.
   */
  public void dragEnter(DragSourceDragEvent dsde) {}
  /**
   * Null implementation for DragSourceListener.
   */
  public void dragOver(DragSourceDragEvent dsde) {}
  /**
   * Null implementation for DragSourceListener.
   */
  public void dropActionChanged(DragSourceDragEvent dsde) {}
  /**
   * Null implementation for DragSourceListener.
   */
  public void dragExit(DragSourceEvent dse) {}
  /**
   * Null implementation for DragSourceListener.
   */
  public void dragDropEnd(DragSourceDropEvent dsde) {}
 
}