using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;

namespace MegaManRipoff.MainGameClasses
{
    /// <summary>
    /// A bird that swoops in, drops its giant egg and flies away. An 
    /// unparalleled example of good parenting.
    /// </summary>
    class PipiBird : Enemy
    {
        #region Member Variables

        /// <summary>
        /// The texture for Pipi birds.
        /// </summary>
        static Texture2D _texture;

        /// <summary>
        /// The Pipi bird's maximum health.
        /// </summary>
        static int _maxHealth;

        /// <summary>
        /// The amount of damage Pipi birds deal.
        /// </summary>
        static int _damage;

        /// <summary>
        /// Holds all possible states for the Pipi bird.
        /// </summary>
        enum State
        {
            Waiting, FlyingIn, FlyingOut
        }

        /// <summary>
        /// The Pipi bird's current state.
        /// </summary>
        State _currentState;

        /// <summary>
        /// The Pipi bird's set of animations.
        /// </summary>
        Dictionary<State, Animation> _animationSet;

        /// <summary>
        /// The speed vector to use when first flying in.
        /// </summary>
        static Vector2 _flyingInSpeed;

        /// <summary>
        /// The Pipi bird's acceleration vector.
        /// </summary>
        static Vector2 _accel;

        /// <summary>
        /// The sound effect used when flying in.
        /// </summary>
        static SoundEffect _descendSound;

        #endregion

        #region Properites

        /// <summary>
        /// Gets the amount of damage Pipi eggs do.
        /// </summary>
        public override int Damage
        {
            get { return _damage; }
        }

        /// <summary>
        /// The Pipi bird's hitbox.
        /// </summary>
        public override Rectangle Hitbox
        {
            get
            {
                if (_currentState == State.FlyingOut)
                    return new Rectangle((int)_position.X - 15, (int)_position.Y - 16, 18, 22);
                else
                    return new Rectangle((int)_position.X - 17, (int)_position.Y - 16, 35, 52);
            }
        }

        #endregion

        /// <summary>
        /// Creates a new Pipi bird.
        /// </summary>
        /// <param name="room">The current room.</param>
        /// <param name="position">The position to create the Pipi bird at.</param>
        /// <param name="direction">The direction of the Pipi bird.</param>
        public PipiBird(Room room, Vector2 position, Direction direction)
            : base(room, position)
        {
            _direction = direction;

            _health = _maxHealth;
        }

        #region Methods

        /// <summary>
        /// Initialises fields for the Pipi bird, dependent on the game's difficulty.
        /// </summary>
        /// <param name="gameDifficulty">The game's difficulty setting.</param>
        new public static void Initialise(GameDifficulty gameDifficulty)
        {
            switch (gameDifficulty)
            {
                case GameDifficulty.Easy:
                    _flyingInSpeed = new Vector2(2.8f, 3.2f);
                    _accel = new Vector2(0, -0.075f);
                    break;
                case GameDifficulty.Hard:
                    _flyingInSpeed = new Vector2(5.2f, 4.7f);
                    _accel = new Vector2(0, -0.2f);
                    break;
                default:
                    _flyingInSpeed = new Vector2(4.8f, 4.2f);
                    _accel = new Vector2(0, -0.18f);
                    break;
            }
            _maxHealth = 1;
            _damage = 2;
        }

