using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using StrategicCombat.Teams;
using StrategicCombat.CombatUnits;
using StrategicCombat.Shots;
using StrategicCombat.Maps;

namespace StrategicCombat.PlayerProfiles
{
    /// <summary>
    /// This class represent a human player profile.
    /// </summary>
    public class HumanPlayerProfile : PlayerProfile
    {

        #region Variables

        // Selection rectangle
        public Vector2 selectionPosition;
        public Color selectionColor = Color.Green;
        public Texture2D selectionRectangle;

        // Movement variables
        public Vector2 selectedMovementPosition;
        public CombatUnit selectedCombatUnit;
        public bool movementAllowed = true;

        // Networking variables
        public byte indexOfSelectedCombatUnit;
        public bool isShooting = false;
        public bool isMoving = false;

        // Input states for different input devices.
        KeyboardState lastKeyboardState;
        GamePadState lastGamePadState;
        MouseState lastMouseState;
        KeyboardState currentKeyboardState;
        GamePadState currentGamePadState;
        MouseState currentMouseState;

        #endregion

        #region Constructors

        /// <summary>
        /// Create a new human player profile
        /// </summary>
        /// <param name="playerId"></param>
        /// <param name="playerName"></param>
        /// <param name="hasTurn"></param>
        /// <param name="team"></param>
        public HumanPlayerProfile(int playerId, String playerName, bool hasTurn, Team team, ContentManager content)
            : base(playerId, playerName, hasTurn, team)
        {
            // Load the selection image.
            this.selectionRectangle = content.Load<Texture2D>("Textures/selectionRectangle");

            // Set selected combat unit
            this.selectedCombatUnit = null;

            // Set the startposition.
            this.selectionPosition = new Vector2(3, 2);
        }

        #endregion

        #region Methods

