using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;

using Microsoft.CSharp;
using System.Reflection;
using System.CodeDom;
using System.CodeDom.Compiler;
using Daifugou;
using System.IO;

namespace DaifugouWpf
{
	public class CodeDom
	{
		static CompilerResults Compile(string source)
		{
			CodeDomProvider provider = new CSharpCodeProvider(
				new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });

			CompilerParameters cp = new CompilerParameters();
			cp.GenerateInMemory = true;
            cp.ReferencedAssemblies.Add("System.Core.dll");
            cp.ReferencedAssemblies.Add(typeof(Game).Assembly.Location);

			CompilerResults cr = provider.CompileAssemblyFromSource(
				cp, source);

			return cr;
		}

        static IArtificialIntelligence Execute(CompilerResults cr)
		{
            if (cr.Errors.HasErrors)
            {
                throw new CodeDomException(cr.Errors);
            }

			Assembly asm = cr.CompiledAssembly;

            var aiType = asm.GetTypes().Where(t => (typeof(IArtificialIntelligence).IsAssignableFrom(t))).FirstOrDefault();

            if (aiType == null)
                return null;

            return aiType.GetConstructor(new Type[0]).Invoke(new object[0]) as IArtificialIntelligence;
		}

        public static IArtificialIntelligence Load(string filename)
        {
            string source;

            using (StreamReader sr = new StreamReader(filename))
            {
                source = sr.ReadToEnd();
            }

            var cr = Compile(source);
            var ai = Execute(cr);

            return ai;
        }
	}

    public class CodeDomException : Exception
    {
        CompilerErrorCollection errors;

        public CompilerErrorCollection Errors
        {
            get { return errors; }
            private set { errors = value; }
        }

        public CodeDomException(CompilerErrorCollection errors) : base("コンパイルエラー", null) { this.errors = errors; }
        public CodeDomException(CompilerErrorCollection errors, Exception innerException) : base("コンパイルエラー", innerException) { this.errors = errors; }
    }
}
