package com.netgrind.core
{
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.utils.Dictionary;
	
	/**
	 * ...
	 * @author netgrind
	 */
	public class Key{
		
		private static var _pressed:Dictionary = new Dictionary();
		private static var _justPressed:Dictionary = new Dictionary();
		private static var _newPressed:Dictionary = new Dictionary();
		private static var _functions:Dictionary = new Dictionary();
		private static var _cancel:Dictionary = new Dictionary();
		private static var _stage:Stage;
		public static var lock:Boolean = false;
		
		public static function init(stage:Stage):void
		{
			_stage = stage;
			stage.addEventListener(KeyboardEvent.KEY_DOWN, onDown);
			stage.addEventListener(KeyboardEvent.KEY_UP, onUp);
			stage.addEventListener(Event.ENTER_FRAME, onFrame);
		}
		
		public static function onFrame(e:Event):void {
			for (var i:* in _justPressed) {
				if (_justPressed[i]) {
					_justPressed[i] = false;
				}
			}
			if (lock) return;
			keys: for (var j:* in _pressed) {
				if ( _pressed[j] && _functions[j] != null) {
					for (var k:int = 0; k < _functions[j].length; k++) {
						if(_functions[j][k][2]){
							_functions[j][k][0].apply(null, _functions[j][k][1]);	
							if (_cancel[j]) {
								continue keys;
							}
						}
					}
				}
			}
			clearCancel()
		}
		
		public static function onDown(e:KeyboardEvent):void {
			if (_pressed[e.keyCode]) {
				_justPressed[e.keyCode] = false;
			}else {
				_justPressed[e.keyCode] = true;
				if (lock) return;
				if (_functions[e.keyCode]) {
					for (var i:int = _functions[e.keyCode].length-1; i >-1 ; i--) {
						try{
							_functions[e.keyCode][i][0].apply(null, _functions[e.keyCode][i][1]);
							
						}catch (err:Error){
							
						}
						if (!_functions[e.keyCode]||_cancel[e.keyCode]) break;
					}
				}
			}
			_pressed[e.keyCode] = true;
			clearCancel();
		}
		public static function onUp(e:KeyboardEvent):void {
			_pressed[e.keyCode] = false;	
			_justPressed[e.keyCode] = false;
		}
		
		private static function clearCancel():void {
			for (var i:* in _cancel) {
				_cancel[i] = false
			}
		}
		
		public static function pressed(key:uint):Boolean {
			if (lock) return false;
			if (_pressed[key]) {
				return true;
			}
			return false;
		}
		
		static public function justPressed(key:uint):Boolean {
			if (lock) return false;
			if (_justPressed[key]) {
				return true;
			}
			return false;
		}
		
		static public function bindFunctionToKeyPress(func:Function, key:uint, ...args):void {
			
			if (!_functions[key]) {
				_functions[key] = new Array();
			}
			_functions[key].push([func, args, false]);
		}
		
		static public function cleanKey(key:uint):void {
			_functions[key] = null;
		}
		
		static public function removeFunctionFromKey(func:Function, key:uint, ...args):void {
			if (_functions[key]) {
				for (var i:int = 0; i < _functions[key].length; i++) {
					if (_functions[key][i][0] == func && (!args.length || _functions[key][i][1] == args)) {
						_functions[key][i][0] = null;
						_functions[key][i] = null;
						_functions[key].splice(i, 1);
						if (_functions[key].length == 0) {
							_functions[key] = null;
						}
						break;
					}
				}
			}
		}
		
		static public function bindFunctionToKeyHold(func:Function, key:uint, ...args):void {
			if (!_functions[key]) {
				_functions[key] = new Array();
			}
			_functions[key].push([func,args,true]);
		}
		
		static public function stopPropagation(key:uint):void {
			_cancel[key] = true;
		}
		
	}
	
}