using System;
using System.ComponentModel;
using System.Collections;
using System.IO;

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


namespace DarkStrideToolbox
{
	public enum BufferedInputEventTypes
	{
		enumMouseWheelMove = 0,
		enumMouseMoved		= 1,
		enumMouseUp			= 2,
		enumMouseDown		= 3,
		enumKeyboardKeyDown = 4,
		enumKeyboardKeyUp	= 5
	};
	public class BufferedInputEvent
	{
		public BufferedInputEventTypes nEvent;
		public object[] oVariables;
	};

	public class DSInputBuffered : DSInputWrapper
	{
		#region Properties
		//private SortedList m_oEvents = new SortedList();
		private System.Collections.ArrayList m_oEvents = new System.Collections.ArrayList();

		private System.Exception m_oDirectInputError = null;
		#endregion


		public DSInputBuffered(){}


		public virtual void ProccessBufferedEvents()
		{
			const string sRoutineName = "DarkStrideToolbox.InputBuffered.ProccessBufferedEvents";
			BufferedInputEvent oEvent = null;
			System.Exception oErrors = null;

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

					if( oEvent.nEvent == BufferedInputEventTypes.enumMouseWheelMove )
					{
						base.MouseWheelMove( (long)oEvent.oVariables[ 0 ] );
					}
					else if( oEvent.nEvent == BufferedInputEventTypes.enumMouseMoved )
					{
						base.MouseMoved( (Vector2)oEvent.oVariables[ 0 ],(MouseState)oEvent.oVariables[ 1 ],(bool[])oEvent.oVariables[ 2 ] );
					}
					else if( oEvent.nEvent == BufferedInputEventTypes.enumMouseUp )
					{
						base.MouseUp( (Vector2)oEvent.oVariables[ 0 ],(long)oEvent.oVariables[ 1 ] );
					}
					else if( oEvent.nEvent == BufferedInputEventTypes.enumMouseDown )
					{
						base.MouseDown( (Vector2)oEvent.oVariables[ 0 ],(long)oEvent.oVariables[ 1 ] );
					}
					else if( oEvent.nEvent == BufferedInputEventTypes.enumKeyboardKeyDown )
					{
						base.KeyboardKeyDown( (Key)oEvent.oVariables[ 0 ],(bool[])oEvent.oVariables[ 1 ] );
					}
					else if( oEvent.nEvent == BufferedInputEventTypes.enumKeyboardKeyUp )
					{
						base.KeyboardKeyUp( (Key)oEvent.oVariables[ 0 ],(bool[])oEvent.oVariables[ 1 ] );
					}


					//Throw any errors that may have occured.
					if( m_oDirectInputError != null )
					{
						lock( m_oDirectInputError )
						{
							oErrors = m_oDirectInputError;
							m_oDirectInputError = null;
						}
						if( oErrors != null )
						{
							throw new System.Exception( "DirectInput Threw an error",oErrors );
						}
					}
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}


