/// <summary>
 /// Get a list of all embedded assemblies
 /// </summary>
 /// <returns>IEnumerable with a containing the names of the resource and of the assemblie</returns>
 public IEnumerable <string> EmbeddedAssemblyNames(IEnumerable <Assembly> assembliesToCheck = null)
 {
     foreach (var loadedAssembly in assembliesToCheck ?? LoadedAssemblies.Where(pair => !AssembliesToIgnore.IsMatch(pair.Key)).Select(pair => pair.Value).ToList())
     {
         string[] resources;
         try
         {
             resources = Resources.GetCachedManifestResourceNames(loadedAssembly);
         }
         catch (Exception ex)
         {
             Log.Warn().WriteLine(ex, "Couldn't retrieve resources from {0}", loadedAssembly.GetName().Name);
             continue;
         }
         foreach (var resource in resources)
         {
             var resourceMatch = _assemblyResourceNameRegex.Match(resource);
             if (resourceMatch.Success)
             {
                 yield return(resourceMatch.Groups["assembly"].Value);
             }
         }
     }
 }
        /// <summary>
        /// This is called when a new assembly is loaded, we need to know this
        /// </summary>
        /// <param name="sender">object</param>
        /// <param name="args">AssemblyLoadEventArgs</param>
        private void AssemblyLoad(object sender, AssemblyLoadEventArgs args)
        {
            var loadedAssembly = args.LoadedAssembly;
            var assemblyName   = loadedAssembly.GetName().Name;

            if (Log.IsVerboseEnabled())
            {
                Log.Verbose().WriteLine("Loaded {0}", assemblyName);
            }
            LoadedAssemblies[assemblyName] = loadedAssembly;

            if (!_applicationConfig.ScanForEmbeddedAssemblies)
            {
                return;
            }

            // Ignore resource checking on certain assemblies
            if (AssembliesToIgnore.IsMatch(assemblyName))
            {
                return;
            }

            string[] resources;
            try
            {
                resources = Resources.GetCachedManifestResourceNames(loadedAssembly);
            }
            catch (Exception ex)
            {
                Log.Warn().WriteLine(ex, "Couldn't retrieve resources from {0}", loadedAssembly.GetName().Name);
                return;
            }
            foreach (var resource in resources)
            {
                var resourceMatch = _assemblyResourceNameRegex.Match(resource);
                if (!resourceMatch.Success)
                {
                    continue;
                }

                var embeddedAssemblyName = resourceMatch.Groups["assembly"].Value;
                if (LoadedAssemblies.ContainsKey(embeddedAssemblyName))
                {
                    // Ignoring already loaded assembly, as we cannot unload.
                    continue;
                }
                var newAssemblyLocation = new AssemblyLocationInformation(embeddedAssemblyName, loadedAssembly, resource);
                if (AvailableAssemblies.TryGetValue(embeddedAssemblyName, out var availableAssemblyLocationInformation))
                {
                    if (availableAssemblyLocationInformation.FileDate > newAssemblyLocation.FileDate)
                    {
                        continue;
                    }
                }
                if (Log.IsVerboseEnabled())
                {
                    Log.Verbose().WriteLine("Detected additional assembly {0} in {1}", embeddedAssemblyName, loadedAssembly.GetName().Name);
                }
                AvailableAssemblies[embeddedAssemblyName] = newAssemblyLocation;
            }
        }
        /// <summary>
        /// Do the one time scan of all the assemblies
        /// </summary>
        private void ScanForAssemblies()
        {
            var assemblies = new HashSet <AssemblyLocationInformation>();

            if (_applicationConfig.ScanForEmbeddedAssemblies)
            {
                foreach (var loadedAssembly in LoadedAssemblies.Where(pair => !AssembliesToIgnore.IsMatch(pair.Key)).Select(pair => pair.Value).ToList())
                {
                    string[] resources;
                    try
                    {
                        resources = Resources.GetCachedManifestResourceNames(loadedAssembly);
                    }
                    catch (Exception ex)
                    {
                        Log.Warn().WriteLine(ex, "Couldn't retrieve resources from {0}", loadedAssembly.GetName().Name);
                        continue;
                    }
                    foreach (var resource in resources)
                    {
                        var resourceMatch = _assemblyResourceNameRegex.Match(resource);
                        if (resourceMatch.Success)
                        {
                            assemblies.Add(new AssemblyLocationInformation(resourceMatch.Groups["assembly"].Value, loadedAssembly, resource));
                        }
                    }
                }
            }

            if (_applicationConfig.UseStrictChecking)
            {
                foreach (var applicationConfigScanDirectory in _applicationConfig.ScanDirectories)
                {
                    if (!Directory.Exists(applicationConfigScanDirectory))
                    {
                        throw new DirectoryNotFoundException(applicationConfigScanDirectory);
                    }
                }
            }
            foreach (var fileLocation in FileLocations.Scan(_applicationConfig.ScanDirectories, _assemblyFilenameRegex, SearchOption.TopDirectoryOnly))
            {
                assemblies.Add(new AssemblyLocationInformation(fileLocation.Item2.Groups["assembly"].Value, fileLocation.Item1));
            }

            // Reduce step 1) Take from the double assemblies only those which are embedded & on the file system in the probing path
            foreach (var assemblyGroup in assemblies.GroupBy(information => information.Name).ToList())
            {
                var groupList = assemblyGroup.ToList();
                if (groupList.Count <= 1)
                {
                    continue;
                }

                // Remove filesystem assemblies from the list which are not in the AssemblyResolveDirectories
                var unneededAssemblies = groupList.Where(info => !info.IsEmbedded && !info.IsOnProbingPath).ToList();
                if (groupList.Count - unneededAssemblies.Count < 1)
                {
                    continue;
                }

                foreach (var unneededAssemblyInformation in unneededAssemblies)
                {
                    assemblies.Remove(unneededAssemblyInformation);
                }
            }

            // Reduce step 2)
            foreach (var assemblyGroup in assemblies.GroupBy(information => information.Name).ToList())
            {
                var groupList = assemblyGroup.ToList();
                if (groupList.Count <= 1)
                {
                    continue;
                }
                // Remove assemblies which are older
                foreach (var unneededAssemblyInformation in groupList.OrderBy(info => info.FileDate).Skip(1).ToList())
                {
                    assemblies.Remove(unneededAssemblyInformation);
                }
            }

            // Create the assembly locations
            foreach (var assemblyLocationInformation in assemblies)
            {
                AvailableAssemblies[assemblyLocationInformation.Name] = assemblyLocationInformation;
            }
        }