/*   **********************************************************************  **
 **   Copyright notice                                                       **
 **                                                                          **
 **   (c) 2003-2006 RSSOwl Development Team                                  **
 **   http://www.rssowl.org/                                                 **
 **                                                                          **
 **   All rights reserved                                                    **
 **                                                                          **
 **   This program and the accompanying materials are made available under   **
 **   the terms of the Eclipse Public License 1.0 which accompanies this     **
 **   distribution, and is available at:                                     **
 **   http://www.rssowl.org/legal/epl-v10.html                               **
 **                                                                          **
 **   A copy is found in the file epl-v10.html and important notices to the  **
 **   license from the team is found in the textfile LICENSE.txt distributed **
 **   in this package.                                                       **
 **                                                                          **
 **   This copyright notice MUST APPEAR in all copies of the file!           **
 **                                                                          **
 **   Contributors:                                                          **
 **     RSSOwl - initial API and implementation (bpasero@rssowl.org)         **
 **                                                                          **
 **  **********************************************************************  */

package net.sourceforge.rssowl.util.shop;

import net.sourceforge.rssowl.controller.GUI;
import net.sourceforge.rssowl.util.GlobalSettings;

import org.eclipse.swt.SWT;

import java.util.Hashtable;

/**
 * Factory class for hotkey concerns in RSSOwl *
 * 
 * @author <a href="mailto:bpasero@rssowl.org">Benjamin Pasero </a>
 * @version 1.2.3
 */
public class HotkeyShop {

  /**
   * Hotkeys for common tasks. <br />
   * The key of each item in the Hashtable is the I18N name of the item the
   * hotkey is set to (e.g. "MENU_EDIT_COPY"). <br />
   * The value is a String[] with the length 2.<br />
   * String[0] contains the hotkeyName (e.g. "Ctrl+B") <br />
   * String[1] contains the hotkeyValue (e.g. "22332")
   */
  public static Hashtable hotKeys = new Hashtable();

  /**
   * Default name for a NULL Accelerator
   */
  public static final String NULL_ACCELERATOR_NAME = "";

  /**
   * Setting the null accelerator to a MenuItem will remove the accelerator from
   * the item.
   */
  public static final int NULL_ACCELERATOR_VALUE = 0;

  /** This utility class constructor is hidden */
  private HotkeyShop() {
  // Protect default constructor
  }

  /**
   * Get the name of a hotkey for the given item.
   * 
   * @param itemName The name of the item.
   * @return String The name of the hotkey, e.g. "Ctrl+B"
   */
  public static String getHotkeyName(String itemName) {
    if (!isHotkeySet(itemName))
      return NULL_ACCELERATOR_NAME;

    return ((String[]) hotKeys.get(itemName))[0];
  }

  /**
   * Get the value of a hotkey for the given item.
   * 
   * @param itemName The name of the item.
   * @return int The value of the hotkey, e.g. 22330
   */
  public static int getHotkeyValue(String itemName) {
    if (!isHotkeySet(itemName))
      return NULL_ACCELERATOR_VALUE;

    return Integer.parseInt(((String[]) hotKeys.get(itemName))[1]);
  }

