using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using StrategicCombat.GameScreens;
using StrategicCombat.Teams;
using StrategicCombat.PlayerProfiles;
using StrategicCombat.GamerStatistics;

namespace StrategicCombat
{
    /// <summary>
    /// The lobby screen provides a place for gamers to congregate before starting
    /// the actual gameplay. It displays a list of all the gamers in the session,
    /// and indicates which ones are currently talking. Each gamer can press a button
    /// to mark themselves as ready: gameplay will begin after everyone has done this.
    /// </summary>
    public class NetworkLobby : GameScreen
    {
        #region Variables

        // Network session.
        NetworkSession networkSession;

        // Voice textures.
        Texture2D hasVoiceTexture;
        Texture2D isTalkingTexture;
        Texture2D voiceMutedTexture;

        // Frame background texture.
        Texture2D frameBackgroundTexture;

        // Teams
        string[] teamStrings = { "USA", "Russia" };

        // Team textures.
        Texture2D teamZeroTexture;
        Texture2D teamOneTexture;
        Texture2D blueCircle;
        Texture2D redCircle;

        // Xbox icons
        Texture2D aButtonTexture;
        Texture2D bButtonTexture;
        Texture2D yButtonTexture;

        // Pc icons
        Texture2D enterButtonTexture;
        Texture2D escapeButtonTexture;
        Texture2D zKeyButtonTexture;

        // Constant x and y offsets
        const int xOffset = 128;
        const int yOffset = 72;

        // Variable used to syncronize settings for all network players.
        bool hasUpdatedSettings = false;

        // Variables for network communication
        PacketWriter packetWriter = new PacketWriter();
        PacketReader packetReader = new PacketReader();

        #endregion

        #region Constructors

        /// <summary>
        /// Constructs a new lobby screen.
        /// </summary>
        public NetworkLobby(NetworkSession networkSession)
        {
            this.networkSession = networkSession;

            TransitionOnTime = TimeSpan.FromSeconds(0.5);
            TransitionOffTime = TimeSpan.FromSeconds(0.5);

            // Test network latency
            //this.networkSession.SimulatedLatency = TimeSpan.FromMilliseconds(10000);
            //this.networkSession.SimulatedPacketLoss = 0.1f;

        }


        /// <summary>
        /// Loads graphics content used by the lobby screen.
        /// </summary>
        public override void LoadContent()
        {
            // Create a new content manager.
            ContentManager content = ScreenManager.Game.Content;

            // Load voice textures.
            hasVoiceTexture = content.Load<Texture2D>("MenuAssets/chat_able");
            isTalkingTexture = content.Load<Texture2D>("MenuAssets/chat_talking");
            voiceMutedTexture = content.Load<Texture2D>("MenuAssets/chat_mute");

            // Load background textures.
            this.frameBackgroundTexture = content.Load<Texture2D>("MenuAssets/white-background");
            this.teamZeroTexture = content.Load<Texture2D>("CombatUnits/LeftCombatUnits/LeftTank75");
            this.teamOneTexture = content.Load<Texture2D>("CombatUnits/RightCombatUnits/RightPlane75");
            this.blueCircle = content.Load<Texture2D>("MenuAssets/blueCircle");
            this.redCircle = content.Load<Texture2D>("MenuAssets/redCircle");

            // Load button textures
            this.aButtonTexture = content.Load<Texture2D>("MenuAssets/a");
            this.bButtonTexture = content.Load<Texture2D>("MenuAssets/b");
            this.yButtonTexture = content.Load<Texture2D>("MenuAssets/y");
            this.enterButtonTexture = content.Load<Texture2D>("MenuAssets/enter");
            this.escapeButtonTexture = content.Load<Texture2D>("MenuAssets/escape");
            this.zKeyButtonTexture = content.Load<Texture2D>("MenuAssets/key_z");

            // Reset gamer statistics to null.
            Program.mainPlayerStatistics = null;
            Program.otherPlayerStatistics = new GamerStats("OtherGamer", 0, 0);

            // Load gamer statistics.
            foreach (LocalNetworkGamer gamer in networkSession.LocalGamers)
            {
                // Get the playerindex
                PlayerIndex playerIndex = gamer.SignedInGamer.PlayerIndex;

                // Get the storage device.
                StorageDevice storageDevice = Program.storageDevices[(int)playerIndex];

                // Load gamer statistics for the gamer.
                if (storageDevice != null && storageDevice.IsConnected)
                {
                    // Get the statistics.
                    GamerStats gamerStats = FileHandler.LoadGamerStatsFromFile(storageDevice);

                    // Load the gamer statistics.
                    if (gamerStats != null)
                        Program.mainPlayerStatistics = gamerStats;
                    else
                        Program.mainPlayerStatistics = new GamerStats(gamer.Gamertag, 0, 0);
                }
                else
                {
                    // Set the gamer statistics to zero.
                    Program.mainPlayerStatistics = new GamerStats(gamer.Gamertag, 0, 0);
                }
            }
        }

