Inheritance: iSerializationEvents
        /// <summary> Processes any incoming FDA (Florida Dark Archive) reports, saves the data to the database, and archives the report in the resource folder </summary>
        /// <param name="Settings"> Instance-wide settings which may be required for this process </param>
        public override void DoWork(InstanceWide_Settings Settings)
        {
            // Step through each incoming folder and look for FDA reports
            if (( !String.IsNullOrEmpty(Settings.Florida.FDA_Report_DropBox)) && (Directory.Exists(Settings.Florida.FDA_Report_DropBox)))
            {
                // Create the FDA process
                FDA_Report_Processor fdaProcessor = new FDA_Report_Processor();

                // Process all pending FDA reports
                fdaProcessor.Process(Settings.Florida.FDA_Report_DropBox);

                // Log successes and failures
                if ((fdaProcessor.Error_Count > 0) || (fdaProcessor.Success_Count > 0))
                {
                    // Clear any previous report
                    SobekCM_Database.Builder_Clear_Item_Error_Log("FDA REPORT", "", "SobekCM Builder");

                    if (fdaProcessor.Error_Count > 0)
                    {
                        OnError("Processed " + fdaProcessor.Success_Count + " FDA reports with " + fdaProcessor.Error_Count + " errors", String.Empty, String.Empty, -1);
                    }
                    else
                    {
                        OnProcess("Processed " + fdaProcessor.Success_Count + " FDA reports", "Standard", String.Empty, String.Empty, -1);
                    }
                }
            }
        }
 /// <summary> Clears the old logs that are ready to be expired, per instance-wide settings </summary>
 /// <param name="Settings"> Instance-wide settings which may be required for this process </param>
 public override void DoWork(InstanceWide_Settings Settings)
 {
     // CLear the old logs
     //Console.WriteLine(dbInstance.Name + " - Expiring old log entries");
     //preloader_logger.AddNonError(dbInstance.Name + " - Expiring old log entries");
     //Library.Database.SobekCM_Database.Builder_Add_Log_Entry(-1, String.Empty, "Standard", "Expiring old log entries", String.Empty);
     //Library.Database.SobekCM_Database.Builder_Expire_Log_Entries(InstanceWide_Settings_Singleton.Settings.Builder_Log_Expiration_Days);
 }
        /// <summary> Rebuilds the static browse pages for the instance and aggregations </summary>
        /// <param name="Settings"> Instance-wide settings which may be required for this process </param>
        public override void DoWork(InstanceWide_Settings Settings)
        {
            //// Rebuild all the static pages
            //Console.WriteLine(dbInstance.Name + " - Rebuilding all static pages");
            //preloader_logger.AddNonError(dbInstance.Name + " - Rebuilding all static pages");
            //long staticRebuildLogId = Library.Database.SobekCM_Database.Builder_Add_Log_Entry(-1, String.Empty, "Standard", "Rebuilding all static pages", String.Empty);

            //Static_Pages_Builder builder = new Static_Pages_Builder(InstanceWide_Settings_Singleton.Settings.Application_Server_URL, InstanceWide_Settings_Singleton.Settings.Static_Pages_Location, InstanceWide_Settings_Singleton.Settings.Application_Server_Network);
            //builder.Rebuild_All_Static_Pages(preloader_logger, false, InstanceWide_Settings_Singleton.Settings.Local_Log_Directory, dbInstance.Name, staticRebuildLogId);
        }
        static void Main(string[] args)
        {
            // Collect the list of directories to look for and read all .xml files
            List<string> directories = new List<string>();

            // Add the default configuration directory first
            directories.Add(@"C:\GitRepository\SobekCM-Web-Application\SobekCM\config\default");

            // Add all of the plug-in foldersm but ensure they are sorted
            string plug_in_folder = @"C:\GitRepository\SobekCM-Web-Application\SobekCM\plugins";
            if (Directory.Exists(plug_in_folder))
            {
                // Get the list of subdirectories
                string[] subdirs = Directory.GetDirectories(plug_in_folder);

                // Ensure it is sorted alphabetically
                SortedList<string, string> subdirs_sorted = new SortedList<string, string>();
                foreach (string thisSubDir in subdirs)
                {
                    // Get the directory name and add to the sorted list
                    string dirName = (new DirectoryInfo(thisSubDir)).Name;
                    subdirs_sorted.Add(dirName, thisSubDir);
                }

                // Now, add each folder correctly sorted
                foreach (string thisSubDir in subdirs_sorted.Values)
                {
                    directories.Add(thisSubDir);
                    if (Directory.Exists(Path.Combine(thisSubDir, "config")))
                        directories.Add(Path.Combine(thisSubDir, "config"));
                }
            }

            // Add the final user configuration directory last
            directories.Add(@"C:\GitRepository\SobekCM-Web-Application\SobekCM\config\user");

            InstanceWide_Settings settings = new InstanceWide_Settings();

            // Read the configuration files
            InstanceWide_Configuration config = SobekCM.Engine_Library.Configuration.Configuration_Files_Reader.Read_Config_Files(directories, settings);

            StringBuilder XmlSb = new StringBuilder();
            TextWriter writerXml = new StringWriter(XmlSb);

            // Write out the config file
            XmlSerializer x = new XmlSerializer(config.GetType());
            x.Serialize(writerXml, config);

            StreamWriter writer = new StreamWriter("output.xml", false);
            writer.Write(XmlSb);
            writer.Flush();
            writer.Close();

            Console.ReadLine();
        }
        /// <summary> Constructor for a new instance of the Worker_BulkLoader class </summary>
        /// <param name="Logger"> Log file object for logging progress </param>
        /// <param name="Verbose"> Flag indicates if the builder is in verbose mode, where it should log alot more information </param>
        /// <param name="DbInstance"> This database instance </param>
        /// <param name="MultiInstanceBuilder"> Flag indicates if this is set to be a multi-instance builder configuration </param>
        /// <param name="LogFileDirectory"> Directory where any log files would be written </param>
        public Worker_BulkLoader(LogFileXhtml Logger, bool Verbose, Database_Instance_Configuration DbInstance, bool MultiInstanceBuilder, string LogFileDirectory )
        {
            // Save the log file and verbose flag
            logger = Logger;
            verbose = Verbose;
            instanceName = DbInstance.Name;
            canAbort = DbInstance.Can_Abort;
            multiInstanceBuilder = MultiInstanceBuilder;
            dbInstance = DbInstance;
            logFileDirectory = LogFileDirectory;

            if (multiInstanceBuilder)
                newItemLimit = 100;
            else
                newItemLimit = -1;

            Add_NonError_To_Log("Worker_BulkLoader.Constructor: Start", verbose, String.Empty, String.Empty, -1);

            // Create new list of collections to build
            aggregationsToRefresh = new List<string>();
            processedItems = new List<BibVidStruct>();
            deletedItems = new List<BibVidStruct>();

            // get all the info
            settings = InstanceWide_Settings_Builder.Build_Settings(dbInstance);
            Refresh_Settings_And_Item_List();

            // Ensure there is SOME instance name
            if (instanceName.Length == 0)
                instanceName = settings.System.System_Name;
            if (verbose)
                settings.Builder.Verbose_Flag = true;

            Add_NonError_To_Log("Worker_BulkLoader.Constructor: Created Static Pages Builder", verbose, String.Empty, String.Empty, -1);

            // Set some defaults
            aborted = false;

            Add_NonError_To_Log("Worker_BulkLoader.Constructor: Building modules for pre, post, and item processing", verbose, String.Empty, String.Empty, -1);

            Add_NonError_To_Log("Worker_BulkLoader.Constructor: Done", verbose, String.Empty, String.Empty, -1);
        }
 /// <summary> Optimizes the solr/lucene indexes for this instance </summary>
 /// <param name="Settings"> Instance-wide settings which may be required for this process </param>
 public override void DoWork(InstanceWide_Settings Settings)
 {
     //// Initiate a solr/lucene index optimization since we are done loading for a while
     //if (DateTime.Now.Day % 2 == 0)
     //{
     //	if (InstanceWide_Settings_Singleton.Settings.Document_Solr_Index_URL.Length > 0)
     //	{
     //		Console.WriteLine("Initiating Solr/Lucene document index optimization");
     //		Solr_Controller.Optimize_Document_Index(InstanceWide_Settings_Singleton.Settings.Document_Solr_Index_URL);
     //	}
     //}
     //else
     //{
     //	if (InstanceWide_Settings_Singleton.Settings.Page_Solr_Index_URL.Length > 0)
     //	{
     //		Console.WriteLine("Initiating Solr/Lucene page index optimization");
     //		Solr_Controller.Optimize_Page_Index(InstanceWide_Settings_Singleton.Settings.Page_Solr_Index_URL);
     //	}
     //}
     //// Sleep for twenty minutes to end this (the index rebuild might take some time)
     //Thread.Sleep(1000 * 20 * 60);
 }
        /// <summary> Refresh the settings and item list from the database </summary>
        /// <returns> TRUE if successful, otherwise FALSE </returns>
        public bool Refresh_Settings_And_Item_List()
        {
            // Disable the cache
            CachedDataManager.Settings.Disabled = true;

            Engine_Database.Connection_String = dbInstance.Connection_String;
            SobekCM_Database.Connection_String = dbInstance.Connection_String;
            Library.Database.SobekCM_Database.Connection_String = dbInstance.Connection_String;

            // Reload all the other data
            Engine_ApplicationCache_Gateway.RefreshAll(dbInstance);

            // Also, pull the engine configuration
            // Try to read the OAI-PMH configuration file
            if (File.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Directory + "\\config\\user\\sobekcm_microservices.config"))
            {
                SobekEngineClient.Read_Config_File(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Directory + "\\config\\user\\sobekcm_microservices.config", Engine_ApplicationCache_Gateway.Settings.Servers.System_Base_URL);
            }
            else if (File.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Directory + "\\config\\default\\sobekcm_microservices.config"))
            {
                SobekEngineClient.Read_Config_File(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Directory + "\\config\\default\\sobekcm_microservices.config", Engine_ApplicationCache_Gateway.Settings.Servers.System_Base_URL);
            }

            if (settings == null)
            {
                Add_Error_To_Log("Unable to pull the newest settings from the database", String.Empty, String.Empty, -1);
                return false;
            }

            // Save the item table
            itemTable = Library.Database.SobekCM_Database.Get_Item_List(true, null).Tables[0];

            // get all the info
            settings = InstanceWide_Settings_Builder.Build_Settings(dbInstance);
            BuilderSettings = new Builder_Modules();
            DataSet builderSettingsTbl = Engine_Database.Get_Builder_Settings(false, null);
            if (builderSettingsTbl == null)
            {
                Add_Error_To_Log("Unable to pull the newest BUILDER settings from the database", String.Empty, String.Empty, -1);
                return false;
            }
            if (!Builder_Settings_Builder.Refresh(BuilderSettings, builderSettingsTbl, false))
            {
                Add_Error_To_Log("Error building the builder settings from the dataset", String.Empty, String.Empty, -1);
                return false;
            }
            List<string> errors = BuilderSettings.Builder_Modules_From_Settings();

            if (( errors != null ) && ( errors.Count > 0 ))
            {
                long logId = Add_Error_To_Log("Error(s) builder the modules from the settings", String.Empty, String.Empty, -1);
                foreach (string thisError in errors)
                {
                    Add_Error_To_Log(thisError, String.Empty, String.Empty, logId);
                }
                return false;
            }

            // Add the event listeners
            foreach (iPreProcessModule thisModule in BuilderSettings.PreProcessModules)
            {
                thisModule.Error += module_Error;
                thisModule.Process += module_Process;
            }
            foreach (iSubmissionPackageModule thisModule in BuilderSettings.DeleteItemModules)
            {
                thisModule.Error += module_Error;
                thisModule.Process += module_Process;
            }
            foreach (iSubmissionPackageModule thisModule in BuilderSettings.ItemProcessModules)
            {
                thisModule.Error += module_Error;
                thisModule.Process += module_Process;
            }
            foreach (iPostProcessModule thisModule in BuilderSettings.PostProcessModules)
            {
                thisModule.Error += module_Error;
                thisModule.Process += module_Process;
            }
            foreach (iFolderModule thisModule in BuilderSettings.AllFolderModules)
            {
                thisModule.Error += module_Error;
                thisModule.Process += module_Process;
            }

            return true;
        }
 /// <summary> Method performs the work of the pre-process builder module </summary>
 /// <param name="Settings"> Instance-wide settings which may be required for this process </param>
 public abstract void DoWork( InstanceWide_Settings Settings );
        /// <summary> Builds the static aggregation-level (and instance-level) browse and RSS feed files </summary>
        /// <param name="AggregationsAffected"> List of aggregations affected during the last process of incoming digital resources </param>
        /// <param name="ProcessedItems"> List of all items just processed (or reprocessed) </param>
        /// <param name="DeletedItems"> List of all delete requests just processed </param>
        /// <param name="Settings"> Instance-wide settings which may be required for this process </param>
        public override void DoWork(List<string> AggregationsAffected, List<BibVidStruct> ProcessedItems, List<BibVidStruct> DeletedItems, InstanceWide_Settings Settings)
        {
            if (AggregationsAffected.Count == 0)
                return;

            long updatedId = OnProcess("....Performing some aggregation update functions", "Aggregation Updates", String.Empty, String.Empty, -1);

            // Create the new statics page builder
            // IN THIS CASE, WE DO NEED TO SET THE SINGLETON, SINCE THIS CALLS THE LIBRARIES
            Engine_ApplicationCache_Gateway.Settings = Settings;
            Static_Pages_Builder staticBuilder = new Static_Pages_Builder(Settings.Servers.Application_Server_URL, Settings.Servers.Static_Pages_Location, Settings.Servers.Application_Server_Network);

            // Step through each aggregation with new items
            foreach (string thisAggrCode in AggregationsAffected)
            {
                // Some aggregations can be excluded
                if ((thisAggrCode != "IUF") && (thisAggrCode != "ALL") && (thisAggrCode.Length > 1))
                {
                    // Get the display aggregation code (lower leading 'i')
                    string display_code = thisAggrCode;
                    if (display_code[0] == 'I')
                        display_code = 'i' + display_code.Substring(1);

                    // Get this item aggregations
                    Complete_Item_Aggregation aggregationCompleteObj = Engine_Database.Get_Item_Aggregation(thisAggrCode, false, null);
                    Item_Aggregation aggregationObj = Item_Aggregation_Utilities.Get_Item_Aggregation( aggregationCompleteObj, Engine_ApplicationCache_Gateway.Settings.System.Default_UI_Language, null);

                    // Get the list of items for this aggregation
                    DataSet aggregation_items = Engine_Database.Simple_Item_List(thisAggrCode, null);

                    // Create the XML list for this aggregation
                    OnProcess("........Building XML item list for " + display_code, "Aggregation Updates", String.Empty, String.Empty, updatedId);
                    try
                    {
                        string aggregation_list_file = Settings.Servers.Static_Pages_Location + "\\" + thisAggrCode.ToLower() + ".xml";
                        if (File.Exists(aggregation_list_file))
                            File.Delete(aggregation_list_file);
                        aggregation_items.WriteXml(aggregation_list_file, XmlWriteMode.WriteSchema);
                    }
                    catch (Exception ee)
                    {
                        OnError("........Error in building XML list for " + display_code + " on " + Settings.Servers.Static_Pages_Location + "\n" + ee.Message, String.Empty, String.Empty, updatedId);
                    }

                    OnProcess("........Building RSS feed for " + display_code, "Aggregation Updates", String.Empty, String.Empty, updatedId);
                    try
                    {
                        staticBuilder.Create_RSS_Feed(thisAggrCode.ToLower(), Settings.Local_Log_Directory, aggregationObj.Name, aggregation_items);
                        try
                        {
                            File.Copy(Settings.Local_Log_Directory + thisAggrCode.ToLower() + "_rss.xml", Settings.Servers.Static_Pages_Location + "\\rss\\" + thisAggrCode.ToLower() + "_rss.xml", true);
                            File.Copy(Settings.Local_Log_Directory + thisAggrCode.ToLower() + "_short_rss.xml", Settings.Servers.Static_Pages_Location + "\\rss\\" + thisAggrCode.ToLower() + "_short_rss.xml", true);
                        }
                        catch (Exception ee)
                        {
                            OnError("........Error in copying RSS feed for " + display_code + " to " + Settings.Servers.Static_Pages_Location + "\n" + ee.Message, String.Empty, String.Empty, updatedId);
                        }
                    }
                    catch (Exception ee)
                    {
                        OnError("........Error in building RSS feed for " + display_code + "\n" + ee.Message, String.Empty, String.Empty, updatedId);
                    }

                    OnProcess("........Building static HTML browse page of links for " + display_code, "Aggregation Updates", String.Empty, String.Empty, updatedId);
                    try
                    {
                        staticBuilder.Build_All_Browse(aggregationObj, aggregation_items);
                        try
                        {
                            File.Copy(Settings.Local_Log_Directory + thisAggrCode.ToLower() + "_rss.xml", Settings.Servers.Static_Pages_Location + "\\rss\\" + thisAggrCode.ToLower() + "_rss.xml", true);
                            File.Copy(Settings.Local_Log_Directory + thisAggrCode.ToLower() + "_short_rss.xml", Settings.Servers.Static_Pages_Location + "\\rss\\" + thisAggrCode.ToLower() + "_short_rss.xml", true);
                        }
                        catch (Exception ee)
                        {
                            OnError("........Error in copying RSS feed for " + display_code + " to " + Settings.Servers.Static_Pages_Location + "\n" + ee.Message, String.Empty, String.Empty, updatedId);
                        }
                    }
                    catch (Exception ee)
                    {
                        OnError("........Error in building RSS feed for " + display_code + "\n" + ee.Message, String.Empty, String.Empty, updatedId);
                    }

                }
            }

            // Build the full instance-wide XML and RSS here as well
            Recreate_Library_XML_and_RSS(updatedId, staticBuilder, Settings);
        }
        private void Recreate_Library_XML_and_RSS(long Builderid, Static_Pages_Builder StaticBuilder, InstanceWide_Settings Settings )
        {
            // Update the RSS Feeds and Item Lists for ALL
            // Build the simple XML result for this build
            OnProcess("........Building XML list for all digital resources", "Aggregation Updates", String.Empty, String.Empty, Builderid);
            try
            {
                DataSet simple_list = Engine_Database.Simple_Item_List(String.Empty, null);
                if (simple_list != null)
                {
                    try
                    {
                        string aggregation_list_file = Settings.Servers.Static_Pages_Location + "\\all.xml";
                        if (File.Exists(aggregation_list_file))
                            File.Delete(aggregation_list_file);
                        simple_list.WriteXml(aggregation_list_file, XmlWriteMode.WriteSchema);
                    }
                    catch (Exception ee)
                    {
                        OnError("........Error in building XML list for all digital resources on " + Settings.Servers.Static_Pages_Location + "\n" + ee.Message, String.Empty, String.Empty, Builderid);
                    }
                }
            }
            catch (Exception ee)
            {
                OnError("........Error in building XML list for all digital resources\n" + ee.Message, String.Empty, String.Empty, Builderid);
            }

            // Create the RSS feed for all ufdc items
            try
            {
                OnProcess("........Building RSS feed for all digital resources", "Aggregation Updates", String.Empty, String.Empty, Builderid);
                DataSet complete_list = Engine_Database.Simple_Item_List(String.Empty, null);

                StaticBuilder.Create_RSS_Feed("all", Settings.Local_Log_Directory, "All Items", complete_list);
                try
                {
                    File.Copy(Settings.Local_Log_Directory + "all_rss.xml", Settings.Servers.Static_Pages_Location + "\\rss\\all_rss.xml", true);
                    File.Copy(Settings.Local_Log_Directory + "all_short_rss.xml", Settings.Servers.Static_Pages_Location + "\\rss\\all_short_rss.xml", true);
                }
                catch (Exception ee)
                {
                    OnError("........Error in copying RSS feed for all digital resources to " + Settings.Servers.Static_Pages_Location + "\n" + ee.Message, String.Empty, String.Empty, Builderid);
                }
            }
            catch (Exception ee)
            {
                OnError("........Error in building RSS feed for all digital resources\n" + ee.Message, String.Empty, String.Empty, Builderid);
            }
        }
 /// <summary> Updates the database-based cached aggregation browse information </summary>
 /// <param name="Settings"> Instance-wide settings which may be required for this process </param>
 public override void DoWork(InstanceWide_Settings Settings)
 {
     SobekCM_Database.Admin_Update_Cached_Aggregation_Metadata_Links();
 }
        /// <summary> Refresh the settings and item list from the database </summary>
        /// <returns> TRUE if successful, otherwise FALSE </returns>
        public bool Refresh_Settings_And_Item_List()
        {
            // Create the tracer for this
            Custom_Tracer tracer = new Custom_Tracer();

            // Disable the cache
            CachedDataManager.Settings.Disabled = true;

            // Set all the database strings appropriately
            Engine_Database.Connection_String = instanceInfo.DatabaseConnection.Connection_String;
            SobekCM_Item_Database.Connection_String = instanceInfo.DatabaseConnection.Connection_String;
            Library.Database.SobekCM_Database.Connection_String = instanceInfo.DatabaseConnection.Connection_String;

            // Get the settings values directly from the database
            settings = InstanceWide_Settings_Builder.Build_Settings(instanceInfo.DatabaseConnection);
            if (settings == null)
            {
                Add_Error_To_Log("Unable to pull the newest settings from the database", String.Empty, String.Empty, -1);
                return false;
            }

            // If this was not refreshed yet, ensure [BASEURL] is replaced
            if (!refreshed)
            {
                // Determine the base url
                string baseUrl = String.IsNullOrWhiteSpace(settings.Servers.Base_URL) ? settings.Servers.Application_Server_URL : settings.Servers.Base_URL;
                List<MicroservicesClient_Endpoint> endpoints = instanceInfo.Microservices.Endpoints;
                foreach (MicroservicesClient_Endpoint thisEndpoint in endpoints)
                {
                    if (thisEndpoint.URL.IndexOf("[BASEURL]") > 0)
                        thisEndpoint.URL = thisEndpoint.URL.Replace("[BASEURL]", baseUrl).Replace("//", "/").Replace("http:/", "http://").Replace("https:/", "https://");
                    else if (( thisEndpoint.URL.IndexOf("http:/") < 0 ) && ( thisEndpoint.URL.IndexOf("https:/") < 0 ))
                        thisEndpoint.URL = ( baseUrl + thisEndpoint.URL).Replace("//", "/").Replace("http:/", "http://").Replace("https:/", "https://");
                }
                refreshed = true;
            }

            // Set the microservice endpoints
            SobekEngineClient.Set_Endpoints(instanceInfo.Microservices);

            // Load the necessary configuration objects into the engine application cache gateway
            try
            {
                Engine_ApplicationCache_Gateway.Configuration.OAI_PMH = SobekEngineClient.Admin.Get_OAI_PMH_Configuration(tracer);
            }
            catch (Exception ee)
            {
                Add_Error_To_Log("Unable to pull the OAI-PMH settings from the engine", String.Empty, String.Empty, -1);
                Add_Error_To_Log(ee.Message, String.Empty, String.Empty, -1);
                return false;
            }

            try
            {
                Engine_ApplicationCache_Gateway.Configuration.Metadata = SobekEngineClient.Admin.Get_Metadata_Configuration(tracer);
            }
            catch (Exception ee)
            {
                Add_Error_To_Log("Unable to pull the metadata settings from the engine", String.Empty, String.Empty, -1);
                Add_Error_To_Log(ee.Message, String.Empty, String.Empty, -1);
                return false;
            }

            try
            {
                Engine_ApplicationCache_Gateway.Configuration.Extensions = SobekEngineClient.Admin.Get_Extensions_Configuration(tracer);
            }
            catch (Exception ee)
            {
                Add_Error_To_Log("Unable to pull the extension settings from the engine", String.Empty, String.Empty, -1);
                Add_Error_To_Log(ee.Message, String.Empty, String.Empty, -1);
                return false;
            }

            // Check for any enabled extensions with assemblies
            ResourceObjectSettings.Clear_Assemblies();
            try
            {
                if ((Engine_ApplicationCache_Gateway.Configuration.Extensions.Extensions != null) && (Engine_ApplicationCache_Gateway.Configuration.Extensions.Extensions.Count > 0))
                {
                    // Step through each extension
                    foreach (ExtensionInfo extensionInfo in Engine_ApplicationCache_Gateway.Configuration.Extensions.Extensions)
                    {
                        // If not enabled, skip it
                        if (!extensionInfo.Enabled) continue;

                        // Look for assemblies
                        if ((extensionInfo.Assemblies != null) && (extensionInfo.Assemblies.Count > 0))
                        {
                            // Step through each assembly
                            foreach (ExtensionAssembly assembly in extensionInfo.Assemblies)
                            {
                                // Find the relative file name
                                if (assembly.FilePath.IndexOf("plugins", StringComparison.OrdinalIgnoreCase) > 0)
                                {
                                    // Determine the network way to get there
                                    string from_plugins = assembly.FilePath.Substring(assembly.FilePath.IndexOf("plugins", StringComparison.OrdinalIgnoreCase));
                                    string network_plugin_file = Path.Combine(settings.Servers.Application_Server_Network, from_plugins);

                                    // Get the plugin filename
                                    string plugin_filename = Path.GetFileName(assembly.FilePath);

                                    // Does this local plugin directory exist for this extension?
                                    string local_path = Path.Combine(pluginRootDirectory, instanceInfo.Name, extensionInfo.Code);
                                    if (!Directory.Exists(local_path))
                                    {
                                        try
                                        {
                                            Directory.CreateDirectory(local_path);
                                        }
                                        catch (Exception ee)
                                        {
                                            Add_Error_To_Log("Error creating the necessary plug-in subdirectory", String.Empty, String.Empty, -1);
                                            Add_Error_To_Log(ee.Message, String.Empty, String.Empty, -1);
                                            return false;
                                        }
                                    }

                                    // Determine if the assembly is here
                                    string local_file = Path.Combine(local_path, plugin_filename);
                                    if (!File.Exists(local_file))
                                    {
                                        File.Copy(network_plugin_file, local_file);
                                    }
                                    else
                                    {
                                        // Do a date check
                                        DateTime webFileDate = File.GetLastWriteTime(network_plugin_file);
                                        DateTime localFileDate = File.GetLastWriteTime(local_file);

                                        if (webFileDate.CompareTo(localFileDate) > 0)
                                        {
                                            File.Copy(network_plugin_file, local_file, true);
                                        }
                                    }

                                    // Also, point the assembly to use the local file
                                    assembly.FilePath = local_file;
                                }
                            }
                        }
                    }

                    // Now, also set this all in the metadata portion
                    // Copy over all the extension information
                    foreach (ExtensionInfo thisExtension in Engine_ApplicationCache_Gateway.Configuration.Extensions.Extensions)
                    {
                        if ((thisExtension.Enabled) && (thisExtension.Assemblies != null))
                        {
                            foreach (ExtensionAssembly thisAssembly in thisExtension.Assemblies)
                            {
                                ResourceObjectSettings.Add_Assembly(thisAssembly.ID, thisAssembly.FilePath);
                            }
                        }
                    }
                }
            }
            catch (Exception ee)
            {
                Add_Error_To_Log("Unable to copy the extension files from the web", String.Empty, String.Empty, -1);
                Add_Error_To_Log(ee.Message, String.Empty, String.Empty, -1);
                return false;
            }

            // Finalize the metadata config
            Engine_ApplicationCache_Gateway.Configuration.Metadata.Finalize_Metadata_Configuration();

            // Set the metadata preferences for writing
            ResourceObjectSettings.MetadataConfig = Engine_ApplicationCache_Gateway.Configuration.Metadata;

            // Also, load the builder configuration this way
            try
            {
                builderSettings = SobekEngineClient.Builder.Get_Builder_Settings(false, tracer);
            }
            catch (Exception ee)
            {
                Add_Error_To_Log("Unable to pull the builder settings from the engine", String.Empty, String.Empty, -1);
                Add_Error_To_Log(ee.Message, String.Empty, String.Empty, -1);
                return false;
            }

            // Build the modules
            builderModules = new Builder_Modules(builderSettings);
            List<string> errors = builderModules.Builder_Modules_From_Settings(instanceInfo.Name);

            if (( errors != null ) && ( errors.Count > 0 ))
            {
                long logId = Add_Error_To_Log("Error(s) builder the modules from the settings", String.Empty, String.Empty, -1);
                foreach (string thisError in errors)
                {
                    Add_Error_To_Log(thisError, String.Empty, String.Empty, logId);
                }
                return false;
            }

            // Add the event listeners
            foreach (iPreProcessModule thisModule in builderModules.PreProcessModules)
            {
                thisModule.Error += module_Error;
                thisModule.Process += module_Process;
            }
            foreach (iSubmissionPackageModule thisModule in builderModules.DeleteItemModules)
            {
                thisModule.Error += module_Error;
                thisModule.Process += module_Process;
            }
            foreach (iSubmissionPackageModule thisModule in builderModules.ItemProcessModules)
            {
                thisModule.Error += module_Error;
                thisModule.Process += module_Process;
            }
            foreach (iPostProcessModule thisModule in builderModules.PostProcessModules)
            {
                thisModule.Error += module_Error;
                thisModule.Process += module_Process;
            }
            foreach (iFolderModule thisModule in builderModules.AllFolderModules)
            {
                thisModule.Error += module_Error;
                thisModule.Process += module_Process;
            }

            return true;
        }
        /// <summary> Refreshes the values from the database settings </summary>
        /// <returns> A fully built instance-wide setting object </returns>
        public static InstanceWide_Configuration Read_Config_Files(List<string> ConfigurationDirectories, InstanceWide_Settings Settings)
        {
            // Start to build the instance wide configuration
            InstanceWide_Configuration returnValue = new InstanceWide_Configuration();

            // Add an initial log, with the data
            returnValue.Source.Add_Log("Beginning to read configuration files (" + DateTime.Now.ToShortDateString() + ")");

            // Log the directories to look within
            returnValue.Source.Add_Log();
            returnValue.Source.Add_Log("Looking in the following directories for config/xml files");
            foreach (string configDir in ConfigurationDirectories)
            {
                returnValue.Source.Add_Log("     " + configDir.ToLower().Replace(Settings.Servers.Application_Server_Network.ToLower(), ""));
            }

            // Step through and get the configuration files to be read (in folder and alphabetical order)
            List<string> configFiles = new List<string>();
            SortedList<string, string> filesSorted = new SortedList<string, string>();
            foreach (string thisConfigDir in ConfigurationDirectories)
            {
                if (Directory.Exists(thisConfigDir))
                {
                    // Get the list of XML and CONFIG files, and read them in alphabetical order
                    string[] files = Tools.SobekCM_File_Utilities.GetFiles(thisConfigDir, "*.xml|*.config");
                    if (files.Length > 0)
                    {
                        // Get all the files and sort by name
                        filesSorted.Clear();
                        foreach (string thisFile in files)
                        {
                            string filename = Path.GetFileName(thisFile);
                            if (filename != null)
                            {
                                filesSorted.Add(filename, thisFile);
                            }
                        }

                        // Add the files to the complete list
                        configFiles.AddRange(filesSorted.Values);
                    }
                }
            }

            // Add the source list to the source
            foreach (string fileFound in configFiles)
            {
                returnValue.Source.Files.Add(fileFound.ToLower().Replace(Settings.Servers.Application_Server_Network.ToLower(), ""));
            }

            // Log this
            returnValue.Source.Add_Log();
            returnValue.Source.Add_Log("Found the following config files to attempt to read:");
            foreach (string configFile in configFiles)
            {
                returnValue.Source.Add_Log("     " + configFile.ToLower().Replace(Settings.Servers.Application_Server_Network.ToLower(), ""));
            }

            // With all the files to read collected and sorted, read each one
            foreach (string thisConfigFile in configFiles)
            {
                if (read_config_file(thisConfigFile, returnValue, Settings))
                    returnValue.HasData = true;
            }

            // Now, perform some final clean-up functions here now that all the files have been read
            engine_config_finalize(returnValue);

            // Copy over all the extension information
            if (returnValue.Extensions.Extensions != null)
            {
                foreach (ExtensionInfo thisExtension in returnValue.Extensions.Extensions)
                {
                    if ((thisExtension.Enabled) && (thisExtension.Assemblies != null))
                    {
                        foreach (ExtensionAssembly thisAssembly in thisExtension.Assemblies)
                        {
                            ResourceObjectSettings.Add_Assembly(thisAssembly.ID, thisAssembly.FilePath);
                        }
                    }
                }
            }

            // Finalize the metadata config
            returnValue.Metadata.Finalize_Metadata_Configuration();

            // Save the metadata configuration to the resource object library
            ResourceObjectSettings.MetadataConfig = returnValue.Metadata;

            returnValue.HasData = true;

            return returnValue;
        }
        /// <summary> Refresh the settings object by pulling the data back from the database </summary>
        /// <returns> TRUE if successful, otherwise FALSE </returns>
        public static bool RefreshSettings()
        {
            try
            {
                lock (settingsLock)
                {
                    if (settings == null)
                        settings = InstanceWide_Settings_Builder.Build_Settings();
                    else
                    {
                        InstanceWide_Settings newSettings = InstanceWide_Settings_Builder.Build_Settings();
                        settings = newSettings;
                    }
                }

                return true;
            }
            catch
            {
                return false;
            }
        }
        private static bool read_config_file(string ConfigFile, InstanceWide_Configuration ConfigObj, InstanceWide_Settings Settings)
        {
            // If the file doesn't exist, that is strange.. but not an error per se
            if (!File.Exists(ConfigFile))
            {
                return true;
            }

            // Add to the log
            ConfigObj.Source.Add_Log();
            string directoryName = "Unknown";
            string directory = Path.GetDirectoryName(ConfigFile);
            try
            {
                string file = Path.GetFileName(ConfigFile);
                DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(ConfigFile));
                directoryName = dirInfo.Name;
                string directory2 = dirInfo.Parent.Name;

                ConfigObj.Source.Add_Log("Reading " + directory2 + "\\" + directoryName + "\\" + file);
            }
            catch
            {
                ConfigObj.Source.Add_Log("Reading " + ConfigFile + " (Error parsing for logging)");
            }

            // Streams used for reading
            Stream readerStream = null;
            XmlTextReader readerXml = null;

            try
            {
                // Check the file for the last modified date
                DateTime lastModifiedDate = (new FileInfo(ConfigFile)).LastWriteTime;
                if (DateTime.Compare(ConfigObj.Source.LatestDateTimeStamp, lastModifiedDate) < 0)
                    ConfigObj.Source.LatestDateTimeStamp = lastModifiedDate;

                // Open a link to the file
                readerStream = new FileStream(ConfigFile, FileMode.Open, FileAccess.Read);

                // Try to read the XML
                readerXml = new XmlTextReader(readerStream);

                // Step through this configuration file
                while (readerXml.Read())
                {
                    if (readerXml.NodeType == XmlNodeType.Element)
                    {
                        switch (readerXml.Name.ToLower())
                        {
                            case "authentication":
                                ConfigObj.Source.Add_Log("        Parsing AUTHENTICATION subtree");
                                read_authentication_details(readerXml.ReadSubtree(), ConfigObj);
                                break;

                            case "oai-pmh":
                                ConfigObj.Source.Add_Log("        Parsing OAI-PMH subtree");
                                read_oai_details(readerXml.ReadSubtree(), ConfigObj);
                                break;

                            case "contactform":
                                ConfigObj.Source.Add_Log("        Parsing CONTACTFORM subtree");
                                read_contactform_details(readerXml.ReadSubtree(), ConfigObj);
                                break;

                            case "briefitem_mapping":
                                ConfigObj.Source.Add_Log("        Parsing BRIEFITEM_MAPPING subtree");
                                read_briefitem_mapping_details(readerXml.ReadSubtree(), ConfigObj);
                                break;

                            case "mapeditor":
                                ConfigObj.Source.Add_Log("        Parsing MAPEDITOR subtree");
                                read_mapeditor_details(readerXml.ReadSubtree(), ConfigObj);
                                break;

                            case "engine":
                                ConfigObj.Source.Add_Log("        Parsing ENGINE subtree");
                                if (readerXml.MoveToAttribute("ClearAll"))
                                {
                                    if ((readerXml.Value.Trim().ToLower() == "true") && ( ConfigObj.Engine != null ))
                                    {
                                        ConfigObj.Engine.ClearAll();
                                    }
                                    readerXml.MoveToElement();
                                }
                                read_engine_details(readerXml.ReadSubtree(), ConfigObj);
                                break;

                            case "qualitycontrol":
                                ConfigObj.Source.Add_Log("        Parsing QUALITYCONTROL subtree");
                                read_quality_control_details(readerXml.ReadSubtree(), ConfigObj);
                                break;

                            case "metadata":
                                ConfigObj.Source.Add_Log("        Parsing METADATA subtree");
                                read_metadata_details(readerXml.ReadSubtree(), ConfigObj);
                                break;

                            case "writerviewers":
                                ConfigObj.Source.Add_Log("        Parsing WRITER/VIEWER subtree");
                                read_writer_viewer_details(readerXml.ReadSubtree(), ConfigObj);
                                break;

                            case "citation":
                                ConfigObj.Source.Add_Log("        Parsing CITATION subtree");
                                read_citation_details(readerXml.ReadSubtree(), ConfigObj);
                                break;

                            case "templateelements":
                            case "templateconfig":
                                ConfigObj.Source.Add_Log("        Parsing TEMPLATE ELEMENTS subtree");
                                read_template_elements_details(readerXml.ReadSubtree(), ConfigObj);
                                break;

                            case "extension":
                                // Ensure the extension configuration exists
                                if (ConfigObj.Extensions == null)
                                    ConfigObj.Extensions = new Extension_Configuration();

                                ConfigObj.Source.Add_Log("        Parsing EXTENSION subtree");
                                ExtensionInfo extensionInfo = read_extension_details(readerXml, ConfigObj, directoryName, directory);

                                // Since this was read here, it must be enabled, but determine enabled date
                                extensionInfo.Enabled = true;
                                ExtensionInfo dbInfo = Settings.ExtensionByCode(extensionInfo.Code);
                                if (dbInfo != null)
                                    extensionInfo.EnabledDate = dbInfo.EnabledDate;

                                // Add this to the list of extensions
                                ConfigObj.Extensions.Add_Extension(extensionInfo);
                                break;

                            case "static_resources":
                                string base_url = Settings.Servers.Base_URL;
                                bool read_section = false;
                                if (readerXml.MoveToAttribute("code"))
                                {
                                    string code = readerXml.Value;
                                    if ((code == "*") || (String.Compare(Settings.Servers.Static_Resources_Config_File, code, StringComparison.OrdinalIgnoreCase) == 0))
                                        read_section = true;
                                    readerXml.MoveToElement();

                                    // Savethe code though, if it wasn't an asterisk
                                    if (( code != "*") && ( !ConfigObj.UI.StaticResources.Static_Resource_Codes.Contains(code.ToLower())))
                                        ConfigObj.UI.StaticResources.Static_Resource_Codes.Add(code.ToLower());
                                }
                                if (readerXml.MoveToAttribute("baseUrl"))
                                {
                                    base_url = readerXml.Value;
                                    readerXml.MoveToElement();
                                }
                                if (read_section)
                                {
                                    ConfigObj.Source.Add_Log("        Parsing active STATIC RESOURCES subtree");
                                    read_static_resource_details(readerXml.ReadSubtree(), ConfigObj, base_url);
                                }
                                else
                                {
                                    ConfigObj.Source.Add_Log("        Skipping inactive STATIC RESOURCES subtree");
                                }
                                break;

                        }
                    }
                }
            }
            catch (Exception ee)
            {
                ConfigObj.Source.Add_Log("EXCEPTION CAUGHT in Configuration_Files_Reader.read_config_files");
                ConfigObj.Source.Add_Log(ee.Message);
                ConfigObj.Source.Add_Log(ee.StackTrace);

                ConfigObj.Source.ErrorEncountered = true;
            }
            finally
            {
                if (readerXml != null)
                {
                    readerXml.Close();
                }
                if (readerStream != null)
                {
                    readerStream.Close();
                }
            }

            return true;
        }
        /// <summary> Refreshes the values from the database settings </summary>
        /// <returns> A fully built instance-wide setting object </returns>
        public static InstanceWide_Configuration Read_Config_Files( InstanceWide_Settings Settings)
        {
            // Get the directories to read
            List<string> configurationDirectories = new List<string>();

            // Add the default configuration directory first
            configurationDirectories.Add(Path.Combine(Settings.Servers.Application_Server_Network, "config", "default"));

            // Add all of the plug-in foldersm but ensure they are sorted
            string plug_in_folder = Path.Combine(Settings.Servers.Application_Server_Network, "plugins");
            List<string> unreadPluginDirectories = new List<string>();
            if (Directory.Exists(plug_in_folder))
            {
                // Get the list of subdirectories
                string[] subdirs = Directory.GetDirectories(plug_in_folder);

                // Ensure it is sorted alphabetically
                SortedList<string, string> subdirs_sorted = new SortedList<string, string>();
                foreach (string thisSubDir in subdirs)
                {
                    // Get the directory name and add to the sorted list
                    string dirName = (new DirectoryInfo(thisSubDir)).Name;

                    // Does this match an enabled extension?
                    if (Settings.ExtensionEnabled(dirName))
                        subdirs_sorted.Add(dirName, thisSubDir);
                    else
                    {
                        // Keep track of all plugin folders though
                        unreadPluginDirectories.Add(thisSubDir);
                    }
                }

                // Now, add each folder correctly sorted
                foreach (string thisSubDir in subdirs_sorted.Values)
                {
                    configurationDirectories.Add(thisSubDir);
                    if (Directory.Exists(Path.Combine(thisSubDir, "config")))
                        configurationDirectories.Add(Path.Combine(thisSubDir, "config"));
                }
            }

            // Add the final user configuration directory last
            configurationDirectories.Add(Path.Combine(Settings.Servers.Application_Server_Network, "config", "user"));

            InstanceWide_Configuration returnValue = Read_Config_Files(configurationDirectories, Settings);

            // Now, handle any changes to the plug-ins folders and ensure database and
            // the plug-in folders are in agreement
            bool extension_change_occured = false;

            // Look for plug-ins that exist in the directory, but not the database
            foreach (string plugInDirectory in unreadPluginDirectories)
            {
                // Get the plug-in name
                string dirName = Path.GetFileName(plugInDirectory);

                // Get the list of XML and CONFIG files, and read them in alphabetical order
                string[] files = Tools.SobekCM_File_Utilities.GetFiles(plugInDirectory, "*.xml|*.config");
                if (files.Length > 0)
                {
                    // Get all the files and sort by name
                    foreach (string thisFile in files)
                    {
                        ExtensionInfo extensionInfo = read_extension_config_file(thisFile);
                        if (extensionInfo != null)
                        {
                            // Does this already exist?
                            ExtensionInfo dbExtensionInfo = Settings.ExtensionByCode(extensionInfo.Code);
                            if (dbExtensionInfo == null)
                            {
                                Engine_Database.Plugin_Add_Update(extensionInfo.Code, extensionInfo.Name, extensionInfo.Version, String.Empty, String.Empty, String.Empty, null);
                                extension_change_occured = true;
                            }
                            else
                            {
                                // Does this need to be updated?
                                if ((String.Compare(dbExtensionInfo.Name, extensionInfo.Name) != 0) || (String.Compare(dbExtensionInfo.Version, extensionInfo.Version) != 0))
                                {
                                    Engine_Database.Plugin_Add_Update(extensionInfo.Code, extensionInfo.Name, extensionInfo.Version, String.Empty, String.Empty, String.Empty, null);
                                    extension_change_occured = true;
                                }
                            }

                            // Must not be enabled, since it wasn't read above
                            extensionInfo.Enabled = false;

                            // Add this to the configuration as well
                            returnValue.Extensions.Add_Extension(extensionInfo);

                            break;
                        }
                    }

                    // Repull the extension information, if it changed
                    if (extension_change_occured)
                        Settings.DbExtensions = Engine_Database.Plugin_Get_All(null);

                }

            }

            return returnValue;
        }
        /// <summary> Checks to see if there are web logs that need to be processed to the usage statistics </summary>
        /// <param name="Settings"> Instance-wide settings which may be required for this process </param>
        public override void DoWork(InstanceWide_Settings Settings)
        {
            // If there is no IIS web log set, then do nothing.  Don't even need a log here.
            if (String.IsNullOrEmpty(Settings.Builder.IIS_Logs_Directory))
                return;

            // Just don't run the first day of the month - ensures logs still not being written
            if (DateTime.Now.Day < 2)
                return;

            // Ensure directory exists and is accessible
            string log_directory = Settings.Builder.IIS_Logs_Directory;
            try
            {
                if (!Directory.Exists(log_directory))
                {
                    OnError("CalculateUsageStatisticsModule : IIS web log directory ( " + log_directory + " ) does not exists or is inaccessible", null, null, -1);
                    return;
                }
            }
            catch (Exception ee)
            {
                OnError("CalculateUsageStatisticsModule : IIS web log directory ( " + log_directory + " ) does not exists or is inaccessible : " + ee.Message, null, null, -1);
                return;
            }

            // Get the temporary workspace directory, and ensure it exists
            string temporary_workspace = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Temporary", "CalculateUsageStatisticsModule");
            try
            {
                if (!Directory.Exists(temporary_workspace))
                    Directory.CreateDirectory(temporary_workspace);
            }
            catch ( Exception ee )
            {
                OnError("CalculateUsageStatisticsModule : Unable to create the temporary workspace ( " + temporary_workspace + " ) : " + ee.Message, null, null, -1);
                return;
            }

            // Clear the temporary workspace
            try
            {
                string[] files = Directory.GetFiles(temporary_workspace);
                foreach (string thisFile in files)
                {
                    File.Delete(thisFile);
                }
            }
            catch (Exception ee)
            {
                OnError("CalculateUsageStatisticsModule : Error caught clearing existing files from the temporary workspace ( " + temporary_workspace + " ) : " + ee.Message, null, null, -1);
                return;
            }

            // Get (and double check) the web directory
            if (String.IsNullOrEmpty(Settings.Servers.Application_Server_Network))
            {
                OnError("CalculateUsageStatisticsModule : No application server network setting!  Correct ASAP!", null, null, -1);
                return;
            }

            // Ensure directory exists and is accessible
            string sobekcm_directory = Settings.Servers.Application_Server_Network;
            try
            {
                if (!Directory.Exists(sobekcm_directory))
                {
                    OnError("CalculateUsageStatisticsModule : Web application server network directory ( " + sobekcm_directory + " ) does not exists or is inaccessible", null, null, -1);
                    return;
                }
            }
            catch (Exception ee)
            {
                OnError("CalculateUsageStatisticsModule : Web application server network  ( " + sobekcm_directory + " ) does not exists or is inaccessible : " + ee.Message, null, null, -1);
                return;
            }

            // Determine which year/months already have been analyzed for this instance
            Statistics_Dates statsDates = new Statistics_Dates();
            Engine_Database.Populate_Statistics_Dates(statsDates, null);

            // Get the list of all IIS web logs
            string[] log_files = Directory.GetFiles( log_directory, "u_ex*.log");

            // If no log files, just return
            if (log_files.Length == 0)
            {
                OnError("CalculateUsageStatisticsModule : No IIS web logs found in directory  ( " + log_directory + " )", null, null, -1);
                return;
            }

            // Get the earliest and latest log files from the IIS web logs
            string earliest = "ZZZZZZZZ";
            string latest = "AAAAAAAA";
            foreach (string thisFile in log_files)
            {
                string thisFileName = Path.GetFileNameWithoutExtension(thisFile);
                if ( String.Compare(thisFileName, earliest, StringComparison.OrdinalIgnoreCase) < 0 )
                    earliest = thisFileName;
                if ( String.Compare(thisFileName, latest, StringComparison.OrdinalIgnoreCase) > 0 )
                    latest = thisFileName;
            }

            // Parse them to determine the earliest and latest year/months
            int earliest_year;
            int earliest_month;
            int latest_year;
            int latest_month;
            try
            {
                earliest_year = 2000 + Int32.Parse(earliest.Substring(4, 2));
                earliest_month = Int32.Parse(earliest.Substring(6, 2));
                latest_year = 2000 + Int32.Parse(latest.Substring(4, 2));
                latest_month = Int32.Parse(latest.Substring(6, 2));
            }
            catch (Exception )
            {
                OnError("CalculateUsageStatisticsModule : Error parsing the earliest or latest log for year/month (" + earliest + " or " + latest + " )", null, null, -1);
                return;
            }

            // Determine what years/months are missing
            List<string> year_month = new List<string>();
            if (statsDates.Earliest_Year == 2000)
            {
                // No stats every collected, so collect them all
                int curr_year = earliest_year;
                int curr_month = earliest_month;
                while ((curr_year < latest_year) || ((curr_year == latest_year) && (curr_month <= latest_month)))
                {
                    if ((curr_year == DateTime.Now.Year) && (curr_month == DateTime.Now.Month))
                        break;

                    year_month.Add(curr_year + curr_month.ToString().PadLeft(2, '0'));

                    curr_month++;
                    if (curr_month > 12)
                    {
                        curr_year++;
                        curr_month = 1;
                    }
                }
            }
            else
            {
                // No stats every collected, so collect them all
                int curr_year = earliest_year;
                int curr_month = earliest_month;
                while ((curr_year < latest_year) || ((curr_year == latest_year) && (curr_month <= latest_month)))
                {
                    if ((curr_year == DateTime.Now.Year) && (curr_month == DateTime.Now.Month))
                        break;

                    if (( curr_year > statsDates.Latest_Year ) || (( curr_year == statsDates.Latest_Year ) && ( curr_month > statsDates.Latest_Month )))
                        year_month.Add(curr_year + curr_month.ToString().PadLeft(2, '0'));

                    curr_month++;
                    if (curr_month > 12)
                    {
                        curr_year++;
                        curr_month = 1;
                    }
                }
            }

            // If no year/months were added , then no work to do
            if (year_month.Count == 0)
                return;

            // Refresh the items
            Engine_ApplicationCache_Gateway.RefreshItems();

            // Create the processor
            SobekCM_Stats_Reader_Processor processor = new SobekCM_Stats_Reader_Processor(log_directory, temporary_workspace, sobekcm_directory, year_month);
            processor.New_Status += processor_New_Status;

            // Create the thread
            processor.Process_IIS_Logs();

            // Delete the cached file, if one exists
            try
            {
                string temp_directory = Path.Combine(Settings.Servers.Application_Server_Network, "temp");
                if (Directory.Exists(temp_directory))
                {
                    string cache_xml_file = Path.Combine(temp_directory, "overall_usage.xml");
                    if (File.Exists(cache_xml_file))
                        File.Delete(cache_xml_file);
                }
            }
            catch { }

            // Shoudl emails be sent?
            if (Settings.Builder.Send_Usage_Emails)
            {
                // Load the text
                string possible_email_body_dir = Path.Combine(Settings.Servers.Application_Server_Network, "design", "extra", "stats");
                Usage_Stats_Email_Helper.Set_Email_Body(Path.Combine(possible_email_body_dir, "stats_email_body.txt"));

                // Send emails for each year/month (in order)
                foreach (string thisYearMonth in year_month)
                {
                    int year = Convert.ToInt32(thisYearMonth.Substring(0, 4));
                    int month = Convert.ToInt32(thisYearMonth.Substring(4, 2));

                    Send_Usage_Emails(year, month, Settings.Servers.System_Base_URL, Settings.System.System_Name, Settings.Email.Setup.DefaultFromAddress, Settings.Email.Setup.DefaultFromDisplay );

                }
            }
        }
        /// <summary> Refresh the settings object by pulling the data back from the database </summary>
        /// <returns> TRUE if successful, otherwise FALSE </returns>
        public static bool RefreshSettings(Database_Instance_Configuration DbInstance )
        {
            try
            {
                lock (settingsLock)
                {
                    if (settings == null)
                        settings = InstanceWide_Settings_Builder.Build_Settings(DbInstance);
                    else
                    {
                        InstanceWide_Settings newSettings = InstanceWide_Settings_Builder.Build_Settings(DbInstance);
                        settings = newSettings;
                    }
                }

                return true;
            }
            catch
            {
                return false;
            }
        }
        /// <summary> Sends aggregated emails on all newly submitted items since the last email </summary>
        /// <param name="Settings"> Instance-wide settings which may be required for this process </param>
        public override void DoWork(InstanceWide_Settings Settings)
        {
            // NOTE: This was all brought over from the BulkLoader this way, it had been commented out ther as well.
            //       To get this to work, will need to do some development here, pull the list of impacted items, etc..

            //Add_NonError_To_Log("\t\tSending emails for new items");

            //// Get the list of institutions
            //DataTable institutions = SobekCM.Library.Database.SobekCM_Database.Get_All_Institutions();

            //// Step through each institution in the item list
            //foreach (string thisInstitution in items_by_location.Keys)
            //{
            //    // Determine the email address
            //    string email = String.Empty;
            //    string institution = String.Empty;

            //    // Determine if these are dLOC
            //    string software = "dLOC";
            //    string help_email = "*****@*****.**";
            //    foreach (string html in items_by_location[thisInstitution])
            //    {
            //        if (html.IndexOf("dloc") < 0)
            //        {
            //            software = "UFDC";
            //            help_email = "*****@*****.**";
            //            break;
            //        }
            //    }

            //    if (thisInstitution.IndexOf("@") > 0)
            //    {
            //        email = thisInstitution;
            //        institution = "New " + software + " items";
            //    }
            //    else
            //    {
            //        // Search the list of institutions by the code
            //        DataRow[] selected = institutions.Select("InstitutionCode = '" + thisInstitution + "' and Load_Email_Notification=1");
            //        if (selected.Length > 0)
            //        {
            //            // Get the email and name of institution from the database
            //            email = selected[0]["Load_Email"].ToString();
            //            institution = "New " + software + " items for " + selected[0]["InstitutionName"].ToString();
            //        }
            //    }

            //    if (email.Length > 0)
            //    {
            //        // Get the name of the institution

            //        // Build the text for the email
            //        StringBuilder bodyBuilder = new StringBuilder();
            //        bodyBuilder.AppendLine("The following items are now available online in " + software + ".<br />");
            //        bodyBuilder.AppendLine("Los siguientes artículos, que usted mandó, están disponibles en línea a través de " + software + ".<br />");
            //        bodyBuilder.AppendLine("Les fichiers suivants ont été téléchargés sur le serveur " + software + ".<br />");
            //        bodyBuilder.AppendLine("<br />");
            //        bodyBuilder.AppendLine("<blockquote>");

            //        foreach (string html in items_by_location[thisInstitution])
            //        {
            //            bodyBuilder.AppendLine(html + "<br />");
            //        }

            //        bodyBuilder.AppendLine("</blockquote>");
            //        bodyBuilder.AppendLine("<br />");
            //        bodyBuilder.AppendLine("This is an automatic email.  Please do not respond to this email.  For any issues please contact " + help_email + ".<br />");
            //        bodyBuilder.AppendLine("Este correo se mandó automáticamente. Por favor no conteste este correo. Si usted tiene alguna pregunta o problema por favor mande un correo a " + help_email + ".<br />");
            //        bodyBuilder.AppendLine("Ceci est une réponse automatique. Veuillez ne pas répondre à ce message.  Envoyez-vos enquêtes directement à " + help_email + ".<br />");

            //        // Send this email
            //        try
            //        {
            //            System.Net.Mail.MailMessage myMail = new System.Net.Mail.MailMessage("*****@*****.**", email);
            //            myMail.Subject = institution;
            //            myMail.IsBodyHtml = true;
            //            myMail.Body = bodyBuilder.ToString();
            //            myMail.IsBodyHtml = true;

            //            // Mail this
            //            System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient("smtp.ufl.edu");
            //            client.Send(myMail);
            //        }
            //        catch (Exception ee)
            //        {
            //            string valu = "rerror";
            //        }
            //    }
            //}
        }
 /// <summary> Method releases all resources </summary>
 public virtual void ReleaseResources()
 {
     Settings = null;
 }
 /// <summary> Method performs the work of the post-process builder module </summary>
 /// <param name="AggregationsAffected"> List of aggregations affected during the last process of incoming digital resources </param>
 /// <param name="ProcessedItems"> List of all items just processed (or reprocessed) </param>
 /// <param name="DeletedItems"> List of all delete requests just processed </param>
 /// <param name="Settings"> Instance-wide settings which may be required for this process </param>
 public abstract void DoWork(List<string> AggregationsAffected, List<BibVidStruct> ProcessedItems, List<BibVidStruct> DeletedItems, InstanceWide_Settings Settings);