private static void ProjectTemplateIndexerThread(object parm)
        {
            try
            {
                var projectTemplateDirectory = new DirectoryInfo(VSConfig.ProjectTemplateDirectory);
                var itemTemplateDirectory    = new DirectoryInfo(VSConfig.ItemTemplateDirectory);
                var additionalLocations      = (List <CustomTemplateLocation>)ConfigurationManager.GetSection("VSTemplateLocationsSection/VSTemplateLocations");
                var stopWatch = new Stopwatch();
                VSConfigIndexOptions options = null;

                if (parm != null)
                {
                    options = (VSConfigIndexOptions)parm;
                }

                RaiseOnIndexingStatus("Project template indexer started");
                stopWatch.Start();

                Debug.Assert(projectTemplateDirectory.Exists);

                if (ProjectTempWorkspace.Exists)
                {
                    try
                    {
                        RecurseDelete(ProjectTempWorkspace);
                    }
                    catch
                    {
                    }
                }

                RecurseDirectory(projectTemplateDirectory, null, options);

                if (additionalLocations != null)
                {
                    additionalLocations.ForEach(c => RecurseDirectory(new DirectoryInfo(c.TemplateLocation.Expand()), new DirectoryInfo(c.CommonLocation.Expand()), options));
                }

                if (ProjectTempWorkspace.Exists)
                {
                    try
                    {
                        RecurseDelete(ProjectTempWorkspace);
                    }
                    catch
                    {
                    }
                }

                stopWatch.Stop();
                RaiseOnIndexingStatus("Project template indexer complete in " + stopWatch.Elapsed.Seconds.ToString() + " seconds.");
            }
            catch (Exception ex)
            {
                throw;
            }

            projectTemplateIndexerEvent.Set();
        }
        private static void RecurseDirectory(DirectoryInfo directory, DirectoryInfo commonLocation = null, VSConfigIndexOptions options = null)
        {
            var resultNotUsed  = 0;
            var subDirectories = directory.GetDirectories();
            var languageRoot   = subDirectories.Length > 0 && subDirectories.All(d => int.TryParse(d.Name, out resultNotUsed));
            var languageID     = Thread.CurrentThread.CurrentCulture.LCID;

            foreach (var fileInfo in directory.GetFiles("*.zip"))
            {
                ProcessZip(fileInfo, commonLocation);
                TemplatesProcessed++;
            }

            if (languageRoot)
            {
                foreach (var subDir in subDirectories.Where(d => d.Name == languageID.ToString()))
                {
                    if (options.ProjectTemplatesFolderRegex != null)
                    {
                        if (subDir.FullName.RegexIsMatch(options.ProjectTemplatesFolderRegex))
                        {
                            RecurseDirectory(subDir, commonLocation, options);
                        }
                    }
                    else
                    {
                        RecurseDirectory(subDir, commonLocation, options);
                    }
                }
            }
            else
            {
                foreach (var subDir in subDirectories)
                {
                    RecurseDirectory(subDir, commonLocation, options);
                }
            }
        }
        private static void ProcessTemplateDirectories(VSConfigIndexOptions options = null)
        {
            var stopWatch = new Stopwatch();

            RaiseOnIndexingStatus("Processing template directories started");
            stopWatch.Start();

            var dirs = projectTemplateDirectories.Values.OrderBy(d => d.SortPriority);

            projectTemplateDirectories.Values.ToList().ForEach(d =>
            {
                Action <int, VSTemplateDirectory> recurse = null;

                recurse = (int indent, VSTemplateDirectory dir) =>
                {
                    // search based on TemplateDir in directory entry (most likely finds none)

                    if (dir.AllTemplateDirs != null)
                    {
                        dir.AllTemplateDirs.ForEach(td =>
                        {
                            var dirTemplates = projectTemplates.Values.Where(t => t.TemplateLocation.StartsWith(td.FullName));

                            if (dirTemplates.Count() > 0)
                            {
                                dirTemplates.ToList().ForEach(t =>
                                {
                                    dir.AllTemplates.Add(t);
                                });
                            }
                        });
                    }

                    // search based on project type

                    if (dir.ProjectType != null)
                    {
                        var dirTemplates2 = projectTemplates.Values.Where(t => t.ProjectTypeName == dir.ProjectType);

                        if (dirTemplates2.Count() > 0)
                        {
                            dirTemplates2.ToList().ForEach(t =>
                            {
                                dir.AllTemplates.Add(t);
                            });
                        }

                        dir.BuildOut();
                        dir.SubDirectories.ForEach(d2 => recurse(indent + 1, d2));
                    }
                };

                recurse(0, d);
            });

            if (options.IndexItemTemplates)
            {
                var generalDirectory = new VSTemplateDirectory("General");

                foreach (var itemTemplate in VSConfigProvider.ItemTemplates.Values.Where(t => string.IsNullOrEmpty(t.TemplateGroupID)).OrderBy(t => t.Name))
                {
                    generalDirectory.AllTemplates.Add(itemTemplate);
                }

                generalDirectory.BuildOut();

                itemTemplateDirectories.Add(generalDirectory.Name, generalDirectory);

                var groups = VSConfigProvider.ItemTemplates.Values.Where(t => !string.IsNullOrEmpty(t.TemplateGroupID)).Select(t => t.TemplateGroupID).Distinct();

                foreach (var group in groups)
                {
                    var groupDirectory = new VSTemplateDirectory(group);

                    foreach (var itemTemplate in VSConfigProvider.ItemTemplates.Values.Where(t => !string.IsNullOrEmpty(t.TemplateGroupID) && t.TemplateGroupID == group).OrderBy(t => t.Name))
                    {
                        groupDirectory.AllTemplates.Add(itemTemplate);
                    }

                    groupDirectory.BuildOut();

                    itemTemplateDirectories.Add(groupDirectory.Name, groupDirectory);
                }
            }

            stopWatch.Stop();
            RaiseOnIndexingStatus("Processing template directories complete in " + stopWatch.Elapsed.Seconds.ToString() + " seconds.");

            directoriesEvent.Set();
        }
        public static void Index(VSConfigIndexOptions options = null)
        {
            if (!indexStarted)
            {
                var stopWatch = new Stopwatch();

                RaiseOnIndexingStatus("Indexing engine started");
                stopWatch.Start();

                itemTemplates         = new Dictionary <string, ICodeItemTemplate>();
                projectTemplates      = new Dictionary <string, ICodeProjectTemplate>();
                projectGroupTemplates = new Dictionary <string, ICodeTemplate>();
                packages = new Dictionary <Guid, VSPackage>();
                projectTemplateDirectories = new Dictionary <Guid, VSTemplateDirectory>();
                itemTemplateDirectories    = new Dictionary <string, VSTemplateDirectory>();
                factoryProjects            = new Dictionary <Guid, VSProjectFactoryProject>();
                services = new Dictionary <Guid, VSService>();

                projectTemplateIndexerEvent = new ManualResetEvent(false);
                itemTemplateIndexerEvent    = new ManualResetEvent(false);
                packageIndexerEvent         = new ManualResetEvent(false);

                if (options == null || options.LoadEnvironmentServices)
                {
                    VSEnvironmentService.LoadEnvironmentServices();
                }

                if (options == null || options.IndexProjectTemplates)
                {
                    // start project templates

                    options.IndexPackages = true;

                    projectTemplateIndexerThread = new Thread(ProjectTemplateIndexerThread);

                    projectTemplateIndexerThread.Priority = ThreadPriority;

                    projectTemplateIndexerThread.Start(options);
                }

                if (options == null || options.IndexItemTemplates)
                {
                    // start item templates

                    options.IndexPackages = true;

                    itemTemplateIndexerThread = new Thread(ItemTemplateIndexerThread);

                    itemTemplateIndexerThread.Priority = ThreadPriority;

                    itemTemplateIndexerThread.Start();
                }

                // start packages

                if (options == null || options.IndexPackages)
                {
                    packageIndexerThread = new Thread(PackageIndexerThread);

                    packageIndexerThread.Priority = ThreadPriority;

                    packageIndexerThread.Start();
                }

                directoriesEvent = new ManualResetEvent(false);

                var task = new Task(() =>
                {
                    if (options == null || options.IndexItemTemplates)
                    {
                        itemTemplateIndexerEvent.WaitOne();
                    }

                    if (options == null || options.IndexProjectTemplates)
                    {
                        projectTemplateIndexerEvent.WaitOne();
                    }

                    ProcessTemplateDirectories(options);

                    stopWatch.Stop();
                    RaiseOnIndexingStatus("Indexing engine complete in " + stopWatch.Elapsed.Seconds.ToString() + " seconds.");
                });

                task.Start();

                indexStarted = true;
            }
        }