/******************************************************************************************************************************

 * @ Original idea by by Binny V A, Original version: 2.00.A 
 * @ http://www.openjs.com/scripts/events/keyboard_shortcuts/
 * @ Original License : BSD
 
 * @ jQuery Plugin by Tzury Bar Yochay 
        mail: tzury.by@gmail.com
        blog: evalinux.wordpress.com
        face: facebook.com/profile.php?id=513676303
        
        (c) Copyrights 2007
        
 * @ jQuery Plugin version Beta (0.0.2)
 * @ License: jQuery-License.
 
TODO:
    add queue support (as in gmail) e.g. 'x' then 'y', etc.
    add mouse + mouse wheel events.

USAGE:
    $.hotkeys.add('Ctrl+c', function(){ alert('copy anyone?');});
    $.hotkeys.add('Ctrl+c', {target:'div#editor', type:'keyup', propagate: true},function(){ alert('copy anyone?');});>
    $.hotkeys.remove('Ctrl+c'); 
    $.hotkeys.remove('Ctrl+c', {target:'div#editor', type:'keypress'}); 
    
******************************************************************************************************************************/
(function(jQuery) {
	jQuery.hotkeys = {
		version : '(beta)(0.0.3)',
		all : {},
		special_keys : {
			8 : 'backspace',
			9 : 'tab',
			13 : 'return',
			19 : 'pause',
			20 : 'capslock',
			27 : 'esc',
			32 : 'space',
			33 : 'pageup',
			34 : 'pagedown',
			35 : 'end',
			36 : 'home',
			37 : 'left',
			38 : 'up',
			39 : 'right',
			40 : 'down',
			45 : 'insert',
			46 : 'del',
			97 : '1',
			98 : '2',
			106 : '*',
			107 : '+',
			109 : '-',
			110 : '.',
			111 : '/',
			112 : 'f1',
			113 : 'f2',
			114 : 'f3',
			115 : 'f4',
			116 : 'f5',
			117 : 'f6',
			118 : 'f7',
			119 : 'f8',
			120 : 'f9',
			121 : 'f10',
			122 : 'f11',
			123 : 'f12',
			144 : 'numlock',
			145 : 'scroll'
		},
		shift_nums : {
			"`" : "~",
			"1" : "!",
			"2" : "@",
			"3" : "#",
			"4" : "$",
			"5" : "%",
			"6" : "^",
			"7" : "&",
			"8" : "*",
			"9" : "(",
			"0" : ")",
			"-" : "_",
			"=" : "+",
			";" : ":",
			"'" : "\"",
			"," : "<",
			"." : ">",
			"/" : "?",
			"\\" : "|"
		},

		add : function(combi, options, callback) {
			if (jQuery.isFunction(options)) {
				callback = options;
				options = {};
			}
			var opt = {}, defaults = {
				type : 'keydown',
				propagate : false,
				disableInInput : false,
				target : jQuery('body')[0],
				checkParent : true
			}, that = this;
			opt = jQuery.extend(opt, defaults, options || {});
			if (opt.target.body)
				opt.target = opt.target.body;
			combi = combi.toLowerCase();
			// inspect if keystroke matches
			var inspector = function(event) {
				event = jQuery.event.fix(event); // jQuery event
				// normalization.
				var element = event.target;
				// @ TextNode -> nodeType == 3
				element = (element.nodeType == 3)
						? element.parentNode
						: element;
				if (opt['disableInInput']) { // Disable shortcut keys in
					// Input, Textarea fields
					var target = jQuery(element);
					if (target.is("input") || target.is("textarea")) {
						return;
					}
				}
				var code = event.which, type = event.type, character = String
						.fromCharCode(code).toLowerCase(), special = that.special_keys[code], shift = event.shiftKey, ctrl = event.ctrlKey, alt = event.altKey, propagate = true, // default
				// behaivour
				mapPoint = null;
				// in opera + safari, the event.target is unpredictable.
				// for example: 'keydown' might be associated with
				// HtmlBodyElement
				// or the element where you last clicked with your mouse.
				if (jQuery.browser.opera || jQuery.browser.safari
						|| opt.checkParent) {
					while (!that.all[element.tagName + '#' + element.id]
							&& element.parentNode) {
						element = element.parentNode;
					}
				}
				if (element.body)
					element = element.body;

				var cbMap = that.all[element.tagName + '#' + element.id].events[type].callbackMap;
				if (!shift && !ctrl && !alt) { // No Modifiers
					mapPoint = cbMap[special] || cbMap[character];
				}
				// deals with combinaitons (alt|ctrl|shift+anything)
				else {
					var modif = '';
					if (alt)
						modif += 'alt+';
					if (ctrl)
						modif += 'ctrl+';
					if (shift)
						modif += 'shift+';
					// modifiers + special keys or modifiers + characters or
					// modifiers + shift characters
					mapPoint = cbMap[modif + special]
							|| cbMap[modif + character]
							|| cbMap[modif + that.shift_nums[character]];
				}
				if (mapPoint) {
					mapPoint.cb(event);
					try {
						if (!mapPoint.propagate) {
							event.stopPropagation();
							event.preventDefault();
							return false;
						}
					} catch (e) {
					}
				}
			};
			// first hook for this element
			if (!this.all[opt.target.tagName + '#' + opt.target.id]) {
				this.all[opt.target.tagName + '#' + opt.target.id] = {
					events : {}
				};
			}
			if (!this.all[opt.target.tagName + '#' + opt.target.id].events[opt.type]) {
				this.all[opt.target.tagName + '#' + opt.target.id].events[opt.type] = {
					callbackMap : {}
				};
				jQuery.event.add(opt.target, opt.type, inspector);
			}
			this.all[opt.target.tagName + '#' + opt.target.id].events[opt.type].callbackMap[combi] = {
				cb : callback,
				propagate : opt.propagate
			};
			return jQuery;
		},
		remove : function(exp, opt) {
			opt = opt || {};
			target = opt.target || jQuery('body')[0];
			type = opt.type || 'keydown';
			exp = exp.toLowerCase();
			if(this.all[target.tagName + '#' + target.id]&&
				this.all[target.tagName + '#' + target.id].events&&
				this.all[target.tagName + '#' + target.id].events[type]&&
				this.all[target.tagName + '#' + target.id].events[type].callbackMap){
				delete this.all[target.tagName + '#' + target.id].events[type].callbackMap[exp];
			}
			return jQuery;
		},
		removeAll : function(opt) {
			opt = opt || {};
			target = opt.target || jQuery('body')[0];
			type = opt.type || 'keydown';			
			if(this.all[target.tagName + '#' + target.id]&&this.all[target.tagName + '#' + target.id].events){
				delete this.all[target.tagName + '#' + target.id].events[type];
				jQuery.event.remove(target, type);
			}
			return jQuery;
		}
	};
	return jQuery;
})(jQuery);