        #endregion

        #region Update

        /// <summary>
        /// Updates the lobby screen.
        /// </summary>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
        {
            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);

            if (!IsExiting)
            {
                // Update the network session
                networkSession.Update();

                if (networkSession.SessionState == NetworkSessionState.Playing)
                {

                    if (networkSession.IsHost)
                    {
                        SendHostTeamValueReliable((LocalNetworkGamer)networkSession.Host);
                    }

                    if (!networkSession.IsHost)
                    {
                        foreach (LocalNetworkGamer gamer in networkSession.LocalGamers)
                        {
                            GetHostTeamValueReliable(gamer);
                        }
                    }

                    if (this.hasUpdatedSettings == true)
                    {
                        // Check if we should leave the lobby and begin gameplay.
                        // We pass null as the controlling player, because the networked
                        // gameplay screen accepts input from any local players who
                        // are in the session, not just a single controlling player.
                        LoadingScreen.Load(ScreenManager, true, null, new GameplayScreen(networkSession, 2));
                    }

                }
                else if (networkSession.IsHost && networkSession.IsEveryoneReady)
                {
                    // It must be at least 2 gamers to start a game.
                    int numberOfGamers = networkSession.AllGamers.Count;

                    // Start the game if there is at least two gamers.
                    if (numberOfGamers == 2)
                        networkSession.StartGame();
                }
                else
                {
                    if (networkSession.Host != null)
                    {
                        if (networkSession.IsHost)
                        {
                            SendHostTeamValue((LocalNetworkGamer)networkSession.Host);
                        }

                        // Send gamer statistics and get the host team value.
                        foreach (LocalNetworkGamer localGamer in networkSession.LocalGamers)
                        {
                            SendGamerStatistics(localGamer);
                            GetNetworkData(localGamer);
                        }
                    }
                }

            } // End of if (!IsExiting)

        } // End of the update method.

        /// <summary>
        /// Handles user input for all the local gamers in the session. Unlike most
        /// screens, which use the InputState class to combine input data from all
        /// gamepads, the lobby needs to individually mark specific players as ready,
        /// so it loops over all the local gamers and reads their inputs individually.
        /// </summary>
        public override void HandleInput(InputState input)
        {
            foreach (LocalNetworkGamer gamer in networkSession.LocalGamers)
            {
                PlayerIndex playerIndex = gamer.SignedInGamer.PlayerIndex;

                PlayerIndex unwantedOutput;

                if (input.IsMenuSelect(playerIndex, out unwantedOutput))
                {
                    HandleMenuSelect(gamer);
                }
                else if (input.IsMenuCancel(playerIndex, out unwantedOutput))
                {
                    HandleMenuCancel(gamer);
                }
                else if (input.IsMenuChangeTeam(playerIndex, out unwantedOutput))
                {
                    HandleMenuChangeTeam(gamer);
                }
            }

        } // End of the HandleInput method.