		public override bool MouseWheelMove( long nDirection )
		{
			const string sRoutineName = "DarkStrideToolbox.InputBuffered.MouseWheelMove";
			BufferedInputEvent oNewEvent = null;

			try
			{
				oNewEvent = GetNewEvent( BufferedInputEventTypes.enumMouseWheelMove );
				oNewEvent.oVariables[ 0 ] = nDirection;

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

			return( false );
		}

		public override bool MouseMoved( Vector2 vCurPos,MouseState oMouseStateData,bool[] baButtons )
		{
			const string sRoutineName = "DarkStrideToolbox.InputBuffered.MouseMoved";
			BufferedInputEvent oNewEvent = null;

			try
			{
				oNewEvent = GetNewEvent( BufferedInputEventTypes.enumMouseMoved );
				oNewEvent.oVariables[ 0 ] = vCurPos;
				oNewEvent.oVariables[ 1 ] = oMouseStateData;
				oNewEvent.oVariables[ 2 ] = baButtons;

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

			return( false );
		}

		public override bool MouseUp( Vector2 vCurPos,long nButton )
		{
			const string sRoutineName = "DarkStrideToolbox.InputBuffered.MouseUp";
			BufferedInputEvent oNewEvent = null;

			try
			{
				oNewEvent = GetNewEvent( BufferedInputEventTypes.enumMouseUp );
				oNewEvent.oVariables[ 0 ] = vCurPos;
				oNewEvent.oVariables[ 1 ] = nButton;

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

			return( false );
		}

		public override bool MouseDown( Vector2 vCurPos,long nButton )
		{
			const string sRoutineName = "DarkStrideToolbox.InputBuffered.MouseDown";
			BufferedInputEvent oNewEvent = null;

			try
			{
				oNewEvent = GetNewEvent( BufferedInputEventTypes.enumMouseDown );
				oNewEvent.oVariables[ 0 ] = vCurPos;
				oNewEvent.oVariables[ 1 ] = nButton;

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

			return( false );
		}

		public override bool KeyboardKeyDown( Key oKey,bool[] oState )
		{
			const string sRoutineName = "DarkStrideToolbox.InputBuffered.KeyboardKeyDown";
			BufferedInputEvent oNewEvent = null;

			try
			{
				oNewEvent = GetNewEvent( BufferedInputEventTypes.enumKeyboardKeyDown );
				oNewEvent.oVariables[ 0 ] = oKey;
				oNewEvent.oVariables[ 1 ] = base.CopyKeyboardState( oState );

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

			return( false );
		}
		public override bool KeyboardKeyUp( Key oKey,bool[] oState )
		{
			const string sRoutineName = "DarkStrideToolbox.InputBuffered.KeyboardKeyUp";
			BufferedInputEvent oNewEvent = null;

			try
			{
				oNewEvent = GetNewEvent( BufferedInputEventTypes.enumKeyboardKeyUp );
				oNewEvent.oVariables[ 0 ] = oKey;
				oNewEvent.oVariables[ 1 ] = base.CopyKeyboardState( oState );

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

			return( false );
		}


		public void ExecuteMouseWheelMove( long nDirection )
		{
			const string sRoutineName = "DarkStrideToolbox.InputBuffered.ExecuteMouseWheelMove";

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

		public void ExecuteMouseMoved( Vector2 vCurPos,MouseState oMouseStateData,bool[] baButtons )
		{
			const string sRoutineName = "DarkStrideToolbox.InputBuffered.ExecuteMouseMoved";

			try
			{
				base.MouseMoved( vCurPos,oMouseStateData,baButtons );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}

		public void ExecuteMouseUp( Vector2 vCurPos,long nButton )
		{
			const string sRoutineName = "DarkStrideToolbox.InputBuffered.ExecuteMouseUp";

			try
			{
				base.MouseUp( vCurPos,nButton );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}

		public void ExecuteMouseDown( Vector2 vCurPos,long nButton )
		{
			const string sRoutineName = "DarkStrideToolbox.InputBuffered.ExecuteMouseDown";

			try
			{
				base.MouseDown( vCurPos,nButton );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}

		public void ExecuteKeyboardKeyDown( Key oKey,bool[] oState )
		{
			const string sRoutineName = "DarkStrideToolbox.InputBuffered.ExecuteKeyboardKeyDown";

			try
			{
				base.KeyboardKeyDown( oKey,oState );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}
		public void ExecuteKeyboardKeyUp( Key oKey,bool[] oState )
		{
			const string sRoutineName = "DarkStrideToolbox.InputBuffered.ExecuteKeyboardKeyUp";

			try
			{
				base.KeyboardKeyUp( oKey,oState );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}

       
		private BufferedInputEvent GetNewEvent( BufferedInputEventTypes eType )
		{
			const string sRoutineName = "DarkStrideToolbox.InputBuffered.GetNewEvent";
			BufferedInputEvent oNewEvent = null;

			try
			{
				oNewEvent = new BufferedInputEvent();
				oNewEvent.nEvent = eType;
				oNewEvent.oVariables = new object[ 3 ];
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( oNewEvent );
		}

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


		public override void Error( System.Exception oError )
		{
			const string sRoutineName = "DarkStrideToolbox.InputBuffered.Error";

			try
			{
				m_oDirectInputError = DSMisc.MergeErrors( oError,m_oDirectInputError );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}



		#region Properties
		public System.Collections.ArrayList Events
		{
			get
			{
				return( m_oEvents );
			}
		}
		#endregion
	}
}
