#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion

namespace GhostArena3D
{
   public class GhostArena3D : Microsoft.Xna.Framework.Game
   {
      #region Fields
      
      private GraphicsDeviceManager graphics;
      
      private ScreenManager screenManager;
      private InputSystem input;
      
      private AudioEngine audio;
      private WaveBank wavebank;
      private SoundBank soundbank;
      
      private DifficultySystem difficultySystem;
      
      private NetworkSession networkSession;
      private AvailableNetworkSessionCollection availableSessions;
      
      #endregion

      #region Properties and Setters
      
      
      public DifficultySystem Difficulty
      {
         get { return difficultySystem; }
      }
      
      
      public SoundBank SoundBank
      {
         get { return soundbank; }
      }


      public NetworkSession NetworkSession
      {
         get { return networkSession; }
      }
      
      
      public AvailableNetworkSessionCollection AvailableSessions
      {
         get { return availableSessions; }
      }


      public void SetDifficulty(int difficulty)
      {
         difficultySystem.SetDifficulty(difficulty);
      }
      
      #endregion

      #region Constructor

      public GhostArena3D()
      {
         graphics = new GraphicsDeviceManager(this);
         Content.RootDirectory = "Content";

         graphics.PreferMultiSampling = true;
         graphics.PreferredBackBufferWidth = 1024;
         graphics.PreferredBackBufferHeight = 768;
         graphics.SynchronizeWithVerticalRetrace = false;
         this.IsFixedTimeStep = false;
         
         Components.Add(new GamerServicesComponent(this));
         
         // Necessary for multi-player.
         SignedInGamer.SignedIn += new EventHandler<SignedInEventArgs>(SignedInGamer_SignedIn);
         
         audio = new AudioEngine("Content/Sounds/GhostArenaGameAudio.xgs");
         wavebank = new WaveBank(audio, "Content/Sounds/Wave Bank.xwb");
         soundbank = new SoundBank(audio, "Content/Sounds/Sound Bank.xsb");
         
         input = new InputSystem(this);
         input.Enabled = false;

         input.AddAction("Move", Control.LeftStick, ActionType.Move, null);
         input.AddAction("Move Foward", Control.DPadUp, ActionType.MoveForward, null);
         input.AddAction("Move Backward", Control.DPadDown, ActionType.MoveBackward, null);
         input.AddAction("Move Left", Control.DPadLeft, ActionType.MoveLeft, null);
         input.AddAction("Move Right", Control.DPadRight, ActionType.MoveRight, null);
         input.AddAction("Fire", Control.RightTrigger, ActionType.Fire, null);
         input.AddAction("Rotate", Control.RightStick, ActionType.Rotate, null);

         Components.Add(input);
         this.Services.AddService(typeof(IInputSystem), input);

         difficultySystem = new DifficultySystem();
         
         screenManager = new ScreenManager(this, graphics);
         Components.Add(screenManager);

         screenManager.AddScreen(new BackgroundScreen());
         screenManager.AddScreen(new MainMenuScreen());
      }
      
      #endregion
      
      #region Networking and Difficulty Related
      
      void SignedInGamer_SignedIn(Object sender, SignedInEventArgs e)
      {
         e.Gamer.Tag = new Player();
         Player player = e.Gamer.Tag as Player;
         
         GamerProfile profile = e.Gamer.GetProfile();
         player.GamerPic = profile.GamerPicture;
         player.GamerTag = e.Gamer.Gamertag;
      }
      
      
      public Player GetSignedInPlayer(PlayerIndex index)
      {
         foreach(SignedInGamer signedInGamer in SignedInGamer.SignedInGamers)
         {
            if(signedInGamer.PlayerIndex == index)
               return (signedInGamer.Tag as Player);
         }
         
         return null;
      }
      
      
      public void CreateSession()
      {
         if(networkSession != null)
            DestroyNetworkSession();

         networkSession = NetworkSession.Create(NetworkSessionType.SystemLink, 1, 2, 0, null);
         
         networkSession.AllowHostMigration = false;
         networkSession.AllowJoinInProgress = false;

         networkSession.GamerJoined += new EventHandler<GamerJoinedEventArgs>(NetworkSession_GamerJoined);
      }


      void NetworkSession_GamerJoined(object sender, GamerJoinedEventArgs e)
      {
         if(e.Gamer.IsLocal == false)
         {
            e.Gamer.Tag = new Player();
            Player player = e.Gamer.Tag as Player;
            player.GamerTag = e.Gamer.Gamertag;
         }
         else
            e.Gamer.Tag = GetLocalPlayer(e.Gamer.Gamertag);
         
         /*Player player = e.Gamer.Tag as Player;
         player.GamerTag = e.Gamer.Gamertag;

         // NOTE: You can't get the gamer picture over Live
         // unless both players are connected to Live it seems.
         // This means two creators club and gold subcriptions
         // just to test.  Because of this we won't display
         // both tags in multiplayer.
         
         // It seems this function will work only for local
         // players or if the player attempting to get the
         // profile is a gold/creators club member.  It is hard
         // to say and the documentation does not mention either
         // way.
         
         if(e.Gamer.IsLocal == true)
         {
            GamerProfile profile = e.Gamer.GetProfile();
            player.GamerPic = profile.GamerPicture;
         }*/
      }
      
      
      Player GetLocalPlayer(string gamerTag)
      {
         foreach(SignedInGamer signedInGamer in SignedInGamer.SignedInGamers)
         {
            if(signedInGamer.Gamertag == gamerTag)
               return (signedInGamer.Tag as Player);
         }
         
         return null;
      }
      
      
      public Player GetFirstNetworkPlayer()
      {
         if(networkSession == null)
            return null;

         return (networkSession.RemoteGamers[0].Tag as Player);
      }
      
      
      public void DestroyNetworkSession()
      {
         if(networkSession != null)
         {
            networkSession.Dispose();
            networkSession = null;
         }
      }
      
      
      public void DestroyAvailableSessions()
      {
         if(availableSessions != null)
         {
            availableSessions.Dispose();
            availableSessions = null;
         }
      }
      
      
      public void SearchForGames()
      {
         availableSessions = NetworkSession.Find(NetworkSessionType.SystemLink, 1, null);
      }
      
      
      public void JoinGame(int game)
      {
         if(networkSession != null)
            DestroyNetworkSession();

         networkSession = NetworkSession.Join(availableSessions[game]);
         networkSession.GamerJoined += new EventHandler<GamerJoinedEventArgs>(NetworkSession_GamerJoined);
         
         DestroyAvailableSessions();
      }

      #endregion
      
      #region Update and Draw


      protected override void Update(GameTime gameTime)
      {
         if(audio != null)
            audio.Update();
         
         if(networkSession != null)
            networkSession.Update();

         base.Update(gameTime);
      }


      protected override void Draw(GameTime gameTime)
      {
         graphics.GraphicsDevice.Clear(Color.Black);

         base.Draw(gameTime);
      }
      
      #endregion
   }
   
   #region Entry
   
   static class Program
   {
      /// <summary>
      /// The main entry point for the application.
      /// </summary>
      static void Main(string[] args)
      {
         using (GhostArena3D game = new GhostArena3D())
         {
            game.Run();
         }
      }
   }
   
   #endregion
}
