function EKey(keyMap, element){
	var options = arguments[1] || {},
		subscribers = [];
	var self = this;
		self.keyMap = keyMap,
		self.element = element;
	var getKeyObjFromEvent = function(evt){
		var keys;
		switch(evt.type){
			case "keydown":
				keys = getKeysFromKeyDown(evt);
				break;
			case "keypress":
				keys = getKeysFromKeyPress(evt);
				break;
			default:
				keys = getKeyObj();
		}
		return keys;
	};
	var getKeysFromKeyDown = function(evt){
		var keys = getKeyObj();
		var keyCode = getKeyCode(evt);
		if(!self.keyMap.modifiable[keyCode]){
			if(self.keyMap.functional[keyCode]){
				keys.modifiable = getModifiable(evt);
				keys.functional[keyCode] = self.keyMap.functional[keyCode];
			}else if(isNonShiftModifer(evt)){
				keys.modifiable = getModifiable(evt);
				keys.printable[keyCode] = self.keyMap.printable[keyCode];
			}
		}/* Safari shits the bed on pure modifiers need to investigate more.
		else{
			keys.modifiable = getModifiable(evt);
		}
		*/ 
		return keys;	
	};
	var getKeysFromKeyPress = function(evt){
		var keys = getKeyObj();
		if(!isNonShiftModifer(evt) && !isFunctionKeyPressEvent(evt)){
			var keyCode = getKeyCode(evt);
			keys.printable[keyCode] = self.keyMap.printable[keyCode];
		}else if(isNonShiftModifer(evt) && !isFunctionKeyPressEvent(evt)){
			var keyCode = getKeyCode(evt);
			keys.modifiable = getModifiable(evt);
			keys.printable[keyCode] = self.keyMap.printable[keyCode];
		}
		return keys;
	};
	var getIndexOfArray = function(arr, val){
		if(arr.indexOf){
			return arr.indexOf(val);
		}else{
			for(var i=0; i<arr.length; i++){
				if(arr[i]==val){
					return i;
				}				
			}
			return -1; 
		}
	}
	var getKeysFromType = function(type){
		var keyObj = getKeyObj();
		var types = type.split("+");
		for(var i in self.keyMap){
			for(var j in self.keyMap[i]){
				if(getIndexOfArray(types, self.keyMap[i][j])!=-1){
					keyObj[i][j] = self.keyMap[i][j];
				}
			}
		}
		return keyObj;
	};
	var getKeyCode = function(evt){
		return (evt.which)?evt.which:evt.keyCode;
	};
	var getKeyObj = function(){
		var keys = {
			"modifiable":{},
			"functional":{},
			"printable":{}
		};
		return keys;
	};
	var getModifiable = function(evt){
		var modifiable = {};
		for(var i in self.keyMap.modifiable){
			try{
				if(evt[self.keyMap.modifiable[i]+"Key"]){
					modifiable[i] = self.keyMap.modifiable[i];
				}
			}catch(err){}
		}
		return modifiable;
	};
	var isFunctionKeyPressEvent = function(evt){
		return (evt.charCode!=undefined && evt.charCode==0)?true:false;
	};
	var isModiferKeyOn = function(evt){
		return (evt.altKey || evt.ctrlKey || evt.metaKey || evt.shiftKey)?true:false;
	};
	var isNonShiftModifer = function(evt){
		return (evt.altKey || evt.ctrlKey || evt.metaKey)?true:false;
	};
	var keyObjToString = function(keyObj){
		var arr = [];
		for(var i in keyObj){
			for(var j in keyObj[i]){
				arr.push(i+"_"+j+"_"+keyObj[i][j]);
			}
		}
		return arr.sort().toString();
	};
	self.addEventListener = function(type, listener){
		var keyObj = getKeysFromType(type);
		subscribers.push({"type":type,"listener":listener, "keyObj":keyObj})
	};
	self.removeEventListener = function(type, listener){
		for(var i=0; i<subscribers.length; i++){
			var sub = subscribers[i];
			var keyObj = getKeysFromType(type);
			var keyStr = keyObjToString(keyObj);
			if(sub && keyObjToString(sub.keyObj)==keyStr && sub.type==type && sub.listener==listener){
				delete subscribers[i];
			}
		}
	};
	self.dispatch = function(evt){
		var keyObj = getKeyObjFromEvent(evt);
		var keyStr = keyObjToString(keyObj);
		for(var i=0; i<subscribers.length; i++){
			var sub = subscribers[i];
			if(sub && keyObjToString(sub.keyObj)==keyStr){
				sub.listener(evt);
			}
		}
	};
	self.EKey = function(){
		YAHOO.util.Event.addListener(element, "keydown", self.dispatch);
		YAHOO.util.Event.addListener(element, "keypress", self.dispatch);
	}();
}