/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed 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 (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/
/**
 * @author Martin Heinemann martin.heinemann@tudor.lu
 *
 *
 *
 * @version
 * <br>$Log: GlobalHotkeyRegister.java,v $
 * <br>Revision 1.8  2013-12-27 18:09:26  donak
 * <br>Cleanup of imports
 * <br>
 * <br>Revision 1.7  2013-07-15 06:18:37  ferring
 * <br>logging changed
 * <br>
 * <br>Revision 1.6  2011-03-23 13:58:16  ferring
 * <br>Fixed an error that made execute action an unassigned action, when pressing a modifier key
 * <br>
 * <br>Revision 1.5  2011-03-10 06:53:34  ferring
 * <br>bug fixed, where all global GECAMedAction had been shown in the patient module top bar, independent of they were specified to be a top button action or not.
 * <br>Now they are only shown, if they ought to be a top button action.
 * <br>
 * <br>Revision 1.4  2011-03-04 09:53:11  ferring
 * <br>Hotkeys for physicians added.
 * <br>It is now possible to make a hotkey consisting of key + modifiers.
 * <br>
 * <br>Revision 1.3  2008-09-25 09:43:07  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.2  2008-01-07 12:44:38  heinemann
 * <br>storage changed to LinkedHashMap to keep the order
 * <br>
 * <br>Revision 1.1  2007-12-04 14:03:37  heinemann
 * <br>moved handling of the hotkeys from MainFrame to RegistrationDesk
 * <br>same with phycianlistener
 * <br>
 *   
 */
package lu.tudor.santec.gecamed.core.gui.listener;

import java.awt.Component;
import java.awt.KeyEventPostProcessor;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Set;

import javax.swing.AbstractAction;
import javax.swing.Action;

import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.utils.WindowToolbox;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

/**
 * @author martin.heinemann@tudor.lu
 * 04.12.2007
 * 14:22:27
 *
 *
 * @version
 * <br>$Log: GlobalHotkeyRegister.java,v $
 * <br>Revision 1.8  2013-12-27 18:09:26  donak
 * <br>Cleanup of imports
 * <br>
 * <br>Revision 1.7  2013-07-15 06:18:37  ferring
 * <br>logging changed
 * <br>
 * <br>Revision 1.6  2011-03-23 13:58:16  ferring
 * <br>Fixed an error that made execute action an unassigned action, when pressing a modifier key
 * <br>
 * <br>Revision 1.5  2011-03-10 06:53:34  ferring
 * <br>bug fixed, where all global GECAMedAction had been shown in the patient module top bar, independent of they were specified to be a top button action or not.
 * <br>Now they are only shown, if they ought to be a top button action.
 * <br>
 * <br>Revision 1.4  2011-03-04 09:53:11  ferring
 * <br>Hotkeys for physicians added.
 * <br>It is now possible to make a hotkey consisting of key + modifiers.
 * <br>
 * <br>Revision 1.3  2008-09-25 09:43:07  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.2  2008-01-07 12:44:38  heinemann
 * <br>storage changed to LinkedHashMap to keep the order
 * <br>
 * <br>Revision 1.1  2007-12-04 14:03:37  heinemann
 * <br>moved handling of the hotkeys from MainFrame to RegistrationDesk
 * <br>same with phycianlistener
 * <br>
 *   
 */
public class GlobalHotkeyRegister {
	
	private static Logger logger = Logger.getLogger("lu.tudor.santec.gecamed.core.gui.listener");
	
	/**
	 * HashMpa to store the global hotkeys and their actions
	 */
	private static LinkedHashMap<String, AbstractAction> hotkeys = new LinkedHashMap<String, AbstractAction>(); 
	
	
	
	/*
	 * Static block to run adminstrativ things
	 */
	static {
		/* ================================================== */
		installKeyboardFocusManager();
		/* ================================================== */
	}
	
	
	private GlobalHotkeyRegister() {
		/* ================================================== */

		/* ================================================== */
	}
	
	
	/* **********************************************************************************
	 *					   H O T K E Y   S E C T I O N
	 * 
	 * ******************************************************************************** */
	

	public static boolean registerHotKey(int key, int modifiers, AbstractAction action) {
		if (key == 0)
			return false;
		
		return registerHotKey(GlobalHotkeyRegister.getKeyString(key, modifiers), action);
	}
	
	
	public static boolean registerHotKey(int key, AbstractAction action) {
		if (key == 0)
			return false;
		
		return registerHotKey(GlobalHotkeyRegister.getKeyString(key, 0), action);
	}
	
	
	
	/**
	 * Register a system wide hotkey
	 * 
	 * @param key
	 * @param action
	 * @return
	 */
	public static boolean registerHotKey(String key, AbstractAction action) {
		/* ================================================== */
		if (key == null || key.equals(""))
			return false;
		
		if (action == null)
			throw new NullPointerException("Can not insert null object in hotKey HashMap");
		
		if (hotkeys.containsKey(key)) {
			logger.info("Hotkey '" + key  + "' is already registered for action: " + ((Action) hotkeys.get(key)).getValue(Action.NAME));
			return false;
		}
		hotkeys.put(key, action);
		logger.info("Hotkey '" + key  + "' registered for action: " + ((Action) hotkeys.get(key)).getValue(Action.NAME));
		
		return true;

		/* ================================================== */
	}

	

	public static AbstractAction getHotKey(int key, int modifiers) {
		return getHotKey(GlobalHotkeyRegister.getKeyString(key, modifiers));
	}
	
	
	public static AbstractAction getHotKey(int key) {
		return getHotKey(GlobalHotkeyRegister.getKeyString(key, 0));
	}

	/**
	 * Return an action for a key code
	 * @param i
	 * @return
	 */
	public static AbstractAction getHotKey(String key) {
		/* ====================================================== */
		return hotkeys.get(key);
		/* ====================================================== */
	}


	/**
	 * Unregister Hotkey
	 * 
	 * @param i
	 * @return
	 */
	public static boolean unregisterHotKey(String key) {
		/* ====================================================== */
		return null != hotkeys.remove(key);
		/* ====================================================== */
	}

	public static boolean unregisterHotKey(int key, int modifiers) {
		return unregisterHotKey(GlobalHotkeyRegister.getKeyString(key, modifiers));
	}

	public static boolean unregisterHotKey(int key) {
		return unregisterHotKey(GlobalHotkeyRegister.getKeyString(key, 0));
	}
	
	/**
	 * Clear all hotkeys
	 */
	public static void clearHotKeys() {
		/* ================================================== */
		hotkeys.clear();
		/* ================================================== */
	}
	
	/**
	 * Return the amount of registered hotkeys
	 * 
	 * @return
	 */
	public static int getHotKeysSize() {
		/* ================================================== */
		return hotkeys.size();
		/* ================================================== */
	}
	
	public static Set<String> getHotKeyKeys() {
		/* ================================================== */
		return hotkeys.keySet();
		/* ================================================== */
	}
	
	/**
	 * Install the KeyboardFocus listener to handle the hotkeys system wide
	 */
	public static void installKeyboardFocusManager() {
		/* ================================================== */
		KeyboardFocusManager.getCurrentKeyboardFocusManager()
				.addKeyEventPostProcessor(new KeyEventPostProcessor() {
					public boolean postProcessKeyEvent(KeyEvent e) {
						if (e.getID() == KeyEvent.KEY_PRESSED) {
							String keyString = getKeyString(e.getKeyCode(), e.getModifiers());
							
							try {
								if (! (WindowToolbox.getOwnerFrame((Component)e.getSource()) instanceof MainFrame))
									return false;
								Action action = null;
								try {
									// try to get action from current Module
									action = GECAMedModule.getCurrentModule().getActionForHotKey(keyString);
								} catch (Exception e2) {
									logger.log(Level.WARN,"Hot Key Action failed!",e2);
								}
								if (action == null) {
									//  try to get global action
									action = getHotKey(keyString);
								}
								// call actionperformed on the found action
								if (action != null) {
									logger.log(Level.INFO,"FIRING SHORTCUT ACTION: '"+ keyString + "' -> " +action.getValue(Action.NAME));
									action.actionPerformed(new ActionEvent(e,1,"key pressed: " +keyString));
								}
							} catch (Exception e1) {
								logger.log(Level.WARN,"Hot Key Action failed!",e1);
							}
						}
						return false;
					}
				});
		/* ================================================== */
	}



	public static Collection<AbstractAction> getAllHotKeyActions() {
		/* ====================================================== */
		return hotkeys.values();
		/* ====================================================== */
	}
	
	/**
	 * Returns the String for the pressed key and its modifiers.<br>
	 * Use this method to get the 
	 * 
	 * @param key
	 * @param modifiers
	 * @return
	 */
	public static String getKeyString (int key, int modifiers)
	{
		if (	   key == 0
				|| key == KeyEvent.VK_META
				|| key == KeyEvent.VK_CONTROL
				|| key == KeyEvent.VK_ALT
				|| key == KeyEvent.VK_SHIFT
				|| key == KeyEvent.VK_ALT_GRAPH)
			// no key set or key is one of the modifiers
			return null;

		/* Taken from the KeyEvent.getModifiersText().
		 * Modified to always return the same text, no matter what locale is set.
		 */
		StringBuffer buf = new StringBuffer();
		if (modifiers != 0)
		{
			if ((modifiers & InputEvent.META_MASK) != 0) 
				buf.append("Meta").append("+");
			
			if ((modifiers & InputEvent.CTRL_MASK) != 0) 
				buf.append("Ctrl").append("+");
			
			if ((modifiers & InputEvent.ALT_MASK) != 0) 
				buf.append("Alt").append("+");
			
			if ((modifiers & InputEvent.SHIFT_MASK) != 0) 
				buf.append("Shift").append("+");
			
			if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) 
				buf.append("Alt Gr").append("+");
		}
		
		
		// add the key
		buf.append(KeyEvent.getKeyText(key));
		
		return buf.toString();
	}
}
