using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace MegaManRipoff.UI
{
    /// <summary>
    /// Utility class designed to handle inputs.
    /// </summary>
    class InputHelper
    {
        #region Member Variables

        /// <summary>
        /// The current keyboard state.
        /// </summary>
        static KeyboardState _currentKeyboardState;

        /// <summary>
        /// The previous keyboard state.
        /// </summary>
        static KeyboardState _previousKeyboardState;

        /// <summary>
        /// The current gamepad state.
        /// </summary>
        static GamePadState _currentGamePadState;

        /// <summary>
        /// The previous gamepad state.
        /// </summary>
        static GamePadState _previousGamePadState;

        //Input keys.
        static Keys _leftKey, _rightKey, _upKey, _downKey, _jumpKey, _shootKey, _startKey;

        //Input buttons.
        static Buttons _jumpButton, _shootButton1, _shootButton2, _startButton;

        /// <summary>
        /// Dead zone used for the gamepad.
        /// </summary>
        static float _deadZone;

        #endregion

        /// <summary>
        /// Static constructor used to set the input keys.
        /// </summary>
        static InputHelper()
        {
            //Set references to the keys used for user input.
            _leftKey = Keys.Left;
            _rightKey = Keys.Right;
            _upKey = Keys.Up;
            _downKey = Keys.Down;
            _jumpKey = Keys.X;
            _shootKey = Keys.Z;
            _startKey = Keys.Enter;

            //Set references to the buttons used for user input.
            _jumpButton = Buttons.A;
            _shootButton1 = Buttons.B;
            _shootButton2 = Buttons.X;
            _startButton = Buttons.Start;
            _deadZone = 0.25f;
        }

        #region Methods

        /// <summary>
        /// Updates the keyboard and gamepad states.
        /// </summary>
        public static void Update()
        {
            _previousKeyboardState = _currentKeyboardState;
            _currentKeyboardState = Keyboard.GetState();

            if (GamePad.GetState(PlayerIndex.One).IsConnected)
            {
                _previousGamePadState = _currentGamePadState;
                _currentGamePadState = GamePad.GetState(PlayerIndex.One);
            }
        }

        /// <summary>
        /// Checks if left is held down on the keyboard and the gamepad. Used by the player object.
        /// </summary>
        /// <returns>Returns true if either the keyboard or the gamepad are holding left.</returns>
        public static bool IsLeftHeld()
        {
            if (GamePad.GetState(PlayerIndex.One).IsConnected)
            {
                return (_currentKeyboardState.IsKeyDown(_leftKey)
                    ^ _currentGamePadState.ThumbSticks.Left.X < -_deadZone);
            }
            else
            {
                return _currentKeyboardState.IsKeyDown(_leftKey);
            }
        }

        /// <summary>
        /// Checks if left is pressed on the keyboard and the gamepad.
        /// </summary>
        /// <returns>Returns true if either the keyboard or the gamepad are pressing left.</returns>
        public static bool IsLeftPressed()
        {
            if (GamePad.GetState(PlayerIndex.One).IsConnected)
            {
                return ((_currentKeyboardState.IsKeyDown(_leftKey) && !_previousKeyboardState.IsKeyDown(_leftKey))
                    ^ (_currentGamePadState.ThumbSticks.Left.X < -_deadZone && _previousGamePadState.ThumbSticks.Left.X >= -_deadZone));
            }
            else
            {
                return _currentKeyboardState.IsKeyDown(_leftKey) && !_previousKeyboardState.IsKeyDown(_leftKey);
            }
        }

        /// <summary>
        /// Checks if right is held down on the keyboard and the gamepad. Used by the player object.
        /// </summary>
        /// <returns>Returns true if either the keyboard or the gamepad are holding right.</returns>
        public static bool IsRightHeld()
        {
            if (GamePad.GetState(PlayerIndex.One).IsConnected)
            {
                return (_currentKeyboardState.IsKeyDown(_rightKey)
                    ^ _currentGamePadState.ThumbSticks.Left.X > _deadZone);
            }
            else
            {
                return _currentKeyboardState.IsKeyDown(_rightKey);
            }
        }

        /// <summary>
        /// Checks if right is pressed on the keyboard and the gamepad.
        /// </summary>
        /// <returns>Returns true if either the keyboard or the gamepad are pressing right.</returns>
        public static bool IsRightPressed()
        {
            if (GamePad.GetState(PlayerIndex.One).IsConnected)
            {
                return ((_currentKeyboardState.IsKeyDown(_rightKey) && !_previousKeyboardState.IsKeyDown(_rightKey))
                    ^ (_currentGamePadState.ThumbSticks.Left.X > _deadZone && _previousGamePadState.ThumbSticks.Left.X <= _deadZone));
            }
            else
            {
                return _currentKeyboardState.IsKeyDown(_rightKey) && !_previousKeyboardState.IsKeyDown(_rightKey);
            }
        }

        /// <summary>
        /// Checks if up is pressed on the keyboard and the gamepad.
        /// </summary>
        /// <returns>Returns true if either the keyboard or the gamepad are pressing up.</returns>
        public static bool IsUpPressed()
        {
            if (GamePad.GetState(PlayerIndex.One).IsConnected)
            {
                return ((_currentKeyboardState.IsKeyDown(_upKey) && !_previousKeyboardState.IsKeyDown(_upKey))
                    ^ (_currentGamePadState.ThumbSticks.Left.Y > _deadZone && _previousGamePadState.ThumbSticks.Left.Y <= _deadZone));
            }
            else
            {
                return _currentKeyboardState.IsKeyDown(_upKey) && !_previousKeyboardState.IsKeyDown(_upKey);
            }
        }

        /// <summary>
        /// Checks if down is held down on the keyboard and the gamepad. Used by the player object.
        /// </summary>
        /// <returns>Returns true if either the keyboard or the gamepad are holding down.</returns>
        public static bool IsDownHeld()
        {
            if (GamePad.GetState(PlayerIndex.One).IsConnected)
            {
                return (_currentKeyboardState.IsKeyDown(_downKey)
                    ^ _currentGamePadState.ThumbSticks.Left.Y < -_deadZone);
            }
            else
            {
                return _currentKeyboardState.IsKeyDown(_downKey);
            }
        }

        /// <summary>
        /// Checks if down is pressed on the keyboard and the gamepad.
        /// </summary>
        /// <returns>Returns true if either the keyboard or the gamepad are pressing down.</returns>
        public static bool IsDownPressed()
        {
            if (GamePad.GetState(PlayerIndex.One).IsConnected)
            {
                return ((_currentKeyboardState.IsKeyDown(_downKey) && !_previousKeyboardState.IsKeyDown(_downKey))
                    ^ (_currentGamePadState.ThumbSticks.Left.Y < -_deadZone && _previousGamePadState.ThumbSticks.Left.Y >= -_deadZone));
            }
            else
            {
                return _currentKeyboardState.IsKeyDown(_downKey) && !_previousKeyboardState.IsKeyDown(_downKey);
            }
        }

        /// <summary>
        /// Checks if jump is held down on the keyboard and the gamepad. Used by the player object.
        /// </summary>
        /// <returns>Returns true if either the keyboard or the gamepad are holding jump.</returns>
        public static bool IsJumpHeld()
        {
            if (GamePad.GetState(PlayerIndex.One).IsConnected)
            {
                return (_currentKeyboardState.IsKeyDown(_jumpKey)
                    ^ _currentGamePadState.IsButtonDown(_jumpButton));
            }
            else
            {
                return _currentKeyboardState.IsKeyDown(_jumpKey);
            }
        }

        /// <summary>
        /// Checks if jump is pressed on the keyboard and the gamepad. Used by the player object.
        /// </summary>
        /// <returns>Returns true if either the keyboard or the gamepad are pressing jump.</returns>
        public static bool IsJumpPressed()
        {
            if (GamePad.GetState(PlayerIndex.One).IsConnected)
            {
                return ((_currentKeyboardState.IsKeyDown(_jumpKey) && !_previousKeyboardState.IsKeyDown(_jumpKey))
                    ^ (_currentGamePadState.IsButtonDown(_jumpButton) && !_previousGamePadState.IsButtonDown(_jumpButton)));
            }
            else
            {
                return _currentKeyboardState.IsKeyDown(_jumpKey) && !_previousKeyboardState.IsKeyDown(_jumpKey);
            }
        }

        /// <summary>
        /// Checks if jump is pressed on the keyboard and the gamepad. Used by the player object.
        /// </summary>
        /// <returns>Returns true if either the keyboard or the gamepad are pressing jump.</returns>
        public static bool IsShootPressed()
        {
            if (GamePad.GetState(PlayerIndex.One).IsConnected)
            {
                return ((_currentKeyboardState.IsKeyDown(_shootKey) && !_previousKeyboardState.IsKeyDown(_shootKey))
                    ^ ((_currentGamePadState.IsButtonDown(_shootButton1) && !_previousGamePadState.IsButtonDown(_shootButton1)))
                    || (_currentGamePadState.IsButtonDown(_shootButton2) && !_previousGamePadState.IsButtonDown(_shootButton2)));
            }
            else
            {
                return _currentKeyboardState.IsKeyDown(_shootKey) && !_previousKeyboardState.IsKeyDown(_shootKey);
            }
        }

        /// <summary>
        /// Checks if start is pressed on the keyboard and the gamepad. Used by the player object.
        /// </summary>
        /// <returns>Returns true if either the keyboard or the gamepad are pressing start.</returns>
        public static bool IsStartPressed()
        {
            if (GamePad.GetState(PlayerIndex.One).IsConnected)
            {
                return ((_currentKeyboardState.IsKeyDown(_startKey) && !_previousKeyboardState.IsKeyDown(_startKey))
                    ^ (_currentGamePadState.IsButtonDown(_startButton) && !_previousGamePadState.IsButtonDown(_startButton)));
            }
            else
            {
                return _currentKeyboardState.IsKeyDown(_startKey) && !_previousKeyboardState.IsKeyDown(_startKey);
            }
        }

        /// <summary>
        /// Chceks if a given key is being held.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>Returns true if the key is being held, false otherwise.</returns>
        public static bool IsKeyHeld(Keys key)
        {
            return _currentKeyboardState.IsKeyDown(key);
        }

        /// <summary>
        /// Chceks if a given key is being pressed.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>Returns true if the key is being pressed, false otherwise.</returns>
        public static bool IsKeyPressed(Keys key)
        {
            return _currentKeyboardState.IsKeyDown(key) && !_previousKeyboardState.IsKeyDown(key);
        }

        #endregion
    }
}