        /// <summary>
        /// Human player movement on the board.
        /// </summary>
        /// <param name="playerIndex"></param>
        /// <param name="currentMap"></param>
        public override bool PlayerMovementOnBoard(PlayerIndex playerIndex, Map currentMap, PlayerProfile otherPlayer)
        {
            // Set previous keyboard and gamepad states
            this.lastKeyboardState = this.currentKeyboardState;
            this.lastGamePadState = this.currentGamePadState;
            this.lastMouseState = this.currentMouseState;
            this.currentKeyboardState = Keyboard.GetState();
            this.currentGamePadState = GamePad.GetState(playerIndex);
            this.currentMouseState = Mouse.GetState();

            // Boolean to mark if a combat unit has moved to a new position
            bool movedToNewPosition = false;

            // Make a selection of a combat unit or make a movement for a combat unit.
            if (this.currentMouseState.LeftButton == ButtonState.Pressed && this.lastMouseState.LeftButton == ButtonState.Released ||
                currentGamePadState.IsButtonDown(Buttons.A) && lastGamePadState.IsButtonUp(Buttons.A))
            {

                // Check if a combat unit is selected
                if (this.selectedCombatUnit == null)
                {
                    // Loop through each combat unit.
                    for (int i = 0; i < this.team.combatUnits.Count; i++)
                    {
                        // If there is a intersection between selection rectangle and the collision rectangle for the combat unit, 
                        // set the selection position and the selected combat unit.
                        if (this.team.combatUnits[i].boardCollisionRectangle.Intersects(currentMap.GetMapRectangle(this.selectionPosition)))
                        {
                            // Set the selection.
                            this.selectedMovementPosition = this.selectionPosition;
                            this.selectedCombatUnit = this.team.combatUnits[i];
                            this.indexOfSelectedCombatUnit = (byte)i;

                            // Break out from the loop.
                            break;
                        }
                    }

                } // End of selection of combat unit.
                // Move a combat unit to a new position.
                else if (this.selectedCombatUnit != null)
                {
                    // Set the flag that movement is allowed.
                    this.movementAllowed = true;

                    // Check for a collision with my own combat units
                    foreach (CombatUnit combatUnit in this.team.combatUnits)
                    {
                        if (combatUnit.boardCollisionRectangle.Intersects(currentMap.GetMapRectangle(this.selectionPosition)))
                        {
                            // You can not move here.
                            this.movementAllowed = false;
                            this.selectedCombatUnit = null;
                        }
                    }

                    // Check for a movement restriction.
                    if (this.movementAllowed == true)
                    {
                        if (this.selectionPosition.Y < (this.selectedMovementPosition.Y - this.selectedCombatUnit.movementRestriction.Y) ||
                            this.selectionPosition.Y > (this.selectedMovementPosition.Y + this.selectedCombatUnit.movementRestriction.Y) ||
                            this.selectionPosition.X < (this.selectedMovementPosition.X - this.selectedCombatUnit.movementRestriction.X) ||
                            this.selectionPosition.X > (this.selectedMovementPosition.X + this.selectedCombatUnit.movementRestriction.X))
                        {
                            // You can not move here.
                            this.movementAllowed = false;
                            this.selectedCombatUnit = null;
                        }
                    }

                    // Check if the movement is allowed.
                    if (this.movementAllowed == true)
                    {
                        // Move the combat unit to the new location
                        this.selectedCombatUnit.currentPosition = this.selectionPosition;

                        // Reset the selection of combat unit to null.
                        this.selectedCombatUnit = null;

                        // The combat unit has moved to a new position
                        movedToNewPosition = true;

                        // Change the turn, give the other player the right to move.
                        this.hasTurn = false;
                        otherPlayer.hasTurn = true;
                    }
                }
            }

            // Move up, down, left and right.
            if (currentKeyboardState.IsKeyDown(Keys.W) && lastKeyboardState.IsKeyUp(Keys.W) ||
                currentGamePadState.ThumbSticks.Left.Y > 0.25f && lastGamePadState.ThumbSticks.Left.Y < 0.25f ||
                currentGamePadState.IsButtonDown(Buttons.DPadUp) && lastGamePadState.IsButtonUp(Buttons.DPadUp))
            {

                // Change the selection position.
                this.selectionPosition.Y--;

            }
            if (currentKeyboardState.IsKeyDown(Keys.S) && lastKeyboardState.IsKeyUp(Keys.S) ||
                currentGamePadState.ThumbSticks.Left.Y < -0.25f && lastGamePadState.ThumbSticks.Left.Y > -0.25f ||
                currentGamePadState.IsButtonDown(Buttons.DPadDown) && lastGamePadState.IsButtonUp(Buttons.DPadDown))
            {

                // Change the selection position.
                this.selectionPosition.Y++;

            }
            if (currentKeyboardState.IsKeyDown(Keys.A) && lastKeyboardState.IsKeyUp(Keys.A) ||
                currentGamePadState.ThumbSticks.Left.X < -0.25f && lastGamePadState.ThumbSticks.Left.X > -0.25f ||
                currentGamePadState.IsButtonDown(Buttons.DPadLeft) && lastGamePadState.IsButtonUp(Buttons.DPadLeft))
            {

                // Change the selection position.
                this.selectionPosition.X--;

            }
            if (currentKeyboardState.IsKeyDown(Keys.D) && lastKeyboardState.IsKeyUp(Keys.D) ||
                currentGamePadState.ThumbSticks.Left.X > 0.25f && lastGamePadState.ThumbSticks.Left.X < 0.25f ||
                currentGamePadState.IsButtonDown(Buttons.DPadRight) && lastGamePadState.IsButtonUp(Buttons.DPadRight))
            {

                // Change the selection position.
                this.selectionPosition.X++;
   
            }

            // Set the color on the selection rectangle.
            if (this.selectedCombatUnit != null)
            {
                // Set the selection color to green.
                this.selectionColor = Color.Green;

                // Check for a collision with my own combat units
                foreach (CombatUnit combatUnit in this.team.combatUnits)
                {
                    if (combatUnit.boardCollisionRectangle.Intersects(currentMap.GetMapRectangle(this.selectionPosition)))
                    {
                        // You can not move here.
                        this.selectionColor = Color.Red;
                    }
                }

                if (this.selectionPosition.Y < (this.selectedMovementPosition.Y - this.selectedCombatUnit.movementRestriction.Y) ||
                    this.selectionPosition.Y > (this.selectedMovementPosition.Y + this.selectedCombatUnit.movementRestriction.Y) ||
                    this.selectionPosition.X < (this.selectedMovementPosition.X - this.selectedCombatUnit.movementRestriction.X) ||
                    this.selectionPosition.X > (this.selectedMovementPosition.X + this.selectedCombatUnit.movementRestriction.X))
                {
                    // You can not move here.
                    this.selectionColor = Color.Red;
                }
            }

            // Check if the selectionPosition is outside of the map, make adjustments if the position is outside the map.
            if (this.selectionPosition.X < 0)
                this.selectionPosition.X++;
            if (this.selectionPosition.X >= currentMap.numberOfxTiles)
                this.selectionPosition.X--;
            if (this.selectionPosition.Y < 0)
                this.selectionPosition.Y++;
            if (this.selectionPosition.Y >= currentMap.numberOfyTiles)
                this.selectionPosition.Y--;

            // Return the boolean
            return movedToNewPosition;

        } // End of the PlayerMovementOnBoard method

