//---------------------------------------------------------------------------------------------------------------------------------------------------
// CSharpCompiler class 
// Designed to execute code with the required assemblies, both C# code as well as DW engine code
// Takes the student code, compiles it into memory, and returns the results
//---------------------------------------------------------------------------------------------------------------------------------------------------
// Engineered by: Amanda Chaffin
//---------------------------------------------------------------------------------------------------------------------------------------------------

namespace DarkWynter.Engine.Compiler
{
    #region Using Statements
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    using System.Runtime.CompilerServices;
    using System.Reflection;
    using Microsoft.CSharp;
    using System.Security;
    using System.Security.Permissions;
    using System.IO; 
    #endregion
    /// <summary>
    /// Creates a CSharpCompiler for use in game
    /// </summary>
    public class CSharpCompiler
    {

        public static object Execute(string source,
                                     string className,
                                     string functionName,
                                     object[] parameters)
        {

            CompilerResults compilerResults = CompileCode(source);

            if (compilerResults.Errors.Count > 0)
            {
                throw new Exception("Not a valid assembly");
            }
            return Execute(compilerResults.CompiledAssembly, className, functionName, parameters);
        }

        /// <summary>
        /// Executes the code with the assembly information
        /// </summary>
        /// <param name="a">assembly provided</param>
        /// <param name="parameters">any needed object parameters</param>6
        /// <param name="callingObject">the object that calls the method</param>
        /// <returns>returns the null object</returns>
        public static object Execute(Assembly a,
                                    // string className,
                                   //  string functionName,
                                     object[] parameters,
                                     ref object callingObject)
        {
            object obj = null;

        
                Type type = a.GetType();
                foreach (Type tempType in a.GetTypes())
                {
                    type = tempType;

                    try
                    {
                        foreach (MethodInfo info in type.GetMethods())
                        {
                            Array tempArray = info.GetParameters();
                            if (info.GetParameters().Length == 0)
                            {
                                if (obj == null)
                                {
                                    obj = Activator.CreateInstance(type);
                                    info.Invoke(obj, null);
                                }
                            }

                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                    }
                }
            
            return obj;
        }
        /// <summary>
        /// Calls the execute function
        /// </summary>
        /// <param name="a">assembly provided</param>
        /// <param name="className">Name of the class to be executed</param>
        /// <param name="parameters">any needed object parameters</param>
        /// <param name="callingObject">the object that calls the method</param>
        /// <returns>returns the null object</returns>
        public static object Execute(Assembly assembly, string className, string functionName, object[] parameters)
        {
            object o = null;
            return Execute(assembly,  parameters, ref o);
        }
        /// <summary>
        /// Gets the student code from the CompilerControl
        /// Adds in the assemblies we use to allow student control of game code
        /// Calls execute
        /// </summary>
        /// <param name="source">Student code</param>
        /// <returns>The results from the compiler</returns>
        public static CompilerResults CompileCode(String source)
        {

            CodeDomProvider provider = new CSharpCodeProvider();
            CompilerParameters compilerParameters = new CompilerParameters();

            // Generate a class library.
            compilerParameters.GenerateExecutable = false;
            compilerParameters.GenerateInMemory = true;

            // Generate debug information.
            compilerParameters.IncludeDebugInformation = false;

            // Add an assembly reference.
            Assembly assembly = Assembly.GetExecutingAssembly();

            foreach (AssemblyName assemblyName in
                            Assembly.GetEntryAssembly().GetReferencedAssemblies())
            {
                if (assemblyName.Name == "DWEngine" ||
                    assemblyName.Name == "DWStream")
                {
                    compilerParameters.ReferencedAssemblies.Add(assemblyName.Name + ".dll");
                }
            }
            // compilerParameters.ReferencedAssemblies.Add("DarkWynterGame" + ".dll");

            // Set the level at which the compiler 
            // should start displaying warnings.
            compilerParameters.WarningLevel = 3;

            // Set whether to treat all warnings as errors.
            compilerParameters.TreatWarningsAsErrors = false;


            // Set compiler argument to optimize output.
            compilerParameters.CompilerOptions = "/optimize";


            // Invoke compilation.
            CompilerResults compilerResults = provider.CompileAssemblyFromSource(
                                        compilerParameters, new string[] { source });

                  return compilerResults;
            //}
           
        }



    }
}