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

namespace StrategicCombat.CombatUnits
{
    
    /// <summary>
    /// This class represent a combat unit.
    /// </summary>
    public abstract class CombatUnit
    {
        #region Variables

        // Movement variables.
        public Vector2 currentPosition;
        public Vector2 movementRestriction;
        public Point combatHealthBarPosition;
        public Vector2 combatStartPosition;
        public Vector2 combatPosition;
        public Vector2 startDirectionVector;
        public Vector2 combatDirection;
        public float movementSpeed;

        // Rectangle
        public Rectangle boardCollisionRectangle;
        public Rectangle combatCollisionRectangle;

        // Textures
        public Texture2D boardUnitTexture;
        public Texture2D combatUnitTexture;
        public Point frameSizeBoard;
        public Point frameSizeCombat;
        public Texture2D healthBarTexture;
        public Texture2D shotTexture;

        // Exploding shot texture
        public Texture2D explodingShotTexture;

        // Texture rotation
        public float rotation;

        // Shots
        public List<Shot> shots;
        public float shotSpeed;
        public float healthDamage;
        public float shotDelay;
        public float shotDelayCounter;

        // Movement sound.
        public int movementDelay;
        public int movementDelayCounter;

        // Health
        public int health;

        // PowerUps
        public List<PowerUp> powerUps;

        // Rotationspeed
        public float rotationSpeedPc = 0.005f;
        public float rotationSpeedXbox = 0.05f;

        #endregion

        #region Constructors

        /// <summary>
        /// Create a new combat unit.
        /// </summary>
        public CombatUnit(ContentManager content, Vector2 position)
        {
            // Load the healthbar texture
            this.healthBarTexture = content.Load<Texture2D>("Textures/whiteTile");

            // Load the exploding shot texture.
            this.explodingShotTexture = content.Load<Texture2D>("Textures/flame256");

            // Set the position.
            this.currentPosition = position;

            // Set the frame size.
            this.frameSizeBoard = new Point(75, 75);
            this.frameSizeCombat = new Point(50, 50);

            // Create the list with shots.
            this.shots = new List<Shot>(200);

            // Create a new list of power ups.
            this.powerUps = new List<PowerUp>(10);

        }

        #endregion

        #region Methods

        /// <summary>
        /// Add a shot to the list of shots.
        /// </summary>
        public abstract void AddShot();

        /// <summary>
        /// Play a movement sound.
        /// </summary>
        public abstract void PlayMovementSound();

        /// <summary>
        /// Play a shooting sound.
        /// </summary>
        public abstract void PlayShootingSound();

        /// <summary>
        /// Update the combat unit on the board.
        /// </summary>
        /// <param name="currentMap"></param>
        public void UpdateOnBoard(Map currentMap)
        {

            // Update the collision rectangle
            this.boardCollisionRectangle = new Rectangle(currentMap.xOffset + (int)this.currentPosition.X * this.frameSizeBoard.X,
                           currentMap.yOffset + (int)this.currentPosition.Y * this.frameSizeBoard.Y, this.frameSizeBoard.X, this.frameSizeBoard.Y);

        } // End of the UpdateOnBoard method.