  /**
   * Assign application default hotkeys.
   */
  public static void initDefaultAccelerators() {
    String cmd = GUI.i18n.getTranslation("LABEL_KEY_COMMAND");
    String ctrl = GUI.i18n.getTranslation("LABEL_KEY_CONTROL");
    String shift = GUI.i18n.getTranslation("LABEL_KEY_SHIFT");

    /** Menu: File */
    if (GlobalSettings.isMac())
      setHotkey("MENU_NEW_FAVORITE", cmd + "+N", SWT.COMMAND | 'n');
    else
      setHotkey("MENU_NEW_FAVORITE", ctrl + "+N", SWT.CTRL | 'n');

    if (GlobalSettings.isMac())
      setHotkey("BUTTON_OPEN", cmd + "+O", SWT.COMMAND | 'o');
    else
      setHotkey("BUTTON_OPEN", ctrl + "+O", SWT.CTRL | 'o');

    if (GlobalSettings.isMac())
      setHotkey("MENU_CLOSE", cmd + "+W", SWT.COMMAND | 'w');
    else if (GlobalSettings.isWindows())
      setHotkey("MENU_CLOSE", ctrl + "+F4", SWT.CTRL | SWT.F4);
    else
      setHotkey("MENU_CLOSE", ctrl + "W", SWT.CTRL | 'w');

    if (GlobalSettings.isMac())
      setHotkey("MENU_CLOSE_ALL", cmd + "+" + shift + "+W", SWT.COMMAND | SWT.SHIFT | 'w');
    else if (GlobalSettings.isWindows())
      setHotkey("MENU_CLOSE_ALL", ctrl + "+" + shift + "+F4", SWT.CTRL | SWT.SHIFT | SWT.F4);
    else
      setHotkey("MENU_CLOSE_ALL", ctrl + "+" + shift + "+W", SWT.CTRL | SWT.SHIFT | 'w');

    if (GlobalSettings.isMac())
      setHotkey("MENU_SAVE", cmd + "+S", SWT.COMMAND | 's');
    else
      setHotkey("MENU_SAVE", ctrl + "+S", SWT.CTRL | 's');

    if (GlobalSettings.useIText()) {
      setHotkey("MENU_GENERATE_PDF", NULL_ACCELERATOR_NAME, NULL_ACCELERATOR_VALUE);
      setHotkey("MENU_GENERATE_RTF", NULL_ACCELERATOR_NAME, NULL_ACCELERATOR_VALUE);
    }
    setHotkey("MENU_GENERATE_HTML", NULL_ACCELERATOR_NAME, NULL_ACCELERATOR_VALUE);
    setHotkey("MENU_WORK_OFFLINE", NULL_ACCELERATOR_NAME, NULL_ACCELERATOR_VALUE);

    if (GlobalSettings.usePrinting()) {
      if (GlobalSettings.isMac())
        setHotkey("TOOLTIP_PRINT", cmd + "+P", SWT.COMMAND | 'p');
      else
        setHotkey("TOOLTIP_PRINT", ctrl + "+P", SWT.CTRL | 'p');
    }

    /** Exit item on Mac placed in Application Menu and not File Menu */
    if (!GlobalSettings.isMac())
      setHotkey("MENU_EXIT", ctrl + "+Q", SWT.CTRL | 'q');
    else
      setHotkey("MENU_EXIT", NULL_ACCELERATOR_NAME, NULL_ACCELERATOR_VALUE);

    /** Menu: Edit */
    if (GlobalSettings.isMac())
      setHotkey("MENU_EDIT_CUT", cmd + "+X", SWT.COMMAND | 'x');
    else
      setHotkey("MENU_EDIT_CUT", ctrl + "+X", SWT.CTRL | 'x');

    if (GlobalSettings.isMac())
      setHotkey("MENU_EDIT_COPY", cmd + "+C", SWT.COMMAND | 'c');
    else
      setHotkey("MENU_EDIT_COPY", ctrl + "+C", SWT.CTRL | 'c');

    if (GlobalSettings.isMac())
      setHotkey("MENU_EDIT_PASTE", cmd + "+V", SWT.COMMAND | 'v');
    else
      setHotkey("MENU_EDIT_PASTE", ctrl + "+V", SWT.CTRL | 'v');

    if (GlobalSettings.isMac())
      setHotkey("MENU_EDIT_SELECT_ALL", cmd + "+A", SWT.COMMAND | 'a');
    else
      setHotkey("MENU_EDIT_SELECT_ALL", ctrl + "+A", SWT.CTRL | 'a');

    if (GlobalSettings.isMac())
      setHotkey("POP_PROPERTIES", cmd + "+I", SWT.COMMAND | 'i');
    else
      setHotkey("POP_PROPERTIES", "Alt+Enter", SWT.ALT | SWT.CR);

    /** Menu: Newsheader */
    if (GlobalSettings.isMac())
      setHotkey("BUTTON_SEARCH", cmd + "+F", SWT.COMMAND | 'f');
    else
      setHotkey("BUTTON_SEARCH", ctrl + "+F", SWT.CTRL | 'f');

    if (GlobalSettings.isMac())
      setHotkey("MENU_RELOAD", cmd + "+R", SWT.COMMAND | 'r');
    else
      setHotkey("MENU_RELOAD", ctrl + "+R", SWT.CTRL | 'r');

    if (GlobalSettings.isMac())
      setHotkey("BUTTON_ADDTO_FAVORITS", cmd + "+D", SWT.COMMAND | 'd');
    else
      setHotkey("BUTTON_ADDTO_FAVORITS", ctrl + "+D", SWT.CTRL | 'd');

    if (GlobalSettings.isMac())
      setHotkey("POP_MAIL_LINK", cmd + "+" + shift + "+M", SWT.COMMAND | SWT.SHIFT | 'm');
    else
      setHotkey("POP_MAIL_LINK", ctrl + "+M", SWT.CTRL | 'm');

    setHotkey("POP_BLOG_NEWS", NULL_ACCELERATOR_NAME, NULL_ACCELERATOR_VALUE);
    setHotkey("POP_COPY_NEWS_URL", NULL_ACCELERATOR_NAME, NULL_ACCELERATOR_VALUE);
    setHotkey("POP_MARK_UNREAD", NULL_ACCELERATOR_NAME, NULL_ACCELERATOR_VALUE);

    if (GlobalSettings.isMac())
      setHotkey("POP_MARK_ALL_READ", cmd + "+" + shift + "+C", SWT.COMMAND | SWT.SHIFT | 'c');
    else
      setHotkey("POP_MARK_ALL_READ", ctrl + "+" + shift + "+C", SWT.CTRL | SWT.SHIFT | 'c');

    /** Menu: Favorites */
    setHotkey("BUTTON_MARK_ALL_READ", NULL_ACCELERATOR_NAME, NULL_ACCELERATOR_VALUE);

    if (GlobalSettings.isMac())
      setHotkey("BUTTON_AGGREGATE_ALL", cmd + "+" + shift + "+A", SWT.COMMAND | SWT.SHIFT | 'a');
    else
      setHotkey("BUTTON_AGGREGATE_ALL", ctrl + "+" + shift + "+A", SWT.CTRL | SWT.SHIFT | 'a');

    if (GlobalSettings.isMac())
      setHotkey("BUTTON_RELOAD_ALL", cmd + "+" + shift + "+R", SWT.COMMAND | SWT.SHIFT | 'r');
    else
      setHotkey("BUTTON_RELOAD_ALL", ctrl + "+" + shift + "+R", SWT.CTRL | SWT.SHIFT | 'r');

    if (GlobalSettings.isMac())
      setHotkey("BUTTON_SEARCH_ALL", cmd + "+" + shift + "+F", SWT.COMMAND | SWT.SHIFT | 'f');
    else
      setHotkey("BUTTON_SEARCH_ALL", ctrl + "+" + shift + "+F", SWT.CTRL | SWT.SHIFT | 'f');

    /** Menu: View */
    if (GlobalSettings.useInternalBrowser()) {
      if (GlobalSettings.isMac())
        setHotkey("MENU_BROWSER_FOR_NEWSTEXT", cmd + "+B", SWT.COMMAND | 'b');
      else
        setHotkey("MENU_BROWSER_FOR_NEWSTEXT", ctrl + "+B", SWT.CTRL | 'b');
    }

    if (GlobalSettings.useIText()) {
      setHotkey("MENU_DISPLAY_FEED_PDF", ctrl + "+1", SWT.CTRL | '1');
      setHotkey("MENU_DISPLAY_FEED_RTF", ctrl + "+2", SWT.CTRL | '2');
    }
    setHotkey("MENU_DISPLAY_FEED_HTML", ctrl + "+3", SWT.CTRL | '3');

    if (GlobalSettings.isMac())
      setHotkey("MENU_MINIMIZE_RSSOWL", cmd + "+M", SWT.COMMAND | 'm');
    else
      setHotkey("MENU_MINIMIZE_RSSOWL", ctrl + "+" + shift + "+X", SWT.CTRL | SWT.SHIFT | 'x');

    if (GlobalSettings.isMac())
      setHotkey("MENU_TOOLBAR", cmd + "+" + "Alt" + "+T", SWT.COMMAND | SWT.ALT | 't');
    else
      setHotkey("MENU_TOOLBAR", NULL_ACCELERATOR_NAME, NULL_ACCELERATOR_VALUE);

    setHotkey("MENU_QUICKVIEW", NULL_ACCELERATOR_NAME, NULL_ACCELERATOR_VALUE);

    if (GlobalSettings.isMac())
      setHotkey("HEADER_RSS_FAVORITES", cmd + "+0", SWT.COMMAND | '0');
    else
      setHotkey("HEADER_RSS_FAVORITES", "F11", SWT.F11);

    /** Menu: Goto */
    if (GlobalSettings.isMac()) {
      setHotkey("MENU_PREVIOUS_TAB", cmd + "+" + shift + "+Left", SWT.COMMAND | SWT.SHIFT | SWT.ARROW_LEFT);
      setHotkey("MENU_NEXT_TAB", cmd + "+" + shift + "+Right", SWT.COMMAND | SWT.SHIFT | SWT.ARROW_RIGHT);
    } else {
      setHotkey("MENU_PREVIOUS_TAB", "F2", SWT.F2);
      setHotkey("MENU_NEXT_TAB", "F3", SWT.F3);
    }

    setHotkey("MENU_NEXT_NEWS", "F", 'f');
    setHotkey("MENU_NEXT_UNREAD_NEWS", "N", 'n');

    /** Menu: Tools */
    if (GlobalSettings.isMac())
      setHotkey("MENU_FEEDSEARCH", cmd + "+G", SWT.COMMAND | 'g');
    else
      setHotkey("MENU_FEEDSEARCH", ctrl + "+G", SWT.CTRL | 'g');

    setHotkey("MENU_FEED_DISCOVERY", NULL_ACCELERATOR_NAME, NULL_ACCELERATOR_VALUE);
    setHotkey("MENU_VALIDATE", NULL_ACCELERATOR_NAME, NULL_ACCELERATOR_VALUE);

    if (GlobalSettings.isMac())
      setHotkey("MENU_PREFERENCES", cmd + "+Comma", SWT.COMMAND | ',');
    else
      setHotkey("MENU_PREFERENCES", NULL_ACCELERATOR_NAME, NULL_ACCELERATOR_VALUE);
  }