        /// <summary>
        /// Handle MenuSelect inputs by marking ourselves as ready.
        /// </summary>
        private void HandleMenuSelect(LocalNetworkGamer gamer)
        {
            if (!gamer.IsReady)
            {
                gamer.IsReady = true;
            }
            else if (gamer.IsHost)
            {
                // The host has an option to force starting the game, even if not
                // everyone has marked themselves ready. If they press select twice
                // in a row, the first time marks the host ready, then the second
                // time we ask if they want to force start.
                MessageBoxScreen messageBox = new MessageBoxScreen(Resources.ConfirmForceStartGame);

                messageBox.Accepted += ConfirmStartGameMessageBoxAccepted;

                ScreenManager.AddScreen(messageBox, gamer.SignedInGamer.PlayerIndex);
            }
        }

        /// <summary>
        /// Event handler for when the host selects ok on the "are you sure
        /// you want to start even though not everyone is ready" message box.
        /// </summary>
        private void ConfirmStartGameMessageBoxAccepted(object sender, PlayerIndexEventArgs e)
        {
            if (networkSession.SessionState == NetworkSessionState.Lobby)
            {
                // It must be at least 2 gamers to start a game.
                int numberOfGamers = networkSession.AllGamers.Count;

                // Start the game if there is at least two gamers.
                if (numberOfGamers == 2)
                    networkSession.StartGame();
                else
                {
                    MessageBoxScreen messageBox = new MessageBoxScreen("You need to be two gamers to be able to start a match.");
                    ScreenManager.AddScreen(messageBox, null);
                }
            }
        }

        /// <summary>
        /// Handle MenuCancel inputs by clearing our ready status, or if it is
        /// already clear, prompting if the user wants to leave the session.
        /// </summary>
        private void HandleMenuCancel(LocalNetworkGamer gamer)
        {
            if (gamer.IsReady)
            {
                gamer.IsReady = false;
            }
            else
            {
                PlayerIndex playerIndex = gamer.SignedInGamer.PlayerIndex;

                NetworkSessionComponent.LeaveSession(ScreenManager, playerIndex);
            }
        }

        /// <summary>
        /// Handle MenuChangeTeam inputs by changing team.
        /// </summary>
        private void HandleMenuChangeTeam(LocalNetworkGamer gamer)
        {
            // It is just the host that are allowed to change teams.
            if (gamer.IsHost)
            {
                // Change the host team.
                Program.hostTeam = (byte)((Program.hostTeam + 1) % teamStrings.Length);

                // Send data about the change.
                SendHostTeamValue(gamer);
            }
        }

        #endregion

        #region Draw

