/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.console.navtree;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;

import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.ToolTipManager;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import org.jboss.console.manager.interfaces.SimpleTreeNodeMenuEntry;
import org.jboss.console.manager.interfaces.TreeAction;
import org.jboss.console.manager.interfaces.TreeNodeMenuEntry;
import org.jboss.console.manager.interfaces.impl.SeparatorTreeNodeMenuEntry;

/**
 * Holder of the browser tree and associated handlers. Can then be embedded
 * in any code such as applet code. Specific actions are handled 
 * through a TreeContext callback object used to communicate between this object
 * and its container.
 *
 * @see org.jboss.console.navtree.TreeContext
 * @see AppletBrowser
 *
 * @author  <a href="mailto:sacha.labourey@cogito-info.ch">Sacha Labourey</a>.
 * @version $Revision: 1.2.2.3 $
 *
 */

public class AdminTreeBrowser
{
   TreeContext ctx = null;
   
   ConsoleTreeModel tm = null;
   TreeCellRenderer cellRenderer = null;
   TreeSelectionListener selectionListener = null;
   OpenNodeAccounter openNodeAccounter = null;
   
   String webHost = null;
   
   public static final String RIGHT_FRAME_NAME = "right";
   
   /** Creates new form AppletTreeBrowser */
   public AdminTreeBrowser (TreeContext ctx) throws Exception
   {
      this.ctx = ctx;      
      
      tm = new ConsoleTreeModel (ctx);
      cellRenderer = new TreeCellRenderer (ctx);
      //selectionListener = new SelectionListener ();
      
      initComponents ();
      
      openNodeAccounter  = new OpenNodeAccounter(getTree());
      
      //getTree().addTreeSelectionListener (selectionListener);
      getTree().addMouseListener (new PopupMenuMgr());
      //getTree().addTreeExpansionListener (openNodeAccounter);
      getTree().getSelectionModel().setSelectionMode (TreeSelectionModel.SINGLE_TREE_SELECTION);
      ToolTipManager.sharedInstance().registerComponent(getTree());      
   }
   
   public void refreshTree (boolean force)
   {
      try
      {
         this.tm.refreshTree (force);
      }
      catch (Exception displayed)
      {
         displayed.printStackTrace();
      }
   }
   
      
   /** This method is called from within the constructor to
    * initialize the form.
    * WARNING: Do NOT modify this code. The content of this method is
    * always regenerated by the Form Editor.
    */
   private void initComponents()//GEN-BEGIN:initComponents
   {
      tree = new javax.swing.JTree();

      tree.setCellRenderer(getCellRenderer());
      tree.setModel(getTreeModel());
      tree.setAutoscrolls(true);

   }//GEN-END:initComponents
   
   
   // Variables declaration - do not modify//GEN-BEGIN:variables
   private javax.swing.JTree tree;
   // End of variables declaration//GEN-END:variables
   
   public TreeCellRenderer getCellRenderer ()
   {
      return this.cellRenderer;
   }
   
   public TreeModel getTreeModel ()
   {
      return this.tm;
   }
   
   public TreeSelectionListener getSelectionListener ()
   {
      return this.selectionListener;
   }
   
   public JTree getTree ()
   {
      return this.tree;
   }
   
   /*
    * Don't use SelectionListener as I am not able to detect clicks on an
    * already selected tree node i.e. no refresh is possible by clicking!
    * => Instead I use the PopupMenuMgr below to do the work
    * 
   public class SelectionListener implements TreeSelectionListener
   {
      
      public SelectionListener () {}
      
      public void valueChanged (TreeSelectionEvent e)
      {
         System.out.println ("in valueChanged");
         Object node = getTree ().getLastSelectedPathComponent ();
         
         if (node == null) return;
                  
         if (node instanceof NodeWrapper)
         {
            NodeWrapper who = (NodeWrapper)node;
            TreeAction act = who.getAssociatedAction ();
            ctx.doAdminTreeAction (act);            
         }
      }      
   }
   */
   
   // -----------------------------------
   
