namespace ElementalGame
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    using System.Reflection;
    using Microsoft.VisualC;

    public class ScriptManager : MarshalByRefObject//, IScriptManager
    {
        public Compiler.Language language = Compiler.Language.NONE;

        CodeDomProvider provider;       // CSharp and VB
        CppCodeProvider cppProvider;    // C++
        ICodeCompiler compiler;
        CompilerResults results;

        public void CreateCompiler(Compiler.Language CodeLanguage)
        {
            //string extension = Path.GetExtension(file);
            switch (CodeLanguage)
            {
                case Compiler.Language.CPP:
                    cppProvider = new CppCodeProvider();
                    break;
                case Compiler.Language.CSHARP:
                    provider = new Microsoft.CSharp.CSharpCodeProvider();
                    break;
                case Compiler.Language.VB:
                    provider = new Microsoft.VisualBasic.VBCodeProvider();
                    break;
                case Compiler.Language.JSHARP:
                    provider = (CodeDomProvider)Activator.CreateInstance(
                        "Microsoft.JScript","Microsoft.JScript.JScriptCodeProvider").Unwrap();
                    break;
            }
        }

        public void CompileFromFile(string file)
        {

            // Set up compiler params
            CompilerParameters compilerparams = new CompilerParameters();
            compilerparams.GenerateInMemory = true;
            compilerparams.GenerateExecutable = true;

            // Get compilation results
            if (language == Compiler.Language.CPP)
            {
                results = cppProvider.CompileAssemblyFromFile(compilerparams, file);
            }
            else
            {
                results = provider.CompileAssemblyFromFile(compilerparams, file);
            }
        }

        public void CompileFromSource(string source)
        {

            // Set up compiler params
            CompilerParameters compilerparams = new CompilerParameters();
            compilerparams.GenerateInMemory = true;
            compilerparams.GenerateExecutable = true;


            // Get compilation results
            if (language == Compiler.Language.CPP)
            {
                results = cppProvider.CompileAssemblyFromSource(compilerparams, source);
            }
            else
            {
                results = provider.CompileAssemblyFromSource(compilerparams, source);
            }

        }

        public void Execute(string[] args)
        {
            // Execute compiled results
            results.CompiledAssembly.EntryPoint.Invoke( null, BindingFlags.Static, null, new object[] { args }, null);
        }
    }



    public class Compiler
    {
        public enum Language { CPP, CSHARP, VB, JSHARP, NONE };


        public Compiler(Language language)
        {
            
        }

        public void CompileFile(string file, string[] args)
        {
            //Create an AppDomain to compile and execute the code
            //This enables us to cancel the execution if needed
            AppDomain executionDomain = AppDomain.CreateDomain("ExecutionDomain");

            ScriptManager manager =
                (ScriptManager)executionDomain.CreateInstanceFromAndUnwrap(
                    typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly.Location, typeof(ScriptManager).FullName);

            manager.CompileFromFile(file);
            manager.Execute(args);

        }

        public void CompileSource(string source, string[] args)
        {
            //Create an AppDomain to compile and execute the code
            //This enables us to cancel the execution if needed
            AppDomain executionDomain = AppDomain.CreateDomain("ExecutionDomain");

            ScriptManager manager =
                (ScriptManager)executionDomain.CreateInstanceFromAndUnwrap(
                    typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly.Location, typeof(ScriptManager).FullName);

            manager.CompileFromSource(source);
            manager.Execute(args);


        }

        // Displays information from a CompilerResults.
        // Complements of MSDN
        // http://msdn2.microsoft.com/en-us/library/system.codedom.compiler.compilerresults.aspx
        public static void DisplayCompilerResults(CompilerResults results)
        {
            // If errors occurred during compilation, output the compiler output and errors.
            if (results.Errors.Count > 0)
            {
                for (int i = 0; i < results.Output.Count; i++)
                    Console.WriteLine(results.Output[i]);
                for (int i = 0; i < results.Errors.Count; i++)
                    Console.WriteLine(i.ToString() + ": " + results.Errors[i].ToString());

            }
            else
            {
                // Display information about the compiler's exit code and the generated assembly.
                Console.WriteLine("Compiler returned with result code: " + results.NativeCompilerReturnValue.ToString());
                Console.WriteLine("Generated assembly name: " + results.CompiledAssembly.FullName);
                if (results.PathToAssembly == null)
                    Console.WriteLine("The assembly has been generated in memory.");
                else
                    Console.WriteLine("Path to assembly: " + results.PathToAssembly);

                // Display temporary files information.
                if (!results.TempFiles.KeepFiles)
                    Console.WriteLine("Temporary build files were deleted.");
                else
                {
                    Console.WriteLine("Temporary build files were not deleted.");
                    // Display a list of the temporary build files
                    //IEnumerator enu = results.TempFiles.GetEnumerator();
                    //for (int i = 0; enu.MoveNext(); i++)
                    //    Console.WriteLine("TempFile " + i.ToString() + ": " + (string)enu.Current);
                }
            }
        }

    }
}