(function($) {
	/**
	 * °ó¶¨¼üÅÌÊÂ¼þ
	 * 
	 * @param type
	 *            (String)
	 * @param scope
	 *            (Object)
	 * @param callback
	 *            (Function)
	 * 
	 */
    $.fn.shortcut = function(type, scope, callback /* ,param,...,param */) {
		return this.each((function(params) {
			return function() {
				var o = this;
				if (type in $.fn.shortcut.defaults) {
					(function(key, cb, config){
						config = config || {};
						config.target = o;
						if (callback && (typeof callback == 'function')) {
							jQuery.hotkeys.add(key, config, function(e) {
								cb.apply(scope || window, [e,callback].concat(params));
							});
						}
					})($.fn.shortcut.defaults[type].key, $.fn.shortcut.defaults[type].cb, $.fn.shortcut.defaults[type].config);
				}
			};
		})(Array.prototype.slice.call(arguments, 3)));
	};
	
	$.fn.removeShortcut = function() {
		return this.each((function(params) {
			return function() {
				for (var i = 0; i < params.length; i++) {
					jQuery.hotkeys
							.remove($.fn.shortcut.defaults[params[i]].key, {target: this});
				}
			};
		})(arguments));
	};
	
	$.fn.removeAllShortcut = function() {
		return this.each(function() {
					jQuery.hotkeys
							.removeAll({target: this});
			}
		);
	};

	$.fn.shortcut.defaults = {
		'backspace' : {key:'backspace', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}},
		'save' : {key:'Ctrl+1', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}},
		'save&add' : {key:'Ctrl+2', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}},
		'close' : {key:'Ctrl+q', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}},
		'open' : {key:'Ctrl+n', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}},
		'edit' : {key:'Ctrl+e', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}},
		'delete' : {key:'del', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}},
		'copy' : {key:'Alt+1', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}},
		'enter' : {key:'return', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}},
		'pageup' : {key:'pageup', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}},
		'pagedown' : {key:'pagedown', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}},
		'home' : {key:'home', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}},
		'end' : {key:'end', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}},
		'space' : {key:'space', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}},
		'doo' : {key:'.', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}, config: {propagate: true}},
		'dll' : {key:'/', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}, config: {propagate: true}},
		'f2' : {key:'f2', cb: function(e, callback) {
			callback.apply(this, Array.prototype.slice.call(arguments, 2));
		}, config: {propagate: true}}
	};
	
	return $;
})(jQuery);
/*

				switch(type) {
				  case 'edit': jQuery.hotkeys.add('Ctrl+e',function(fn,obj){});
				  case 'del': jQuery.hotkeys.add('del',function(fn,obj){});
				  case 'copy': jQuery.hotkeys.add('Alt+v',function(fn,obj){});
				  case 'enter': jQuery.hotkeys.add('return',function(fn,obj){fn.apply(this,arguments)});
				  
				  case 'pgUp': jQuery.hotkeys.add('pageup',function(fn,obj){});
				  case 'pgDown': jQuery.hotkeys.add('pagedown',function(fn,obj){});
				  case 'home': jQuery.hotkeys.add('home',function(fn,obj){});
				  case 'end': jQuery.hotkeys.add('end',function(fn,obj){});
				  
				  case 'doo': jQuery.hotkeys.add('.',{propagate: true},function(){dbClick(fn)}); 
				  case 'dll': jQuery.hotkeys.add('/',{propagate: true},function(){dbClick(fn)}); 
				  
			   }
*/
