using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

using System.CodeDom.Compiler;
using System.Reflection;


/*
		public enum Languages
		{
			VB,
			CSharp
		}

		public static CompilerResults CompileScript(string Source, string Reference, Languages Language)
		{
			CodeDomProvider provider = null;

			switch(Language)
			{
				case Languages.VB:
					provider = new Microsoft.VisualBasic.VBCodeProvider();
					break;
				case Languages.CSharp:
					provider = new Microsoft.CSharp.CSharpCodeProvider();
					break;
			}

			return CompileScript(Source, Reference, provider);
		}

		public static CompilerResults CompileScript(string Source, string Reference, CodeDomProvider Provider)
		{
			ICodeCompiler compiler = Provider.CreateCompiler();
			CompilerParameters parms = new CompilerParameters();
			CompilerResults results;

			// Configure parameters
			parms.GenerateExecutable = false;
			parms.GenerateInMemory = true;
			parms.IncludeDebugInformation = false;
			if (Reference != null && Reference.Length != 0)
				parms.ReferencedAssemblies.Add(Reference);
			parms.ReferencedAssemblies.Add("System.Windows.Forms.dll");
			parms.ReferencedAssemblies.Add("System.dll");

			// Compile
			results = compiler.CompileAssemblyFromSource(parms, Source);

			return results;
		}

		public static object FindInterface(System.Reflection.Assembly DLL, string InterfaceName)
		{
			// Loop through types looking for one that implements the given interface
			foreach(Type t in DLL.GetTypes())
			{
				if (t.GetInterface(InterfaceName, true) != null)
					return DLL.CreateInstance(t.FullName);
			}

			return null;
*/

namespace DarkStrideToolbox
{
	[Serializable]
	public class DSCompiler
	{
		#region Properties
		public enum Languages
		{
			VB,
			CSharp,
			JScript
		}

		
		private struct Script
		{
			public CompilerResults m_oCompiledCode;
			public string m_sCode;
			public string m_sKey;
		};

		private DSSortedList		m_oScripts = new DSSortedList();
		private CodeDomProvider		m_oProvider = null;
		private ICodeCompiler		m_oCompiler = null;
		private CompilerParameters	m_oParam = null;

		private Script				m_oCurrentCode;
		#endregion


		public DSCompiler( Languages nLanguage )
		{
			const string sRoutineName = "DarkStrideToolbox.DSCompiler.DSScripts";

			try
			{
				if( nLanguage == Languages.CSharp )
				{
					m_oProvider = new Microsoft.CSharp.CSharpCodeProvider();
				}
				else if( nLanguage == Languages.JScript )
				{
					m_oProvider = new Microsoft.JScript.JScriptCodeProvider();
				}
				else if( nLanguage == Languages.VB )
				{
					m_oProvider = new Microsoft.VisualBasic.VBCodeProvider();
				}

				m_oCompiler = m_oProvider.CreateCompiler();
				m_oParam = new CompilerParameters();

				m_oParam.GenerateExecutable = false;
				m_oParam.GenerateInMemory = true;
				m_oParam.IncludeDebugInformation = false;
			}
			catch( System.Exception e )
			{
				throw new System.Exception( sRoutineName,e );
			}
		}
		public void AddReference( string sReference )
		{
			const string sRoutineName = "DarkStrideToolbox.DSCompiler.DSScripts";

			try
			{
				//Executing assembly must be explicitly referenced
				m_oParam.ReferencedAssemblies.Add( sReference );
			}
			catch( System.Exception e )
			{
				throw new System.Exception( sRoutineName,e );
			}
		}


		public string GetCode( string sKey )
		{
			const string sRoutineName = "DarkStrideToolbox.DSCompiler.GetCode";
			string sRetVal = null;

			try
			{
				if( m_oScripts.ContainsKey( sKey ) == true )
				{
					sRetVal = (string)m_oScripts.GetByKey( sKey );
				}
			}
			catch( System.Exception e )
			{
				throw new System.Exception( sRoutineName,e );
			}

			return( sRetVal );
		}


		public object GetClassInstance( string sCodeKey,string sClassName )
		{
			const string sRoutineName = "DarkStrideToolbox.DSCompiler.GetClassInstance";
			Script oScript;
			Type oType;
			object oRetVal = null;