        /// <summary>
        /// Draws the lobby screen.
        /// </summary>
        public override void Draw(GameTime gameTime)
        {
            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
            SpriteFont font = ScreenManager.Font;
            Texture2D frameTexture = ScreenManager.blankTexture;

            Vector2 gamerTagPosition = new Vector2(194, 164);

            // Make the lobby slide into place during transitions.
            float transitionOffset = (float)Math.Pow(TransitionPosition, 2);

            if (ScreenState == ScreenState.TransitionOn)
                gamerTagPosition.X -= transitionOffset * 256;
            else
                gamerTagPosition.X += transitionOffset * 512;

            spriteBatch.Begin();

            // Draw the screen title.
            string title = Resources.Lobby;

            Vector2 titlePosition = new Vector2(xOffset, yOffset + 10);
            Vector2 titleOrigin = Vector2.Zero;
            Color titleColor = Color.White * TransitionAlpha;
            float titleScale = 2f;

            titlePosition.Y -= transitionOffset * 100;

            // Draw a rectangle for the game title
            spriteBatch.Draw(frameTexture, new Rectangle(0, yOffset, 1280, 68), Color.Orange * TransitionAlpha);

            // Dark shadow
            spriteBatch.DrawString(font, title, new Vector2(titlePosition.X + 1, titlePosition.Y + 1), Color.DarkGray * TransitionAlpha, 0,
                                   titleOrigin, titleScale, SpriteEffects.None, 0);

            // Title text
            spriteBatch.DrawString(font, title, titlePosition, titleColor, 0, titleOrigin, titleScale, SpriteEffects.None, 0);

            // Draw the first rectangle.
            spriteBatch.Draw(frameTexture, new Vector2(190, 160), new Rectangle(0, 0, 400, 400), Color.Black * TransitionAlpha, 0, Vector2.Zero, 1, SpriteEffects.None, 0);
            spriteBatch.Draw(frameBackgroundTexture, new Vector2(192, 162), new Rectangle(0, 0, 396, 396), Color.White * TransitionAlpha, 0, Vector2.Zero, 1, SpriteEffects.None, 0f);

            if (networkSession.IsHost)
            {
                spriteBatch.Draw(this.blueCircle, new Vector2(210, 200), new Rectangle(0, 0, 32, 32), Color.White * TransitionAlpha, 0, Vector2.Zero, 0.75f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "team wins: " + Program.mainPlayerStatistics.blueTeamWins, new Vector2(242, 198), Color.DarkGray * TransitionAlpha, 0, Vector2.Zero, 1.25f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "team wins: " + Program.mainPlayerStatistics.blueTeamWins, new Vector2(241, 197), Color.Yellow * TransitionAlpha, 0, Vector2.Zero, 1.25f, SpriteEffects.None, 0);
                spriteBatch.Draw(this.redCircle, new Vector2(210, 225), new Rectangle(0, 0, 32, 32), Color.White * TransitionAlpha, 0, Vector2.Zero, 0.75f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "team wins: " + Program.mainPlayerStatistics.redTeamWins, new Vector2(242, 224), Color.DarkGray * TransitionAlpha, 0, Vector2.Zero, 1.25f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "team wins: " + Program.mainPlayerStatistics.redTeamWins, new Vector2(241, 223), Color.Yellow * TransitionAlpha, 0, Vector2.Zero, 1.25f, SpriteEffects.None, 0);
            }
            else
            {
                spriteBatch.Draw(this.blueCircle, new Vector2(210, 200), new Rectangle(0, 0, 32, 32), Color.White * TransitionAlpha, 0, Vector2.Zero, 0.75f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "team wins: " + Program.otherPlayerStatistics.blueTeamWins, new Vector2(242, 198), Color.DarkGray * TransitionAlpha, 0, Vector2.Zero, 1.25f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "team wins: " + Program.otherPlayerStatistics.blueTeamWins, new Vector2(241, 197), Color.Yellow * TransitionAlpha, 0, Vector2.Zero, 1.25f, SpriteEffects.None, 0);
                spriteBatch.Draw(this.redCircle, new Vector2(210, 225), new Rectangle(0, 0, 32, 32), Color.White * TransitionAlpha, 0, Vector2.Zero, 0.75f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "team wins: " + Program.otherPlayerStatistics.redTeamWins, new Vector2(242, 224), Color.DarkGray * TransitionAlpha, 0, Vector2.Zero, 1.25f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "team wins: " + Program.otherPlayerStatistics.redTeamWins, new Vector2(241, 223), Color.Yellow * TransitionAlpha, 0, Vector2.Zero, 1.25f, SpriteEffects.None, 0);
            }

            if (Program.hostTeam == 0)
            {
                spriteBatch.DrawString(font, this.teamStrings[0], new Vector2(392, 272), Color.DarkGray * TransitionAlpha, 0, new Vector2(font.MeasureString(this.teamStrings[0]).X / 2, 0), 2f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, this.teamStrings[0], new Vector2(390, 270), Color.Blue * TransitionAlpha, 0, new Vector2(font.MeasureString(this.teamStrings[0]).X / 2, 0), 2f, SpriteEffects.None, 0);
                spriteBatch.Draw(this.teamZeroTexture, new Vector2(390, 380), new Rectangle(0, 0, 75, 75), Color.White * TransitionAlpha, 0, new Vector2(37.5f, 37.5f), 1.5f, SpriteEffects.None, 0);
            }
            else if (Program.hostTeam == 1)
            {
                spriteBatch.DrawString(font, this.teamStrings[1], new Vector2(392, 272), Color.DarkGray * TransitionAlpha, 0, new Vector2(font.MeasureString(this.teamStrings[1]).X / 2, 0), 2f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, this.teamStrings[1], new Vector2(390, 270), Color.Red * TransitionAlpha, 0, new Vector2(font.MeasureString(this.teamStrings[1]).X / 2, 0), 2f, SpriteEffects.None, 0);
                spriteBatch.Draw(this.teamOneTexture, new Vector2(390, 380), new Rectangle(0, 0, 75, 75), Color.White * TransitionAlpha, 0, new Vector2(37.5f, 37.5f), 1.5f, SpriteEffects.None, 0);
            }

            // Draw the second rectangle.
            spriteBatch.Draw(frameTexture, new Vector2(690, 160), new Rectangle(0, 0, 400, 400), Color.Black * TransitionAlpha, 0, Vector2.Zero, 1, SpriteEffects.None, 0);
            spriteBatch.Draw(frameBackgroundTexture, new Vector2(692, 162), new Rectangle(0, 0, 396, 396), Color.White * TransitionAlpha, 0, Vector2.Zero, 1, SpriteEffects.None, 0);

            if (networkSession.AllGamers.Count == 2 && networkSession.IsHost)
            {
                spriteBatch.Draw(this.blueCircle, new Vector2(710, 200), new Rectangle(0, 0, 32, 32), Color.White * TransitionAlpha, 0, Vector2.Zero, 0.75f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "team wins: " + Program.otherPlayerStatistics.blueTeamWins, new Vector2(742, 199), Color.DarkGray * TransitionAlpha, 0, Vector2.Zero, 1.25f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "team wins: " + Program.otherPlayerStatistics.blueTeamWins, new Vector2(741, 197), Color.Yellow * TransitionAlpha, 0, Vector2.Zero, 1.25f, SpriteEffects.None, 0);
                spriteBatch.Draw(this.redCircle, new Vector2(710, 225), new Rectangle(0, 0, 32, 32), Color.White * TransitionAlpha, 0, Vector2.Zero, 0.75f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "team wins: " + Program.otherPlayerStatistics.redTeamWins, new Vector2(742, 225), Color.DarkGray * TransitionAlpha, 0, Vector2.Zero, 1.25f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "team wins: " + Program.otherPlayerStatistics.redTeamWins, new Vector2(741, 223), Color.Yellow * TransitionAlpha, 0, Vector2.Zero, 1.25f, SpriteEffects.None, 0);
            }
            else if(networkSession.AllGamers.Count == 2 && !networkSession.IsHost)
            {      
                spriteBatch.Draw(this.blueCircle, new Vector2(710, 200), new Rectangle(0, 0, 32, 32), Color.White * TransitionAlpha, 0, Vector2.Zero, 0.75f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "team wins: " + Program.mainPlayerStatistics.blueTeamWins, new Vector2(742, 198), Color.DarkGray * TransitionAlpha, 0, Vector2.Zero, 1.25f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "team wins: " + Program.mainPlayerStatistics.blueTeamWins, new Vector2(741, 197), Color.Yellow * TransitionAlpha, 0, Vector2.Zero, 1.25f, SpriteEffects.None, 0);
                spriteBatch.Draw(this.redCircle, new Vector2(710, 225), new Rectangle(0, 0, 32, 32), Color.White * TransitionAlpha, 0, Vector2.Zero, 0.75f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "team wins: " + Program.mainPlayerStatistics.redTeamWins, new Vector2(742, 224), Color.DarkGray * TransitionAlpha, 0, Vector2.Zero, 1.25f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "team wins: " + Program.mainPlayerStatistics.redTeamWins, new Vector2(741, 223), Color.Yellow * TransitionAlpha, 0, Vector2.Zero, 1.25f, SpriteEffects.None, 0);
            }

            if (networkSession.AllGamers.Count == 2 && Program.hostTeam == 1)
            {
                spriteBatch.DrawString(font, this.teamStrings[0], new Vector2(892, 272), Color.DarkGray * TransitionAlpha, 0, new Vector2(font.MeasureString(this.teamStrings[0]).X / 2, 0), 2f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, this.teamStrings[0], new Vector2(890, 270), Color.Blue * TransitionAlpha, 0, new Vector2(font.MeasureString(this.teamStrings[0]).X / 2, 0), 2f, SpriteEffects.None, 0);
                spriteBatch.Draw(this.teamZeroTexture, new Vector2(890, 380), new Rectangle(0, 0, 75, 75), Color.White * TransitionAlpha, 0, new Vector2(37.5f, 37.5f), 1.5f, SpriteEffects.None, 0);
            }
            else if (networkSession.AllGamers.Count == 2 && Program.hostTeam == 0)
            {
                spriteBatch.DrawString(font, this.teamStrings[1], new Vector2(892, 272), Color.DarkGray * TransitionAlpha, 0, new Vector2(font.MeasureString(this.teamStrings[1]).X / 2, 0), 2f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, this.teamStrings[1], new Vector2(890, 270), Color.Red * TransitionAlpha, 0, new Vector2(font.MeasureString(this.teamStrings[1]).X / 2, 0), 2f, SpriteEffects.None, 0);
                spriteBatch.Draw(this.teamOneTexture, new Vector2(890, 380), new Rectangle(0, 0, 75, 75), Color.White * TransitionAlpha, 0, new Vector2(37.5f, 37.5f), 1.5f, SpriteEffects.None, 0);
            }

            // Draw gamer tags and is ready text for gamers.
            foreach (NetworkGamer gamer in networkSession.AllGamers)
            {
                if(gamer.IsHost)
                    DrawGamer(gamer, gamerTagPosition);
                else
                    DrawGamer(gamer, new Vector2(gamerTagPosition.X + 500, gamerTagPosition.Y));

            }

            // Draw a rectangle for buttons and keys
            spriteBatch.Draw(frameTexture, new Rectangle(0, 598, 1280, 48), Color.Orange * TransitionAlpha);

            // Button panel
            float buttonTextScale = 1.25f;
            String selectText = "Ready";
            String backText = "Leave game/Not ready";
            String changeTeamText = "Change team";
            float selectStringSize = xOffset + 32 + 40 + (font.MeasureString(selectText).X * buttonTextScale) + 5;
            float backStringSize = selectStringSize + 32 + 40 + (font.MeasureString(backText).X * buttonTextScale) + 5;

#if (!XBOX360)

            // Draw select key with text (enter button)
            spriteBatch.Draw(enterButtonTexture, new Vector2(xOffset, 720 - yOffset - 42), Color.White * TransitionAlpha);

            spriteBatch.DrawString(font, selectText, new Vector2(xOffset + 41, 720 - yOffset - 40), Color.DarkGray * TransitionAlpha, 0,
                                   Vector2.Zero, buttonTextScale, SpriteEffects.None, 0);
            spriteBatch.DrawString(font, selectText, new Vector2(xOffset + 40, 720 - yOffset - 41), Color.White * TransitionAlpha, 0,
                                   Vector2.Zero, buttonTextScale, SpriteEffects.None, 0);

            // Draw back button with text (esc button)
            spriteBatch.Draw(escapeButtonTexture, new Vector2(selectStringSize, 720 - yOffset - 42), Color.White * TransitionAlpha);

            spriteBatch.DrawString(font, backText, new Vector2(selectStringSize + 41, 720 - yOffset - 40), Color.DarkGray * TransitionAlpha, 0,
                                   Vector2.Zero, buttonTextScale, SpriteEffects.None, 0);
            spriteBatch.DrawString(font, backText, new Vector2(selectStringSize + 40, 720 - yOffset - 41), Color.White * TransitionAlpha, 0,
                                   Vector2.Zero, buttonTextScale, SpriteEffects.None, 0);

            if (networkSession.IsHost)
            {
                // Draw change team button with text (z button)
                spriteBatch.Draw(zKeyButtonTexture, new Vector2(backStringSize, 720 - yOffset - 42), Color.White * TransitionAlpha);

                spriteBatch.DrawString(font, changeTeamText, new Vector2(backStringSize + 41, 720 - yOffset - 40), Color.DarkGray * TransitionAlpha, 0,
                                       Vector2.Zero, buttonTextScale, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, changeTeamText, new Vector2(backStringSize + 40, 720 - yOffset - 41), Color.White * TransitionAlpha, 0,
                                       Vector2.Zero, buttonTextScale, SpriteEffects.None, 0);
            }

#endif

#if (XBOX360)

                // Draw select key with text (a button)
            spriteBatch.Draw(aButtonTexture, new Vector2(xOffset, 720 - yOffset - 42), Color.White * TransitionAlpha);

            spriteBatch.DrawString(font, selectText, new Vector2(xOffset + 41, 720 - yOffset - 40), Color.DarkGray * TransitionAlpha, 0,
                                   Vector2.Zero, buttonTextScale, SpriteEffects.None, 0);
            spriteBatch.DrawString(font, selectText, new Vector2(xOffset + 40, 720 - yOffset - 41), Color.White * TransitionAlpha, 0,
                                   Vector2.Zero, buttonTextScale, SpriteEffects.None, 0);

            // Draw back button with text (b button)
            spriteBatch.Draw(bButtonTexture, new Vector2(selectStringSize, 720 - yOffset - 42), Color.White * TransitionAlpha);

            spriteBatch.DrawString(font, backText, new Vector2(selectStringSize + 41, 720 - yOffset - 40), Color.DarkGray * TransitionAlpha, 0,
                                   Vector2.Zero, buttonTextScale, SpriteEffects.None, 0);
            spriteBatch.DrawString(font, backText, new Vector2(selectStringSize + 40, 720 - yOffset - 41), Color.White * TransitionAlpha, 0,
                                   Vector2.Zero, buttonTextScale, SpriteEffects.None, 0);

            if (networkSession.IsHost)
            {
                // Draw change team button with text (y button)
                spriteBatch.Draw(yButtonTexture, new Vector2(backStringSize, 720 - yOffset - 42), Color.White * TransitionAlpha);

                spriteBatch.DrawString(font, changeTeamText, new Vector2(backStringSize + 41, 720 - yOffset - 40), Color.DarkGray * TransitionAlpha, 0,
                                       Vector2.Zero, buttonTextScale, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, changeTeamText, new Vector2(backStringSize + 40, 720 - yOffset - 41), Color.White * TransitionAlpha, 0,
                                       Vector2.Zero, buttonTextScale, SpriteEffects.None, 0);
            }

#endif

            spriteBatch.End();

        } // End of the draw method.