        /// <summary>
        /// Handles player movement in a combat.
        /// </summary>
        /// <param name="playerIndex"></param>
        /// <param name="currentCombatScene"></param>
        public override void PlayerMovementInCombat(Viewport viewPort, PlayerIndex playerIndex, PlayerProfile otherPlayer, CombatScene currentCombatScene)
        {
            this.lastKeyboardState = this.currentKeyboardState;
            this.lastGamePadState = this.currentGamePadState;
            this.currentKeyboardState = Keyboard.GetState();
            this.currentGamePadState = GamePad.GetState(playerIndex);
            this.currentMouseState = Mouse.GetState();

            // Is the player moving.
            bool isPlayerMoving = false;

            // Move up, down, left and right.
            if (currentKeyboardState.IsKeyDown(Keys.W) || currentGamePadState.ThumbSticks.Left.Y > 0.25f ||
                currentGamePadState.IsButtonDown(Buttons.DPadUp))
            {

                // Change the combat position.
                if (this.combatUnitInCombat is LeftPlane || this.combatUnitInCombat is RightPlane)
                {
                    if (isPlayerMoving == false)
                    {
                        this.combatUnitInCombat.combatPosition += this.combatUnitInCombat.combatDirection * this.combatUnitInCombat.movementSpeed;

                        // The combat unit is moving.
                        isPlayerMoving = true;
                    }
                }
                else
                {
                    this.combatUnitInCombat.combatPosition.Y -= this.combatUnitInCombat.movementSpeed;

                    // The combat unit is moving.
                    isPlayerMoving = true;
                }

            }
            if (currentKeyboardState.IsKeyDown(Keys.S) || currentGamePadState.ThumbSticks.Left.Y < -0.25f ||
                currentGamePadState.IsButtonDown(Buttons.DPadDown))
            {
                // Change the combat position.
                if (this.combatUnitInCombat is LeftPlane || this.combatUnitInCombat is RightPlane)
                {
                    if (isPlayerMoving == false)
                    {
                        this.combatUnitInCombat.combatPosition += this.combatUnitInCombat.combatDirection * this.combatUnitInCombat.movementSpeed;

                        // The combat unit is moving.
                        isPlayerMoving = true;
                    }

                }
                else
                {
                    this.combatUnitInCombat.combatPosition.Y += this.combatUnitInCombat.movementSpeed;
                    
                    // The combat unit is moving.
                    isPlayerMoving = true;
                }

            }
            if (currentKeyboardState.IsKeyDown(Keys.A) || currentGamePadState.ThumbSticks.Left.X < -0.25f ||
                currentGamePadState.IsButtonDown(Buttons.DPadLeft))
            {

                // Change the combat position.
                if (this.combatUnitInCombat is LeftPlane || this.combatUnitInCombat is RightPlane)
                {
                    if (isPlayerMoving == false)
                    {
                        this.combatUnitInCombat.combatPosition += this.combatUnitInCombat.combatDirection * this.combatUnitInCombat.movementSpeed;

                        // The combat unit is moving.
                        isPlayerMoving = true;
                    }
                }
                else
                {
                    this.combatUnitInCombat.combatPosition.X -= this.combatUnitInCombat.movementSpeed;

                    // The combat unit is moving.
                    isPlayerMoving = true;
                }

                // Change the combat position.
                //this.combatUnitInCombat.combatPosition += Vector2.Transform(this.combatUnitInCombat.combatDirection, 
                //Matrix.CreateRotationZ(MathHelper.ToRadians(270))) * this.combatUnitInCombat.movementSpeed;

            }
            if (currentKeyboardState.IsKeyDown(Keys.D) || currentGamePadState.ThumbSticks.Left.X > 0.25f ||
                currentGamePadState.IsButtonDown(Buttons.DPadRight))
            {

                // Change the combat position.
                if (this.combatUnitInCombat is LeftPlane || this.combatUnitInCombat is RightPlane)
                {
                    if (isPlayerMoving == false)
                    {
                        this.combatUnitInCombat.combatPosition += this.combatUnitInCombat.combatDirection * this.combatUnitInCombat.movementSpeed;

                        // The combat unit is moving.
                        isPlayerMoving = true;
                    }
                }
                else
                {
                    this.combatUnitInCombat.combatPosition.X += this.combatUnitInCombat.movementSpeed;

                    // The combat unit is moving.
                    isPlayerMoving = true;
                }

                // Change the combat position.
                //this.combatUnitInCombat.combatPosition += Vector2.Transform(this.combatUnitInCombat.combatDirection, 
                // Matrix.CreateRotationZ(MathHelper.ToRadians(90))) * this.combatUnitInCombat.movementSpeed;
  
            }

            // Check if we should play a movement sound.
            if (this.combatUnitInCombat.movementDelayCounter <= 0)
            {
                // Play movement sound.
                if (isPlayerMoving == true)
                {
                    this.combatUnitInCombat.PlayMovementSound();
                    this.combatUnitInCombat.movementDelayCounter = this.combatUnitInCombat.movementDelay;
                    this.isMoving = true;
                }
                else
                {
                    this.isMoving = false;
                }
            }
            else
            {
                this.combatUnitInCombat.movementDelayCounter--;
            }

            // Check if the player is outside of the combat scene, make adjustments if that is the case.
            if (this.combatUnitInCombat.combatPosition.X - (this.combatUnitInCombat.frameSizeCombat.X / 2) < currentCombatScene.combatSceneRectangle.Left)
                this.combatUnitInCombat.combatPosition.X = currentCombatScene.combatSceneRectangle.Left + (this.combatUnitInCombat.frameSizeCombat.X / 2);
            if (this.combatUnitInCombat.combatPosition.X + (this.combatUnitInCombat.frameSizeCombat.X / 2) >
                currentCombatScene.combatSceneRectangle.Right)
                this.combatUnitInCombat.combatPosition.X = currentCombatScene.combatSceneRectangle.Right - (this.combatUnitInCombat.frameSizeCombat.X / 2);
            if (this.combatUnitInCombat.combatPosition.Y - (this.combatUnitInCombat.frameSizeCombat.Y / 2) < currentCombatScene.combatSceneRectangle.Top)
                this.combatUnitInCombat.combatPosition.Y = currentCombatScene.combatSceneRectangle.Top + (this.combatUnitInCombat.frameSizeCombat.Y / 2);
            if (this.combatUnitInCombat.combatPosition.Y + (this.combatUnitInCombat.frameSizeCombat.Y / 2) >
                currentCombatScene.combatSceneRectangle.Bottom)
                this.combatUnitInCombat.combatPosition.Y = currentCombatScene.combatSceneRectangle.Bottom - (this.combatUnitInCombat.frameSizeCombat.Y / 2);

            // No movement restrictions for planes.
            if (!(this.combatUnitInCombat is LeftPlane || this.combatUnitInCombat is RightPlane))
            {

                // Check if there is a collision with a barrier.
                foreach (Rectangle rectangle in currentCombatScene.barriers)
                {
                    if (this.combatUnitInCombat.combatCollisionRectangle.Intersects(rectangle))
                    {
                        // Check if the collision is with the left, right, top or bottom side of the rectangle.
                        if (this.combatUnitInCombat.combatPosition.X < rectangle.Left)
                        {
                            this.combatUnitInCombat.combatPosition.X = rectangle.Left - (this.combatUnitInCombat.frameSizeCombat.X / 2);
                        }
                        if (this.combatUnitInCombat.combatPosition.X > rectangle.Right)
                        {
                            this.combatUnitInCombat.combatPosition.X = rectangle.Right + (this.combatUnitInCombat.frameSizeCombat.X / 2);
                        }
                        if (this.combatUnitInCombat.combatPosition.Y < rectangle.Top)
                        {
                            this.combatUnitInCombat.combatPosition.Y = rectangle.Top - (this.combatUnitInCombat.frameSizeCombat.X / 2);
                        }
                        if (this.combatUnitInCombat.combatPosition.Y > rectangle.Bottom)
                        {
                            this.combatUnitInCombat.combatPosition.Y = rectangle.Bottom + (this.combatUnitInCombat.frameSizeCombat.X / 2);
                        }

                        // Break out from the loop
                        break;
                    }
                }

            } // End of if not a plane.

#if (!XBOX360)
            // Check if the combat unit not is shooting
            if (this.currentKeyboardState.IsKeyUp(Keys.Space))
            {
                this.isShooting = false;
            }
#endif
#if XBOX360
            // Check if the combat unit not is shooting
            if (currentGamePadState.IsButtonUp(Buttons.RightTrigger))
            {
                this.isShooting = false;
            }
#endif

            if (this.combatUnitInCombat.combatDirection == Vector2.Zero)
                this.combatUnitInCombat.combatDirection = this.combatUnitInCombat.startDirectionVector;

            // Rotate the combat unit
            Vector2 directionVector = Vector2.Zero;
              
#if (!XBOX360)
            // Rotate on a pc.
            if (currentKeyboardState.IsKeyDown(Keys.D))
                directionVector.X += 1;
            if (currentKeyboardState.IsKeyDown(Keys.A))
                directionVector.X += -1;
            if (currentKeyboardState.IsKeyDown(Keys.W))
                directionVector.Y += -1;
            if (currentKeyboardState.IsKeyDown(Keys.S))
                directionVector.Y += 1;

            if (directionVector != Vector2.Zero)
            {
                directionVector.Normalize();
                this.combatUnitInCombat.combatDirection = directionVector;
            }
#endif

#if XBOX360
            // Rotate on Xbox
            if (currentGamePadState.ThumbSticks.Right.X > 0.25f || currentGamePadState.ThumbSticks.Right.X < -0.25f)
                directionVector.X += currentGamePadState.ThumbSticks.Right.X;
            if (currentGamePadState.ThumbSticks.Right.Y > 0.25f || currentGamePadState.ThumbSticks.Right.Y < -0.25f)
                directionVector.Y -= currentGamePadState.ThumbSticks.Right.Y;

            if (directionVector != Vector2.Zero)
            {
                directionVector.Normalize();
                this.combatUnitInCombat.combatDirection = directionVector;
            }
#endif

            // Set the rotation for the combat unit
            if (directionVector != Vector2.Zero)
            {
                float perpDot = (this.combatUnitInCombat.startDirectionVector.X * directionVector.Y) - (this.combatUnitInCombat.startDirectionVector.Y * directionVector.X);
                this.combatUnitInCombat.rotation = (float)Math.Atan2(perpDot, Vector2.Dot(this.combatUnitInCombat.startDirectionVector, directionVector));
            }

#if (!XBOX360)
            // Check if we should add a shot.
            if (this.combatUnitInCombat.shotDelayCounter <= 0)
            {
                if (this.currentKeyboardState.IsKeyDown(Keys.Space))
                {
                    this.combatUnitInCombat.AddShot();
                    this.isShooting = true;
                    this.combatUnitInCombat.shotDelayCounter = this.combatUnitInCombat.shotDelay;
                    this.combatUnitInCombat.PlayShootingSound();
                }
            }
            else
            {
                this.combatUnitInCombat.shotDelayCounter--;
            }
            
#endif
#if XBOX360
            // Check if we should add a shot.
            if (this.combatUnitInCombat.shotDelayCounter <= 0)
            {
                if (currentGamePadState.IsButtonDown(Buttons.RightTrigger))
                {
                    this.combatUnitInCombat.AddShot();
                    this.isShooting = true;
                    this.combatUnitInCombat.shotDelayCounter = this.combatUnitInCombat.shotDelay;
                    this.combatUnitInCombat.PlayShootingSound();
                }
            }
            else
            {
                this.combatUnitInCombat.shotDelayCounter--;
            }
#endif


            //#if (!XBOX360)
//            this.combatUnitInCombat.rotation += (this.currentMouseState.X - this.lastMouseState.X) * this.combatUnitInCombat.rotationSpeedPc;
//#endif
//#if XBOX360
//            this.combatUnitInCombat.rotation += (this.currentGamePadState.ThumbSticks.Right.X) * this.combatUnitInCombat.rotationSpeedXbox;
//#endif

            //this.combatUnitInCombat.combatDirection = Vector2.Transform(this.combatUnitInCombat.startDirectionVector, Matrix.CreateRotationZ(this.combatUnitInCombat.rotation));

            // Reset the mouse to the middle of the screen
            Mouse.SetPosition(viewPort.Width / 2, viewPort.Height / 2);

            this.lastMouseState = Mouse.GetState();
            
        } // End of PlayerMovementInCombat method.

