package meyermike 
{
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;
    
    /**
     * ...
     * @author Mike Meyer
     */
    public class InputUtil 
    {
        public static const KEYSTATE_UP:uint           = 0;
        public static const KEYSTATE_JUSTPRESSED:uint  = 1;
        public static const KEYSTATE_HELD:uint         = 2;
        public static const KEYSTATE_JUSTRELEASED:uint = 3;
        
        private static var sKeyStates:Object = new Object();
        
        /**
         * Get InputUtil ready to be used
         */
        public static function Init():void
        {
            Main.sInstance.stage.addEventListener(KeyboardEvent.KEY_DOWN, OnKeyDown);
            Main.sInstance.stage.addEventListener(KeyboardEvent.KEY_UP, OnKeyUp);
        }
        
        /**
         * clean up
         */
        public static function Shutdown():void
        {
            Main.sInstance.stage.removeEventListener(KeyboardEvent.KEY_DOWN, OnKeyDown);
            Main.sInstance.stage.removeEventListener(KeyboardEvent.KEY_UP, OnKeyUp);
        }
        
        /**
         * make the JUST X'ed states go to the more permanent ones
         */
        public static function Update():void
        {
            for (var key:String in InputUtil.sKeyStates)
            {
                switch (InputUtil.sKeyStates[key])
                {
                    case InputUtil.KEYSTATE_JUSTPRESSED:
                        InputUtil.sKeyStates[key] = InputUtil.KEYSTATE_HELD;
                        break;
                    case InputUtil.KEYSTATE_JUSTRELEASED:
                        InputUtil.sKeyStates[key] = InputUtil.KEYSTATE_UP;
                        break;
                }
            }
        }
        
        /**
         * update the states when a key is pressed
         */
        private static function OnKeyDown(e:KeyboardEvent):void
        {
            if (InputUtil.sKeyStates.hasOwnProperty(e.keyCode))
            {
                switch (InputUtil.sKeyStates[e.keyCode])
                {
                    case InputUtil.KEYSTATE_UP: 
                    case InputUtil.KEYSTATE_JUSTRELEASED: 
                        InputUtil.sKeyStates[e.keyCode] = InputUtil.KEYSTATE_JUSTPRESSED;
                        break;
                    case InputUtil.KEYSTATE_JUSTPRESSED: 
                    case InputUtil.KEYSTATE_HELD: 
                        // stay there, let Update handle it
                        break;
                }
            }
            else
            {
                InputUtil.sKeyStates[e.keyCode] = InputUtil.KEYSTATE_JUSTPRESSED;
            }
        }
        
        /**
         * update the states when a key is released
         */
        private static function OnKeyUp(e:KeyboardEvent):void
        {
            if (InputUtil.sKeyStates.hasOwnProperty(e.keyCode))
            {
                switch (InputUtil.sKeyStates[e.keyCode])
                {
                    case InputUtil.KEYSTATE_UP:
                    case InputUtil.KEYSTATE_JUSTRELEASED:
                        // stay there
                        break;
                    case InputUtil.KEYSTATE_JUSTPRESSED:
                    case InputUtil.KEYSTATE_HELD: 
                        InputUtil.sKeyStates[e.keyCode] = InputUtil.KEYSTATE_JUSTRELEASED;
                        break;
                }
            }
            else
            {
                InputUtil.sKeyStates[e.keyCode] = InputUtil.KEYSTATE_JUSTRELEASED;
            }
        }
        
        /**
         * tell whether a key is down or not
         */
        public static function IsDown(keyCode:uint):Boolean
        {
            if (InputUtil.sKeyStates.hasOwnProperty(keyCode))
            {
                return ( (InputUtil.sKeyStates[keyCode] == InputUtil.KEYSTATE_HELD) || (InputUtil.sKeyStates[keyCode] == InputUtil.KEYSTATE_JUSTPRESSED) );
            }
            else
            {
                return false;
            }
        }
        
        /**
         * tell whether a key is up or not
         */
        public static function IsUp(keyCode:uint):Boolean
        {
            if (InputUtil.sKeyStates.hasOwnProperty(keyCode))
            {
                return ( (InputUtil.sKeyStates[keyCode] == InputUtil.KEYSTATE_UP) || (InputUtil.sKeyStates[keyCode] == InputUtil.KEYSTATE_JUSTRELEASED) );
            }
            else
            {
                return true;
            }
        }
        
        /**
         * tell whether a key has been released for a frame or more
         */
        public static function IsReleased(keyCode:uint):Boolean
        {
            if (InputUtil.sKeyStates.hasOwnProperty(keyCode))
            {
                return (InputUtil.sKeyStates[keyCode] == InputUtil.KEYSTATE_UP);
            }
            else
            {
                return true;
            }
        }
        
        /**
         * tell whether a key has been held for a frame or more
         */
        public static function IsHeld(keyCode:uint):Boolean
        {
            if (InputUtil.sKeyStates.hasOwnProperty(keyCode))
            {
                return (InputUtil.sKeyStates[keyCode] == InputUtil.KEYSTATE_HELD);
            }
            else
            {
                return false;
            }
        }
        
        /**
         * tell whether a key was just pressed this frame
         */
        public static function WasJustPressed(keyCode:uint):Boolean
        {
            if (InputUtil.sKeyStates.hasOwnProperty(keyCode))
            {
                return (InputUtil.sKeyStates[keyCode] == InputUtil.KEYSTATE_JUSTPRESSED);
            }
            else
            {
                return false;
            }
        }
        
        /**
         * tell whether a key was just released this frame
         */
        public static function WasJustReleased(keyCode:uint):Boolean
        {
            if (InputUtil.sKeyStates.hasOwnProperty(keyCode))
            {
                return (InputUtil.sKeyStates[keyCode] == InputUtil.KEYSTATE_JUSTRELEASED);
            }
            else
            {
                return false;
            }
        }
        
        /**
         * get the keystate directly
         */
        public static function GetKeyState(keyCode:uint):uint
        {
            if (InputUtil.sKeyStates.hasOwnProperty(keyCode))
            {
                return InputUtil.sKeyStates[keyCode];
            }
            else
            {
                return InputUtil.KEYSTATE_UP;
            }
        }
    }
}