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;
using Microsoft.Xna.Framework.Media;
using MegaManRipoff.UI;

namespace MegaManRipoff.GameOverClasses
{
    /// <summary>
    /// Handles the game over screen.
    /// </summary>
    class GameOverScreen : GameState
    {
        #region Member Variables

        /// <summary>
        /// The game's difficulty setting, used so that the main game can be
        /// resumed on the same difficulty.
        /// </summary>
        GameDifficulty _gameDifficulty;

        /// <summary>
        /// The camera used for displaying the title screen nicely.
        /// </summary>
        Camera _camera;

        /// <summary>
        /// The text used for the press start display.
        /// </summary>
        readonly string _gameOverText = "Game Over";

        /// <summary>
        /// The texture used for the game over screen.
        /// </summary>
        Texture2D _gameOverTexture;

        /// <summary>
        /// The font used for the game over text.
        /// </summary>
        SpriteFont _gameOverFont;

        /// <summary>
        /// The font used for the menu.
        /// </summary>
        SpriteFont _menuFont;

        /// <summary>
        /// The texture used for the cursor.
        /// </summary>
        Texture2D _cursorTexture;

        /// <summary>
        /// The offset of the cursor from the selected menu item.
        /// </summary>
        readonly Vector2 _cursorOffset = new Vector2(-28, 9);

        /// <summary>
        /// The game over menu.
        /// </summary>
        Menu _menu;

        /// <summary>
        /// The menu's items, used to subscribe and unsubscribe to/from their selection events.
        /// </summary>
        MenuItem _continueItem, _quitItem;

        /// <summary>
        /// The game over jingle.
        /// </summary>
        Song _music;

        /// <summary>
        /// Whether or not the jingle has played.
        /// </summary>
        bool _hasPlayed;

        /// <summary>
        /// Keeps track of how long to wait, in ticks, before creating the
        /// game over menu.
        /// </summary>
        int _waitTimer;

        /// <summary>
        /// The length of time to wait, in ticks, before creating the game
        /// over menu.
        /// </summary>
        const int WaitDuration = 360;

        #endregion

        /// <summary>
        /// The event called when the game over screen quits.
        /// </summary>
        public override event GameStateQuit OnGameStateQuit;

        /// <summary>
        /// Creates a new game over screen.
        /// </summary>
        /// <param name="game1">The current game.</param>
        /// <param name="gameDifficulty">The game's difficulty setting, used so
        /// that the main game can be resumed on the same difficulty.</param>
        public GameOverScreen(Game1 game1, GameDifficulty gameDifficulty)
            : base(game1)
        {
            _gameDifficulty = gameDifficulty;

            _waitTimer = WaitDuration;
        }

        #region Methods

        /// <summary>
        /// Initialises the game over screen.
        /// </summary>
        public override void Initialise()
        {
            //Create the camera.
            _camera = new Camera(_game1.GraphicsDevice, Vector2.Zero);
        }

        /// <summary>
        /// Loads the assets required by the game over screen.
        /// </summary>
        /// <param name="content">The game's content manager.</param>
        public override void LoadContent(ContentManager content)
        {
            _music = content.Load<Song>("Music\\GameOver");

            _gameOverTexture = content.Load<Texture2D>("Images\\GameOver");
            _cursorTexture = content.Load<Texture2D>("Images\\Cursor");

            _gameOverFont = content.Load<SpriteFont>("Fonts\\SegoeUI");
            _menuFont = content.Load<SpriteFont>("Fonts\\SegoeUISmall");

            Menu.LoadContent(content);
        }

        /// <summary>
        /// Plays the game over music once.
        /// </summary>
        private void PlayMusic()
        {
            //This ensures the music only plays once.
            if (!_hasPlayed && Game1.MUSIC)
            {
                MediaPlayer.IsRepeating = false;
                MediaPlayer.Play(_music);
                _hasPlayed = true;
            }
        }

