using System;
using System.Text;
using System.Collections;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;

using System.Runtime;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX.DirectPlay;
using Microsoft.DirectX.DirectInput;

using System.Threading;
using System.Net;


namespace DarkStrideToolbox
{
	//This class holds some random functions that didn't fit anywhere else.  Their are too few string minipulation functions
	//to bother with a string class.  And the random stuff doesn't really belong in the math class.  So its a miscilanious
	//collection of any thing that doesn't fit anywhere else!  :)
	[Serializable]
	public class DSMisc
	{
		#region Properties
		//Used for GetRnd
		private static Random m_oRand = null;
		private static long m_nLastRandomTick;
		#endregion


		public DSMisc(){}


		[System.Security.SuppressUnmanagedCodeSecurity]//We won't use this maliciously
		[DllImport("kernel32")]
		public static extern bool QueryPerformanceCounter( ref long nPerformanceCount );
		public static long GetQueryPerformanceCounter()
		{
			long nPerformanceCount = 0;

			if( QueryPerformanceCounter( ref nPerformanceCount ) == false )
			{
				throw new System.Exception( "Error:  Unable to process QueryPerformanceCounter." );
			}

			return( nPerformanceCount );
		}
		[System.Security.SuppressUnmanagedCodeSecurity]//We won't use this maliciously
		[DllImport("kernel32")]
		public static extern bool QueryPerformanceFrequency( ref long nPerformanceFrequency );
		public static long GetQueryPerformanceFrequency()
		{
			long nPerformanceFrequency = 0;

			if( QueryPerformanceFrequency( ref nPerformanceFrequency ) == false )
			{
				throw new System.Exception( "Error:  Unable to process QueryPerformanceFrequency." );
			}

			return( nPerformanceFrequency );
		}


		//Get a random number from the classes random number generator.  
		public static int GetRnd( int nLow, int nHigh )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.GetRnd";			
			int nValue = 0;

