using System;
using System.Collections.Generic;
using System.Text;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Reflection;
using System.IO;
using System.Diagnostics;
using System.Collections.Specialized;
using Microsoft.CSharp;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Reflection;


namespace CSTextEditor
{
    public delegate void CompilerOutputDelegate(string outputLine);
    
    
    public class CSCompiler
    {

        public CSharpCodeProvider codeProvider = new CSharpCodeProvider();

        public String text;
        public string[] references;
        private Assembly cachedScriptAssembly = null;


        public CSCompiler() { }

        public CSCompiler(String code, string[] referenceLibraries)
        {
            this.text = code;
            references = referenceLibraries;
        }



        public void Compile(CompilerOutputDelegate cod)
        {
            try
            {
                cachedScriptAssembly = Compile(this, cod).CompiledAssembly;
            }
            catch (System.IO.FileNotFoundException exp)
            {
                throw new Exception("Unable to load script assembly (probably a complier error, check debug output)", exp);
            }
        }


        public void Run(CompilerOutputDelegate cod, object subject, object[] parameters, PermissionSet permissionSet)
        {
            if (cachedScriptAssembly == null)
            {
                cachedScriptAssembly = Compile(this, cod).CompiledAssembly;
            }


            if (cachedScriptAssembly != null)
            {
                // run script
                //this.cachedScriptAssembly.GetType( Template.ScriptClassName ).GetMethod( Template.ScriptMainMethodName ).Invoke(subject, parameters);

                Process process = new Process();
                process.StartInfo.FileName = cachedScriptAssembly.Location;
                process.Start();

            }
        }


        private CompilerResults Compile(CSCompiler code, CompilerOutputDelegate cod)
        {
            CompilerParameters compileParams = new CompilerParameters();
            compileParams.GenerateExecutable = true;
            compileParams.GenerateInMemory = false;
            compileParams.IncludeDebugInformation = false;
            compileParams.TreatWarningsAsErrors = true;
            compileParams.ReferencedAssemblies.AddRange(code.references);

            CompilerResults results = codeProvider.CompileAssemblyFromSource(compileParams, code.text);

            if (results.Errors.HasErrors)
            {
                cod("-- Compilation of script failed");

                foreach (CompilerError err in results.Errors)
                {
                    cod(err.ToString());
                }
            }
            else
            {
                cod("-- Compilation of script succesfull");
            }
            return results;
        }


        public static PermissionSet GetDefaultScriptPermissionSet()
        {
            PermissionSet internalDefScriptPermSet = new PermissionSet(PermissionState.None);
            internalDefScriptPermSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
            internalDefScriptPermSet.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.MemberAccess));

            return internalDefScriptPermSet;
        }
    }
}