        /// <summary>
        /// Helper draws the gamertag and status icons for a single NetworkGamer.
        /// </summary>
        private void DrawGamer(NetworkGamer gamer, Vector2 gamerTagPosition)
        {
            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
            SpriteFont font = ScreenManager.Font;

            //Vector2 iconWidth = new Vector2(34, 0);
            Vector2 iconOffset = new Vector2(362, 4);

            Vector2 iconPosition = gamerTagPosition + iconOffset;

            // Draw the "is ready" icon.
            if (gamer.IsReady)
            {
                spriteBatch.DrawString(font, "Ready", new Vector2(gamerTagPosition.X + 198, 472), Color.DarkOrange * TransitionAlpha, 0, new Vector2(font.MeasureString("Ready").X / 2, 0), 2f, SpriteEffects.None, 0);
                spriteBatch.DrawString(font, "Ready", new Vector2(gamerTagPosition.X + 198, 470), Color.Yellow * TransitionAlpha, 0, new Vector2(font.MeasureString("Ready").X / 2, 0), 2f, SpriteEffects.None, 0);
            }

            // Draw the "is muted", "is talking", or "has voice" icon.
            if (gamer.IsMutedByLocalUser)
            {
                spriteBatch.Draw(voiceMutedTexture, iconPosition, Color.Red * TransitionAlpha);
            }
            else if (gamer.IsTalking)
            {
                spriteBatch.Draw(isTalkingTexture, iconPosition, Color.Yellow * TransitionAlpha);
            }
            else if (gamer.HasVoice)
            {
                spriteBatch.Draw(hasVoiceTexture, iconPosition, Color.White * TransitionAlpha);
            }

            // Draw the gamertag, normally in white, but yellow for local players.
            string text = gamer.Gamertag;

            // Set the color
            Color color = Color.Yellow;

            // Gray shadow
            spriteBatch.DrawString(font, text, new Vector2(gamerTagPosition.X + 2, gamerTagPosition.Y + 2), Color.DarkGray * TransitionAlpha, 0, Vector2.Zero, 1.5f, SpriteEffects.None, 0);

            // Text
            spriteBatch.DrawString(font, text, gamerTagPosition, color * TransitionAlpha, 0, Vector2.Zero, 1.5f, SpriteEffects.None, 0);

        } // End of the DrawGamer method.

