using System;

using Microsoft.DirectX.DirectPlay;


namespace DarkStrideToolbox
{
	public enum BufferedNetworkEventTypes
	{
		enumPlayerJoined		= 0,
		enumPlayerQuit			= 1,
		enumHostMigrated		= 2,
		enumDataReceived		= 3,
		enumSessionTerminated	= 4,
		enumConnection			= 5,
		enumGameListUpdate		= 6,
		enumCanceledGameSearch	= 7
	};
	public class BufferedNetworkEvent
	{
		public BufferedNetworkEventTypes nEvent;
		public object[] oVariables;
	};

	public class DSNetworkBuffered : DSNetworkWrapper
	{
		#region Properties
		private System.Collections.ArrayList m_oEvents = new System.Collections.ArrayList();

		private bool m_bIWillBeHostEventually = true;
		#endregion


		public DSNetworkBuffered()
		{
		}


		public override void HostGame( ServiceProviderInformation oServiceProvider, Guid oAppGuid, string sSessionName, string sMyPlayerName,int nPort )
		{
			m_bIWillBeHostEventually = true;
            base.HostGame( oServiceProvider,oAppGuid,sSessionName,sMyPlayerName,nPort );
		}

		public override void JoinGame( FindHostsResponseInformation oGame,string sMyPlayerName )
		{
			m_bIWillBeHostEventually = false;
            base.JoinGame( oGame,sMyPlayerName );
		}

		public virtual void ProccessBufferedEvents()
		{
			BufferedNetworkEvent oEvent = null;


			while( m_oEvents.Count > 0 )
			{
				lock( m_oEvents )
				{
					if( m_oEvents.Count > 0 )
					{
						oEvent = (BufferedNetworkEvent)m_oEvents[ 0 ];
						m_oEvents.RemoveAt( 0 );
					}
					else
					{
						break;
					}
				}

				if( oEvent.nEvent == BufferedNetworkEventTypes.enumPlayerJoined )
				{
					base.PlayerJoined( null,(Microsoft.DirectX.DirectPlay.PlayerCreatedEventArgs)oEvent.oVariables[ 0 ] );
				}
				else if( oEvent.nEvent == BufferedNetworkEventTypes.enumPlayerQuit )
				{
					base.PlayerQuit( null,(Microsoft.DirectX.DirectPlay.PlayerDestroyedEventArgs)oEvent.oVariables[ 0 ] );
				}
				else if( oEvent.nEvent == BufferedNetworkEventTypes.enumHostMigrated )
				{
					base.HostMigrated( null,(Microsoft.DirectX.DirectPlay.HostMigratedEventArgs)oEvent.oVariables[ 0 ] );
				}
				else if( oEvent.nEvent == BufferedNetworkEventTypes.enumDataReceived )
				{
					base.DataReceived( (int)oEvent.oVariables[ 0 ],(DSNetworkPacket)oEvent.oVariables[ 1 ] );
				}
				else if( oEvent.nEvent == BufferedNetworkEventTypes.enumSessionTerminated )
				{
					base.SessionTerminated( null,(Microsoft.DirectX.DirectPlay.SessionTerminatedEventArgs)oEvent.oVariables[ 0 ] );
				}
				else if( oEvent.nEvent == BufferedNetworkEventTypes.enumConnection )
				{
					base.Connection( (Microsoft.DirectX.DirectPlay.ResultCode)oEvent.oVariables[ 0 ],(string)oEvent.oVariables[ 1 ],(bool)oEvent.oVariables[ 2 ] );
				}
				else if( oEvent.nEvent == BufferedNetworkEventTypes.enumGameListUpdate )
				{
					base.GameListUpdate( (DarkStrideToolbox.FindHostsResponseInformation)oEvent.oVariables[ 0 ] );
				}
				else if( oEvent.nEvent == BufferedNetworkEventTypes.enumCanceledGameSearch )
				{
					base.CanceledGameSearch();
				}
			}
		}