			try
			{
				//Init the random generator if it hasn't been yet.
				InitializeRandomGenerator();

				//Return the value we've generated.
				if( nLow > nHigh )
				{
					nValue = m_oRand.Next( nHigh,nLow-1 );
				}
				else
				{
					nValue = m_oRand.Next( nLow, nHigh+1 );
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
			return( nValue );
		}
		public static double GetRnd( double nLow, double nHigh )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.GetRnd";			
			double nValue = 0;
			double nDiff = 0;

			try
			{
				//Init the random generator if it hasn't been yet.
				InitializeRandomGenerator();

				//Return the value we've generated.
				if( nLow < 0 && nHigh >= 0 )
				{
					nDiff = ( nLow * -1 ) + nHigh;
					nValue = DSMisc.GetRnd();
					nValue = nValue * nDiff + nLow;
				}
				else if( nLow >= 0 && nHigh < 0 )
				{
					nDiff = ( nHigh * -1 ) + nLow;
					nValue = DSMisc.GetRnd();
					nValue = nValue * nDiff + nHigh;
				}
				else if( nLow > nHigh)
				{
					nDiff = nLow - nHigh;
					nValue = DSMisc.GetRnd();
					nValue = nValue * nDiff + nHigh;
				}
				else if( nHigh >= nLow )
				{
					nDiff = nHigh - nLow;
					nValue = DSMisc.GetRnd();
					nValue = nValue * nDiff + nLow;
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
			return( nValue );
		}
		public static double GetRnd()
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.GetRnd";			
			double nValue = 0;

			try
			{
				//Init the random generator if it hasn't been yet.
				InitializeRandomGenerator();

				//Return the value we've generated.
				nValue = m_oRand.NextDouble();
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
			return( nValue );
		}

		private static void InitializeRandomGenerator()
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.InitializeRandomGenerator";			
			int nNewTick = 0;

			try
			{
				if( m_oRand == null )
				{
					nNewTick = (int)DateTime.Now.Ticks;
					//If these two numbers are the same it means were in a tight loop thats being called faster than the
					//milisecond ticks variable is changing.  To address this we will artifically incrament teh tick 
					//counter by one and use that.
					if( m_nLastRandomTick == nNewTick )
					{
						nNewTick += 1;
					}
					m_nLastRandomTick = nNewTick;

					//Now initialize our random number generator.
					m_oRand = new Random( (int)nNewTick );
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}

		
		//This function mimics a VB function I fell in love with.  It splits a string automatically.  C# has such a function
		//but its irritatingly limited to only spliting on characters not full strings.
		public static string Join( string[] saPeices,string sDelimiter )
		{
			string sRetVal = "";


			for( int i=0 ; i<saPeices.Length ; i++ )
			{
				if( sRetVal.Length > 0 )
				{
					sRetVal += sDelimiter;
				}
				sRetVal += saPeices[ i ];
			}


			return( sRetVal );
		}
		public static string[] Split( String sSource,String sDelimiter )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.Split";
			ArrayList oParts = new ArrayList();
			string sTempIn = sSource;
			string[] saRetVal = null;
			string sTemp;
			long nLen = 0;
			int i = 0;			
			
			try
			{
				if( sTempIn == null )
				{
					saRetVal = new string[ 0 ];
				}
					//12/13/2004 Chris Hill  If their are no items in the list we still need to
					//return a string array with one string in it.
				else if( sTempIn.IndexOf( sDelimiter ) == -1 )
				{
					saRetVal = new string[ 1 ];
					saRetVal[ 0 ] = sTempIn;
				}
				else
				{
					while( sTempIn.IndexOf( sDelimiter ) > -1 )
					{
						sTemp = sTempIn.Substring( 0, sTempIn.IndexOf( sDelimiter ) );
						sTempIn = sTempIn.Substring( sTempIn.IndexOf( sDelimiter )+sDelimiter.Length );

						oParts.Add( sTemp );

						//In case that was the last delimiter, add the remainder into the properties list.
						if( sTempIn.IndexOf( sDelimiter ) == -1 )
						{
							oParts.Add( sTempIn );
						}
					}

					nLen = oParts.Count;
					saRetVal = new string[ nLen ];

					for( i=0 ; i<nLen ; i++ )
					{
						saRetVal[ i ] = (string)oParts[ i ];
					}
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
			return( saRetVal );
		}


		//04/24/2003 Chris Hill  This function returns a string ~32 chars long that simulates a microsoft 
		//GUID (Globally Unique ID).  Why not use the real MS GUID?  Because then I don't get info like when
		//it was created and what it is from (i.e. the preface).
		public static string GetGUID( string sPreface )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.GetGUID";
			string sNewGUID = "";
			System.Guid oGUID;
			DateTime dtNow = DateTime.Now;

			try
			{
				oGUID = System.Guid.NewGuid(); 
				sNewGUID = sPreface + oGUID.ToString();

				/*sNewGUID = "<" + 
							sPreface + "_" + 
							dtNow.Month + "/" + dtNow.Day + "/" + dtNow.Year + "_" + 
							dtNow.Hour + ":" + dtNow.Minute + ":" + dtNow.Second + "." + dtNow.Millisecond + "_" + 
							GetRnd( 0,10000 ) +
							">";*/
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
			return( sNewGUID );
		}
		public static string GetGUID()
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.GetGUID";
			string sNewGUID = "";

			try
			{
				sNewGUID = GetGUID( "" );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
			return( sNewGUID );
		}


		//This function returns a file name of the users choosing.
		public static string OpenFile( string sFilters,string sFileName,string sPath,string sTitle )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.OpenFile";
			System.Windows.Forms.OpenFileDialog oFileDialog = null;
			System.IO.FileInfo oFileInfo = null;
			string sRetFileName = "";

			try
			{
				//Display the OpenFileName dialog. Then, try to load the specified file
				oFileDialog = new OpenFileDialog();

				oFileDialog.Filter = sFilters;
				oFileDialog.FileName = sFileName;
				oFileDialog.InitialDirectory = sPath;
				oFileDialog.Title = sTitle;
				oFileDialog.CheckFileExists = true;
				oFileDialog.Multiselect = false;
				oFileDialog.ShowReadOnly = false;
				oFileDialog.ShowDialog();

				oFileInfo = new System.IO.FileInfo( oFileDialog.FileName );
				sRetFileName = oFileInfo.Name;
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
			return( sRetFileName );
		}
		public static string OpenFile( string sFilters,string sFileName,string sPath )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.OpenFile";
			string sRetFileName = "";

			try
			{
				sRetFileName = OpenFile( sFilters,sFileName,sPath,"Open File" );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
			return( sRetFileName );
		}

		public static MemoryStream GetMemStreamFromFile( string sFileName )
		{
			byte[] oFile = null;
			FileStream oFileStream = null;
			BinaryReader oBinaryReader = null;
			MemoryStream oMemoryStream = null;
			OpenFileDialog oOpenFileDialog = new OpenFileDialog();


			//Open the file.
			oFileStream = new FileStream( sFileName, FileMode.Open );
			//Create a BinaryReader on the file.
			oBinaryReader = new BinaryReader( oFileStream );
			//Read the contents of the file into the array.
			oFile = oBinaryReader.ReadBytes( Convert.ToInt32( oFileStream.Length ) );

			//Clean up the streams
			oFileStream.Close();
			oBinaryReader.Close();

			//Get a memory stream
			oMemoryStream = new MemoryStream();
			oMemoryStream.Write( oFile,0,oFile.Length );
				
			return( oMemoryStream );
		}


		//02/14/2007 Chris Hill  These handy one line file functions are quick and easy.
		public static string GetFile( string sFileName )
		{
			StreamReader oStream = null;
			string sLine = "";


			//Open the file and parse it!
			oStream = new StreamReader( sFileName );
			//Read in the header information
			sLine = oStream.ReadToEnd();
			oStream.Close();


			return( sLine );
		}

		public static void PutFile( string sFileName,string sFileContents )
		{
			DSMisc.WriteToDebugFile( sFileName,true,false,0,sFileContents );
		}
		public static string GetBinaryFile( string sFileName )
		{
			FileStream oFileStream = new FileStream( sFileName,FileMode.Open );
			BinaryReader oBinaryStream = new BinaryReader( oFileStream );
			string sRetVal = "";


			sRetVal = oBinaryStream.ReadString();

			oBinaryStream.Close();
			oFileStream.Close();


			return( sRetVal );
		}
		
		public static void PutBinaryFile( string sFileName,string sFileContents )
		{
			FileStream oFileStream = null;
			BinaryWriter oBinaryStream = null;


			oFileStream = new FileStream( sFileName,FileMode.Create );

			oBinaryStream = new BinaryWriter( oFileStream );
			oBinaryStream.Write( sFileContents );

			oBinaryStream.Close();
			oFileStream.Close();
		}
		

		//07/08/2006 Chris Hill  Check if the file exists.  Since this function
		public static bool FileExists( string sFileName )
		{
			/*StreamReader oStream = null;
			bool bFileExists = false;


			try
			{
				//Open the file and parse it!
				oStream = new StreamReader( sFileName );

				bFileExists = true;
			}
			catch
			{
			}
			finally
			{
				if( oStream != null )
				{
					oStream.Close();
				}
			}


			return( bFileExists );*/
			return( System.IO.File.Exists( sFileName ) );
		}


		//Counts how many times a certain character is in a string
		public static int NumberOfInstances( string sSource,string sSearchFor )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.NumberOfInstances";
			int nNumInstFound = 0;
			int nPos = 0;

			try
			{
				nPos = sSource.IndexOf( sSearchFor,0 );
				while( nPos >= 0 )
				{
					nNumInstFound++;
					nPos = sSource.IndexOf( sSearchFor,nPos+1 );
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
			return( nNumInstFound );
		}

		//02/26/2006 Chris Hill  I need to tell if a string has a number in it.
		public static bool IsNumericLong( string sSource )
		{
			long nResult = 0;


			try
			{
				nResult = Convert.ToInt64( sSource );
				return( true );
			}
			catch
			{
				return( false );
			}
		}
		public static bool IsNumericDouble( string sSource )
		{
			double nResult = 0;


			try
			{
				nResult = Convert.ToDouble( sSource );
				return( true );
			}
			catch
			{
				return( false );
			}
		}


		//This function is allot like substring... so why have it?  Because Left, unlike substring can handle strings
		//that aren't long enough.  This is of course a carryover from the old VB left function.
		public static string Left( string sSource,int nNum )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.Left";
			string sRetVal = "";

			try
			{
				if( sSource.Length < nNum )
				{
					sRetVal = sSource;
				}
				else
				{
					sRetVal = sSource.Substring( 0,nNum );
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( sRetVal );
		}

		//02/27/2006 Chris Hill  this epeats a string a certain number of times
		public static string Repeat( string sSource,int nNum )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.Repeat";
			string sRetVal = "";

			try
			{
				sRetVal = DSMisc.Repeat( sSource,(long)nNum );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( sRetVal );
		}

		public static string Repeat( string sSource,long nNum )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.Repeat";
			string sRetVal = "";

			try
			{
				for( int i=0 ; i<nNum ; i++ )
				{
					sRetVal += sSource;
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( sRetVal );
		}


		//This function walks the recursive list of errors and displays them all
		public static void ShowErrors( System.Exception oError )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.ShowErrors";	
			System.Exception oInner = oError.InnerException;
			string sErrors = "";
			long nCount = 2;

			try
			{
				sErrors = "1.)   " + oError.Message;
				while( oInner != null )
				{
					sErrors += "\n" + nCount.ToString() + ".)   " + oInner.Message;

					if( oInner.StackTrace != null )
					{
						sErrors += "\n" + oInner.StackTrace;
					}

					nCount++;
					oInner = oInner.InnerException;
				}

				sErrors += "\n" + oError.StackTrace;

				MessageBox.Show( sErrors,"Error Stack" );
			}
			catch( System.Exception oEx )
			{
				MessageBox.Show( "Critical Error In <" + sRoutineName + ">.  " + oEx.Message );
			}
		}


		//Merge our changes together and return a combined exception list
		public static System.Exception MergeErrors( System.Exception oErrors1,System.Exception oErrors2 )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.MergeErrors";	
			System.Exception oNewErrors = null;
			System.Exception oInnermostError = null;
			ArrayList oErrorMessages = new ArrayList();

			try
			{
				if( oErrors2 != null )
				{
					oNewErrors = new System.Exception( oErrors2.Message,oErrors2.InnerException );
				}

				if( oErrors1 != null )
				{
					oInnermostError = oErrors1.InnerException;
					oErrorMessages.Add( oErrors1.Message );
					if( oInnermostError != null )
					{
						while( oInnermostError.InnerException != null )
						{		
							oErrorMessages.Add( oInnermostError.Message );				
							oInnermostError = oInnermostError.InnerException;
						}
						oErrorMessages.Add( oInnermostError.Message );
					}

					for( int i=oErrorMessages.Count-1 ; i>=0 ; i-- )
					{
						oNewErrors = new System.Exception( (string)oErrorMessages[ i ],oNewErrors );
					}
				}
			}
			catch( System.Exception oEx )
			{
				MessageBox.Show( "Critical Error In <" + sRoutineName + ">.  " + oEx.Message );
			}
			return( oNewErrors );
		}
		

		//This function returns the current working path.  It won't be needed once we are out of development

		public static string GetDevelopmentAppPath()
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.GetDevelopmentAppPath";	
			string sCurPath = "";
			string[] saParamaters = null;
			int nPos = 0;

			try
			{
				//sCurPath = Environment.CurrentDirectory;
				saParamaters= Environment.GetCommandLineArgs();
				sCurPath = saParamaters[ 0 ];
				nPos = sCurPath.LastIndexOf( @"\" );
				if( nPos > -1 )
				{
					sCurPath = sCurPath.Substring( 0,nPos );
				}

				//If we are in debug mode then we want to backup two directories so that
				//we can use whats in the project directory.

				if( System.Diagnostics.Debugger.IsAttached == true )
				{
					//This would be enough... except we don't want to use
					//				C:\Src\LegacyRealm\Bin\Debug
					//We want to use 
					//				C:\Src\LegacyRealm
					//So strip off the last two parts
					nPos = sCurPath.LastIndexOf( @"\bin\" );
					if( nPos > -1 )
					{
						sCurPath = sCurPath.Substring( 0,nPos );
					}
				}

				sCurPath += @"\";
			}
			catch( System.Exception oEx )
			{
				DSMisc.ShowErrors( new System.Exception( sRoutineName + " Failed.",oEx ) );
			}
			return( sCurPath );
		}


		//Chris Not Done
		//public static string KeyToStringModifier( string sSource,Key oKey,KeyboardState oState,ref int nPos )		
		/*
		 Delete  
		Back  
		Right  
		Left  
		PageDown  
		DownArrow  
		RightArrow  
		LeftArrow  
		PageUp  
		UpArrow  
		BackSpace  
		Down  
		End  
		Up  
		 * */
		public static bool IsAlphaKey( Key oKey )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.KeyToStringModifier";
			bool bRetVal = false;

			try
			{
				if( oKey == Key.A ){ bRetVal = true; }
				else if( oKey == Key.B ){ bRetVal = true; }
				else if( oKey == Key.C ){ bRetVal = true; }
				else if( oKey == Key.D ){ bRetVal = true; }
				else if( oKey == Key.E ){ bRetVal = true; }
				else if( oKey == Key.F ){ bRetVal = true; }
				else if( oKey == Key.G ){ bRetVal = true; }
				else if( oKey == Key.H ){ bRetVal = true; }
				else if( oKey == Key.I ){ bRetVal = true; }
				else if( oKey == Key.J ){ bRetVal = true; }
				else if( oKey == Key.K ){ bRetVal = true; }
				else if( oKey == Key.L ){ bRetVal = true; }
				else if( oKey == Key.M ){ bRetVal = true; }
				else if( oKey == Key.N ){ bRetVal = true; }
				else if( oKey == Key.O ){ bRetVal = true; }
				else if( oKey == Key.P ){ bRetVal = true; }
				else if( oKey == Key.Q ){ bRetVal = true; }
				else if( oKey == Key.R ){ bRetVal = true; }
				else if( oKey == Key.S ){ bRetVal = true; }
				else if( oKey == Key.T ){ bRetVal = true; }
				else if( oKey == Key.U ){ bRetVal = true; }
				else if( oKey == Key.V ){ bRetVal = true; }
				else if( oKey == Key.W ){ bRetVal = true; }
				else if( oKey == Key.X ){ bRetVal = true; }
				else if( oKey == Key.Y ){ bRetVal = true; }
				else if( oKey == Key.Z ){ bRetVal = true; }

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

			return( bRetVal );
		}
		public static bool IsNumericKey( Key oKey )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.KeyToStringModifier";
			bool bRetVal = false;

			try
			{
				if( oKey == Key.D0 ){ bRetVal = true; }
				else if( oKey == Key.D1 ){ bRetVal = true; }
				else if( oKey == Key.D2 ){ bRetVal = true; }
				else if( oKey == Key.D3 ){ bRetVal = true; }
				else if( oKey == Key.D4 ){ bRetVal = true; }
				else if( oKey == Key.D5 ){ bRetVal = true; }
				else if( oKey == Key.D6 ){ bRetVal = true; }
				else if( oKey == Key.D7 ){ bRetVal = true; }
				else if( oKey == Key.D8 ){ bRetVal = true; }
				else if( oKey == Key.D9 ){ bRetVal = true; }
				else if( oKey == Key.NumPad0 ){ bRetVal = true; }
				else if( oKey == Key.NumPad3 ){ bRetVal = true; }
				else if( oKey == Key.NumPad2 ){ bRetVal = true; }
				else if( oKey == Key.NumPad1 ){ bRetVal = true; }
				else if( oKey == Key.NumPad6 ){ bRetVal = true; }
				else if( oKey == Key.NumPad5 ){ bRetVal = true; }
				else if( oKey == Key.NumPad4 ){ bRetVal = true; }
				else if( oKey == Key.NumPad9 ){ bRetVal = true; }
				else if( oKey == Key.NumPad8 ){ bRetVal = true; }
				else if( oKey == Key.NumPad7 ){ bRetVal = true; }
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( bRetVal );
		}
		public static bool IsNumPadNumericKey( Key oKey )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.IsNumPadNumericKey";
			bool bRetVal = false;

			try
			{
				if( oKey == Key.NumPad0 ){ bRetVal = true; }
				else if( oKey == Key.NumPad3 ){ bRetVal = true; }
				else if( oKey == Key.NumPad2 ){ bRetVal = true; }
				else if( oKey == Key.NumPad1 ){ bRetVal = true; }
				else if( oKey == Key.NumPad6 ){ bRetVal = true; }
				else if( oKey == Key.NumPad5 ){ bRetVal = true; }
				else if( oKey == Key.NumPad4 ){ bRetVal = true; }
				else if( oKey == Key.NumPad9 ){ bRetVal = true; }
				else if( oKey == Key.NumPad8 ){ bRetVal = true; }
				else if( oKey == Key.NumPad7 ){ bRetVal = true; }
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( bRetVal );
		}
		public static string KeyToChar( Key oKey )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.KeyToChar";
			string sRetVal = "";

			try
			{
				//Alpha
				if( oKey == Key.A ){ sRetVal = "A"; }
				else if( oKey == Key.B ){ sRetVal = "B"; }
				else if( oKey == Key.C ){ sRetVal = "C"; }
				else if( oKey == Key.D ){ sRetVal = "D"; }
				else if( oKey == Key.E ){ sRetVal = "E"; }
				else if( oKey == Key.F ){ sRetVal = "F"; }
				else if( oKey == Key.G ){ sRetVal = "G"; }
				else if( oKey == Key.H ){ sRetVal = "H"; }
				else if( oKey == Key.I ){ sRetVal = "I"; }
				else if( oKey == Key.J ){ sRetVal = "J"; }
				else if( oKey == Key.K ){ sRetVal = "K"; }
				else if( oKey == Key.L ){ sRetVal = "L"; }
				else if( oKey == Key.M ){ sRetVal = "M"; }
				else if( oKey == Key.N ){ sRetVal = "N"; }
				else if( oKey == Key.O ){ sRetVal = "O"; }
				else if( oKey == Key.P ){ sRetVal = "P"; }
				else if( oKey == Key.Q ){ sRetVal = "Q"; }
				else if( oKey == Key.R ){ sRetVal = "R"; }
				else if( oKey == Key.S ){ sRetVal = "S"; }
				else if( oKey == Key.T ){ sRetVal = "T"; }
				else if( oKey == Key.U ){ sRetVal = "U"; }
				else if( oKey == Key.V ){ sRetVal = "V"; }
				else if( oKey == Key.W ){ sRetVal = "W"; }
				else if( oKey == Key.X ){ sRetVal = "X"; }
				else if( oKey == Key.Y ){ sRetVal = "Y"; }
				else if( oKey == Key.Z ){ sRetVal = "Z"; }

					//Numeric
				else if( oKey == Key.D0 ){ sRetVal = "0"; }
				else if( oKey == Key.D1 ){ sRetVal = "1"; }
				else if( oKey == Key.D2 ){ sRetVal = "2"; }
				else if( oKey == Key.D3 ){ sRetVal = "3"; }
				else if( oKey == Key.D4 ){ sRetVal = "4"; }
				else if( oKey == Key.D5 ){ sRetVal = "5"; }
				else if( oKey == Key.D6 ){ sRetVal = "6"; }
				else if( oKey == Key.D7 ){ sRetVal = "7"; }
				else if( oKey == Key.D8 ){ sRetVal = "8"; }
				else if( oKey == Key.D9 ){ sRetVal = "9"; }
				else if( oKey == Key.NumPad0 ){ sRetVal = "0"; }
				else if( oKey == Key.NumPad3 ){ sRetVal = "3"; }
				else if( oKey == Key.NumPad2 ){ sRetVal = "2"; }
				else if( oKey == Key.NumPad1 ){ sRetVal = "1"; }
				else if( oKey == Key.NumPad6 ){ sRetVal = "6"; }
				else if( oKey == Key.NumPad5 ){ sRetVal = "5"; }
				else if( oKey == Key.NumPad4 ){ sRetVal = "4"; }
				else if( oKey == Key.NumPad9 ){ sRetVal = "9"; }
				else if( oKey == Key.NumPad8 ){ sRetVal = "8"; }
				else if( oKey == Key.NumPad7 ){ sRetVal = "7"; }

					//Symbols
					//else if( oKey == Key.Decimal		){ sRetVal = "."; }//This is actually the delete key
				else if( oKey == Key.Period  		){ sRetVal = "."; }
					//else if( oKey == Key.Divide  		){ sRetVal = ""; }
				else if( oKey == Key.Add  			){ sRetVal = "+"; }
				else if( oKey == Key.NumPadPlus  	){ sRetVal = "+"; }
				else if( oKey == Key.Subtract  		){ sRetVal = "-"; }
				else if( oKey == Key.Minus  		){ sRetVal = "-"; }
				else if( oKey == Key.NumPadMinus  	){ sRetVal = "-"; }
				else if( oKey == Key.Multiply  		){ sRetVal = "*"; }
				else if( oKey == Key.NumPadStar  	){ sRetVal = "*"; }
				else if( oKey == Key.RightBracket 	){ sRetVal = "]"; }
				else if( oKey == Key.LeftBracket  	){ sRetVal = "["; }
				else if( oKey == Key.Tab  			){ sRetVal = "     "; }
				else if( oKey == Key.NumPadSlash  	){ sRetVal = "/"; }
				else if( oKey == Key.NumPadPeriod  	){ sRetVal = "."; }
				else if( oKey == Key.NumPadComma  	){ sRetVal = ","; }
				else if( oKey == Key.NumPadEnter  	){ sRetVal = "\n"; }
				else if( oKey == Key.Return  		){ sRetVal = "\n"; }
				else if( oKey == Key.Underline  	){ sRetVal = "_"; }
				else if( oKey == Key.Colon  		){ sRetVal = ";"; }
				else if( oKey == Key.Space  		){ sRetVal = " "; }
				else if( oKey == Key.Slash  		){ sRetVal = "/"; }
				else if( oKey == Key.Comma  		){ sRetVal = ","; }
				else if( oKey == Key.BackSlash  	){ sRetVal = "\\"; }
				else if( oKey == Key.Apostrophe  	){ sRetVal = "'"; }
				else if( oKey == Key.SemiColon  	){ sRetVal = ":"; }				
					//else if( oKey == Key.Escape 		){ sRetVal = ""; }
				else if( oKey == Key.Equals			){ sRetVal = "="; }
				else if( oKey == Key.Grave			){ sRetVal = "`"; }
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( sRetVal );
		}
		//12/02/2004 Chris Hill  The previous function takes the exact key and maps it to a character.  But if shift is down
		//then it should map to a different character!  So if we have shift data then we can get a better key estimate.
		public static string KeyToChar( Key oKey,bool[] oState )
		{
			return( KeyToChar( oKey,oState,
				oState[ (int)Key.CapsLock ],
				oState[ (int)Key.Numlock ] ) );
		}
		public static string KeyToChar( Key oKey,bool[] oState,bool bCapsToggled,bool bNumLockToggled )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.KeyToChar";
			string sRetVal = "";
			bool bShift = false;

			try
			{
				bShift = bCapsToggled != ( oState[ (int)Key.LeftShift ] == true || oState[ (int)Key.RightShift ] == true );
				sRetVal = DSMisc.KeyToChar( oKey );

				//Alpha
				if( DSMisc.IsAlphaKey( oKey ) == true )
				{
					if( bShift == false )
					{
						sRetVal = sRetVal.ToLower();
					}
				}
					//Numeric
				else if( DSMisc.IsNumericKey( oKey ) == true )
				{
					if( DSMisc.IsNumPadNumericKey( oKey ) == true )
					{
						if( bNumLockToggled == false ){}
						else if( oKey == Key.NumPad0 ){ sRetVal = "0"; }
						else if( oKey == Key.NumPad3 ){ sRetVal = "3"; }
						else if( oKey == Key.NumPad2 ){ sRetVal = "2"; }
						else if( oKey == Key.NumPad1 ){ sRetVal = "1"; }
						else if( oKey == Key.NumPad6 ){ sRetVal = "6"; }
						else if( oKey == Key.NumPad5 ){ sRetVal = "5"; }
						else if( oKey == Key.NumPad4 ){ sRetVal = "4"; }
						else if( oKey == Key.NumPad9 ){ sRetVal = "9"; }
						else if( oKey == Key.NumPad8 ){ sRetVal = "8"; }
						else if( oKey == Key.NumPad7 ){ sRetVal = "7"; }
					}
					else if( bShift == true )
					{
						if( sRetVal.CompareTo( "0" ) == 0 ){ sRetVal = ")"; }
						else if( sRetVal.CompareTo( "1" ) == 0 ){ sRetVal = "!"; }
						else if( sRetVal.CompareTo( "2" ) == 0 ){ sRetVal = "@"; }
						else if( sRetVal.CompareTo( "3" ) == 0 ){ sRetVal = "#"; }
						else if( sRetVal.CompareTo( "4" ) == 0 ){ sRetVal = "$"; }
						else if( sRetVal.CompareTo( "5" ) == 0 ){ sRetVal = "%"; }
						else if( sRetVal.CompareTo( "6" ) == 0 ){ sRetVal = "^"; }
						else if( sRetVal.CompareTo( "7" ) == 0 ){ sRetVal = "&"; }
						else if( sRetVal.CompareTo( "8" ) == 0 ){ sRetVal = "*"; }
						else if( sRetVal.CompareTo( "9" ) == 0 ){ sRetVal = "("; }
					}
				}
					//Symbols
				else
				{
					if( bShift == true )
					{
						if( oKey == Key.Decimal			){ sRetVal = "."; }
						else if( sRetVal.CompareTo( "." ) == 0	){ sRetVal = ">"; }
						else if( sRetVal.CompareTo( "]" ) == 0	){ sRetVal = "}"; }
						else if( sRetVal.CompareTo( "[" ) == 0	){ sRetVal = "{"; }
						else if( sRetVal.CompareTo( "/" ) == 0	){ sRetVal = "?"; }
						else if( sRetVal.CompareTo( "," ) == 0	){ sRetVal = "<"; }
						else if( sRetVal.CompareTo( "-" ) == 0	){ sRetVal = "_"; }
						else if( sRetVal.CompareTo( ";" ) == 0	){ sRetVal = ":"; }
						else if( sRetVal.CompareTo( "\\" ) == 0	){ sRetVal = "|"; }
						else if( sRetVal.CompareTo( "`" ) == 0	){ sRetVal = "~"; }
						else if( sRetVal.CompareTo( "'" ) == 0	){ sRetVal = "\""; }
						else if( sRetVal.CompareTo( "=" ) == 0	){ sRetVal = "+"; }
					}
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( sRetVal );
		}


		//06/09/2006 Chris Hill  These functions break an intereger into its hi and low words.
		private static int High( int nValue ) 
		{
			return( nValue > 0 ? nValue >> 0x10 : (nValue >> 0x10) & 0x1 );
		}
		private static int Low( int nValue ) 
		{
			return( nValue & 0xffff );
		}


		//02/20/2004 Chris Hill  This function takes any serializable object and turns it into a string.  In allot of
		//cases the string it creates will be bigger than the custom string I as the developer can create.  However
		//not having to create and maintain a serialize function is nice.  I have no idea how versioning will work.
		public static string Serialize( object oObjectToSerialize )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.Serialize";
			string sRetVal = "";
			BinaryFormatter oBinaryFormatter = null;
			MemoryStream oMemoryStream = null;
			byte[] baObject = null;
			//char cChar;

			try
			{
				//08/17/2005 Chris Hill  If they pass us an empty object then return a blank string
				if( oObjectToSerialize == null )
				{
					sRetVal = "";
				}
				else
				{
					// Opens a file and serializes the object into it in binary format.
					oMemoryStream = new MemoryStream();
					oBinaryFormatter = new BinaryFormatter();

					//Get our serialized object
					oBinaryFormatter.Serialize( oMemoryStream,oObjectToSerialize );

					//Convert stream to string
					baObject = oMemoryStream.ToArray();
					sRetVal = Convert.ToBase64String( baObject );
					/*for( long i=0 ; i<baObject.Length ; i++ )
					{
						cChar = Convert.ToChar( baObject[ i ] );
						sRetVal += cChar.ToString();
					}*/

					//Clean up after ourselves.
					oMemoryStream.Close();
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( sRetVal );
		}
		public static object DeSerialize( string sSerializedObject )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.DeSerialize";
			BinaryFormatter oBinaryFormatter = null;
			MemoryStream oMemoryStream = null;
			object oRetVal = null;
			byte[] baFile = null;
			//char cChar;
			//byte bByte;

			try
			{
				//08/17/2005 Chris Hill  If they pass us an empty string return null.
				if( sSerializedObject.Length != 0 )
				{
					oMemoryStream = new MemoryStream();
					oBinaryFormatter = new BinaryFormatter();

					baFile = Convert.FromBase64String( sSerializedObject );
					oMemoryStream.Write( baFile,0,baFile.Length );
					/*for( long i = 0 ; i < sSerializedObject.Length ; i++ )
					{
						cChar = Convert.ToChar( sSerializedObject.Substring((int)i,1) );
						bByte = Convert.ToByte( cChar );
						oMemoryStream.WriteByte( bByte );
					}*/

					oMemoryStream.Position = 0;
					oRetVal = oBinaryFormatter.Deserialize( oMemoryStream );

					oMemoryStream.Close();
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( oRetVal );
		}
		public static void Serialize( object oObjectToSerialize,string sFileName )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.Serialize";
			BinaryFormatter oBinaryFormatter = null;
			FileStream oFileStream = null;

			try
			{
				// Opens a file and serializes the object into it in binary format.
				oFileStream = new FileStream( sFileName,FileMode.Create,FileAccess.Write,FileShare.Write );
				oBinaryFormatter = new BinaryFormatter();

				//Get our serialized object
				oBinaryFormatter.Serialize( oFileStream,oObjectToSerialize );
				
				oFileStream.Close();
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}
		public static object DeSerialize( string sSerializedObject,string sFileName )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.DeSerialize";
			BinaryFormatter oBinaryFormatter = null;
			FileStream oFileStream = null;
			object oRetVal = null;

			try
			{
				//Create our tools
				oFileStream = new FileStream( sFileName,FileMode.Open,FileAccess.Read );
				oBinaryFormatter = new BinaryFormatter();

				//Get our object
				oRetVal = oBinaryFormatter.Deserialize( oFileStream );

				//Clean up
				oFileStream.Close();
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( oRetVal );
		}


		//05/19/2004 Chris Hill  These functions are usefull when dealing with binary or serialized data.  They convert
		//hex to string and vice versa.
		public static string StrToHex( string sInput )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.StrToHex";
			string sRetVal = "";
			string sHex = "";
			byte bByte;
			char cChar;

			try
			{
				for( int i=0 ; i<sInput.Length ; i++ )
				{
					cChar = Convert.ToChar( sInput.Substring( i,1 ) );
					bByte = Convert.ToByte( cChar );

					//Tweek it
					sHex  = bByte.ToString( "X" );
					if( sHex.Length == 1 )
					{
						sHex = "0" + sHex;
					}

					sRetVal += sHex;
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( sRetVal );
		}
		public static string HexToStr( string sInput )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.HexToStr";
			string sRetVal = "";
			string sHex = "";
			byte bByte;
			char cChar;

			try
			{
				for( int i=0 ; i<sInput.Length ; i+=2 )
				{
					sHex = sInput.Substring( i,2 );
					bByte = Convert.ToByte( sHex,16 );
					cChar = Convert.ToChar( bByte );
					sRetVal += cChar.ToString();
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( sRetVal );
		}


		//05/09/2006 Chris Hill  Need to convert strings to byte arrays
		public static BitArray ConvertStringToBitArray( string sStringToConvert )
		{
			BitArray oRetVal = new BitArray( sStringToConvert.Length * 8 );
			long nValue = 0;
			char cChar = '0';


			for( int i=0 ; i<sStringToConvert.Length ; i++ )
			{
				cChar = sStringToConvert.ToCharArray( i,1 )[ 0 ];
				nValue = cChar;
				DSMisc.ConvertIntToBitArray( oRetVal,i*8,8,nValue );
			}

			return( oRetVal );
		}
		public static string ConvertBitArrayToString( BitArray oValues )
		{
			string sRetVal = "";
			long nValue = 0;
			char cChar = '0';
		

			for( int i=0 ; i<oValues.Length ; i+=8 )
			{
				nValue = DSMisc.ConvertBitArrayToInt( oValues,i,8 );
				cChar = Convert.ToChar( nValue );
				sRetVal += cChar.ToString();
			}


			return( sRetVal );
		}
		public static void ConvertIntToBitArray( BitArray oSerialized,int nStartPos,long nNumBytesToUse,long nValue )
		{
			long nTemp = nValue;
			int nPos = nStartPos;


			//Calculate how many didgets needed
			for( int i=0 ; i<nNumBytesToUse ; i++ )
			{
				oSerialized[ (int)nNumBytesToUse - i - 1 + nStartPos ] = ( ( nTemp & 1 ) == 1 );
				nTemp = nTemp >> 1;
			}
		}
		public static long ConvertBitArrayToInt( BitArray oSerialized,int nStartPos,long nNumBytesToUse )
		{
			long nTemp = 0;
			long nTotal = 0;


			//Calculate our value
			for( int nPos=(int)nNumBytesToUse ; nPos>0 ; nPos-- )
			{
				nTemp = 0;
				if( nPos+nStartPos-1 >= oSerialized.Length )
				{
					nTemp = 0;
				}
				else if( oSerialized[ nPos+nStartPos-1 ] == true )
				{
					nTemp = 1;
				}
				nTemp = nTemp << (int)(nNumBytesToUse - nPos);
				nTotal += nTemp;
			}


			return( nTotal );
		}

		public static int GetNumberOfBitsUsedIn( int nValue )
		{
			return( DSMisc.GetNumberOfBitsUsedIn( (long)nValue ) );
		}
		public static int GetNumberOfBitsUsedIn( long nValue )
		{
			long nTemp = nValue;
			int nDidgetsUsed = 0;

			while( nTemp > 0 )
			{
				nTemp = nTemp >> 1;
				nDidgetsUsed++;
			}

			return( nDidgetsUsed );
		}


		//Get the minimum and maximum values
		public static double Min( double dVal1,double dVal2 )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.Min";
			double dRetVal = 0;

			try
			{
				if( dVal1 < dVal2 )
				{
					dRetVal = dVal1;
				}
				else
				{
					dRetVal = dVal2;
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( dRetVal );
		}
		public static long Min( long nVal1,long nVal2 )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.Min";
			long nRetVal = 0;

			try
			{
				if( nVal1 < nVal2 )
				{
					nRetVal = nVal1;
				}
				else
				{
					nRetVal = nVal2;
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( nRetVal );
		}
		public static int Min( int nVal1,int nVal2 )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.Min";
			int nRetVal = 0;

			try
			{
				if( nVal1 < nVal2 )
				{
					nRetVal = nVal1;
				}
				else
				{
					nRetVal = nVal2;
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( nRetVal );
		}
		public static float Min( float nVal1,float nVal2 )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.Min";
			float nRetVal = 0;

			try
			{
				if( nVal1 < nVal2 )
				{
					nRetVal = nVal1;
				}
				else
				{
					nRetVal = nVal2;
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( nRetVal );
		}
		public static double Max( double dVal1,double dVal2 )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.Max";
			double dRetVal = 0;

			try
			{
				if( dVal1 > dVal2 )
				{
					dRetVal = dVal1;
				}
				else
				{
					dRetVal = dVal2;
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( dRetVal );
		}
		public static long Max( long nVal1,long nVal2 )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.Max";
			long nRetVal = 0;

			try
			{
				if( nVal1 > nVal2 )
				{
					nRetVal = nVal1;
				}
				else
				{
					nRetVal = nVal2;
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( nRetVal );
		}
		public static int Max( int nVal1,int nVal2 )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.Max";
			int nRetVal = 0;

			try
			{
				if( nVal1 > nVal2 )
				{
					nRetVal = nVal1;
				}
				else
				{
					nRetVal = nVal2;
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( nRetVal );
		}

		public static float Max( float nVal1,float nVal2 )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.Max";
			float nRetVal = 0;

			try
			{
				if( nVal1 > nVal2 )
				{
					nRetVal = nVal1;
				}
				else
				{
					nRetVal = nVal2;
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( nRetVal );
		}

		public static long Between( long nMinVal,long nNewVal,long nMaxVal )
		{
			long nRetVal = nNewVal;
			nRetVal = DSMisc.Max( nRetVal,nMinVal );
			nRetVal = DSMisc.Min( nRetVal,nMaxVal );

			return( nRetVal );
		}
		public static int Between( int nMinVal,int nNewVal,int nMaxVal )
		{
			int nRetVal = nNewVal;
			nRetVal = DSMisc.Max( nRetVal,nMinVal );
			nRetVal = DSMisc.Min( nRetVal,nMaxVal );

			return( nRetVal );
		}
		public static float Between( float nMinVal,float nNewVal,float nMaxVal )
		{
			float nRetVal = nNewVal;
			nRetVal = DSMisc.Max( nRetVal,nMinVal );
			nRetVal = DSMisc.Min( nRetVal,nMaxVal );

			return( nRetVal );
		}
		public static double Between( double nMinVal,double nNewVal,double nMaxVal )
		{
			double nRetVal = nNewVal;
			nRetVal = DSMisc.Max( nRetVal,nMinVal );
			nRetVal = DSMisc.Min( nRetVal,nMaxVal );

			return( nRetVal );
		}


		//10/05/2006 Chris Hill  Handy functions to testing what a string really si.
		public static bool IsNumber( string strNumber )
		{
			Regex objNotNumberPattern = new Regex("[^0-9.-]");
			Regex objTwoDotPattern = new Regex("[0-9]*[.][0-9]*[.][0-9]*");
			Regex objTwoMinusPattern = new Regex("[0-9]*[-][0-9]*[-][0-9]*");
			String strValidRealPattern = "^([-]|[.]|[-.]|[0-9])[0-9]*[.]*[0-9]+$";
			String strValidIntegerPattern = "^([-]|[0-9])[0-9]*$";
			Regex objNumberPattern = new Regex("(" + strValidRealPattern +")|(" + strValidIntegerPattern + ")");

			return( !objNotNumberPattern.IsMatch(strNumber) &&
				    !objTwoDotPattern.IsMatch(strNumber) &&
				    !objTwoMinusPattern.IsMatch(strNumber) &&
				    objNumberPattern.IsMatch(strNumber) );
		} 
		// Function To test for Alphabets. 
		public static bool IsAlpha( string strToCheck )
		{
			Regex objAlphaPattern=new Regex("[^a-zA-Z]");
			return !objAlphaPattern.IsMatch(strToCheck);
		}
		// Function to Check for AlphaNumeric.
		public static bool IsAlphaNumeric( string strToCheck )
		{
			Regex objAlphaNumericPattern=new Regex("[^a-zA-Z0-9]");
			return !objAlphaNumericPattern.IsMatch(strToCheck); 
		}


		//07/27/2005 Chris Hill  These equations tell you the distance between two points.
		public static double Distance( double nX1,double nY1,double nX2,double nY2 )
		{
			double nRetVal = Math.Sqrt( ( nX1-nX2 )*( nX1-nX2 ) + 
										( nY1-nY2 )*( nY1-nY2 ) );
			return( nRetVal );
		}
		public static double Distance( long nX1,long nY1,long nX2,long nY2 )
		{
			double nRetVal = Math.Sqrt( ( nX1-nX2 )*( nX1-nX2 ) + 
									    ( nY1-nY2 )*( nY1-nY2 ) );
			return( nRetVal );
		}
		public static double Distance( int nX1,int nY1,int nX2,int nY2 )
		{
			double nRetVal = Math.Sqrt( ( nX1-nX2 )*( nX1-nX2 ) + 
										( nY1-nY2 )*( nY1-nY2 ) );
			return( nRetVal );
		}


		//06/30/2005 Chris Hill  This function returns the bottom-most base class.  If you have a class that
		//is derived from another class that is derived from another class, the basetype returns the
		//next lowest not the bottom-most base class, which can be very annoying.
		public static Type BottomMostBaseType( Type oType )
		{
			Type oRetType = oType;

			while( oRetType.BaseType != null && oRetType.BaseType.FullName != "System.Object" )
			{
				oRetType = oRetType.BaseType;
			}

			return( oRetType );
		}


		//10/05/2006 Chris Hill  This returns the IP assocated with this machine.
		//11/13/2006 Chris Hill  Enhanced to get the external IP not the internal.
		public static string GetMyIP()
		{
			return( GetMyIP( false,"" ) );
		}
		//Local addresses
		//10.0.0.0 to 10.255.255.255
		//172.16.0.0 to 172.31.255.255
		//192.168.0.0 to 192.168.255.255
		public static string GetMyIP( bool bDebugMode,string sDebugFileName )
		{
			string sTempDebugFileName = sDebugFileName;
			string sIP = "";
			string sInternalIP = "";


            //Make sure we have a debug file name
			if( bDebugMode == true && sTempDebugFileName.Length == 0 )
			{
				sTempDebugFileName = DSMisc.GetDevelopmentAppPath() + "GetMyIP_" + DateTime.Now.ToString( "yyyyMMdd_hhmm" ) + ".log";
			}

			WriteSafetlyToDebug( sTempDebugFileName,bDebugMode,"Starting GetMyIP" );

			//Now start by deciding if my address is local or not
			sInternalIP = GetMyInternalIP();
			WriteSafetlyToDebug( sTempDebugFileName,bDebugMode," - Internal IP = " + sInternalIP );

			if( IsIPInternal( sInternalIP ) == true )
			{
				WriteSafetlyToDebug( sTempDebugFileName,bDebugMode," - IP is internal" );

				WriteSafetlyToDebug( sTempDebugFileName,bDebugMode," - Pinging http://www.whatismyip.com/" );
				sIP = ParseURL( "http://www.whatismyip.com/","<TITLE>WhatIsMyIP.com - ","</TITLE>" );
				WriteSafetlyToDebug( sTempDebugFileName,bDebugMode,"   - IP = " + sIP );
				if( sIP.Length == 0 )
				{
					WriteSafetlyToDebug( sTempDebugFileName,bDebugMode," - Pinging http://checkip.dyndns.org/" );
					sIP = ParseURL( "http://checkip.dyndns.org/","<body>Current IP Address: ","</body>" );
					WriteSafetlyToDebug( sTempDebugFileName,bDebugMode,"   - IP = " + sIP );
				}
				if( sIP.Length == 0 )
				{
					WriteSafetlyToDebug( sTempDebugFileName,bDebugMode," - Pinging http://www.ipchicken.com/" );
					sIP = ParseURL( "http://www.ipchicken.com/","Address: \n","</font>" );
					WriteSafetlyToDebug( sTempDebugFileName,bDebugMode,"   - IP = " + sIP );
				}
				if( sIP.Length == 0 )
				{
					WriteSafetlyToDebug( sTempDebugFileName,bDebugMode," - Failed to find external IP, use internal" );
					sIP = sInternalIP;
				}
			}
			else
			{
				WriteSafetlyToDebug( sTempDebugFileName,bDebugMode," - IP is external" );
				sIP = sInternalIP;
			}

			WriteSafetlyToDebug( sTempDebugFileName,bDebugMode," - IP Found: " + sIP );


			return( sIP );
		}
		private static bool WriteSafetlyToDebug( string sFileName,bool bDebugMode,string sMessage )
		{
			try
			{
				DSMisc.WriteToDebugFile( sFileName,bDebugMode,sMessage );
				return( true );
			}
			catch
			{
				return( false );
			}
		}
		private static string ParseURL( string sURL,string sPrefix,string sTerminator )
		{
			WebClient oWebClient = new WebClient(); 
			string sHTML = "";
			string sIP = "";
			int nStartPos = 0;
			int nStopPos = 0;
			byte[] naHTML = null;
			UTF8Encoding oUTF8 = new UTF8Encoding(); 


			naHTML = oWebClient.DownloadData( sURL ); 			
			sHTML = oUTF8.GetString( naHTML ); 

			nStartPos = sHTML.IndexOf( sPrefix,0 );
			if( nStartPos != -1 )
			{
				nStartPos += sPrefix.Length;
				nStopPos = sHTML.IndexOf( sTerminator,nStartPos );
				if( nStopPos != -1 )
				{
					sIP = sHTML.Substring( nStartPos,nStopPos - nStartPos );
				}
			}


			return( sIP.Trim() );
		}

		public static string GetMyInternalIP()
		{
			string strHostName = "";

			// Getting Ip address of local machine...
			// First get the host name of local machine.
			strHostName = System.Net.Dns.GetHostName ();
          
			// Then using host name, get the IP address list..
			IPHostEntry ipEntry = System.Net.Dns.GetHostByName (strHostName);
			IPAddress [] addr = ipEntry.AddressList;
			for (int i = 0; i < addr.Length; i++)
			{
				return( addr[i].ToString() );
			}

			return( "" );
		}

		//11/14/2006 Chris Hill  This function takes an IP address and deteremines if its an internal or external address.
		//10.0.0.0 to 10.255.255.255
		//172.16.0.0 to 172.31.255.255
		//192.168.0.0 to 192.168.255.255
		public static bool IsIPInternal( string sIP )
		{
			string[] saParts = null;
			bool bInternal = true;


            saParts = DSMisc.Split( sIP,"." );
			if( saParts.Length == 4 )
			{
				if( saParts[0].Trim() == "10" ||
					( saParts[0].Trim() == "172" && saParts[1].Trim() == "16" ) ||
					( saParts[0].Trim() == "192" && saParts[1].Trim() == "168" ) )
				{
					bInternal = true;
				}
				else
				{
					bInternal = false;
				}				
			}
			else
			{
				throw new System.Exception( "Invalid IP format <" + sIP + ">." );
			}


			return( bInternal );
		}


		//08/10/2005 Chris Hill  This function is equivilant to VB's ReDim.  It will redimension an array
		//with new paramaters.
		public static object[] ReDim1DArray( object[] oaCurArray,long nNewLength )
		{
			object[] oaNewArray = null;

			oaNewArray = new object[ nNewLength ];

			for( long i=0 ; i<oaCurArray.GetLength( 0 ) ; i++ )
			{
				oaNewArray[ i ] = oaCurArray[ i ];
			}

			return( oaNewArray );
		}
		public static object[,] ReDim2DArray( object[,] oaCurArray,long nNewWidth,long nNewHeight )
		{
			object[,] oaNewArray = null;

			oaNewArray = new object[ nNewWidth,nNewHeight ];

			for( long nY=0 ; nY<oaCurArray.GetLength( 0 ) ; nY++ )
			{
				for( long nX=0 ; nX<oaCurArray.GetLength( 1 ) ; nX++ )
				{
					oaNewArray[ nY,nX ] = oaCurArray[ nY,nX ];
				}
			}

			return( oaNewArray );
		}


		//11/29/2006 Chris Hill  Is this channel in existance yet?
		public static TcpChannel GetRegisteredChannel( string sChannelName )
		{
			IChannel[] oaRegisteredChannels = ChannelServices.RegisteredChannels;

			for( int i=0 ; i<oaRegisteredChannels.Length ; i++ )
			{
				if( oaRegisteredChannels[i].ChannelName == sChannelName )
				{
					return( (TcpChannel)oaRegisteredChannels[i] );
				}
			}

			return( null );
		}
		public static bool IsChannelRegistered( string sChannelName )
		{
			IChannel[] oaRegisteredChannels = ChannelServices.RegisteredChannels;

			for( int i=0 ; i<oaRegisteredChannels.Length ; i++ )
			{
				if( oaRegisteredChannels[i].ChannelName == sChannelName )
				{
					return( true );
				}
			}

			return( false );
		}


		//11/20/2004 Chris Hill  This function will write a text string out to a file.  Its 
		//purpose is to be used in debug log files so it is not the most effiecient.  The 
		//third paramater is a boolean indicating weather or not the write should happen.
		public static void WriteToDebugFile( string sDebugFileName,string sDebugMessage )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.WriteToDebugFile";	

			try
			{
				WriteToDebugFile( sDebugFileName,true,true,0,sDebugMessage );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}
		public static void WriteToDebugFile( string sDebugFileName,bool bWriteToFile,string sDebugMessage )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.WriteToDebugFile";	

			try
			{
				WriteToDebugFile( sDebugFileName,bWriteToFile,true,0,sDebugMessage );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}
		public static void WriteToDebugFile( string sDebugFileName,bool bWriteToFile,long nLevel,string sDebugMessage )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.WriteToDebugFile";	

			try
			{
				WriteToDebugFile( sDebugFileName,bWriteToFile,true,nLevel,sDebugMessage );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}
		/*public static void WriteToDebugFile( string sDebugFileName,bool bWriteToFile,bool bAddTimeStamp,long nLevel,string sDebugMessage )
		{
			WriteToDebugFileThreadManager oNewWrite = null;

			try
			{
				oNewWrite = new WriteToDebugFileThreadManager( sDebugFileName,bWriteToFile,bAddTimeStamp,nLevel,sDebugMessage );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( "DarkStrideToolbox.DSMisc.WriteToDebugFile Failed.",oEx );
			}
		}*/
		public static void WriteToDebugFile( string sDebugFileName,bool bWriteToFile,bool bAddTimeStamp,long nLevel,string sDebugMessage )
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.WriteToDebugFile";	
			StreamWriter oStream = null;
			string sMsg = "";
			bool bError = true;
			long nErrorCount = 0;

			try
			{
				if( bWriteToFile == true )
				{
					//12/28/2004 Chris Hill  The file may not be available yet...
					while( bError == true )
					{
						try
						{
							oStream = new StreamWriter( sDebugFileName,true );
							bError = false;
						}
						catch( System.IO.IOException oEx )
						{
							if( nErrorCount++ > 20 )
							{
								throw new System.Exception( sRoutineName + " Failed.",oEx );
							}
						}
					}

					if( bAddTimeStamp == true )
					{
						sMsg =	DateTime.Now.ToString( "hh:mm:ss.fffffff" ) + " - ";
					}

					//Add in some tabs
					if( nLevel > 0 )
					{
						for( int i=0 ; i<nLevel ; i++ )
						{
							sMsg += "	";
						}
					}

					sMsg += sDebugMessage;

					oStream.WriteLine( sMsg );
					oStream.Close();
				}
			}
			catch
			{
				//throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}

	}

	public class WriteToDebugFileThreadManager
	{
		#region Properties
		private string m_sDebugFileName = "";
		private bool m_bWriteToFile = false;
		private bool m_bAddTimeStamp = false;
		private long m_nLevel = 0;
		private string m_sDebugMessage = "";
		#endregion

		public WriteToDebugFileThreadManager( string sDebugFileName,bool bWriteToFile,bool bAddTimeStamp,long nLevel,string sDebugMessage )
		{
			Thread oWriteThread = null;


			if( bWriteToFile == true )
			{
				m_sDebugFileName	= sDebugFileName;
				m_bWriteToFile		= bWriteToFile;
				m_bAddTimeStamp		= bAddTimeStamp;
				m_nLevel			= nLevel;
				m_sDebugMessage		= sDebugMessage;

				oWriteThread = new Thread( new ThreadStart( WriteToDebug ) );
				oWriteThread.IsBackground = true;
				//oWriteThread.Priority = System.Threading.ThreadPriority.BelowNormal;
				oWriteThread.Start();
			}
		}
		private void WriteToDebug()
		{
			const string sRoutineName = "DarkStrideToolbox.DSMisc.WriteToDebugFileThreadManager.WriteToDebugFile";	
			StreamWriter oStream = null;
			string sMsg = "";
			bool bError = true;
			long nErrorCount = 0;

			try
			{
				if( m_bWriteToFile == true )
				{
					//12/28/2004 Chris Hill  The file may not be available yet...
					while( bError == true )
					{
						try
						{
							oStream = new StreamWriter( m_sDebugFileName,true );
							bError = false;
						}
						catch( System.IO.IOException oEx )
						{
							if( nErrorCount++ > 20 )
							{
								throw new System.Exception( sRoutineName + " Failed.",oEx );
							}
						}
					}

					if( m_bAddTimeStamp == true )
					{
						sMsg =	DateTime.Now.ToString( "hh:mm:ss.fffffff" ) + " - ";
					}

					//Add in some tabs
					if( m_nLevel > 0 )
					{
						for( int i=0 ; i<m_nLevel ; i++ )
						{
							sMsg += "	";
						}
					}

					sMsg += m_sDebugMessage;

					oStream.WriteLine( sMsg );
					oStream.Close();
				}
			}
			catch
			{
				DSMisc.WriteToDebugFile( DSMisc.GetDevelopmentAppPath() + "FailedDebugWrites.log","Failed writing to debug file <" + m_sDebugFileName + "> the message <" + sMsg + ">." );
				//throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}
	}
}
