/* HelpManager.java
 * =========================================================================
 * This file is part of the GrInvIn project - http://www.grinvin.org
 * 
 * Copyright (C) 2005-2008 Universiteit Gent
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 * 
 * This program 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
 * General Public License for more details.
 * 
 * A copy of the GNU General Public License can be found in the file
 * LICENSE.txt provided with the source distribution of this program (see
 * the META-INF directory in the source jar). This license can also be
 * found on the GNU website at http://www.gnu.org/licenses/gpl.html.
 * 
 * If you did not receive a copy of the GNU General Public License along
 * with this program, contact the lead developer, or write to the Free
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

package org.grinvin.help;

import java.awt.Component;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.help.BadIDException;
import javax.help.CSH;
import javax.help.DefaultHelpBroker;
import javax.help.HelpBroker;
import javax.help.HelpSet;
import javax.help.HelpSetException;
import javax.help.Map.ID;
import javax.swing.JMenu;
import javax.swing.JPopupMenu;

/**
 * Central managing of context-sensitive help
 */
public class HelpManager {
    
    private static HelpSet hs = null;
    
    private static HelpBroker hb = null;
    
    private static CSH.DisplayHelpAfterTracking dhat = null;
    
    private static boolean helpLoaded;
    
    private static final ResourceBundle BUNDLE = ResourceBundle.getBundle ("org.grinvin.help.help");

 //first load the helpfiles
 static {
        String helpHS = "org/grinvin/helpsets/grinvin";
        String invariantsHS = "org/grinvin/helpsets/invariants";
        String graphfactoriesHS = "org/grinvin/helpsets/graphfactories";
        String generatorsHS = "org/grinvin/helpsets/generators";
        ClassLoader cl = HelpManager.class.getClassLoader();
        try {
            URL hsURL = HelpSet.findHelpSet(cl, helpHS);
            hs = new HelpSet(null, hsURL);
            
            //load invariants and merge them into the helpset
            URL invhsURL = HelpSet.findHelpSet(cl, invariantsHS);
            HelpSet invhs = new HelpSet(null, invhsURL);
            invhs.setLocalMap(InvariantMap.getInstance());
            hs.add(invhs);
            
            //load graphfactories and merge them into the helpset
            URL grfhsURL = HelpSet.findHelpSet(cl, graphfactoriesHS);
            HelpSet grfhs = new HelpSet(null, grfhsURL);
            grfhs.setLocalMap(GraphFactoryMap.getInstance());
            hs.add(grfhs);
            
            //load generators and merge them into the helpset
            URL genhsURL = HelpSet.findHelpSet(cl, generatorsHS);
            HelpSet genhs = new HelpSet(null, genhsURL);
            genhs.setLocalMap(GeneratorMap.getInstance());
            hs.add(genhs);
            
            hb = hs.createHelpBroker();
            dhat = new CSH.DisplayHelpAfterTracking(hb);
            //dhat = new CSH.DisplayHelpAfterTracking(HelpManager.getHelpSet(), "javax.help.Popup", "popup");
            
            new Thread(new Runnable() {
                public void run() {
                    hb.initPresentation();
                }
            }).start();
            
            helpLoaded = true;
        } catch (HelpSetException e) {
            Logger.getLogger("org.grinvin.io").log(Level.WARNING, BUNDLE.getString("error.notloaded"));
            helpLoaded = false;
        } catch (ExceptionInInitializerError e) {
            //possibly thrown by GraphFactoryMap.getInstance()
            Logger.getLogger("org.grinvin.io").log(Level.WARNING, BUNDLE.getString("error.notloaded"));
            helpLoaded = false;
        }
    }
 
 /**
  * returns the helpset
  */
 public static HelpSet getHelpSet() {
     return hs;
 }
 
 /**
  * returns true if the help files were loaded without errors
  */
 public static boolean isHelpLoaded(){
     return helpLoaded;
 }
 
 public static void startTracking(){
     if(helpLoaded)
         dhat.actionPerformed(new ActionEvent(hb, ActionEvent.ACTION_PERFORMED, ""));
 }
 
 /**
  * add context-sensitive help for a component.
  */
 public static void setHelpIDString(Component comp, String id){
     if(!helpLoaded)
         return;
     try {
         ID.create(id, hs);
         CSH.setHelpIDString(comp, id);
         if(!(comp instanceof JMenu)) //don't add a popupmenu to a menu!
             comp.addMouseListener(new HelpPopupListener(comp, id));
     } catch (BadIDException e) {
         //invalid ID: if help is loaded we log this
         if(helpLoaded)
             Logger.getLogger("org.grinvin.io").log(Level.WARNING, BUNDLE.getString("error.invalidID") + id);
     }
 }
 
 public static void enableHelpKey(Component comp, String id) {
     if(helpLoaded)
         hb.enableHelpKey(comp, id, null);
 }
 
 /**
  * display the given id in the help window.
  */
 public static void showID(String id) {
     if(helpLoaded) {
        hb.setCurrentID(id);
        hb.setDisplayed(true);
     }
 }
 
 public static ResourceBundle getResourceBundle(){
     return BUNDLE;
 }

 /**
  * returns the help window.
  */
  public static Window getWindow(){
     return ((DefaultHelpBroker)hb).getWindowPresentation().getHelpWindow();
 }
  
  /**
   * returns the id of the current help page, or if no id exists the url of the current page.
   */
  public static String getCurrentHelpPage(){
      ID id = hb.getCurrentID();
      if(id != null)
          return id.getIDString();
      else
          return hb.getCurrentURL().toString();
  }
  
  /**
   * delegates to HelpBroker
   */
  public static String getCurrentView(){
      return hb.getCurrentView();
  }
  
  /**
   * Class that adds a popupmenu with access to the context-sensitive help
   * to a component and listens for mouse events on that component.
   */
  private static class HelpPopupListener extends MouseAdapter {
      
      private JPopupMenu popup;
      private Component comp;
      
      public HelpPopupListener(Component comp, String id){
          super();
          popup = new JPopupMenu();
          popup.add(new CSHAction(id));
          this.comp = comp;
          if(comp == null)
              throw new NullPointerException("Component can't be null.");
      }
      
      public void mousePressed(MouseEvent e) {
          if (e.isPopupTrigger() && comp.equals(e.getComponent())) {
              popup.show(comp, e.getX(), e.getY());
          }
      }

      public void mouseReleased(MouseEvent e) {
          if (e.isPopupTrigger() && comp.equals(e.getComponent())) {
              popup.show(comp, e.getX(), e.getY());
          }
      }
  }
}