			try
			{
				if( m_oScripts.ContainsKey( sCodeKey ) == true )
				{
					oScript = (Script)m_oScripts.GetByKey( sCodeKey );
					oType = oScript.m_oCompiledCode.CompiledAssembly.GetType( sClassName ); 
					oRetVal = Activator.CreateInstance( oType );
				}
				else
				{
					oRetVal = null;
				}	
			}
			catch( System.Exception e )
			{
				throw new System.Exception( sRoutineName,e );
			}

			return( oRetVal );
		}


		public bool Compile( string sCode,ref System.CodeDom.Compiler.CompilerErrorCollection oErrors )
		{
			const string sRoutineName = "DarkStrideToolbox.DSCompiler.Compile";
			bool bSuccess = true;

			try
			{
				bSuccess = Compile( DSMisc.GetGUID( "Code" ),sCode,ref oErrors );
			}
			catch( System.Exception e )
			{
				throw new System.Exception( sRoutineName,e );
			}

			return( bSuccess );
		}
		public bool Compile( string sKey,string sCode,ref System.CodeDom.Compiler.CompilerErrorCollection oErrors )
		{
			const string sRoutineName = "DarkStrideToolbox.DSCompiler.Compile";
			Script oNewScript;
			bool bSuccess = true;

			try
			{
				oErrors = null;

				if( m_oScripts.ContainsKey( sKey ) == true )
				{
					m_oScripts.Remove( sKey );
				}

				oNewScript.m_sKey = sKey;
				oNewScript.m_sCode = sCode;
				oNewScript.m_oCompiledCode = m_oCompiler.CompileAssemblyFromSource( m_oParam,sCode );

				bSuccess = ( oNewScript.m_oCompiledCode.Errors.Count == 0 );
				if( bSuccess == false )
				{
					oErrors = oNewScript.m_oCompiledCode.Errors;
				}
				else
				{
					m_oScripts.Add( sKey,oNewScript );
				}
			}
			catch( System.Exception e )
			{
				throw new System.Exception( sRoutineName,e );
			}

			return( bSuccess );
		}


		public bool ExecuteStaticMethod( string sCodeKey,string sFunctionClass,string sFunctionCall,object[] oaFunctionArguments )
		{
			const string sRoutineName = "DarkStrideToolbox.DSCompiler.ExecuteStaticMethod";
			bool bSuccess = true;

			try
			{
				m_oCurrentCode = (Script)m_oScripts.GetByKey( sCodeKey );
				bSuccess = Execute( null,sFunctionClass,sFunctionCall,oaFunctionArguments );
			}
			catch( System.Exception e )
			{
				throw new System.Exception( sRoutineName,e );
			}

			return( bSuccess );
		}
		public bool ExecuteStaticMethod( string sFunctionClass,string sFunctionCall,object[] oaFunctionArguments )
		{
			const string sRoutineName = "DarkStrideToolbox.DSCompiler.ExecuteStaticMethod";
			bool bSuccess = true;

			try
			{
				bSuccess = Execute( null,sFunctionClass,sFunctionCall,oaFunctionArguments );
			}
			catch( System.Exception e )
			{
				throw new System.Exception( sRoutineName,e );
			}

			return( bSuccess );
		}


		public bool ExecuteMethod( string sCodeKey,object oInstance,string sFunctionCall,object[] oaFunctionArguments )
		{
			const string sRoutineName = "DarkStrideToolbox.DSCompiler.ExecuteMethod";
			bool bSuccess = true;

			try
			{
				m_oCurrentCode = (Script)m_oScripts.GetByKey( sCodeKey );
				bSuccess = Execute( oInstance,oInstance.GetType().Name,sFunctionCall,oaFunctionArguments );
			}
			catch( System.Exception e )
			{
				throw new System.Exception( sRoutineName,e );
			}

			return( bSuccess );
		}
		public bool ExecuteMethod( object oInstance,string sFunctionCall,object[] oaFunctionArguments )
		{
			const string sRoutineName = "DarkStrideToolbox.DSCompiler.ExecuteMethod";
			bool bSuccess = true;

			try
			{
				bSuccess = Execute( oInstance,oInstance.GetType().Name,sFunctionCall,oaFunctionArguments );
			}
			catch( System.Exception e )
			{
				throw new System.Exception( sRoutineName,e );
			}

			return( bSuccess );
		}