  /**
   * Check if a hotkey is set for the given item.
   * 
   * @param itemName The name of the item.
   * @return boolean TRUE if a hotkey is set for the item.
   */
  public static boolean isHotkeySet(String itemName) {
    if (!hotKeys.containsKey(itemName))
      return false;

    return Integer.parseInt(((String[]) hotKeys.get(itemName))[1]) != NULL_ACCELERATOR_VALUE;
  }

  /**
   * This Method returns TRUE in case the given accelerator is printable, e.g.
   * inside a form. Accelerators being printable are not written into an input
   * field in case typed. Instead the connected menuitem will be selected.
   * Therefor all printable accelerators have to be removed as soon as the user
   * has entered an input field.
   * 
   * @param value The key value to check.
   * @return boolean TRUE in case the key value is printable.
   */
  public static boolean isPrintableAccelerator(int value) {

    /** Char Range a-z */
    if (97 <= value && value <= 122)
      return true;

    /** Char Range Shift + a-z */
    if (131169 <= value && value <= 131194)
      return true;

    /** Char Range 0-9 */
    if (48 <= value && value <= 57)
      return true;

    /** Char Range Shift + 0-9 */
    if (131120 <= value && value <= 131129)
      return true;

    /** Arrows */
    if (16777217 <= value && value <= 16777220)
      return true;

    /** Space */
    if (value == 32)
      return true;

    /** Line and Underline */
    if (value == 45 || value == 131117)
      return true;

    /** Page Up and Page Down */
    if (value == 16777221 || value == 16777222)
      return true;

    return false;
  }

  /**
   * Set a hotkey to the item.
   * 
   * @param itemName The I18N name of the item
   * @param keyName The name of the hotkey (e.g. "CTRL+B")
   * @param keyValue The value of the hotkey (e.g. 22330)
   */
  public static void setHotkey(String itemName, String keyName, int keyValue) {
    setHotkey(itemName, keyName, String.valueOf(keyValue));
  }

  /**
   * Set a hotkey to the item.
   * 
   * @param itemName The I18N name of the item
   * @param keyName The name of the hotkey (e.g. "CTRL+B")
   * @param keyValue The value of the hotkey (e.g. "22330")
   */
  public static void setHotkey(String itemName, String keyName, String keyValue) {
    hotKeys.put(itemName, new String[] { keyName, keyValue });
  }
}