using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace FredriksdalAssault2
{
    class EndGameScreen : MenuScreen
    {
        #region Variables

        NetworkSession networkSession;

        // Assault mode
        private String winningTeam;
        private List<PlayerProfile> attackers;
        private List<PlayerProfile> defenders;

        // Deathmatch mode
        private List<PlayerProfile> players;

        #endregion

        #region Constructors

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="networkSession"></param>
        public EndGameScreen(NetworkSession networkSession)
            : base(Resources.EndOfGame)
        {
            // Set the network session
            this.networkSession = networkSession;

            // Add menu entries
            if (networkSession == null)
            {
                // If this is a single player game, add the Quit menu entry.
                MenuEntry quitGameMenuEntry = new MenuEntry(Resources.QuitGame);
                quitGameMenuEntry.Selected += QuitGameMenuEntrySelected;
                MenuEntries.Add(quitGameMenuEntry);
            }
            else
            {
                // If we are hosting a network game, add the Return to Lobby menu entry.
                if (networkSession.IsHost)
                {
                    MenuEntry lobbyMenuEntry = new MenuEntry(Resources.ReturnToLobby);
                    lobbyMenuEntry.Selected += ReturnToLobbyMenuEntrySelected;
                    MenuEntries.Add(lobbyMenuEntry);
                }

                // Add the End/Leave Session menu entry.
                string leaveEntryText = networkSession.IsHost ? Resources.EndSession :
                                                                Resources.LeaveSession;

                MenuEntry leaveSessionMenuEntry = new MenuEntry(leaveEntryText);
                leaveSessionMenuEntry.Selected += LeaveSessionMenuEntrySelected;
                MenuEntries.Add(leaveSessionMenuEntry);
            }

            // Call methods to add players to lists
            if (Program.gameMode == 0)
                addAssaultPlayers();
            else if (Program.gameMode == 1)
                addDeathMatchPlayers();
        }

        /// <summary>
        /// Constructor for a assault game.
        /// </summary>
        /// <param name="networkSession"></param>
        /// <param name="winningTeam"></param>
        public EndGameScreen(NetworkSession networkSession, String winningTeam)
            : base(Resources.EndOfGame)
        {
            // Set the network session
            this.networkSession = networkSession;
            this.winningTeam = winningTeam;

            // Add menu entries
            if (networkSession == null)
            {
                // If this is a single player game, add the Quit menu entry.
                MenuEntry quitGameMenuEntry = new MenuEntry(Resources.QuitGame);
                quitGameMenuEntry.Selected += QuitGameMenuEntrySelected;
                MenuEntries.Add(quitGameMenuEntry);
            }
            else
            {
                // If we are hosting a network game, add the Return to Lobby menu entry.
                if (networkSession.IsHost)
                {
                    MenuEntry lobbyMenuEntry = new MenuEntry(Resources.ReturnToLobby);
                    lobbyMenuEntry.Selected += ReturnToLobbyMenuEntrySelected;
                    MenuEntries.Add(lobbyMenuEntry);
                }

                // Add the End/Leave Session menu entry.
                string leaveEntryText = networkSession.IsHost ? Resources.EndSession :
                                                                Resources.LeaveSession;

                MenuEntry leaveSessionMenuEntry = new MenuEntry(leaveEntryText);
                leaveSessionMenuEntry.Selected += LeaveSessionMenuEntrySelected;
                MenuEntries.Add(leaveSessionMenuEntry);
            }

            // Call methods to add players to lists
            if (Program.gameMode == 0)
                addAssaultPlayers();
            else if (Program.gameMode == 1)
                addDeathMatchPlayers();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Helper method to add players to lists in the Assault game mode.
        /// </summary>
        private void addAssaultPlayers()
        {
            //ContentManager content = ScreenManager.Game.Content; // Temp for debugging

            // Create a list of attackers and a list of defenders
            attackers = new List<PlayerProfile>(9);
            defenders = new List<PlayerProfile>(9);

            // For each person in the session...
            foreach (NetworkGamer gamer in networkSession.AllGamers)
            {
                // Look up the player object belonging to this network gamer.
                NetworkPlayerProfile player = gamer.Tag as NetworkPlayerProfile;

                if (player.isAttacking)
                {
                    attackers.Add(player);
                }
                else
                {
                    defenders.Add(player);
                }
            }

            //// Debugging (Add eight more players in each list)
            //for (int k = 1; k < 8; k++)
            //{

            //    PlayerData newPlayer = new PlayerData(content, (byte)k, "Nisse " + k, true);
            //    newPlayer.numberOfKills = (Int16)(k * 2);
            //    newPlayer.collectedBarrels = (byte)k;
            //    attackers.Add(newPlayer);

            //    PlayerData newPlayer2 = new PlayerData(content, (byte)k, "Pelle " + k, false);
            //    newPlayer.numberOfKills = (Int16)(k * 3);
            //    defenders.Add(newPlayer2);

            //}

            // Sort lists on number of kills
            attackers.Sort();
            defenders.Sort();

        } // End of addAssaultPlayers

        /// <summary>
        /// Helper method to add players to lists in the Deathmatch game mode.
        /// </summary>
        private void addDeathMatchPlayers()
        {
            //ContentManager content = ScreenManager.Game.Content; // Temp for debugging

            // Create a list of players in a deathmatch game.
            players = new List<PlayerProfile>(18);

            // For each person in the session...
            foreach (NetworkGamer gamer in networkSession.AllGamers)
            {
                // Look up the player object belonging to this network gamer.
                NetworkPlayerProfile player = gamer.Tag as NetworkPlayerProfile;

                // Add the player in the players list
                players.Add(player);

            }

            //// Debugging (Add eight more players in each list)
            //for (int k = 1; k < 16; k++)
            //{

            //    PlayerData newPlayer = new PlayerData(content, (byte)k, "Nisse " + k, true);
            //    newPlayer.numberOfKills = (Int16)(k * 2);
            //    players.Add(newPlayer);

            //}

            // Sort the lists on number of kills
            players.Sort();

        } // End of addDeathMatchPlayers

        /// <summary>
        /// Draw on the end game screen.
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);

            if (Program.gameMode == 0)
                DrawAssault();
            else if (Program.gameMode == 1)
                DrawDeathMatch();
        }

        /// <summary>
        /// Draw game statistics.
        /// </summary>
        private void DrawAssault()
        {
            // Create reference variables.
            GraphicsDevice graphicsDevice = ScreenManager.GraphicsDevice;
            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
            SpriteFont font = ScreenManager.Font;
            int safeAreaTop = graphicsDevice.Viewport.TitleSafeArea.Top;
            
            // Start draw in 2D
            spriteBatch.Begin();

            // Properties for text on the end game screen
            String winningTeamString = this.winningTeam + " won the game!";
            float textScale = 0.7f;
            Color textColor = Color.White * TransitionAlpha;

            // Draw the winning team.
            spriteBatch.DrawString(font, winningTeamString, new Vector2(graphicsDevice.Viewport.Width / 2, safeAreaTop + 10), textColor, 0,
                                   new Vector2(font.MeasureString(winningTeamString).X / 2, 0), 1.5f, SpriteEffects.None, 0);

            // Draw the attacker heading
            spriteBatch.DrawString(font, "-- Attackers --", new Vector2(graphicsDevice.Viewport.Width / 2, 300), textColor, 0,
                                   new Vector2(400,0), textScale, SpriteEffects.None, 0);

            // A offset for each name to print.
            int offset = 25;

            // Draw each attacker in the list
            for (int i = 0; i < attackers.Count; i++)
            {
                String playerString = (i + 1) + ". " + attackers[i].playerName + " " + attackers[i].numberOfKills + " (" + attackers[i].collectedBarrels + ")";
                spriteBatch.DrawString(font, playerString, new Vector2(graphicsDevice.Viewport.Width / 2, 300 + offset), textColor, 0,
                                   new Vector2(400, 0), textScale, SpriteEffects.None, 0);

                // Add to the offset
                offset += 25;
            }

            // Reset the offset
            offset = 25;

            // Draw the defender heading
            spriteBatch.DrawString(font, "-- Defenders --", new Vector2(graphicsDevice.Viewport.Width / 2, 300), textColor, 0,
                                   new Vector2(-200, 0), textScale, SpriteEffects.None, 0);

            // Draw each defender in the list
            for (int i = 0; i < defenders.Count; i++)
            {
                String playerString = (i + 1) + ". " + defenders[i].playerName + " " + defenders[i].numberOfKills + " (" + defenders[i].collectedBarrels + ")";
                spriteBatch.DrawString(font, playerString, new Vector2(graphicsDevice.Viewport.Width / 2, 300 + offset), textColor, 0,
                                   new Vector2(-200, 0), textScale, SpriteEffects.None, 0);

                // Add to the offset
                offset += 25;
            }

            spriteBatch.End();

        }

        /// <summary>
        /// Draw game statistics for death match.
        /// </summary>
        private void DrawDeathMatch()
        {
            // Create reference variables.
            GraphicsDevice graphicsDevice = ScreenManager.GraphicsDevice;
            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
            SpriteFont font = ScreenManager.Font;
            int safeAreaTop = graphicsDevice.Viewport.TitleSafeArea.Top;
            
            // Start draw in 2D
            spriteBatch.Begin();

            // Properties for text on the end game screen
            String winningPlayerString = players[0].playerName + " won the game!";
            float textScale = 0.7f;
            Color textColor = Color.White * TransitionAlpha;

            // Draw the winning team.
            spriteBatch.DrawString(font, winningPlayerString, new Vector2(graphicsDevice.Viewport.Width / 2, safeAreaTop + 10), textColor, 0,
                                   new Vector2(font.MeasureString(winningPlayerString).X / 2, 0), 1.5f, SpriteEffects.None, 0);

            // A offset for each name to print.
            int offsetFirstColumn = 25;
            int offsetSecondColumn = 25;

            // Draw each player in the list
            for (int i = 0; i < players.Count; i++)
            {

                // Create the player string.
                String playerString = (i + 1) + ". " + players[i].playerName + " " + players[i].numberOfKills;

                // Draw 8 players on each side of the screen.
                if (i < 8)
                {
                    spriteBatch.DrawString(font, playerString, new Vector2(graphicsDevice.Viewport.Width / 2, 300 + offsetFirstColumn), textColor, 0,
                                       new Vector2(400, 0), textScale, SpriteEffects.None, 0);
                    
                    // Add to the offset
                    offsetFirstColumn += 25;
                }
                else
                {
                    spriteBatch.DrawString(font, playerString, new Vector2(graphicsDevice.Viewport.Width / 2, 300 + offsetSecondColumn), textColor, 0,
                                       new Vector2(-200, 0), textScale, SpriteEffects.None, 0);

                    // Add to the offset
                    offsetSecondColumn += 25;
                }
            }

            spriteBatch.End();

        }

        #endregion

        #region EventHandlers

        /// <summary>
        /// Event handler for when the Quit Game menu entry is selected.
        /// </summary>
        void QuitGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
        {
            MessageBoxScreen confirmQuitMessageBox =
                                    new MessageBoxScreen(Resources.ConfirmQuitGame);

            confirmQuitMessageBox.Accepted += ConfirmQuitMessageBoxAccepted;

            ScreenManager.AddScreen(confirmQuitMessageBox, ControllingPlayer);
        }

        /// <summary>
        /// Event handler for when the user selects ok on the "are you sure
        /// you want to quit" message box. This uses the loading screen to
        /// transition from the game back to the main menu screen.
        /// </summary>
        void ConfirmQuitMessageBoxAccepted(object sender, PlayerIndexEventArgs e)
        {
            LoadingScreen.Load(ScreenManager, false, null, new BackgroundScreen(),
                                                           new MainMenuScreen());
        }

        /// <summary>
        /// Event handler for when the Return to Lobby menu entry is selected.
        /// </summary>
        void ReturnToLobbyMenuEntrySelected(object sender, PlayerIndexEventArgs e)
        {
            if (networkSession.SessionState == NetworkSessionState.Playing)
            {
                networkSession.EndGame();
            }
        }

        /// <summary>
        /// Event handler for when the End/Leave Session menu entry is selected.
        /// </summary>
        void LeaveSessionMenuEntrySelected(object sender, PlayerIndexEventArgs e)
        {
            NetworkSessionComponent.LeaveSession(ScreenManager, e.PlayerIndex);
        }

        #endregion

    } // End of class

} // End of namespace
