using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;

namespace Blindfold.Managers
{
    public class InputManager : GameComponent
    {
        private Main game;
        private KeyboardState kbstate = new KeyboardState();
        private KeyboardState oldkbstate = new KeyboardState();
        private GamePadState[] gpstate = new GamePadState[4];
        private GamePadState[] oldgpstate = new GamePadState[4];
        private MouseState mstate = new MouseState();
        private MouseState oldmstate = new MouseState();

        public Rectangle mouseBounds;

        private bool kbcontrol;
        private GamePadDeadZone deadZoneMode = new GamePadDeadZone();
        private PlayerIndex pi = new PlayerIndex();

        public InputManager(Main game) : base(game)
        {
            this.game = game;
            this.deadZoneMode = GamePadDeadZone.Circular;
            if (!GamePad.GetState(pi).IsConnected)
            {
                kbcontrol = true;
            }
            this.mouseBounds = new Rectangle(0, 0, 1, 1);
        }

        public char getLetter()
        {
            for (int i = 65; i <= 90; i++)
            {
                Keys k = (Keys)((char)i);
                if (keyHit(k))
                {
                    return (char)i;
                }
            }
            if (keyHit(Keys.Space))
            {
                return ' ';
            }
            else if (keyHit(Keys.Back))
            {
                return '<';
            }
            return '1';
        }

        public bool MouseHit(int a)
        {
            switch (a)
            {
                case 0: //LeftMouseButton
                    return (mstate.LeftButton == ButtonState.Pressed && oldmstate.LeftButton == ButtonState.Released);
                case 1: //RightMouseButton
                    return (mstate.RightButton == ButtonState.Pressed && oldmstate.RightButton == ButtonState.Released);
                case 2: //MiddleMouseButton
                    return (mstate.MiddleButton == ButtonState.Pressed && oldmstate.MiddleButton == ButtonState.Released);
                default:
                    return false;
            }
        }

        public bool MouseDown(int a)
        {
            switch (a)
            {
                case 0: //LeftMouseButton
                    return (mstate.LeftButton == ButtonState.Pressed);
                case 1: //RightMouseButton
                    return (mstate.RightButton == ButtonState.Pressed);
                case 2: //MiddleMouseButton
                    return (mstate.MiddleButton == ButtonState.Pressed);
                default:
                    return false;
            }
        }

        public bool getScrollDir()
        {
            return ((mstate.ScrollWheelValue - oldmstate.ScrollWheelValue) > 0) ? true : false;
        }

        public double getScrollValue()
        {
            return mstate.ScrollWheelValue;
        }

        public double getScrollChange()
        {
            return (oldmstate.ScrollWheelValue - mstate.ScrollWheelValue);
        }

        //GAMEPAD
        /// <summary>
        /// Returns whether a button was released.
        /// </summary>
        /// /// <param name="b">The button that should be checked.</param>
        /// /// <param name="playerIndex">Player that should be checked.</param>
        public bool buttonRelease(Buttons b,int playerIndex)
        {
            return (gpstate[playerIndex].IsButtonUp(b) && oldgpstate[playerIndex].IsButtonDown(b));
        }

        /// <summary>
        /// Returns whether a button was hit.
        /// </summary>
        /// /// <param name="b">The button that should be checked.</param>
        /// /// <param name="playerIndex">Player that should be checked.</param>
        public bool buttonHit(Buttons b, int playerIndex)
        {
            return (gpstate[playerIndex].IsButtonDown(b) && oldgpstate[playerIndex].IsButtonUp(b));
        }

        /// <summary>
        /// Returns whether a button is down.
        /// </summary>
        /// /// <param name="b">The button that should be checked.</param>
        /// /// <param name="playerIndex">Player that should be checked.</param>
        public bool buttonDown(Buttons b, int playerIndex)
        {
            return gpstate[playerIndex].IsButtonDown(b);
        }

        public void vibrateGamepad(int playerIndex, float intensety)
        {
            switch (playerIndex)
            {
                case 0:
                    GamePad.SetVibration(PlayerIndex.One, intensety, intensety);
                    break;
                case 1:
                    GamePad.SetVibration(PlayerIndex.One, intensety, intensety);
                    break;
                case 2:
                    GamePad.SetVibration(PlayerIndex.One, intensety, intensety);
                    break;
                case 3:
                    GamePad.SetVibration(PlayerIndex.One, intensety, intensety);
                    break;
            }
        }

        /// <summary>
        /// Returns the direction of the Left Thumbstick.
        /// </summary>
        /// /// <param name="playerIndex">Player that should be checked.</param>
        public Vector2 getLeftDir(int playerIndex)
        {
            Vector2 v = gpstate[playerIndex].ThumbSticks.Left;
            if(!v.Equals(new Vector2(0,0)))
            {
                v.Normalize();
            }
            v.Y *= -1;
            return v;
        }

        /// <summary>
        /// Returns the direction of the Right Thumbstick.
        /// </summary>
        /// /// <param name="playerIndex">Player that should be checked.</param>
        public Vector2 getRightDir(int playerIndex)
        {
            Vector2 v = gpstate[playerIndex].ThumbSticks.Right;
            if(!v.Equals(new Vector2(0,0)))
            {
                v.Normalize();
            }
            v.Y *= -1;
            return v;
        }

        //KEAYBOARD
        /// <summary>
        /// Returns whether a key was released.
        /// </summary>
        /// /// <param name="k">The key that should be checked.</param>
        public bool keyRelease(Keys k)
        {
            return (kbstate.IsKeyUp(k) && oldkbstate.IsKeyDown(k));
        }

        /// <summary>
        /// Returns whether a key was hit.
        /// </summary>
        /// /// <param name="k">The key that should be checked.</param>
        public bool keyHit(Keys k)
        {
            return (kbstate.IsKeyDown(k) && oldkbstate.IsKeyUp(k));
        }

        /// <summary>
        /// Returns whether a key is down.
        /// </summary>
        /// /// <param name="k">The key that should be checked.</param>
        public bool keyDown(Keys k)
        {
            return kbstate.IsKeyDown(k);
        }



        public override void Update(GameTime gameTime)
        {

            oldkbstate = kbstate;
            kbstate = Keyboard.GetState();
            for (int i = 0; i < 4; i++)
            {
                oldgpstate[i] = gpstate[i];
                switch (i)
                {
                    case 0:
                        pi = PlayerIndex.One;
                        break;
                    case 1:
                        pi = PlayerIndex.Two;
                        break;
                    case 2:
                        pi = PlayerIndex.Three;
                        break;
                    case 3:
                        pi = PlayerIndex.Four;
                        break;
                }
                gpstate[i] = GamePad.GetState(pi, deadZoneMode);
            }
            oldmstate = mstate;
            mstate = Mouse.GetState();

            this.mouseBounds.X = mstate.X;
            this.mouseBounds.Y = mstate.Y;

            isStateChanged();
        }

        /// <summary>
        /// Returns whether the Keyboard has changed at all.
        /// </summary>
        public bool isStateChanged()
        {
            if (!kbstate.Equals(oldkbstate))
            {
                kbcontrol = true;
                return true;
            }
            else if (!gpstate.Equals(oldgpstate))
            {
                kbcontrol = false;
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}