        /// <summary>
        /// Initialises all animations for the Pipi bird.
        /// </summary>
        protected override void InitialiseAnimations()
        {
            _animationSet = new Dictionary<State, Animation>();

            //Flying in.
            Animation flyingIn = new Animation(new Tuple<Rectangle, Vector2, int>(
                new Rectangle(0, 0, 43, 52), new Vector2(-17, -16), 3), 0);
            flyingIn.AddFrame(new Tuple<Rectangle, Vector2, int>(
                new Rectangle(43, 0, 43, 52), new Vector2(-17, -16), 3));
            flyingIn.AddFrame(new Tuple<Rectangle, Vector2, int>(
                new Rectangle(86, 0, 43, 52), new Vector2(-17, -16), 3));
            _animationSet.Add(State.FlyingIn, flyingIn);

            //Waiting (also laziness).
            _animationSet.Add(State.Waiting, flyingIn);

            //Flying out.
            Animation flyingOut = new Animation(new Tuple<Rectangle, Vector2, int>(
                new Rectangle(127, 0, 35, 32), new Vector2(-17, -16), 3), 3);
            flyingOut.AddFrame(new Tuple<Rectangle, Vector2, int>(
                new Rectangle(170, 0, 43, 32), new Vector2(-17, -16), 3));
            flyingOut.AddFrame(new Tuple<Rectangle, Vector2, int>(
                new Rectangle(213, 0, 38, 32), new Vector2(-17, -16), 3));
            flyingOut.AddFrame(new Tuple<Rectangle, Vector2, int>(
                new Rectangle(258, 0, 44, 22), new Vector2(-19, -16), 3));
            flyingOut.AddFrame(new Tuple<Rectangle, Vector2, int>(
                new Rectangle(302, 0, 46, 22), new Vector2(-19, -16), 3));
            flyingOut.AddFrame(new Tuple<Rectangle, Vector2, int>(
                new Rectangle(348, 0, 44, 22), new Vector2(-19, -16), 3));
            _animationSet.Add(State.FlyingOut, flyingOut);
        }

        /// <summary>
        /// Loads the assets for the Pipi birds.
        /// </summary>
        /// <param name="content">The game's content manager.</param>
        new public static void LoadContent(ContentManager content)
        {
            _texture = content.Load<Texture2D>("Images\\PipiBird");

            _descendSound = content.Load<SoundEffect>("Sounds\\Descend");
        }

        /// <summary>
        /// Changes the Pipi bird's state as necessary.
        /// </summary>
        private void UpdateState()
        {
            //If we're waiting but we're now in the camera's view, begin
            //flying down.
            if (_currentState == State.Waiting && _room.Camera.IsInView(Hitbox))
            {
                _speed = _flyingInSpeed;
                _currentState = State.FlyingIn;

                //Play the sound effect.
                _descendSound.Play();
            }

            //If we're flying in but we're now moving upwards, drop the egg and
            //reset our state.
            if (_currentState == State.FlyingIn && _speed.Y <= 0)
            {
                _room.Add(new PipiEgg(_room, new Vector2(_position.X, _position.Y + 20), _direction));
                _currentState = State.FlyingOut;
            }

            //If we're flying out but we're now not in the camera's view, remove
            //this object from the room.
            if (_currentState == State.FlyingOut && !_room.Camera.IsInView(Hitbox))
            {
                _room.Remove(this);
            }
        }

        /// <summary>
        /// Updates the Pipi bird.
        /// </summary>
        /// <param name="gameTime">The current snapshot of time.</param>
        public override void Update(GameTime gameTime)
        {
            //Apply speed to position.
            _position.X += _speed.X * (int)_direction;
            _position.Y += _speed.Y;

            //Apply acceleration to speed, if we're not waiting.
            if (_currentState != State.Waiting)
            {
                _speed.X += _accel.X * (int)_direction;
                _speed.Y += _accel.Y;
            }

            //Update state.
            UpdateState();

            //Update animation and call the base class update method.
            _animationSet[_currentState].Update();
            base.Update(gameTime);
        }

        /// <summary>
        /// Draws the Pipi bird to the screen.
        /// </summary>
        /// <param name="spriteBatch">The sprite batch to draw to.</param>
        public override void Draw(SpriteBatch spriteBatch)
        {
            //Account for post-hit invincibility flashing.
            if ((_invincibiltyTimer / 2) % 2 == 0)
            {
                //Flip the sprite as needed.
                SpriteEffects directionEffects;

                if (_direction == Direction.Left)
                    directionEffects = SpriteEffects.None;
                else
                    directionEffects = SpriteEffects.FlipHorizontally;

                //Get the necessary details from the current animation frame.
                Rectangle currentFrameSource = _animationSet[_currentState].CurrentFrame.Item1;
                Vector2 currentFrameOffset = _animationSet[_currentState].CurrentFrame.Item2;

                spriteBatch.Draw(_texture,
                                 _position + currentFrameOffset,
                                 currentFrameSource,
                                 Color.White,
                                 0,
                                 Vector2.Zero,
                                 1,
                                 directionEffects,
                                 0);
            }
        }

        #endregion
    }
}
