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.GamerServices;
using StrategicCombat.GameScreens;

namespace StrategicCombat
{
    /// <summary>
    /// This class represent the lobby for a local 2 player game.
    /// </summary>
    public class LocalNetworkLobby : GameScreen
    {
        #region Variables

        // The network session.
        NetworkSession networkSession;

        // Frame background texture.
        Texture2D frameBackgroundTexture;

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

        // Team textures.
        Texture2D teamZeroTexture;
        Texture2D teamOneTexture;

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

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

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

        #endregion

        #region Constructors

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

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

        }

        /// <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 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");

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

        }

        #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)
            {
                if (networkSession.SessionState == NetworkSessionState.Playing)
                {
                   
                    // 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, 1));

                }
                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();
                }
            }
        }

        /// <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)
        {

            // Handle input for each gamer in the network session.
            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);
                }

            }

            // Handle input for all gamers that wants to join this game.
            PlayerIndex NotSignedInPlayerIndex;

            if (input.IsMenuJoinGame(null, out NotSignedInPlayerIndex))
            {
                // First, we need to make sure a suitable gamer profile is signed in.
                ProfileSignInScreen profileSignIn = new ProfileSignInScreen(NetworkSessionType.Local);

                // Hook up an event so once the ProfileSignInScreen is happy.
                profileSignIn.ProfileSignedIn += delegate
                {
                    // Handle the player join event.
                    HandleMenuJoinGame(Gamer.SignedInGamers[NotSignedInPlayerIndex]);

                };

                // Activate the ProfileSignInScreen.
                ScreenManager.AddScreen(profileSignIn, NotSignedInPlayerIndex);

            }  

        } // 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);
            }
        }

        /// <summary>
        /// Handle MenuMenuJoinGame inputs.
        /// </summary>
        private void HandleMenuJoinGame(SignedInGamer gamer)
        {
            // Mark the playerExists flag as false.
            bool playerExists = false;

            // Loop throug each localNetworkGamer in the current network session.
            foreach (LocalNetworkGamer localGamer in networkSession.LocalGamers)
            {
                if (localGamer.Gamertag == gamer.Gamertag)
                {
                    playerExists = true;
                }
            }

            // Add the gamer if he does not exist.
            if (playerExists == false && networkSession.LocalGamers.Count < NetworkSessionComponent.MaxLocalGamers)
            {
                networkSession.AddLocalGamer(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.LocalMultiplayer;

            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 (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 && 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 (LocalNetworkGamer gamer in networkSession.LocalGamers)
            {
                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";
            String joinText = "Join game";
            float selectStringSize = xOffset + 32 + 40 + (font.MeasureString(selectText).X * buttonTextScale) + 5;
            float backStringSize = selectStringSize + 32 + 40 + (font.MeasureString(backText).X * buttonTextScale) + 5;
            float changeTeamSize = backStringSize + 32 + 40 + (font.MeasureString(changeTeamText).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);

            // 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);

            // Draw join button with text (x button)
            spriteBatch.Draw(xKeyButtonTexture, new Vector2(changeTeamSize, 720 - yOffset - 42), Color.White * TransitionAlpha);

            spriteBatch.DrawString(font, joinText, new Vector2(changeTeamSize + 41, 720 - yOffset - 40), Color.DarkGray * TransitionAlpha, 0,
                                   Vector2.Zero, buttonTextScale, SpriteEffects.None, 0);
            spriteBatch.DrawString(font, joinText, new Vector2(changeTeamSize + 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);

            // 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);

            // Draw join button with text (x button)
            spriteBatch.Draw(xButtonTexture, new Vector2(changeTeamSize, 720 - yOffset - 42), Color.White * TransitionAlpha);

            spriteBatch.DrawString(font, joinText, new Vector2(changeTeamSize + 41, 720 - yOffset - 40), Color.DarkGray * TransitionAlpha, 0,
                                   Vector2.Zero, buttonTextScale, SpriteEffects.None, 0);
            spriteBatch.DrawString(font, joinText, new Vector2(changeTeamSize + 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;

            // 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 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

    } // End of class

} // End of namespace