   public class OpenNodeAccounter 
      implements javax.swing.event.TreeExpansionListener, javax.swing.event.TreeModelListener
   {
      protected java.util.TreeSet openNodes = new java.util.TreeSet ();
      
      public OpenNodeAccounter (JTree tree)
      {
         tree.getModel ().addTreeModelListener (this);
      }
      
      public void treeExpanded(javax.swing.event.TreeExpansionEvent event)
      {         
         openNodes.add (((NodeWrapper)(event.getSource ())).getPath ());         
         //System.out.println (event.getPath().getClass ().toString ());
         //openNodes.add (event.getPath ());
      }
      
      public void treeCollapsed(javax.swing.event.TreeExpansionEvent event)
      {
         openNodes.remove (((NodeWrapper)(event.getSource ())).getPath ());
         //openNodes.remove (event.getPath ());
      }
      
      public void treeNodesChanged (javax.swing.event.TreeModelEvent e)
      {
         /*
         java.util.Iterator iter = openNodes.iterator ();
         while (iter.hasNext ())
         {
            javax.swing.tree.TreePath path = (javax.swing.tree.TreePath)iter.next ();
            tree.expandPath (path);
         }
         */
         /*
         RootWrapper root = (RootWrapper)tm.getRoot ();
         int max = root.getChildCount ();
         for (int i=0; i<max ; i++)
         {
            StdNodeWrapper son = (StdNodeWrapper)root.getChild (i);
            if (openNodes.contains (son.getPath ()))
               recursivelyOpen (son);
         } 
           */               

      }
      
      public void recursivelyOpen (NodeWrapper son)
      {         
      }
      
      public void treeNodesInserted (javax.swing.event.TreeModelEvent e){}
      public void treeNodesRemoved (javax.swing.event.TreeModelEvent e){}
      public void treeStructureChanged (javax.swing.event.TreeModelEvent e)  { }
      
   }
   
   // -----------------------------------
   
   public class PopupMenuMgr extends MouseAdapter
   {
      HashMap menus = new HashMap ();
      
      public PopupMenuMgr (){}

      public void mousePressed( MouseEvent e )
      {
         mouseReleased(e);
      }     
 
      public void mouseReleased( MouseEvent e ) 
      {
         TreePath loc = getTree().getPathForLocation(e.getX(), e.getY());
         if (loc == null)//Path not found because
            return;//right click does not occur on a node or a leaf

         getTree().setSelectionPath (loc);

         if ( e.isPopupTrigger()) 
         {                        
            Object node = getTree ().getLastSelectedPathComponent ();
            if (node == null) return;
            
            JPopupMenu popup = null;
            if (menus.containsKey (node))
            {
               popup = (JPopupMenu)menus.get (node);
            }
            else if (node instanceof NodeWrapper)
            {
               NodeWrapper who = (NodeWrapper)node;
               
               TreeNodeMenuEntry[] entries = who.getMenuEntries ();
               
               if (entries != null && entries.length > 0)
               {
                  popup = new JPopupMenu();
                  popup.setOpaque(true);
                  popup.setLightWeightPopupEnabled(true);
                  menus.put (node, popup);
                  
                  // we must lazy-create the menu
                  //
                  for (int i=0; i<entries.length; i++)
                  {
                     if (entries[i] instanceof SeparatorTreeNodeMenuEntry)
                     {
                        popup.addSeparator ();
                     }
                     else if (entries[i] instanceof SimpleTreeNodeMenuEntry)
                     {
                        final SimpleTreeNodeMenuEntry txt = (SimpleTreeNodeMenuEntry)entries[i];
                        JMenuItem mi = new JMenuItem(txt.getText ());
                        mi.addActionListener ( new ActionListener ()
                        {
                           public void actionPerformed(ActionEvent e)  
                           {
                              ctx.doPopupMenuAction (txt);                                      
                           }
                        }                        
                        );
                        popup.add(mi);
                     }
                  }
               }
               
            }                              

            if (popup != null)
               popup.show( (JComponent)e.getSource(), e.getX(), e.getY() );
         }
         else
         {
            Object node = getTree ().getLastSelectedPathComponent ();
                     
            if (node != null && node instanceof NodeWrapper)
            {
               NodeWrapper who = (NodeWrapper)node;
               TreeAction act = who.getAssociatedAction ();
               ctx.doAdminTreeAction (act);            
            }
            
         }
      } 
   }
}
