/// <summary>
 /// </summary>
 /// <param name="statusCallback"></param>
 /// <param name="wordDictionaryFile"></param>
 public DictionaryPapyrusNameResolver(IStatusCallbackService statusCallback, string wordDictionaryFile = null)
 {
     statusCallbackService = statusCallback;
     // "wordlist.txt"
     if (string.IsNullOrEmpty(wordDictionaryFile))
     {
         return;
     }
     if (File.Exists(wordDictionaryFile))
     {
         statusCallbackService.WriteLine("Loading wordlist... This may take a few seconds.");
         WordList = File.ReadAllLines(wordDictionaryFile);
     }
     else
     {
         statusCallbackService.WriteLine("Wordlist was not found, skipping...");
         WordList = new string[0];
     }
 }
        /// <summary>
        ///     Builds a .NET Assembly using the input Papyrus Source
        /// </summary>
        /// <param name="inputSourceFiles"></param>
        public async void BuildAssembly(string[] inputSourceFiles)
        {
            // @"C:\The Elder Scrolls V Skyrim\Data\scripts\Source"
            var files = inputSourceFiles;

            var resolvedAssemblyName = AssemblyNameResolver.Resolve(null);

            CoreAssembly = AssemblyDefinition.CreateAssembly(
                resolvedAssemblyName,
                resolvedAssemblyName.Name, ModuleKind.Dll);

            MainModule = CoreAssembly.MainModule;

            var papyrusObjects = new List <PapyrusAssemblyObject>();

            StatusCallback.WriteLine("Parsing Papyrus... This usually takes about 30 seconds.");

            totalFilesToParse = files.Length;

            var asyncParse = files.Select(Parse);

            papyrusObjects.AddRange(await Task.WhenAll(asyncParse.ToArray()));

            StatusCallback.Title = "PapyrusDotNet";

            StatusCallback.WriteLine("Adding object references... This usually takes about a minute.");
            foreach (var pasObj in papyrusObjects)
            {
                AddedTypeReferences.Add(TypeReferenceResolver.Resolve(MainModule, null, pasObj.Name));
            }

            foreach (var pas in papyrusObjects)
            {
                MainModule.Types.Add(TypeDefinitionResolver.Resolve(MainModule, pas));
            }

            StatusCallback.WriteLine("Resolving object references... This usually takes about 30 seconds.");
            foreach (var t in MainModule.Types)
            {
                foreach (var f in t.Methods)
                {
                    var typeDefinition = MainModule.Types.FirstOrDefault(ty => ty.FullName == f.ReturnType.FullName);
                    f.ReturnType = TypeReferenceResolver.Resolve(MainModule, typeDefinition, f.ReturnType.FullName);
                    foreach (var p in f.Parameters)
                    {
                        var td = MainModule.Types.FirstOrDefault(ty => ty.FullName == p.ParameterType.FullName);
                        if (td != null)
                        {
                            /*	// Most likely a System object.
                             *  p.ParameterType = GetTypeReference(null, p.ParameterType.FullName);
                             * else */
                            p.ParameterType = TypeReferenceResolver.Resolve(MainModule, typeDefinition, td.FullName);
                        }
                    }
                }
            }

            StatusCallback.WriteLine("Importing Papyrus specific attributes...");


            var allAttributesToInclude = Assembly.GetExecutingAssembly().GetTypes().Where(
                t => t.Name.ToLower().EndsWith("attribute")
                //TODO: we should include the PapyrusDotNet.System here as well.
                );

            foreach (var attr in allAttributesToInclude)
            {
                ImportType(MainModule, attr);
            }

            CoreAssembly.Write(AssemblyNameResolver.OutputLibraryFilename);

            StatusCallback.ForegroundColor = ConsoleColor.Green;
            StatusCallback.WriteLine(AssemblyNameResolver.OutputLibraryFilename + " successefully generated.");
            StatusCallback.ResetColor();
        }
        public TypeDefinition Resolve(ModuleDefinition mainModule, PapyrusAssemblyObject input)
        {
            var newType = new TypeDefinition(assemblyNameResolver.BaseNamespace, input.Name, TypeAttributes.Class)
            {
                IsPublic = true
            };


            // newType.DeclaringType = newType;
            if (!string.IsNullOrEmpty(input.ExtendsName))
            {
                newType.BaseType = new TypeReference(assemblyNameResolver.BaseNamespace, input.ExtendsName, mainModule,
                                                     mainModule);
                // newType.DeclaringType = MainModule.Types.FirstOrDefault(t => t.FullName == newType.BaseType.FullName);
                newType.Scope = mainModule;
            }
            else
            {
                newType.BaseType = mainModule.TypeSystem.Object;
                newType.Scope    = mainModule;
            }

            statusCallback.WriteLine("Generating Type '" + assemblyNameResolver.BaseNamespace + "." + input.Name +
                                     "'...");

            foreach (var prop in input.PropertyTable)
            {
                var typeRef = referenceResolver.Resolve(mainModule, null, prop.Type);
                var pro     = new PropertyDefinition(prop.Name, PropertyAttributes.HasDefault, typeRef);
                newType.Properties.Add(pro);
            }

            // newType.AddDefaultConstructor();

            builder.AddEmptyConstructor(newType);

            builder.AddVirtualOnInit(newType);

            foreach (var papyrusAsmState in input.States)
            {
                foreach (var papyrusAsmFunction in papyrusAsmState.Functions)
                {
                    var typeReference = referenceResolver.Resolve(mainModule, null, papyrusAsmFunction.ReturnType);
                    // var typeRef = MainModule.TypeSystem.Void;

                    var function = new MethodDefinition(papyrusAsmFunction.Name, MethodAttributes.Public, typeReference)
                    {
                        IsStatic = papyrusAsmFunction.IsStatic
                    };

                    if (function.IsStatic)
                    {
                        function.HasThis = false;
                    }
                    if (!function.IsStatic && papyrusAsmFunction.Name.StartsWith("On") || papyrusAsmFunction.IsEvent)
                    {
                        function.IsVirtual = true;
                    }
                    else
                    {
                        function.IsVirtual = false;
                    }

                    builder.CreateEmptyFunctionBody(ref function);

                    foreach (var par in papyrusAsmFunction.Params)
                    {
                        var resolvedTypeReference = referenceResolver.Resolve(mainModule, null, par.Type);
                        // var typeRefp = MainModule.TypeSystem.Object;

                        var nPar = new ParameterDefinition(par.Name, ParameterAttributes.None, resolvedTypeReference);
                        function.Parameters.Add(nPar);
                    }
                    var skipAdd = false;
                    foreach (var m in newType.Methods)
                    {
                        if (m.Name == function.Name)
                        {
                            if (m.Parameters.Count == function.Parameters.Count)
                            {
                                skipAdd = true;
                                for (var pi = 0; pi < m.Parameters.Count; pi++)
                                {
                                    if (m.Parameters[pi].ParameterType.FullName !=
                                        function.Parameters[pi].ParameterType.FullName)
                                    {
                                        skipAdd = false;
                                    }
                                }
                                break;
                            }
                        }
                    }
                    if (!skipAdd)
                    {
                        newType.Methods.Add(function);
                    }
                }
            }
            return(newType);
        }