        /// <summary>
        /// Draw the human player profile on the board.
        /// </summary>
        /// <param name="spriteBatch"></param>
        /// <param name="currentMap"></param>
        public override void DrawOnBoard(SpriteBatch spriteBatch, SpriteFont font, Map currentMap)
        {
            // Draw the team on the board
            this.team.DrawTeamOnBoard(spriteBatch);

            // Draw the selection rectangle
            if (this.hasTurn == true)
            {
                if (this.selectedCombatUnit != null)
                {
                    spriteBatch.Draw(this.selectionRectangle, currentMap.GetMapRectangle(this.selectionPosition), this.selectionColor);
                }
                else
                {
                    spriteBatch.Draw(this.selectionRectangle, currentMap.GetMapRectangle(this.selectionPosition), Color.White);
                }     
            }

            // Draw a message if a movement not is allowed.
            if (this.movementAllowed == false)
            {
                // Variables
                Vector2 textPosition = new Vector2(currentMap.xOffset, currentMap.yOffset + currentMap.numberOfyTiles * currentMap.tileSize);
                String message = "You are not allowed to move to that tile, try again :).";

                spriteBatch.DrawString(font, message, textPosition + new Vector2(1, 1), Color.DarkGray, 0, Vector2.Zero, 1.1f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, message, textPosition, Color.White, 0, Vector2.Zero, 1.1f, SpriteEffects.None, 0);
            }

        } // End of the DrawOnBoard method

        #endregion

    } // End of class

} // End of namespace