        #endregion

        #region Networking

        /// <summary>
        /// Send a value about the host team.
        /// </summary>
        private void SendHostTeamValue(LocalNetworkGamer server)
        {
            // Set data type, 10: host team value in order
            byte dataType = 10;

            // Write the attacking value to a network packet.
            packetWriter.Write(dataType);
            packetWriter.Write(Program.hostTeam);

            // Send it in order.
            server.SendData(packetWriter, SendDataOptions.InOrder);

        } // End of the SendHostTeamValue method.

        /// <summary>
        /// Send gamer statistics to the other gamers.
        /// </summary>
        private void SendGamerStatistics(LocalNetworkGamer gamer)
        {
            // Set data type, 11: gamer statistics
            byte dataType = 11;

            // Write the attacking value to a network packet.
            packetWriter.Write(dataType);
            packetWriter.Write(Program.mainPlayerStatistics.blueTeamWins);
            packetWriter.Write(Program.mainPlayerStatistics.redTeamWins);

            // Send the data in order.
            gamer.SendData(packetWriter, SendDataOptions.InOrder);

        } // End of the SendGamerStatistics method.

        /// <summary>
        /// Send a value about the host team.
        /// </summary>
        private void SendHostTeamValueReliable(LocalNetworkGamer server)
        {
            // Set data type, 12: host team value reliable.
            byte dataType = 12;

            // Write the attacking value to a network packet.
            packetWriter.Write(dataType);
            packetWriter.Write(Program.hostTeam);

            // Send it reliable because we need to be sure that this packet
            // get to the destination.
            server.SendData(packetWriter, SendDataOptions.InOrder);

            // Mark the server as ready to start the game.
            this.hasUpdatedSettings = true;

        } // End of the SendHostTeamValueReliable method.

