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.Graphics;
using MegaManRipoff.UI;

namespace MegaManRipoff.TitleScreenClasses
{
    /// <summary>
    /// Handles the display of the controls window.
    /// </summary>
    class ControlsWindow
    {
        #region Member Variables

        /// <summary>
        /// The position of the controls window.
        /// </summary>
        Vector2 _position;

        /// <summary>
        /// The texture used for the controls window.
        /// </summary>
        static Texture2D _texture;

        /// <summary>
        /// The texture used for the arrows that indicate
        /// another section of the window.
        /// </summary>
        static Texture2D _arrowTexture;

        /// <summary>
        /// The font used for the controls window heading.
        /// </summary>
        static SpriteFont _font;

        /// <summary>
        /// The states of the controls window.
        /// </summary>
        public enum State
        {
            Closed, Open
        }

        /// <summary>
        /// The current state of the control window.
        /// </summary>
        State _currentState;
        
        /// <summary>
        /// The pages that the controls window can display.
        /// </summary>
        enum Page : int
        {
            Story = 0,
            KeyboardControls = 1,
            GamepadControls = 2
        }

        /// <summary>
        /// The page the controls window is currently displaying.
        /// </summary>
        Page _page;

        /// <summary>
        /// The sound effect used when the page displayed is changed.
        /// </summary>
        static SoundEffect _selectionChangedSound;

        /// <summary>
        /// The sound effect used when the controls window is closed.
        /// </summary>
        static SoundEffect _closedSound;

        /// <summary>
        /// A timer used to make the arrow flash on and off.
        /// </summary>
        int _arrowFlashTimer;

        const int ArrowFlashDuration = 12;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the current state of the controls window.
        /// </summary>
        public State CurrentState
        {
            get { return _currentState; }
            set { _currentState = value; }
        }

        #endregion

        /// <summary>
        /// Creates a new controls window.
        /// </summary>
        public ControlsWindow()
        {
            _currentState = State.Closed;
            _page = Page.Story;
            _position = new Vector2(64, Camera.VIEWPORT_HEIGHT + 64);
        }

        #region Methods

        /// <summary>
        /// Loads the assets required by the controls window.
        /// </summary>
        /// <param name="content">The game's content manager.</param>
        public static void LoadContent(ContentManager content)
        {
            _texture = content.Load<Texture2D>("Images\\Controls");
            _arrowTexture = content.Load<Texture2D>("Images\\ControlsArrow");

            _font = content.Load<SpriteFont>("Fonts\\SegoeUI");

            _selectionChangedSound = content.Load<SoundEffect>("Sounds\\Select");
            _closedSound = content.Load<SoundEffect>("Sounds\\Selected");
        }

        /// <summary>
        /// Responds to the user's input.
        /// </summary>
        private void HandleInput()
        {
            //Handle moving to other pages.
            if (InputHelper.IsRightPressed() && (int)_page < 2)
            {
                _page++;
                _selectionChangedSound.Play();
            }
            else
            {
                if (InputHelper.IsLeftPressed() && (int)_page > 0)
                {
                    _page--;
                    _selectionChangedSound.Play();
                }
            }
            
            //If the select, back or start button is input, close this window.
            if (InputHelper.IsJumpPressed() || InputHelper.IsStartPressed()
                || InputHelper.IsShootPressed())
            {
                _currentState = State.Closed;
                _closedSound.Play();
            }
        }

        /// <summary>
        /// Moves the controls window to its proper position, depending on
        /// its current state.
        /// </summary>
        private void MoveToPosition()
        {
            switch (_currentState)
            {
                case State.Open:
                    _position.Y = MathHelper.SmoothStep(_position.Y, 32, 0.3f);
                    break;
                case State.Closed:
                    _position.Y = MathHelper.SmoothStep(_position.Y, Camera.VIEWPORT_HEIGHT + 64, 0.3f);
                    break;
            }
        }

        /// <summary>
        /// Updates the controls window.
        /// </summary>
        /// <param name="gameTime">The current snapshot of time.</param>
        public void Update(GameTime gameTime)
        {
            //If the window is open, accept user input.
            if (_currentState == State.Open)
                HandleInput();

            MoveToPosition();
        }

        /// <summary>
        /// Causes the arrow to flash on and off.
        /// </summary>
        /// <returns>Returns if the arrow is visible.</returns>
        private bool ArrowIsFlashing()
        {
            //Increase the timer.
            _arrowFlashTimer++;

            //Return a magic formula which determines if the arrow is flashing.
            return ((_arrowFlashTimer / ArrowFlashDuration) % 2) == 1;
        }

        /// <summary>
        /// Draws the controls window to the screen.
        /// </summary>
        /// <param name="spriteBatch">The sprite batch to draw to.</param>
        public void Draw(SpriteBatch spriteBatch)
        {
            //Construct the source rectangles and the header text of the page
            //that is being displayed. This coding practice is awful, but
            //I was in a hurry. Sorry!!
            string headerText;
            Rectangle sourceRectangle;
            bool useLeftArrow, useRightArrow;

            switch (_page)
            {
                case Page.Story:
                    headerText = "Story";
                    sourceRectangle = new Rectangle(0, 0, 384, 224);
                    useLeftArrow = false;
                    useRightArrow = true;
                    break;
                case Page.KeyboardControls:
                    headerText = "Keyboard Controls";
                    sourceRectangle = new Rectangle(0, 224, 384, 224);
                    useLeftArrow = true;
                    useRightArrow = true;
                    break;
                default:
                    headerText = "Gamepad Controls";
                    sourceRectangle = new Rectangle(0, 448, 384, 224);
                    useLeftArrow = true;
                    useRightArrow = false;
                    break;
            }

            //Draw the controls window.
            spriteBatch.Draw(_texture, _position, sourceRectangle, Color.White);

            //Draw the header.
            spriteBatch.DrawString(_font, headerText, new Vector2(_position.X + 193 - (_font.MeasureString(headerText).X / 2),
                                                                  _position.Y + 7), Color.Black);
            spriteBatch.DrawString(_font, headerText, new Vector2(_position.X + 192 - (_font.MeasureString(headerText).X / 2),
                                                                  _position.Y + 6), Color.White);

            //Draw the flashing arrow(s).
            if (ArrowIsFlashing())
            {
                if (useLeftArrow)
                    spriteBatch.Draw(_arrowTexture, _position + new Vector2(48, 16), new Rectangle(0, 0, 24, 22), Color.White);

                if (useRightArrow)
                    spriteBatch.Draw(_arrowTexture, _position + new Vector2(312, 16), new Rectangle(24, 0, 24, 22), Color.White);
            }
        }

        #endregion
    }
}
