using System;
using Microsoft.DirectX;
using Microsoft.DirectX.DirectPlay;


namespace DarkStrideToolbox
{
	//This class is used to manage network traffic.  It handles the parsing and de-parsing of network messages.  Unlike
	//WinSock I don't need to worry about partial or extra message segments so this is really just a glorified array.
	public class DSNetworkPacket
	{
		#region Constants
		private const string m_cPARAM_SEPERATOR = "[°]";
		#endregion

		#region Properties
		//11/09/2004 Chris Hill  You can't use sorted list, it doesn't allow duplicates.
		//private DSSortedList m_oParamaters = new DSSortedList();
		private System.Collections.ArrayList m_oParamaters = new System.Collections.ArrayList();
		private long m_nMsgType = 0;
		private bool m_bSystemMessage = false;
		#endregion


		//This function group is how you create the packet.  You pass in the paramaters you want created.
		public DSNetworkPacket(){}

		public DSNetworkPacket( long nMsgType)
		{
			MsgType = nMsgType;
		}
		public DSNetworkPacket( long nMsgType,string sParam1 )
		{
			const string sRoutineName = "DarkStrideToolbox.NetworkPacket.NetworkPacket";

			try
			{
				MsgType = nMsgType;
				m_oParamaters.Add( sParam1 );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}
		public DSNetworkPacket( long nMsgType,string sParam1,string sParam2 )
		{
			const string sRoutineName = "DarkStrideToolbox.NetworkPacket.NetworkPacket";

			try
			{
				MsgType = nMsgType;
				m_oParamaters.Add( sParam1 );
				m_oParamaters.Add( sParam2 );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}
		public DSNetworkPacket( long nMsgType,string sParam1,string sParam2,string sParam3 )
		{
			const string sRoutineName = "DarkStrideToolbox.NetworkPacket.NetworkPacket";

			try
			{
				MsgType = nMsgType;
				m_oParamaters.Add( sParam1 );
				m_oParamaters.Add( sParam2 );
				m_oParamaters.Add( sParam3 );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}
		public DSNetworkPacket( long nMsgType,string sParam1,string sParam2,string sParam3,string sParam4 )
		{
			const string sRoutineName = "DarkStrideToolbox.NetworkPacket.NetworkPacket";

			try
			{
				MsgType = nMsgType;
				m_oParamaters.Add( sParam1 );
				m_oParamaters.Add( sParam2 );
				m_oParamaters.Add( sParam3 );
				m_oParamaters.Add( sParam4 );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}
		public DSNetworkPacket( long nMsgType,string sParam1,string sParam2,string sParam3,string sParam4,string sParam5 )
		{
			const string sRoutineName = "DarkStrideToolbox.NetworkPacket.NetworkPacket";

			try
			{
				MsgType = nMsgType;
				m_oParamaters.Add( sParam1 );
				m_oParamaters.Add( sParam2 );
				m_oParamaters.Add( sParam3 );
				m_oParamaters.Add( sParam4 );
				m_oParamaters.Add( sParam5 );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}
		public DSNetworkPacket( long nMsgType,string[] saParams )
		{
			const string sRoutineName = "DarkStrideToolbox.NetworkPacket.NetworkPacket";

			try
			{
				MsgType = nMsgType;

				for( int i=0 ; i<saParams.GetLength(0) ; i++ )
				{
					m_oParamaters.Add( saParams[ i ] );
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}

		public DSNetworkPacket( ReceiveEventArgs oPacket )
		{
			const string sRoutineName = "DarkStrideToolbox.NetworkPacket.NetworkPacket";

			try
			{
				ParsePacket( oPacket );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}


		//This function breaks apart the arguments passed in and seperates them out into the perspective arguments.
		public void ParsePacket( ReceiveEventArgs e )
		{
			const string sRoutineName = "DarkStrideToolbox.NetworkPacket.ParsePacket";
			string sMsg = "";

			try
			{
				/*//packets can't be stored, their internals get dropped.  Need to clone the packet somehow 
				//into a storage object		
				Microsoft.DirectX.DirectPlay.ReceiveMessage oRM = e.Message;
				Microsoft.DirectX.DirectPlay.NetworkPacket oNP = oRM.ReceiveData;
				sMsg = oNP.ReadString();*/

				sMsg = e.Message.ReceiveData.ReadString();
				ParsePacket( sMsg );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}

		public long ParsePacket( string sMessage )
		{
			const string sRoutineName = "DarkStrideToolbox.NetworkPacket.ParsePacket";
			long i = 0;
			string[] saParamaters = null;
			long nMsgType = 0;

			try
			{
				saParamaters = DSMisc.Split( sMessage,m_cPARAM_SEPERATOR );
			
				if( saParamaters.Length == 0 )
				{
					this.MsgType = 0;
					throw new MissingFieldException( "This packet contains no paramaters and no packet type" );
				}
				else
				{
					this.MsgType = Convert.ToInt64( saParamaters[ 0 ] );
					this.SystemMessage = Convert.ToBoolean( saParamaters[ 1 ] );
					for( i=2 ; i<saParamaters.Length-1 ; i++ )
					{
						m_oParamaters.Add( saParamaters[ i ] );
					}
				}

				nMsgType = this.MsgType;
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
			return( nMsgType );
		}


		//This function returns a system network packet from the arguments in this class.  This packet is in theory ready
		//to be sent over the network to whoever we are talking to.
		public Microsoft.DirectX.DirectPlay.NetworkPacket GetPacket()
		{
			const string sRoutineName = "DarkStrideToolbox.NetworkPacket.GetPacket";
			string sMsg = "";
			Microsoft.DirectX.DirectPlay.NetworkPacket oPacket = null;

			try
			{
				oPacket = new Microsoft.DirectX.DirectPlay.NetworkPacket();

				//Get our message string
				sMsg = MsgType + m_cPARAM_SEPERATOR + 
					   m_bSystemMessage.ToString() + m_cPARAM_SEPERATOR;
				for( int i=0 ; i<m_oParamaters.Count ; i++ )
				{
					sMsg += Convert.ToString( m_oParamaters[ i ] ) + m_cPARAM_SEPERATOR;
				}

				oPacket.Write( sMsg );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
			return( oPacket );
		}


		//These functions manipulate the paramaters in the class.  
		public string GetParamater( long nIndex )
		{
			const string sRoutineName = "DarkStrideToolbox.NetworkPacket.GetParamater";
			string sRetVal = "";

			try
			{
				sRetVal = Convert.ToString( m_oParamaters[ (int)nIndex ] );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
			return( sRetVal );
		}

		public void AddParamater( string sValue )
		{
			const string sRoutineName = "DarkStrideToolbox.NetworkPacket.AddParamater";

			try
			{
				if( sValue.IndexOf( m_cPARAM_SEPERATOR ) > -1 )
				{
					throw new SystemException( "Paramater passed in contains an illegal string, " + m_cPARAM_SEPERATOR );
				}
				else
				{
					m_oParamaters.Add( sValue );
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}



		#region Properties
		public long ParamaterCount
		{
			get
			{
				return( m_oParamaters.Count );
			}
		}

		public long MsgType
		{
			get
			{
				return( m_nMsgType );
			}
			set
			{
				m_nMsgType = value;
			}
		}

		public bool SystemMessage
		{
			get
			{
				return( m_bSystemMessage );
			}
			set
			{
				m_bSystemMessage = value;
			}
		}
		#endregion
	}
}
