using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MegaManRipoff.UI;

namespace MegaManRipoff.MainGameClasses
{
    /// <summary>
    /// Causes the screen to go dark whenever the player is inside the defined area.
    /// </summary>
    class DarkArea : Entity
    {
        #region Member Variables

        /// <summary>
        /// The effective area of this dark area.
        /// </summary>
        Rectangle _area;

        /// <summary>
        /// The states of the dark area.
        /// </summary>
        enum State
        {
            Light, Dark
        }

        /// <summary>
        /// The current state of this dark area.
        /// </summary>
        State _currentState;

        /// <summary>
        /// The sides of the area that the player could enter. None is used to signify that
        /// the player has not entered the area.
        /// </summary>
        enum EnteringSide
        {
            None, Left, Right
        }

        /// <summary>
        /// The side of the area that the player entered to cause the dark area to activate.
        /// </summary>
        EnteringSide _enteringSide;

        /// <summary>
        /// The alpha component of the colour that the screen is currently being tinted with.
        /// </summary>
        float _alpha;

        /// <summary>
        /// The amount that the alpha value increases when the lights are turning off.
        /// </summary>
        const float AlphaIncrease = 0.025f;

        /// <summary>
        /// The amount that the alpha value decreases when the lights are turning on.
        /// </summary>
        const float AlphaDecrease = -0.01f;

        #endregion

        /// <summary>
        /// Creates a new dark area.
        /// </summary>
        /// <param name="room">The current room.</param>
        /// <param name="area">The effective area.</param>
        public DarkArea(Room room, Rectangle area)
            : base(room, new Vector2(area.Left, area.Top))
        {
            _area = area;

            _currentState = State.Light;
            _enteringSide = EnteringSide.None;
            _alpha = 0;
        }

        #region Methods

        /// <summary>
        /// This method exists so that a NotImplementedException isn't thrown.
        /// </summary>
        protected override void InitialiseAnimations()
        {
            //Do nothing - the dark area doesn't have animations.
        }

        /// <summary>
        /// Updates collision with the player, and turns off or on the lights accordingly.
        /// </summary>
        private void CollideWithPlayer()
        {
            //Check that the player intersects first...
            if (_room.PlayerOne.Hitbox.Intersects(_area))
            {
                //If this is the player's first collision with the area, decide what side of
                //the area he is entering from and start dimming the screen.
                if (_enteringSide == EnteringSide.None)
                {
                    if (_room.PlayerOne.Position.X < _area.Center.X)
                        _enteringSide = EnteringSide.Left;
                    else
                        _enteringSide = EnteringSide.Right;

                    _currentState = State.Dark;
                }
            }
            //Otherwise, if the player does not intersect...
            else
            {
                //If the player is leaving the effective area from the opposite side to which
                //he entered, start lighting the screen.
                if ((_enteringSide == EnteringSide.Left && _room.PlayerOne.Position.X > _area.Center.X)
                    || (_enteringSide == EnteringSide.Right && _room.PlayerOne.Position.X < _area.Center.X))
                {
                    _currentState = State.Light;
                }
            }
        }

        /// <summary>
        /// Changes the colour to dim the screen depending on the current state.
        /// </summary>
        private void ChangeDimmingColour()
        {
            //If the lights aren't on but they should be, decrease the alpha.
            if (_currentState == State.Light && _alpha != 0)
            {
                _alpha = Math.Max(_alpha + AlphaDecrease, 0);
            }
            else
            {
                //...and similarly for if the lights are on but they shouldn't be.
                if (_currentState == State.Dark && _alpha != 1)
                {
                    _alpha = Math.Min(_alpha + AlphaIncrease, 1);
                }
            }

            //An additional check - if the lights are fully on and the entering side of the player
            //has been set, remove this entity - it cannot cause the lights to dim again.
            if (_currentState == State.Light && _alpha == 0 && _enteringSide != EnteringSide.None)
            {
                _room.Remove(this);
            }
        }

        /// <summary>
        /// Updates the dark area.
        /// </summary>
        /// <param name="gameTime">The current snapshot of time.</param>
        public override void Update(GameTime gameTime)
        {
            CollideWithPlayer();
            ChangeDimmingColour();
        }

        /// <summary>
        /// Draws the screen tint.
        /// </summary>
        /// <param name="spriteBatch">The sprite batch to draw to.</param>
        public override void Draw(SpriteBatch spriteBatch)
        {
            //Dim the screen.
            Texture2D dimmer = new Texture2D(spriteBatch.GraphicsDevice, 1, 1);
            dimmer.SetData(new Color[] { new Color(new Vector4(0, 0, 0, _alpha)) });
            spriteBatch.Draw(dimmer,
                             _room.Camera.Area,
                             Color.White);
        }

        #endregion
    }
}