        /// <summary>
        /// Update the combat unit in a combat.
        /// </summary>
        /// <param name="gameTime"></param>
        /// <param name="combatScene"></param>
        public void UpdateInCombat(GameTime gameTime, CombatScene combatScene)
        {

            // Update the collision rectangle for a combat
            this.combatCollisionRectangle = new Rectangle((int)(this.combatPosition.X - (this.frameSizeCombat.Y / 2)),
                           (int)(this.combatPosition.Y - (this.frameSizeCombat.Y / 2)), this.frameSizeCombat.X, this.frameSizeCombat.Y);

            // Update shots.
            for (int i = 0; i < this.shots.Count; i++)
            {
                // Update shot position.
                this.shots[i].UpdateShot(gameTime);

                // A flag to mark if a shot has been removed.
                bool shotHasBeenRemoved = false;

                // Remove shots that are outside of the combat area.
                if (this.shots[i].shotPosition.X < combatScene.combatSceneRectangle.Left || this.shots[i].shotPosition.X > combatScene.combatSceneRectangle.Right ||
                this.shots[i].shotPosition.Y < combatScene.combatSceneRectangle.Top || this.shots[i].shotPosition.Y > combatScene.combatSceneRectangle.Bottom)
                {

                    if (this.shots[i].isBouncing == true)
                    {
                        if (this.shots[i].shotPosition.X < combatScene.combatSceneRectangle.Left || this.shots[i].shotPosition.X > combatScene.combatSceneRectangle.Right)
                            this.shots[i].shotDirection.X *= -1;
                        if (this.shots[i].shotPosition.Y < combatScene.combatSceneRectangle.Top || this.shots[i].shotPosition.Y > combatScene.combatSceneRectangle.Bottom)
                            this.shots[i].shotDirection.Y *= -1;

                    }
                    else if (this.shots[i].isExploding == true)
                    {
                        // Stop the bullet
                        this.shots[i].shotDirection = new Vector2(0, 0);

                        // Set the shot duration to 30
                        if (this.shots[i].shotDuration > 30)
                        {
                            this.shots[i].shotDuration = 30;
                        }
                    }
                    else
                    {
                        if (!(this is RightBazooka))
                        {
                            this.shots.RemoveAt(i);
                            shotHasBeenRemoved = true;
                        }
                    }
                }
                else
                {
                    // Check to remove shots caused by a collision.
                    if (!(this is RightPlane || this is LeftFlameThrower))
                    {
                        // Check for a collision with a barrier.
                        foreach (Rectangle rectangle in combatScene.barriers)
                        {
                            if (this.shots[i].shotCollisionRectangle.Intersects(rectangle))
                            {
                                if (this.shots[i].isBouncing == true)
                                {
                                    bool hasBounced = false;

                                    // Make the bullet bounce.
                                    if (this.shots[i].shotPosition.Y < rectangle.Top || this.shots[i].shotPosition.Y > rectangle.Bottom)
                                    {
                                        this.shots[i].shotDirection.Y *= -1;
                                        hasBounced = true;
                                    }
                                    else if (this.shots[i].shotPosition.X < rectangle.Left || this.shots[i].shotPosition.X > rectangle.Right)
                                    {
                                        this.shots[i].shotDirection.X *= -1;
                                        hasBounced = true;
                                    }

                                    // Remove a shot that not have bounced.
                                    if(hasBounced == false)
                                    {
                                        this.shots.RemoveAt(i);
                                        shotHasBeenRemoved = true;
                                    }

                                    // Break out from the loop
                                    break;
                                }
                                else if (this.shots[i].isExploding == true)
                                {
                                    // Stop the bullet
                                    this.shots[i].shotDirection = new Vector2(0, 0);

                                    // Set the shot duration to 30.
                                    if (this.shots[i].shotDuration > 30)
                                        this.shots[i].shotDuration = 30;
                                }
                                else
                                {
                                    if (!(this is RightBazooka))
                                    {
                                        this.shots.RemoveAt(i);
                                        shotHasBeenRemoved = true;
                                        break;
                                    }
                                }
                            }
                        }
                    }      
                }

                // Remove shots that have runned out from duration.
                if (shotHasBeenRemoved == false && this.shots[i].infiniteShotDuration == false)
                {
                    if (this.shots[i].shotDuration <= 0)
                    {
                        if (this.shots[i].isExploding == true)
                        {
                            // Add a shot for the explosion.
                            this.shots.Add(new Shot(this.shots[i].shotPosition, Vector2.Zero,
                                0, new Point(256, 256), false, 20, false, false));

                            Program.soundBank.PlayCue("bomberPlaneShot");

                            // Remove the old shot
                            this.shots.RemoveAt(i);
                        }
                        else
                        {
                            this.shots.RemoveAt(i);
                        }
                    }
                    else
                    {
                        this.shots[i].shotDuration--;
                    }
                }
            }

        } // End of the UpdateInCombat method.

        /// <summary>
        /// Draw the combat unit on the board
        /// </summary>
        /// <param name="spriteBatch"></param>
        /// <param name="boardRectangle"></param>
        public void DrawOnBoard(SpriteBatch spriteBatch)
        {
            // Draw the combat unit.
            spriteBatch.Draw(this.boardUnitTexture, this.boardCollisionRectangle, new Rectangle(0, 0,
                    frameSizeBoard.X, frameSizeBoard.Y), Color.White, 0, Vector2.Zero, SpriteEffects.None, 0);

        } // End of the DrawOnBoard method.

        /// <summary>
        /// Draw the combat unit in a combat.
        /// </summary>
        /// <param name="spriteBatch"></param>
        /// <param name="boardRectangle"></param>
        public void DrawInCombat(SpriteBatch spriteBatch)
        {

            // Draw shots.
            foreach (Shot shot in this.shots)
            {
                if(this is RightBazooka && shot.isExploding == false)
                    shot.DrawShot(spriteBatch, this.explodingShotTexture);
                else
                    shot.DrawShot(spriteBatch, this.shotTexture);
            }

            // Draw the combat unit.
            spriteBatch.Draw(this.combatUnitTexture, this.combatPosition, null, Color.White, this.rotation,
                new Vector2(this.frameSizeCombat.X / 2, this.frameSizeCombat.X / 2), 1f, SpriteEffects.None, 0);

            // Draw the healthbar.
            spriteBatch.Draw(this.healthBarTexture, new Rectangle(this.combatHealthBarPosition.X, this.combatHealthBarPosition.Y - this.health, 20, this.health), Color.Green);

        } // End of the DrawOnBoard method.

        #endregion

    } // End of class

} // End of namespace