		public bool Execute( string sCodeKey,object oInstance,string sFunctionClass,string sFunctionCall,object[] oaFunctionArguments )
		{
			const string sRoutineName = "DarkStrideToolbox.DSCompiler.Execute";
			bool bSuccess = true;

			try
			{
				m_oCurrentCode = (Script)m_oScripts.GetByKey( sCodeKey );
				bSuccess = Execute( oInstance,oInstance.GetType().Name,sFunctionCall,oaFunctionArguments );
			}
			catch( System.Exception e )
			{
				throw new System.Exception( sRoutineName,e );
			}

			return( bSuccess );
		}

		public bool Execute( object oInstance,string sFunctionClass,string sFunctionCall,object[] oaFunctionArguments )
		{
			const string sRoutineName = "DarkStrideToolbox.DSCompiler.Execute";
			Assembly oAssembly = null;
			Type oScriptType = null;
			bool bSuccess = true;

			try
			{
				oAssembly = m_oCurrentCode.m_oCompiledCode.CompiledAssembly;
				oScriptType = oAssembly.GetType( sFunctionClass );

				try
				{
					oScriptType.InvokeMember(sFunctionCall, BindingFlags.Public
												| BindingFlags.Static | BindingFlags.InvokeMethod,
												null, oInstance, oaFunctionArguments ); 
				}
				catch( System.Exception e )
				{
					bSuccess = false;
					throw new System.Exception( "The error <" + e.Message + "> was received when calling <" + sFunctionClass + "." + sFunctionCall + ">" );
				}
			}
			catch( System.Exception e )
			{
				throw new System.Exception( sRoutineName,e );
			}

			return( bSuccess );
		}


		public static System.Exception ConvertCompileErrorsToExceptions( System.CodeDom.Compiler.CompilerErrorCollection oErrors )
		{
			const string sRoutineName = "DarkStrideToolbox.DSCompiler.Execute";
			string sMsg = "";
			System.Exception oSysExc = null;

			try
			{
				foreach( System.CodeDom.Compiler.CompilerError oError in oErrors )
				{
					sMsg = "Line " + oError.Line.ToString() + ".  ";

					if( oError.IsWarning == true )
					{
						sMsg += "Warning ";
					}
					else
					{
						sMsg += "Error ";
					}

					sMsg += oError.ErrorNumber.ToString() + ":  " + oError.ErrorText + "      (" + oError.FileName + ")";

					oSysExc = new System.Exception( sMsg,oSysExc );
				}
			}
			catch( System.Exception e )
			{
				throw new System.Exception( sRoutineName,e );
			}

			return( oSysExc );
		}

		public static object FindInterface( System.Reflection.Assembly oDLL, string oInterfaceName )
		{
			const string sRoutineName = "DarkStrideToolbox.DSCompiler.FindInterface";
			object oRetVal = null;

			try
			{
				// Loop through types looking for one that implements the given interface
				foreach( Type oType in oDLL.GetTypes())
				{
					if( oType.GetInterface( oInterfaceName,true ) != null )
					{
						oRetVal = oDLL.CreateInstance( oType.FullName );
						break;
					}
				}
			}
			catch( System.Exception e )
			{
				throw new System.Exception( sRoutineName,e );
			}

			return( oRetVal );
		}


		public CompilerResults CompiledCode( string sKey )
		{
			const string sRoutineName = "DarkStrideToolbox.DSCompiler.CompiledCode";
			Script oScript;
			CompilerResults oResults = null;

			try
			{
				if( m_oScripts.ContainsKey( sKey ) == true )
				{
					oScript = (Script)m_oScripts.GetByKey( sKey );
					oResults = oScript.m_oCompiledCode; 
				}
				else
				{
					throw new System.Exception( "Unable to locate script with key <" + sKey + ">." );
				}
			}
			catch( System.Exception e )
			{
				throw new System.Exception( sRoutineName,e );
			}

			return( oResults );
		}



		#region Properties
		#endregion
	}
}