
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RecrownedAthenaeum.Render;
using System;

namespace RecrownedAthenaeum.ScreenSystem
{
    /// <summary>
    /// A screen specifically meant to fill in loading times.
    /// </summary>
    public class LoadingScreen : Screen, ITransition
    {
        private const float ENTER_TIME = 2f;
        private const float EXIT_TIME = 1f;
        Game game;
        readonly Texture2D texture;
        Color color;
        Rectangle textureBounds;
        readonly float proportion;
        bool recorded;
        float rR, rG, rB;
        float progR, progG, progB;
        float progC = 254;
        float rotation;
        readonly bool rotate;
        Vector2 origin;

        /// <summary>
        /// Constructs a loading screen.
        /// </summary>
        /// <param name="game">The game itself to adjust mouse settings and such.</param>
        /// <param name="screenImage"></param>
        /// <param name="proportion"></param>
        /// <param name="rotate"></param>
        public LoadingScreen(Game game, Texture2D screenImage, float proportion, bool rotate = false) : base(true)
        {
            this.game = game;
            this.texture = screenImage;
            this.proportion = proportion;
            this.rotate = rotate;
            Transitions.Add(this);
        }

        /// <inheritdoc />
        public override void Show()
        {
            game.IsMouseVisible = false;
            base.Show();
        }

        /// <inheritdoc />
        public override void Hide()
        {
            game.IsMouseVisible = true;
            base.Hide();
        }

        /// <summary>
        /// Sets things to correct values for start of transition.
        /// </summary>
        /// <param name="dimensions">The window dimensions.</param>
        public void InitiateTransition(Rectangle dimensions)
        {
            color = Color.White;
            textureBounds.Width = (int)(height * proportion);
            textureBounds.Height = (int)(height * proportion);
            textureBounds.X = (width) / 2;
            textureBounds.Y = (height) / 2;
            origin.X = texture.Width / 2f;
            origin.Y = texture.Height / 2f;
        }

        void DoRotate(float deltaf)
        {
            rotation += (2f / 3f) * (float)Math.PI * deltaf;
            if (rotation >= 2 * Math.PI)
            {
                rotation = 0;
            }
        }

        /// <summary>
        /// Draws the transition.
        /// </summary>
        /// <param name="spriteBatch">Batch to use.</param>
        public void DrawTransition(ConsistentSpriteBatch spriteBatch)
        {
            spriteBatch.Draw(texture, textureBounds, null, color, rotation, origin, SpriteEffects.None, 0f);
        }

        /// <summary>
        /// Updates the entering transition.
        /// </summary>
        /// <param name="delta">Time passed between frames.</param>
        /// <param name="waiting">Whether or not this transition should be waiting.</param>
        /// <returns>Whether or not transition is complete.</returns>
        public bool UpdateEnteringTransition(double delta, bool waiting)
        {
            float deltaf = (float)delta;
            if (rotate)
            {
                DoRotate(deltaf);
            }
            if (waiting)
            {
                if (progR < 254 || progG < 254 || progB < 254)
                {
                    if (!recorded)
                    {
                        rR = (Color.White.R - BackgroundColor.R) / ENTER_TIME;
                        rG = (Color.White.G - BackgroundColor.G) / ENTER_TIME;
                        rB = (Color.White.B - BackgroundColor.B) / ENTER_TIME;
                        recorded = true;
                    }
                    progR += rR * deltaf;
                    progR = Math.Min(progR, 254);
                    progG += rG * deltaf;
                    progG = Math.Min(progG, 254);
                    progB += rB * deltaf;
                    progB = Math.Min(progB, 254);
                    BackgroundColor.R = (byte)progR;
                    BackgroundColor.G = (byte)progG;
                    BackgroundColor.B = (byte)progB;
                }
                else
                {
                    StartExitTransition(true);
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Updates the exiting transition.
        /// </summary>
        /// <param name="delta">Time passed between frames.</param>
        /// <param name="waiting">Whether or not this transition should be waiting.</param>
        /// <returns>Whether or not transition is complete.</returns>
        public bool UpdateExitingTransition(double delta, bool waiting)
        {
            float deltaf = (float)delta;
            if (rotate)
            {
                DoRotate(deltaf);
            }
            if (progC > 0)
            {
                float rate = deltaf * 255 / EXIT_TIME;
                progC -= rate;
                progC = Math.Max(progC, 0);
                color.R = (byte)progC;
                color.G = (byte)progC;
                color.B = (byte)progC;
                color.A = (byte)progC;
            }
            else
            {
                return true;
            }
            return false;
        }

    }
}