        /// <summary>
        /// Creates the game over menu.
        /// </summary>
        private void CreateMenu()
        {
            _menu = new Menu(_menuFont, _cursorTexture, _cursorOffset, false);

            _continueItem = new MenuItem(_menu,
                                         "Continue",
                                         new Vector2(_camera.Area.Center.X - (_menuFont.MeasureString("Continue").X / 2),
                                                     _camera.Area.Center.Y - (_menuFont.MeasureString("Continue").Y / 2)),
                                         70);
            _continueItem.OnSelected += new Selected(_continueItem_OnSelected);
            _menu.AddItem(_continueItem);

            _quitItem = new MenuItem(_menu,
                                     "Quit",
                                     new Vector2(_camera.Area.Center.X - (_menuFont.MeasureString("Continue").X / 2),
                                                 _camera.Area.Center.Y + (_menuFont.MeasureString("Continue").Y / 2)),
                                     70);
            _quitItem.OnSelected += new Selected(_quitItem_OnSelected);
            _menu.AddItem(_quitItem);
        }

        /// <summary>
        /// Waits until the game over jingle music finishes before creating
        /// the game over menu.
        /// </summary>
        private void WaitUntilMusicFinishes()
        {
            //Decrement the timer; if it is now zero, create the game over
            //menu.
            if (--_waitTimer <= 0)
                CreateMenu();
        }

        /// <summary>
        /// Updates the game over screen.
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Update(GameTime gameTime)
        {
            //Play the music.
            PlayMusic();
            
            //Update the input handler.
            InputHelper.Update();

            //Update the camera (used for scaling).
            _camera.Update();

            //If the menu doesn't exist, update the timer.
            if (_menu == null)
            {
                WaitUntilMusicFinishes();
            }
            //Update the menu if it exists.
            else
            {
                _menu.Update(gameTime);
            }
        }

        /// <summary>
        /// Draws the game over text to the screen.
        /// </summary>
        private void DrawGameOverText(SpriteBatch spriteBatch)
        {
            //Position the string at the centre of the screen.
            Vector2 position = new Vector2(_camera.Area.Center.X - (_gameOverFont.MeasureString(_gameOverText).X / 2),
                                           _camera.Area.Center.Y - (_gameOverFont.MeasureString(_gameOverText).Y / 2));

            //Draw the shadow, then the actual text.
            spriteBatch.DrawString(_gameOverFont,
                                   _gameOverText,
                                   position + Vector2.One,
                                   Color.Black);
            spriteBatch.DrawString(_gameOverFont,
                                   _gameOverText,
                                   position,
                                   Color.White);
        }

        /// <summary>
        /// Draws the game over screen to the screen.
        /// </summary>
        /// <param name="spriteBatch">The sprite batch to draw to.</param>
        public override void Draw(SpriteBatch spriteBatch)
        {
            //Start the sprite batch.
            spriteBatch.Begin(SpriteSortMode.Deferred,
                              BlendState.AlphaBlend,
                              SamplerState.PointWrap,
                              null, null, null,
                              _camera.ScaleTransformation);

            //Draw the title texture.
            spriteBatch.Draw(_gameOverTexture, Vector2.Zero, Color.White);

            //Draw the game over if the menu hasn't been created.
            if (_menu == null)
                DrawGameOverText(spriteBatch);
            else
                _menu.Draw(spriteBatch);

            spriteBatch.End();
        }

        #endregion

        #region Event Handles

        /// <summary>
        /// Method called when the continue item is selected.
        /// </summary>
        /// <param name="sender">The menu item that was selected.</param>
        /// <param name="e">Event arguments.</param>
        void _continueItem_OnSelected(object sender, EventArgs e)
        {
            //Go to the main game, if there is a subscriber for the game state quit event. By not specifying
            //a level index in the GameStateQuitEventArgs constructor, the most recent level will be resumed.
            if (OnGameStateQuit != null)
                OnGameStateQuit(this, new GameStateQuitEventArgs(Game1.State.MainGame, _gameDifficulty));
        }

        /// <summary>
        /// Method called when the quit item is selected.
        /// </summary>
        /// <param name="sender">The menu item that was selected.</param>
        /// <param name="e">Event arguments.</param>
        void _quitItem_OnSelected(object sender, EventArgs e)
        {
            //Go to the title screen, if there is a subscriber for the game state quit event.
            if (OnGameStateQuit != null)
                OnGameStateQuit(this, new GameStateQuitEventArgs(Game1.State.TitleScreen, _gameDifficulty));
        }

        #endregion
    }
}
