/// <summary> [HELPER] Gets the entire collection hierarchy (used for hierarchical tree displays) </summary>
        /// <param name="Tracer"></param>
        /// <returns> Fully built aggregation hierarchy </returns>
        /// <remarks> This may be public now, but this will be converted into a private helped class with
        /// the release of SobekCM 5.0 </remarks>
        public static Aggregation_Hierarchy get_aggregation_hierarchy(Custom_Tracer Tracer)
        {
            // Get the aggregation code manager
            Aggregation_Hierarchy returnValue = CachedDataManager.Aggregations.Retrieve_Aggregation_Hierarchy(Tracer);

            if (returnValue != null)
            {
                Tracer.Add_Trace("AggregationServices.get_aggregation_hierarchy", "Found aggregation hierarchy in the cache");
                return(returnValue);
            }

            Tracer.Add_Trace("AggregationServices.get_aggregation_hierarchy", "Aggregation hierarchy NOT found in the cache.. will build");

            // Build the collection hierarchy (from the database)
            returnValue = Item_Aggregation_Utilities.Get_Collection_Hierarchy(Tracer);

            // Store in the cache
            if (returnValue != null)
            {
                Tracer.Add_Trace("AggregationServices.get_aggregation_hierarchy", "Storing built aggregation hierarchy in cache");
                CachedDataManager.Aggregations.Store_Aggregation_Hierarchy(returnValue, Tracer);
            }
            else
            {
                Tracer.Add_Trace("AggregationServices.get_aggregation_hierarchy", "Aggregation hierarchy not built correctly, NULL returned from Item_Aggregation_Utilities.Get_Collection_Hierarchy method");
            }

            return(returnValue);
        }
        /// <summary> [HELPER] Gets the complete (language agnostic) item aggregation, by aggregation code </summary>
        /// <param name="AggregationCode"> Code the requested aggregation </param>
        /// <param name="UseCache"> Flag indicates if the cache should be checed and used to store the final product </param>
        /// <param name="Tracer"></param>
        /// <returns> Fully built language-agnostic aggregation, with all related configurations </returns>
        /// <remarks> This may be public now, but this will be converted into a private helped class with
        /// the release of SobekCM 5.0 </remarks>
        public static Complete_Item_Aggregation get_complete_aggregation(string AggregationCode, bool UseCache, Custom_Tracer Tracer)
        {
            // Try to pull this from the cache
            if (UseCache)
            {
                Complete_Item_Aggregation cacheAggr = CachedDataManager.Aggregations.Retrieve_Complete_Item_Aggregation(AggregationCode, Tracer);
                if (cacheAggr != null)
                {
                    Tracer.Add_Trace("AggregationServices.get_complete_aggregation", "Found complete item aggregation in the cache");
                    return(cacheAggr);
                }

                Tracer.Add_Trace("AggregationServices.get_complete_aggregation", "Complete item aggregation NOT found in the cache.. will build");

                // Either use the cache version, or build the complete item aggregation
                Complete_Item_Aggregation itemAggr = Item_Aggregation_Utilities.Get_Complete_Item_Aggregation(AggregationCode, Tracer);

                // If this is the ALL collection, add subcollections by thematic heading
                if (String.Compare(AggregationCode, "all", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    foreach (Thematic_Heading thisTheme in Engine_ApplicationCache_Gateway.Thematic_Headings)
                    {
                        // Build the list of html to display
                        ReadOnlyCollection <Item_Aggregation_Related_Aggregations> thisThemesAggrs = Engine_ApplicationCache_Gateway.Codes.Aggregations_By_ThemeID(thisTheme.ID);
                        foreach (Item_Aggregation_Related_Aggregations thisAggr in thisThemesAggrs)
                        {
                            if ((!thisAggr.Hidden) && (thisAggr.Active))
                            {
                                itemAggr.Add_Child_Aggregation(new Item_Aggregation_Related_Aggregations(thisAggr.Code, thisAggr.Name, thisAggr.Type, thisAggr.Active, thisAggr.Hidden));
                            }
                        }
                    }
                }

                // Now, save this to the cache
                if (itemAggr != null)
                {
                    Tracer.Add_Trace("AggregationServices.get_complete_aggregation", "Store the built complete item aggregation in the cache");

                    CachedDataManager.Aggregations.Store_Complete_Item_Aggregation(AggregationCode, itemAggr, Tracer);
                }
                else
                {
                    Tracer.Add_Trace("AggregationServices.get_complete_aggregation", "Output from Item_Aggregation_Utilities.Get_Complete_Item_Aggregation is NULL");
                }

                return(itemAggr);
            }

            // else..
            Tracer.Add_Trace("AggregationServices.get_complete_aggregation", "UseCache parameter is FALSE, will not use the cache for this request");

            return(Item_Aggregation_Utilities.Get_Complete_Item_Aggregation(AggregationCode, Tracer));
        }
        /// <summary> [HELPER] Gets the language-specific item aggregation, by aggregation code and language code </summary>
        /// <param name="AggregationCode"> Code for the aggregation </param>
        /// <param name="RequestedLanguage"> Requested language to retrieve </param>
        /// <param name="DefaultLanguage"> Default interface language, in case the requested language does not exist </param>
        /// <param name="Tracer"></param>
        /// <returns> Built language-specific item aggregation object </returns>
        /// <remarks> This may be public now, but this will be converted into a private helped class with
        /// the release of SobekCM 5.0 </remarks>
        public static Item_Aggregation get_item_aggregation(string AggregationCode, Web_Language_Enum RequestedLanguage, Web_Language_Enum DefaultLanguage, Custom_Tracer Tracer)
        {
            // Try to pull from the cache
            Item_Aggregation cacheInst = CachedDataManager.Aggregations.Retrieve_Item_Aggregation(AggregationCode, RequestedLanguage, Tracer);

            if (cacheInst != null)
            {
                Tracer.Add_Trace("AggregationServices.get_item_aggregation", "Found language-specific item aggregation in the cache");
                return(cacheInst);
            }

            Tracer.Add_Trace("AggregationServices.get_item_aggregation", "Language-specific item aggregation NOT found in the cache.. will build");

            // Get the complete aggregation
            Complete_Item_Aggregation compAggr = get_complete_aggregation(AggregationCode, true, Tracer);

            // If the complete aggregation was null, just return null now
            if (compAggr == null)
            {
                Tracer.Add_Trace("AggregationServices.get_item_aggregation", "Complete item aggregation not built correctly.. returning NULL");
                return(null);
            }

            // Get the language-specific version
            Item_Aggregation returnValue = Item_Aggregation_Utilities.Get_Item_Aggregation(compAggr, RequestedLanguage, Tracer);

            // Store in cache again, if not NULL
            if (returnValue != null)
            {
                Tracer.Add_Trace("AggregationServices.get_item_aggregation", "Storing built Language-specific item aggregation in cache");

                CachedDataManager.Aggregations.Store_Item_Aggregation(AggregationCode, RequestedLanguage, returnValue, Tracer);
            }
            else
            {
                Tracer.Add_Trace("AggregationServices.get_item_aggregation", "Language-specific item aggregation not built correctly by Item_Aggregation_Utilities.Get_Item_Aggregation.. returning NULL");
            }

            return(returnValue);
        }
        /// <summary> Gets the browse or info object and any other needed data for display ( text to display) </summary>
        /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
        /// <param name="Aggregation_Object"> Item Aggregation object</param>
        /// <param name="Base_Directory"> Base directory location under which the the CMS/info source file will be found</param>
        /// <param name="Current_User"> Currently logged on user, which can determine which items to show </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        /// <param name="Browse_Object"> [OUT] Stores all the information about this browse or info </param>
        /// <param name="Complete_Result_Set_Info"> [OUT] Information about the entire set of results </param>
        /// <param name="Paged_Results"> [OUT] List of search results for the requested page of results </param>
        /// <param name="Browse_Info_Display_Text"> [OUT] Static HTML-based content to be displayed if this is browing a staticly created html source file </param>
        /// <returns> TRUE if successful, otherwise FALSE </returns>
        /// <remarks> This attempts to pull the objects from the cache.  If unsuccessful, it builds the objects from the
        /// database and hands off to the <see cref="CachedDataManager" /> to store in the cache </remarks>
        protected static bool Get_Browse_Info(Navigation_Object Current_Mode,
                                              Item_Aggregation Aggregation_Object,
                                              string Base_Directory,
                                              User_Object Current_User,
                                              Custom_Tracer Tracer,
                                              out Item_Aggregation_Child_Page Browse_Object,
                                              out Search_Results_Statistics Complete_Result_Set_Info,
                                              out List <iSearch_Title_Result> Paged_Results,
                                              out HTML_Based_Content Browse_Info_Display_Text)
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("abstractHtmlSubwriter.Get_Browse_Info", String.Empty);
            }

            // Set output initially to null
            Paged_Results            = null;
            Complete_Result_Set_Info = null;
            Browse_Info_Display_Text = null;

            // First, make sure the browse submode is valid
            Browse_Object = Aggregation_Object.Child_Page_By_Code(Current_Mode.Info_Browse_Mode);

            if (Browse_Object == null)
            {
                Current_Mode.Error_Message = "Unable to retrieve browse/info item '" + Current_Mode.Info_Browse_Mode + "'";
                return(false);
            }

            // Is this a table result, or a string?
            switch (Browse_Object.Source_Data_Type)
            {
            case Item_Aggregation_Child_Source_Data_Enum.Database_Table:

                // Set the current sort to ZERO, if currently set to ONE and this is an ALL BROWSE.
                // Those two sorts are the same in this case
                int sort = Current_Mode.Sort.HasValue ? Math.Max(Current_Mode.Sort.Value, ((ushort)1)) : 1;
                if ((sort == 0) && (Browse_Object.Code == "all"))
                {
                    sort = 1;
                }

                // Special code if this is a JSON browse
                string browse_code = Current_Mode.Info_Browse_Mode;
                if (Current_Mode.Writer_Type == Writer_Type_Enum.JSON)
                {
                    browse_code = browse_code + "_JSON";
                    sort        = 12;
                }

                // Get the page count in the results
                int current_page_index = Current_Mode.Page.HasValue ? Math.Max(Current_Mode.Page.Value, ((ushort)1)) : 1;

                // Determine if this is a special search type which returns more rows and is not cached.
                // This is used to return the results as XML and DATASET
                bool special_search_type = false;
                int  results_per_page    = 20;
                if ((Current_Mode.Writer_Type == Writer_Type_Enum.XML) || (Current_Mode.Writer_Type == Writer_Type_Enum.DataSet))
                {
                    results_per_page    = 1000000;
                    special_search_type = true;
                    sort = 2;     // Sort by BibID always for these
                }

                Tracer.Add_Trace("abstractHtmlSubwriter.Get_Browse_Info", "Current_Mode.Writer_Type=[" + Current_Mode.Writer_Type.ToString() + "].");
                Tracer.Add_Trace("abstractHtmlSubwriter.Get_Browse_Info", "Current_Mode.Results_Display_Type=[" + Current_Mode.Result_Display_Type + "].");

                if (String.Equals(Current_Mode.Result_Display_Type, "timeline", StringComparison.OrdinalIgnoreCase))
                {
                    Tracer.Add_Trace("abstractHtmlSubwriter.Get_Browse_Info", "Is timeline, setting browse results_per_page and sort.");

                    results_per_page = 20000;
                    sort             = 12;
                }

                // Set the flags for how much data is needed.  (i.e., do we need to pull ANYTHING?  or
                // perhaps just the next page of results ( as opposed to pulling facets again).
                bool need_browse_statistics = true;
                bool need_paged_results     = true;
                if ((!special_search_type) && (Current_User == null))
                {
                    // Look to see if the browse statistics are available on any cache for this browse
                    Complete_Result_Set_Info = CachedDataManager.Retrieve_Browse_Result_Statistics(Aggregation_Object.Code, browse_code, Tracer);
                    if (Complete_Result_Set_Info != null)
                    {
                        need_browse_statistics = false;
                    }

                    // Look to see if the paged results are available on any cache..
                    Paged_Results = CachedDataManager.Retrieve_Browse_Results(Aggregation_Object.Code, browse_code, current_page_index, sort, (uint)results_per_page, Tracer);
                    if (Paged_Results != null)
                    {
                        need_paged_results = false;
                    }
                }

                // Was a copy found in the cache?
                if ((!need_browse_statistics) && (!need_paged_results))
                {
                    if (Tracer != null)
                    {
                        Tracer.Add_Trace("SobekCM_Assistant.Get_Browse_Info", "Browse statistics and paged results retrieved from cache");
                    }
                }
                else
                {
                    if (Tracer != null)
                    {
                        Tracer.Add_Trace("SobekCM_Assistant.Get_Browse_Info", "Building results information");
                    }

                    // Try to pull more than one page, so we can cache the next page or so
                    List <List <iSearch_Title_Result> > pagesOfResults;

                    // Get from the hierarchy object
                    Multiple_Paged_Results_Args returnArgs = Item_Aggregation_Utilities.Get_Browse_Results(Aggregation_Object, Browse_Object, current_page_index, sort, results_per_page, !special_search_type, need_browse_statistics, Current_User, Tracer);
                    if (need_browse_statistics)
                    {
                        Complete_Result_Set_Info = returnArgs.Statistics;
                    }
                    pagesOfResults = returnArgs.Paged_Results;
                    if ((pagesOfResults != null) && (pagesOfResults.Count > 0))
                    {
                        Paged_Results = pagesOfResults[0];
                    }

                    // Save the overall result set statistics to the cache if something was pulled
                    if ((!special_search_type) && (Current_User == null))
                    {
                        if ((need_browse_statistics) && (Complete_Result_Set_Info != null))
                        {
                            CachedDataManager.Store_Browse_Result_Statistics(Aggregation_Object.Code, browse_code, Complete_Result_Set_Info, Tracer);
                        }

                        // Save the overall result set statistics to the cache if something was pulled
                        if ((need_paged_results) && (Paged_Results != null))
                        {
                            CachedDataManager.Store_Browse_Results(Aggregation_Object.Code, browse_code, current_page_index, sort, (uint)results_per_page, pagesOfResults, Tracer);
                        }
                    }
                }
                break;

            case Item_Aggregation_Child_Source_Data_Enum.Static_HTML:
                Browse_Info_Display_Text = SobekEngineClient.Aggregations.Get_Aggregation_HTML_Child_Page(Aggregation_Object.Code, Aggregation_Object.Language, UI_ApplicationCache_Gateway.Settings.System.Default_UI_Language, Browse_Object.Code, Tracer);
                break;
            }
            return(true);
        }
        public void ReCreate_Aggregation_Level_Pages(List <string> AggregationsAffected, InstanceWide_Settings Settings, long UpdateID)
        {
            // Determine, and create the local work space
            string localWorkArea = Path.Combine(MultiInstance_Builder_Settings.Builder_Executable_Directory, "temp");

            try
            {
                if (!Directory.Exists(localWorkArea))
                {
                    Directory.CreateDirectory(localWorkArea);
                }
            }
            catch
            {
                OnError("Error creating the temporary work area in BuildAggregationBrowsesModule: " + localWorkArea, UpdateID);
                return;
            }

            // Build the primary URL
            string primaryUrl = Settings.Servers.Application_Server_URL;

            if (String.IsNullOrEmpty(primaryUrl))
            {
                OnError("Primary system URL is not set", UpdateID);
                return;
            }
            if (primaryUrl[primaryUrl.Length - 1] != '/')
            {
                primaryUrl = primaryUrl + "/";
            }

            // 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);

            try
            {
                // Step through each aggregation with new items
                foreach (string thisAggrCode in AggregationsAffected)
                {
                    // Some aggregations can be excluded
                    if ((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, 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, UpdateID);
                        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, UpdateID);
                        }

                        OnProcess("........Building RSS feed for " + display_code, UpdateID);
                        try
                        {
                            if (Create_RSS_Feed(thisAggrCode.ToLower(), localWorkArea, aggregationObj.Name, aggregation_items, primaryUrl))
                            {
                                try
                                {
                                    // Copy the two generated RSS files over to the server
                                    File.Copy(Path.Combine(localWorkArea, thisAggrCode.ToLower() + "_rss.xml"), Path.Combine(Settings.Servers.Static_Pages_Location, "rss", thisAggrCode.ToLower() + "_rss.xml"), true);
                                    File.Copy(Path.Combine(localWorkArea, thisAggrCode.ToLower() + "_short_rss.xml"), Path.Combine(Settings.Servers.Static_Pages_Location, "rss", thisAggrCode.ToLower() + "_short_rss.xml"), true);

                                    // Delete the temporary files as well
                                    File.Delete(Path.Combine(localWorkArea, thisAggrCode.ToLower() + "_rss.xml"));
                                    File.Delete(Path.Combine(localWorkArea, thisAggrCode.ToLower() + "_short_rss.xml"));
                                }
                                catch (Exception ee)
                                {
                                    OnError("........Error in copying RSS feed for " + display_code + " to " + Settings.Servers.Static_Pages_Location + "\n" + ee.Message, UpdateID);
                                }
                            }
                        }
                        catch (Exception ee)
                        {
                            OnError("........Error in building RSS feed for " + display_code + "\n" + ee.Message, UpdateID);
                        }

                        OnProcess("........Building static HTML browse page of links for " + display_code, UpdateID);
                        try
                        {
                            string destinationFile = Path.Combine(localWorkArea, thisAggrCode.ToLower() + "_all.html");
                            if (Build_All_Browse(aggregationObj, aggregation_items, destinationFile, primaryUrl, UpdateID))
                            {
                                try
                                {
                                    File.Copy(destinationFile, Path.Combine(Settings.Servers.Static_Pages_Location, thisAggrCode.ToLower() + "_all.html"), true);
                                }
                                catch (Exception ee)
                                {
                                    OnError("........Error in copying HTML browse for " + display_code + " to " + Settings.Servers.Static_Pages_Location + "\n" + ee.Message, UpdateID);
                                }
                            }
                        }
                        catch (Exception ee)
                        {
                            OnError("........Error in building HTML browse for " + display_code + "\n" + ee.Message, UpdateID);
                        }
                    }
                }

                // Build the full instance-wide XML and RSS here as well
                Recreate_Library_XML_and_RSS(UpdateID, Settings, localWorkArea, primaryUrl);
            }
            catch (Exception ee)
            {
                OnError("Exception caught in BuildAggregationBrowsesModule", UpdateID);
                OnError(ee.Message, UpdateID);
                OnError(ee.StackTrace, UpdateID);
            }
        }