        /// <summary>
        /// Get network data from 
        /// </summary>
        /// <param name="gamer"></param>
        private void GetNetworkData(LocalNetworkGamer gamer)
        {

            // Keep reading as long as incoming packets are available.
            while (gamer.IsDataAvailable)
            {
                NetworkGamer sender;

                // Read a single packet from the network.
                gamer.ReceiveData(packetReader, out sender);

                // Do not get our own packages.
                if (!sender.IsLocal)
                {
                    byte dataType = packetReader.ReadByte();

                    // Host team data.
                    if (dataType == 10)
                    {
                        // Read the attacking value from the server.
                        byte hostTeam = packetReader.ReadByte();

                        // Update the attacking team value in the program.
                        Program.hostTeam = hostTeam;
                    }

                    // Gamer statistics.
                    if (dataType == 11)
                    {
                        // Read the data from the package.
                        int blueTeamWins = packetReader.ReadInt32();
                        int redTeamWins = packetReader.ReadInt32();

                        Program.otherPlayerStatistics.blueTeamWins = blueTeamWins;
                        Program.otherPlayerStatistics.redTeamWins = redTeamWins;
                    }
                }
            }

        } // End of the GetNetworkData method.

        /// <summary>
        /// Get a value about the start value for attacking team from the server.
        /// </summary>
        /// <param name="gamer"></param>
        private void GetHostTeamValueReliable(LocalNetworkGamer gamer)
        {

            // Keep reading as long as incoming packets are available.
            while (gamer.IsDataAvailable)
            {
                NetworkGamer sender;

                // Read a single packet from the network.
                gamer.ReceiveData(packetReader, out sender);

                // Do not get our own packages.
                if (!sender.IsLocal)
                {
                    byte dataType = packetReader.ReadByte();

                    // Host team value reliable.
                    if (dataType == 12)
                    {
                        // Read the attacking value from the server.
                        byte hostTeam = packetReader.ReadByte();

                        // Update the attacking team value in the program.
                        Program.hostTeam = hostTeam;

                        // Mark the client as ready to start the game.
                        this.hasUpdatedSettings = true;
                    }
                }
            }

        } // End of the GetHostTeamValueReliable method.

        #endregion

    } // End of class

} // End of namespace