		public override void PlayerJoined(object sender, PlayerCreatedEventArgs e)
		{
			BufferedNetworkEvent oNewEvent = null;

			oNewEvent = GetNewEvent( BufferedNetworkEventTypes.enumPlayerJoined );
			oNewEvent.oVariables[ 0 ] = e;

			AddEvent( oNewEvent );
		}

		public override void PlayerQuit(object sender, PlayerDestroyedEventArgs e)
		{
			BufferedNetworkEvent oNewEvent = null;

			oNewEvent = GetNewEvent( BufferedNetworkEventTypes.enumPlayerQuit );
			oNewEvent.oVariables[ 0 ] = e;

			AddEvent( oNewEvent );
		}

		public override void HostMigrated(object sender, HostMigratedEventArgs e)
		{
			BufferedNetworkEvent oNewEvent = null;

			oNewEvent = GetNewEvent( BufferedNetworkEventTypes.enumHostMigrated );
			oNewEvent.oVariables[ 0 ] = e;

			AddEvent( oNewEvent );
		}

		public override void DataReceived(object sender, ReceiveEventArgs e)
		{
			DSNetworkPacket oPacket = null;
			BufferedNetworkEvent oNewEvent = null;

			oNewEvent = GetNewEvent( BufferedNetworkEventTypes.enumDataReceived );
			oPacket = new DSNetworkPacket( e );
			oNewEvent.oVariables[ 0 ] = e.Message.SenderID;
			oNewEvent.oVariables[ 1 ] = oPacket;

			AddEvent( oNewEvent );
		}

		public override void SessionTerminated(object sender, SessionTerminatedEventArgs e)
		{
			BufferedNetworkEvent oNewEvent = null;

			oNewEvent = GetNewEvent( BufferedNetworkEventTypes.enumSessionTerminated );
			oNewEvent.oVariables[ 0 ] = e;

			AddEvent( oNewEvent );
		}
		
		public override void Connection( Microsoft.DirectX.DirectPlay.ResultCode oCode,string sDescription,bool bConnectionSuccessful )
		{
			BufferedNetworkEvent oNewEvent = null;

			oNewEvent = GetNewEvent( BufferedNetworkEventTypes.enumConnection );
			oNewEvent.oVariables[ 0 ] = oCode;
			oNewEvent.oVariables[ 1 ] = sDescription;
			oNewEvent.oVariables[ 2 ] = bConnectionSuccessful;

			AddEvent( oNewEvent );
		}
		public override void GameListUpdate( FindHostsResponseInformation oGameInfo )
		{
			BufferedNetworkEvent oNewEvent = null;

			oNewEvent = GetNewEvent( BufferedNetworkEventTypes.enumGameListUpdate );
			oNewEvent.oVariables[ 0 ] = oGameInfo;

			AddEvent( oNewEvent );
		}
		public override void CanceledGameSearch()
		{
			BufferedNetworkEvent oNewEvent = null;

			oNewEvent = GetNewEvent( BufferedNetworkEventTypes.enumCanceledGameSearch );

			AddEvent( oNewEvent );
		}


		private BufferedNetworkEvent GetNewEvent( BufferedNetworkEventTypes eType )
		{
			BufferedNetworkEvent oNewEvent = null;


			oNewEvent = new BufferedNetworkEvent();
			oNewEvent.nEvent = eType;
			oNewEvent.oVariables = new object[ 3 ];


			return( oNewEvent );
		}

		private void AddEvent( BufferedNetworkEvent oNewEvent )
		{
			lock( m_oEvents )
			{
				m_oEvents.Add( oNewEvent );
			}
		}



		#region Properties
		public override bool IAmTheHost
		{
			get
			{
				bool bAmTheHost = ( base.Me != null && base.Me.IAmHost ) || m_bIWillBeHostEventually == true;
				return( bAmTheHost );
			}
		}
		#endregion 
	}
}
