/// <summary> Method returns the table of results for the browse indicated </summary>
        /// <param name = "ItemAggr">Object with all the information about the browse</param>
        /// <param name = "Page"> Page of results requested for the indicated browse </param>
        /// <param name = "Sort"> Sort applied to the results before being returned </param>
        /// <param name="Potentially_Include_Facets"> Flag indicates if facets could be included in this browse results </param>
        /// <param name = "Need_Browse_Statistics"> Flag indicates if the browse statistics (facets and total counts) are required for this browse as well </param>
        /// <param name = "Tracer">Trace object keeps a list of each method executed and important milestones in rendering</param>
        /// <param name="Results_Per_Page"> Number of results to retrieve per page</param>
        /// <returns> Resutls for the browse or info in table form </returns>
        public static Multiple_Paged_Results_Args Gat_All_Browse(Complete_Item_Aggregation ItemAggr,
                                                                 int Page, int Sort, int Results_Per_Page,
                                                                 bool Potentially_Include_Facets, bool Need_Browse_Statistics,
                                                                 Custom_Tracer Tracer)
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("Item_Aggregation_Utilities.Get_Browse_Results", String.Empty);
            }

            // Get the list of facets first
            List <short> facetsList = ItemAggr.Facets;

            if (!Potentially_Include_Facets)
            {
                facetsList = null;
            }

            // Pull data from the database if necessary

            // Get this browse from the database
            if ((ItemAggr.ID < 0) || (ItemAggr.Code.ToUpper() == "ALL"))
            {
                return(Engine_Database.Get_All_Browse_Paged(false, false, Results_Per_Page, Page, Sort, Need_Browse_Statistics, facetsList, Need_Browse_Statistics, Tracer));
            }

            return(Engine_Database.Get_Item_Aggregation_Browse_Paged(ItemAggr.Code, false, false, Results_Per_Page, Page, Sort, Need_Browse_Statistics, facetsList, Need_Browse_Statistics, Tracer));
        }
        /// <summary> Checks the appropriate design folders to add any existing browse or info pages to the item aggregation </summary>
        /// <param name="ThisObject"> Item aggregation object to add the browse and info pages to</param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering</param>
        /// <remarks>This method is only called if the item aggregation does not have an existing XML configuration file.</remarks>
        protected static void Add_Browse_Files(Complete_Item_Aggregation ThisObject, Custom_Tracer Tracer)
        {
            // Collect the list of items in the browse folder
            if (Directory.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location + ThisObject.ObjDirectory + "html/browse"))
            {
                string[] files = Directory.GetFiles(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location + ThisObject.ObjDirectory + "html/browse", "*.htm*");
                foreach (string thisFile in files)
                {
                    // Get the new browse info object
                    Complete_Item_Aggregation_Child_Page newBrowse = Get_Item_Aggregation_Browse_Info(thisFile, Item_Aggregation_Child_Visibility_Enum.Main_Menu, Tracer);
                    if (newBrowse != null)
                    {
                        ThisObject.Add_Child_Page(newBrowse);
                    }
                }
            }

            // Collect the list of items in the info folder
            if (Directory.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location + ThisObject.ObjDirectory + "html/info"))
            {
                string[] files = Directory.GetFiles(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location + ThisObject.ObjDirectory + "html/info", "*.htm*");
                foreach (string thisFile in files)
                {
                    // Get the title for this file
                    // Get the new browse info object
                    Complete_Item_Aggregation_Child_Page newInfo = Get_Item_Aggregation_Browse_Info(thisFile, Item_Aggregation_Child_Visibility_Enum.None, Tracer);
                    if (newInfo != null)
                    {
                        ThisObject.Add_Child_Page(newInfo);
                    }
                }
            }
        }
        /// <summary> Stores the copmlete item aggregation object to the cache </summary>
        /// <param name="Aggregation_Code"> Code for the item aggregation to store </param>
        /// <param name="StoreObject"> Item aggregation object to store for later retrieval </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering</param>
        public void Store_Complete_Item_Aggregation(string Aggregation_Code, Complete_Item_Aggregation StoreObject, Custom_Tracer Tracer)
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("CachedDataManager.Store_Item_Aggregation", "Entering Store_Item_Aggregation method");
            }

            // If the cache is disabled, just return before even tracing
            if (settings.Disabled)
            {
                if (Tracer != null)
                {
                    Tracer.Add_Trace("CachedDataManager.Store_Item_Aggregation", "Caching is disabled");
                }
                return;
            }

            // Determine the key
            string key = "AGGR|" + Aggregation_Code.ToUpper() + "|COMPLETE";

            // Check the number of item aggregationPermissions currently locally cached
            //int items_cached = 0;
            const int LOCAL_EXPIRATION = 15;

            // Locally cache if this doesn't exceed the limit
            if (Tracer != null)
            {
                Tracer.Add_Trace("CachedDataManager.Store_Item_Aggregation", "Adding object '" + key + "' to the local cache with expiration of " + LOCAL_EXPIRATION + " minute(s)");
            }

            HttpContext.Current.Cache.Insert(key, StoreObject, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(LOCAL_EXPIRATION));
        }
        /// <summary> Adds the ALL ITEMS and NEW ITEMS browses to the item aggregation, if the display options and last added
        /// item date call for it </summary>
        /// <param name="ThisObject"> Item aggregation to which to add the ALL ITEMS and NEW ITEMS browse</param>
        /// <remarks>This method is always called while building an item aggregation, irregardless of whether there is an
        /// item aggregation configuration XML file or not.</remarks>
        protected static void Add_All_New_Browses(Complete_Item_Aggregation ThisObject)
        {
            // If this is the main home page for this site, do not show ALL since we cannot browse ALL items
            if (!ThisObject.Can_Browse_Items)
            {
                return;
            }

            // If this is in the display options, and the item browses
            if ((ThisObject.Display_Options.Length == 0) || (ThisObject.Display_Options.IndexOf("I") >= 0))
            {
                // Add the ALL browse, if there should be one
                ThisObject.Add_Child_Page(Item_Aggregation_Child_Visibility_Enum.Main_Menu, "all", String.Empty, "All Items");

                // Add the NEW search, if the ALL search exists
                if ((ThisObject.Get_Browse_Info_Object("all") != null) && (ThisObject.Show_New_Item_Browse))
                {
                    ThisObject.Add_Child_Page(Item_Aggregation_Child_Visibility_Enum.Main_Menu, "new", String.Empty, "Recently Added Items");
                }
            }
            else
            {
                // Add the ALL browse as an info
                ThisObject.Add_Child_Page(Item_Aggregation_Child_Visibility_Enum.None, "all", String.Empty, "All Items");
            }
        }
        /// <summary> Gets the complete (language agnostic) item aggregation, by aggregation code </summary>
        /// <param name="Response"></param>
        /// <param name="UrlSegments"></param>
        /// <param name="QueryString"></param>
        /// <param name="Protocol"></param>
        /// <param name="IsDebug"></param>
        public void GetCompleteAggregationByCode(HttpResponse Response, List <string> UrlSegments, NameValueCollection QueryString, Microservice_Endpoint_Protocol_Enum Protocol, bool IsDebug)
        {
            if (UrlSegments.Count > 0)
            {
                Custom_Tracer tracer = new Custom_Tracer();

                try
                {
                    // Get the aggregation code to get from the URL segments
                    string aggrCode = UrlSegments[0];
                    tracer.Add_Trace("AggregationServices.GetCompleteAggregationByCode", "Build and return '" + aggrCode + "' complete item aggregation");

                    // Get the complete aggregation
                    Complete_Item_Aggregation returnValue = get_complete_aggregation(aggrCode, true, tracer);

                    // If this was debug mode, then just write the tracer
                    if (IsDebug)
                    {
                        Response.ContentType = "text/plain";
                        Response.Output.WriteLine("DEBUG MODE DETECTED");
                        Response.Output.WriteLine();
                        Response.Output.WriteLine(tracer.Text_Trace);

                        return;
                    }

                    // Get the JSON-P callback function
                    string json_callback = "parseCompleteAggregation";
                    if ((Protocol == Microservice_Endpoint_Protocol_Enum.JSON_P) && (!String.IsNullOrEmpty(QueryString["callback"])))
                    {
                        json_callback = QueryString["callback"];
                    }

                    // Use the base class to serialize the object according to request protocol
                    Serialize(returnValue, Response, Protocol, json_callback);
                }
                catch (Exception ee)
                {
                    if (IsDebug)
                    {
                        Response.ContentType = "text/plain";
                        Response.Output.WriteLine("EXCEPTION CAUGHT!");
                        Response.Output.WriteLine();
                        Response.Output.WriteLine(ee.Message);
                        Response.Output.WriteLine();
                        Response.Output.WriteLine(ee.StackTrace);
                        Response.Output.WriteLine();
                        Response.Output.WriteLine(tracer.Text_Trace);
                        return;
                    }

                    Response.ContentType = "text/plain";
                    Response.Output.WriteLine("Error completing request");
                    Response.StatusCode = 500;
                }
            }
        }
        /// <summary> Reads the item aggregation configuration file and populates the new data into the
        /// item aggregation object </summary>
        /// <param name="HierarchyObject"> Item aggregation object to populate</param>
        /// <param name="FileLocation"> Full name of the item aggregation configuration XML file </param>
        public void Add_Info_From_XML_File(Complete_Item_Aggregation HierarchyObject, string FileLocation)
        {
            // Get the directory from the file location
            string directory = (new FileInfo(FileLocation)).DirectoryName;

            // Load this XML file
            XmlDocument hierarchyXml = new XmlDocument();

            hierarchyXml.Load(FileLocation);

            // create the node reader
            XmlNodeReader nodeReader = new XmlNodeReader(hierarchyXml);

            // Read all the nodes
            while (nodeReader.Read())
            {
                // If this is the beginning tag for an element, assign the next values accordingly
                if (nodeReader.NodeType == XmlNodeType.Element)
                {
                    // Get the node name, trimmed and to upper
                    string nodeName = nodeReader.Name.Trim().ToUpper();

                    // switch the rest based on the tag name
                    switch (nodeName)
                    {
                    case "HI:SETTINGS":
                        read_settings(nodeReader, HierarchyObject);
                        break;

                    case "HI:HOME":
                        read_home(nodeReader, HierarchyObject);
                        break;

                    case "HI:BANNER":
                        read_banners(nodeReader, HierarchyObject);
                        break;

                    case "HI:DIRECTIVES":
                        read_directives(nodeReader, HierarchyObject, directory);
                        break;

                    case "HI:HIGHLIGHTS":
                        read_highlights(nodeReader, HierarchyObject);
                        break;

                    case "HI:BROWSE":
                        read_browse(true, nodeReader, HierarchyObject);
                        break;

                    case "HI:INFO":
                        read_browse(false, nodeReader, HierarchyObject);
                        break;
                    }
                }
            }
        }
        /// <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> Finds the home page source file and banner images or html for this item aggregation </summary>
        /// <param name="ThisObject"> Item aggregation to add the home page link and banner html </param>
        /// <remarks>This method is only called if the item aggregation does not have an existing XML configuration file. </remarks>
        protected static void Add_HTML(Complete_Item_Aggregation ThisObject)
        {
            // Just use the standard home text
            if (File.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location + ThisObject.ObjDirectory + "html/home/text.html"))
            {
                ThisObject.Add_Home_Page_File("html/home/text.html", Engine_ApplicationCache_Gateway.Settings.System.Default_UI_Language, false);
            }
            if (File.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location + ThisObject.ObjDirectory + "html/home/text_en.html"))
            {
                ThisObject.Add_Home_Page_File("html/home/text_en.html", Web_Language_Enum.English, false);
            }
            if (File.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location + ThisObject.ObjDirectory + "html/home/text_fr.html"))
            {
                ThisObject.Add_Home_Page_File("html/home/text_fr.html", Web_Language_Enum.French, false);
            }
            if (File.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location + ThisObject.ObjDirectory + "html/home/text_es.html"))
            {
                ThisObject.Add_Home_Page_File("html/home/text_es.html", Web_Language_Enum.Spanish, false);
            }
            if (File.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location + ThisObject.ObjDirectory + "html/home/text_sp.html"))
            {
                ThisObject.Add_Home_Page_File("html/home/text_sp.html", Web_Language_Enum.Spanish, false);
            }

            // Just use the standard banner image
            if (File.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location + ThisObject.ObjDirectory + "images/banners/coll.jpg"))
            {
                ThisObject.Add_Banner_Image("images/banners/coll.jpg", Engine_ApplicationCache_Gateway.Settings.System.Default_UI_Language);
            }
            if (File.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location + ThisObject.ObjDirectory + "images/banners/coll_en.jpg"))
            {
                ThisObject.Add_Banner_Image("images/banners/coll_en.jpg", Web_Language_Enum.English);
            }
            if (File.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location + ThisObject.ObjDirectory + "images/banners/coll_fr.jpg"))
            {
                ThisObject.Add_Banner_Image("images/banners/coll_fr.jpg", Web_Language_Enum.French);
            }
            if (File.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location + ThisObject.ObjDirectory + "images/banners/coll_es.jpg"))
            {
                ThisObject.Add_Banner_Image("images/banners/coll_es.jpg", Web_Language_Enum.Spanish);
            }
            if (File.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location + ThisObject.ObjDirectory + "images/banners/coll_sp.jpg"))
            {
                ThisObject.Add_Banner_Image("images/banners/coll_sp.jpg", Web_Language_Enum.Spanish);
            }
        }
        private static void read_home(XmlNodeReader NodeReader, Complete_Item_Aggregation HierarchyObject)
        {
            while (NodeReader.Read())
            {
                // If this is the beginning tag for an element, assign the next values accordingly
                if (NodeReader.NodeType == XmlNodeType.Element)
                {
                    // Get the node name, trimmed and to upper
                    string nodeName = NodeReader.Name.Trim().ToUpper();

                    // switch the rest based on the tag name
                    switch (nodeName)
                    {
                    case "HI:BODY":
                        Web_Language_Enum langEnum = Web_Language_Enum.DEFAULT;
                        bool isCustom = false;
                        if ((NodeReader.HasAttributes) && (NodeReader.MoveToAttribute("lang")))
                        {
                            string bodyLanguage = NodeReader.GetAttribute("lang");
                            langEnum = Web_Language_Enum_Converter.Code_To_Enum(bodyLanguage);
                        }
                        if ((NodeReader.HasAttributes) && (NodeReader.MoveToAttribute("isCustom")))
                        {
                            string attribute = NodeReader.GetAttribute("isCustom");
                            if (attribute != null && attribute.ToLower() == "true")
                            {
                                isCustom = true;
                            }
                        }

                        NodeReader.Read();
                        HierarchyObject.Add_Home_Page_File(NodeReader.Value, langEnum, isCustom);
                        break;
                    }
                }

                if ((NodeReader.NodeType == XmlNodeType.EndElement) && (NodeReader.Name.Trim().ToUpper() == "HI:HOME"))
                {
                    return;
                }
            }
        }
        /// <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> Method gets the HOME PAGE html for the appropriate UI settings </summary>
        /// <param name="CompAggr"> Complete item aggregation object </param>
        /// <param name = "Language"> Current language of the user interface </param>
        /// <param name = "Tracer">Trace object keeps a list of each method executed and important milestones in rendering</param>
        /// <returns>Home page HTML</returns>
        private static HTML_Based_Content Get_Home_HTML(Complete_Item_Aggregation CompAggr, Web_Language_Enum Language, Custom_Tracer Tracer)
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("Item_Aggregation_Utilities.Get_Home_HTML", "Reading home text source file");
            }

            string homeFileSource = "";

            // Get the home file source
            if (CompAggr.Home_Page_File(Language) != null)
            {
                homeFileSource = Path.Combine(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location, CompAggr.ObjDirectory, CompAggr.Home_Page_File(Language).Source);
            }

            // If no home file source even found, return a message to that affect
            if (homeFileSource.Length == 0)
            {
                return(new HTML_Based_Content("<div class=\"error_div\">NO HOME PAGE SOURCE FILE FOUND</div>", null, homeFileSource));
            }

            // Do the rest in a try/catch
            try
            {
                // Does the file exist?
                if (!File.Exists(homeFileSource))
                {
                    return(new HTML_Based_Content("<div class=\"error_div\">HOME PAGE SOURCE FILE '" + homeFileSource + "' DOES NOT EXIST.</div>", null, homeFileSource));
                }

                HTML_Based_Content content = HTML_Based_Content_Reader.Read_HTML_File(homeFileSource, true, Tracer);
                content.Source = homeFileSource;

                return(content);
            }
            catch (Exception ee)
            {
                return(new HTML_Based_Content("<div class=\"error_div\">EXCEPTION CAUGHT WHILE TRYING TO READ THE HOME PAGE SOURCE FILE '" + homeFileSource + "'.<br /><br />ERROR: " + ee.Message + "</div>", null, homeFileSource));
            }
        }
        /// <summary> Retrieves the complete item aggregation obejct from the cache  </summary>
        /// <param name="Aggregation_Code"> Code for the item aggregation to retrieve </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering</param>
        /// <returns> Either NULL or the complete item aggregation object </returns>
        public Complete_Item_Aggregation Retrieve_Complete_Item_Aggregation(string Aggregation_Code, Custom_Tracer Tracer)
        {
            // If the cache is disabled, just return before even tracing
            if ((settings.Disabled) || (HttpContext.Current == null))
            {
                return(null);
            }

            if (Tracer != null)
            {
                Tracer.Add_Trace("CachedDataManager.Retrieve_Item_Aggregation", "");
            }

            // Determine the key
            string key = "AGGR|" + Aggregation_Code.ToUpper() + "|COMPLETE";

            // See if this is in the local cache first
            Complete_Item_Aggregation returnValue = HttpContext.Current.Cache.Get(key) as Complete_Item_Aggregation;

            if (returnValue != null)
            {
                if (Tracer != null)
                {
                    Tracer.Add_Trace("CachedDataManager.Retrieve_Item_Aggregation", "Found item aggregation on local cache");
                }

                return(returnValue);
            }

            if (Tracer != null)
            {
                Tracer.Add_Trace("CachedDataManager.Retrieve_Item_Aggregation", "Aggregation not found in either the local cache ");
            }

            // Since everything failed, just return null
            return(null);
        }
        public void Simple_Results_XML(HttpResponse Response, List <string> UrlSegments, NameValueCollection QueryString, Microservice_Endpoint_Protocol_Enum Protocol, bool IsDebug)
        {
            // Local trace
            Custom_Tracer tracer = new Custom_Tracer();

            tracer.Add_Trace("SimpleResultsEndpoints.Simple_Results_XML");

            // Get all the searh field necessary from the query string
            Results_Arguments args = new Results_Arguments(QueryString);

            // Additional results arguments
            // limit number of results
            int     artificial_result_limitation = -1;
            Boolean isNumeric = false;

            if (!String.IsNullOrEmpty(QueryString["limit_results"]))
            {
                isNumeric = Int32.TryParse(QueryString["limit_results"], out artificial_result_limitation);

                if (!isNumeric)
                {
                    artificial_result_limitation = -1;
                }
                else if (artificial_result_limitation < 1)
                {
                    artificial_result_limitation = -1;
                }
            }

            int pagenum = 1;

            if (!String.IsNullOrEmpty(QueryString["page"]))
            {
                isNumeric = Int32.TryParse(QueryString["page"], out pagenum);

                if (!isNumeric)
                {
                    pagenum = 1;
                }
                else if (pagenum < 1)
                {
                    pagenum = 1;
                }
                else if (pagenum > 1)
                {
                    artificial_result_limitation = -1;
                }
            }

            // Was a collection indicated?
            if (UrlSegments.Count > 0)
            {
                args.Aggregation = UrlSegments[0];
            }

            // Get the aggregation object (we need to know which facets to use, etc.. )
            tracer.Add_Trace("SimpleResultsEndpoints.Get_Search_Results_Set", "Get the '" + args.Aggregation + "' item aggregation (for facets, etc..)");
            Complete_Item_Aggregation aggr = AggregationServices.get_complete_aggregation(args.Aggregation, true, tracer);

            // If no aggregation was returned, that is an error
            if (aggr == null)
            {
                tracer.Add_Trace("SimpleResultsEndpoints.Simple_Results_XML", "Returned aggregation was NULL... aggregation code may not be valid");

                if (IsDebug)
                {
                    Response.ContentType = "text/plain";
                    Response.Output.WriteLine("DEBUG MODE DETECTED");
                    Response.Output.WriteLine();
                    Response.Output.WriteLine(tracer.Text_Trace);
                    return;
                }

                Response.ContentType = "text/plain";
                Response.Output.WriteLine("Error occurred or aggregation '" + args.Aggregation + "' not valid");
                Response.StatusCode = 500;
                return;
            }

            // Perform the search
            tracer.Add_Trace("SimpleResultsEndpoints.Simple_Results_XML", "Perform the search");
            Search_Results_Statistics   resultsStats;
            List <iSearch_Title_Result> resultsPage;
            ResultsEndpointErrorEnum    error = Get_Search_Results(args, aggr, false, tracer, out resultsStats, out resultsPage);

            // Was this in debug mode?
            // If this was debug mode, then just write the tracer
            if (IsDebug)
            {
                tracer.Add_Trace("SimpleResultsEndpoints.Simple_Results_XML", "Debug mode detected");

                Response.ContentType = "text/plain";
                Response.Output.WriteLine("DEBUG MODE DETECTED");
                Response.Output.WriteLine();
                Response.Output.WriteLine(tracer.Text_Trace);
                return;
            }

            try
            {
                tracer.Add_Trace("SimpleResultsEndpoints.Simple_Results_XML", "Begin writing the XML result to the response");
                Response.Output.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>");

                int count_pages = (int)Math.Floor((double)resultsStats.Total_Items / 20);

                if (count_pages == 0)
                {
                    count_pages = 1;
                }

                if (pagenum > count_pages)
                {
                    pagenum = count_pages;
                }

                Response.Output.WriteLine("<results total_items=\"" + resultsStats.Total_Items + "\" total_titles=\"" + resultsStats.Total_Titles + "\" page_count=\"" + count_pages + "\" max_results_per_page=\"20\"");

                if (artificial_result_limitation != -1)
                {
                    Response.Output.WriteLine("limit_results=\"" + artificial_result_limitation + "\"");
                }

                Response.Output.WriteLine(">");

                // Map to the results object title / item
                tracer.Add_Trace("SimpleResultsEndpoints.Get_Search_Results_Set", "Map to the results object title / item");

                // resultnum
                int resultnum = 0;

                if (pagenum > 1)
                {
                    resultnum = ((pagenum - 1) * 20);
                }

                if (resultsPage != null)
                {
                    foreach (iSearch_Title_Result thisResult in resultsPage)
                    {
                        // Every results should have an item
                        if (thisResult.Item_Count == 0)
                        {
                            continue;
                        }
                        else
                        {
                            resultnum++;
                        }

                        if (artificial_result_limitation != -1 && resultnum > artificial_result_limitation)
                        {
                            tracer.Add_Trace("SimpleResultsEndpoints.Simple_Results_XML", "Reached limit [" + artificial_result_limitation + "].");
                            break;
                        }

                        // add each descriptive field over
                        iSearch_Item_Result itemResult = thisResult.Get_Item(0);

                        string bibid     = thisResult.BibID;
                        string title     = thisResult.GroupTitle;
                        string vid       = itemResult.VID;
                        string thumbnail = itemResult.MainThumbnail;

                        Response.Output.WriteLine("  <result resultnum=\"" + resultnum + "\" bibid=\"" + bibid + "\" vid=\"" + vid + "\">");
                        Response.Output.WriteLine("    <title>" + HttpUtility.HtmlEncode(title) + "</title>");
                        Response.Output.WriteLine("    <url_item>" + Engine_ApplicationCache_Gateway.Settings.Servers.Application_Server_URL + bibid + "/" + vid + "/</url_item>");

                        if (!String.IsNullOrEmpty(thumbnail))
                        {
                            try
                            {
                                Response.Output.WriteLine("    <url_thumbnail>" + Engine_ApplicationCache_Gateway.Settings.Servers.Image_URL +
                                                          SobekFileSystem.AssociFilePath(bibid, vid).Replace("\\", "/") + thumbnail.Trim() + "</url_thumbnail>");
                            }
                            catch (Exception ee)
                            {
                                Response.Output.WriteLine("ERROR WRITING THUMBNAIL");
                                Response.Output.WriteLine(ee.Message);
                                Response.Output.WriteLine(ee.StackTrace);
                            }
                        }

                        int field_index = 0;

                        if (resultsStats.Metadata_Labels.Count > 0)
                        {
                            Response.Output.WriteLine("<metadata>");

                            foreach (string metadataTerm in resultsStats.Metadata_Labels)
                            {
                                if (!String.IsNullOrWhiteSpace(thisResult.Metadata_Display_Values[field_index]))
                                {
                                    // how to display this metadata field?
                                    string metadataTermDisplay = metadataTerm;
                                    string termString          = thisResult.Metadata_Display_Values[field_index];

                                    if (termString.IndexOf("|") > 0)
                                    {
                                        string[] splitter = termString.Split("|".ToCharArray());

                                        foreach (string thisSplit in splitter)
                                        {
                                            if (!String.IsNullOrWhiteSpace(thisSplit))
                                            {
                                                Response.Output.WriteLine("    <" + metadataTermDisplay + ">" + HttpUtility.HtmlEncode(thisSplit.Trim()) + "</" + metadataTermDisplay + ">");
                                            }
                                        }
                                    }
                                    else
                                    {
                                        Response.Output.WriteLine("    <" + metadataTermDisplay + ">" + HttpUtility.HtmlEncode(termString.Trim()) + "</" + metadataTermDisplay + ">");
                                    }
                                }

                                field_index++;
                            }

                            Response.Output.WriteLine("</metadata>");
                        }

                        Response.Output.WriteLine("  </result>");
                    }
                }

                Response.Output.WriteLine("</results>");

                tracer.Add_Trace("SimpleResultsEndpoints.Simple_Results_XML", "Done writing the XML result to the response");
            }
            catch (Exception ee)
            {
                Response.Output.Write(ee.Message);
                Response.Output.Write(ee.StackTrace);
            }

            // If an error occurred, return the error
            switch (error)
            {
            case ResultsEndpointErrorEnum.Database_Exception:
                Response.ContentType = "text/plain";
                Response.Output.WriteLine("Database exception");
                Response.StatusCode = 500;
                return;

            case ResultsEndpointErrorEnum.Database_Timeout_Exception:
                Response.ContentType = "text/plain";
                Response.Output.WriteLine("Database timeout");
                Response.StatusCode = 500;
                return;

            case ResultsEndpointErrorEnum.Solr_Exception:
                Response.ContentType = "text/plain";
                Response.Output.WriteLine("Solr exception");
                Response.StatusCode = 500;
                return;

            case ResultsEndpointErrorEnum.Unknown:
                Response.ContentType = "text/plain";
                Response.Output.WriteLine("Unknown error");
                Response.StatusCode = 500;
                return;
            }

            // If debug, show the trace
            if (IsDebug)
            {
                Response.ContentType = "text/plain";
                Response.Output.WriteLine("DEBUG MODE DETECTED");
                Response.Output.WriteLine();
                Response.Output.WriteLine(tracer.Text_Trace);
                return;
            }
        }
        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);
            }
        }
        /// <summary> Compares the two aggregation objects and returns a list of differences for saving as milestones
        /// during aggregation curatorial or administrative work </summary>
        /// <param name="Base"> Base item aggregation </param>
        /// <param name="Compared"> New item aggregation object to compare to the base </param>
        /// <returns> List of changes between the two aggregation objects </returns>
        public static List <string> Compare(Complete_Item_Aggregation Base, Complete_Item_Aggregation Compared)
        {
            // TODO: Facet comparison below needs to look up the name of the facet,
            // TODO: rather than just showing the primary key to the facet

            List <string> changes = new List <string>();

            // code
            if (!Base.Code.Equals(Compared.Code))
            {
                changes.Add("Changed code ( '" + Base.Code + "' --> '" + Compared.Code + "' )");
            }

            // parents
            List <string> base_parents     = new List <string>();
            List <string> compared_parents = new List <string>();

            if (Base.Parents != null)
            {
                foreach (Item_Aggregation_Related_Aggregations parentAggr in Base.Parents)
                {
                    // Look in compared for a match
                    if ((Compared.Parents == null) || (Compared.Parents.All(CompareAggr => String.Compare(parentAggr.Code, CompareAggr.Code, StringComparison.InvariantCultureIgnoreCase) != 0)))
                    {
                        base_parents.Add(parentAggr.Code);
                    }
                }
            }
            if (Compared.Parents != null)
            {
                foreach (Item_Aggregation_Related_Aggregations parentAggr in Compared.Parents)
                {
                    // Look in base for a match
                    if ((Base.Parents == null) || (Base.Parents.All(CompareAggr => String.Compare(parentAggr.Code, CompareAggr.Code, StringComparison.InvariantCultureIgnoreCase) != 0)))
                    {
                        compared_parents.Add(parentAggr.Code);
                    }
                }
            }
            if (base_parents.Count > 0)
            {
                if (base_parents.Count == 1)
                {
                    changes.Add("Removed parent " + base_parents[0]);
                }
                else
                {
                    StringBuilder builder = new StringBuilder("Removed parents " + base_parents[0]);
                    for (int i = 1; i < base_parents.Count; i++)
                    {
                        builder.Append(", " + base_parents[i]);
                    }
                    changes.Add(builder.ToString());
                }
            }
            if (compared_parents.Count > 0)
            {
                if (compared_parents.Count == 1)
                {
                    changes.Add("Added parent " + compared_parents[0]);
                }
                else
                {
                    StringBuilder builder = new StringBuilder("Added parents " + compared_parents[0]);
                    for (int i = 1; i < compared_parents.Count; i++)
                    {
                        builder.Append(", " + compared_parents[i]);
                    }
                    changes.Add(builder.ToString());
                }
            }

            // name
            if (!Base.Name.Equals(Compared.Name))
            {
                changes.Add("Changed name ( '" + Base.Name + "' --> '" + Compared.Name + "' )");
            }

            // short name
            if (!Base.ShortName.Equals(Compared.ShortName))
            {
                changes.Add("Changed short name ( '" + Base.ShortName + "' --> '" + Compared.ShortName + "' )");
            }

            // description
            if (!Base.Description.Equals(Compared.Description))
            {
                changes.Add("Changed description");
            }

            // type
            if (!Base.Type.Equals(Compared.Type))
            {
                changes.Add("Changed type ( '" + Base.Type + "' --> '" + Compared.Type + "' )");
            }

            // email address
            compare_nullable_strings(Base.Contact_Email, Compared.Contact_Email, "contact email", changes);

            // external link
            compare_nullable_strings(Base.External_Link, Compared.External_Link, "external link", changes);

            // Hidden flag
            if (Base.Hidden != Compared.Hidden)
            {
                if (Compared.Hidden)
                {
                    changes.Add("Removed from parent home page");
                }
                else
                {
                    changes.Add("Added to parent home page");
                }
            }

            // active flag
            if (Base.Active != Compared.Active)
            {
                if (Compared.Active)
                {
                    changes.Add("Aggregation activated");
                }
                else
                {
                    changes.Add("Aggregation deactivated");
                }
            }

            // thematic headings
            if (Base.Thematic_Heading == null)
            {
                if (Compared.Thematic_Heading != null)
                {
                    changes.Add("Added to thematic heading '" + Compared.Thematic_Heading.Text + "'");
                }
            }
            else
            {
                if (Compared.Thematic_Heading == null)
                {
                    changes.Add("Removed from thematic heading '" + Base.Thematic_Heading.Text + "'");
                }
                else
                {
                    if (Base.Thematic_Heading.ID != Compared.Thematic_Heading.ID)
                    {
                        changes.Add("Changed thematic heading ( '" + Base.Thematic_Heading.Text + "' --> '" + Compared.Thematic_Heading.Text + "' )");
                    }
                }
            }

            // web skin
            List <string> base_skins     = new List <string>();
            List <string> compared_skins = new List <string>();

            if (Base.Web_Skins != null)
            {
                foreach (string thisSkin in Base.Web_Skins)
                {
                    // Look in compared for a match
                    if ((Compared.Web_Skins == null) || (Compared.Web_Skins.All(CompareSkin => String.Compare(thisSkin, CompareSkin, StringComparison.InvariantCultureIgnoreCase) != 0)))
                    {
                        base_skins.Add(thisSkin);
                    }
                }
            }
            if (Compared.Web_Skins != null)
            {
                foreach (string thisSkin in Compared.Web_Skins)
                {
                    // Look in base for a match
                    if ((Base.Web_Skins == null) || (Base.Web_Skins.All(CompareSkin => String.Compare(thisSkin, CompareSkin, StringComparison.InvariantCultureIgnoreCase) != 0)))
                    {
                        compared_skins.Add(thisSkin);
                    }
                }
            }
            if (base_skins.Count > 0)
            {
                if (base_skins.Count == 1)
                {
                    changes.Add("Removed web skin " + base_skins[0]);
                }
                else
                {
                    StringBuilder builder = new StringBuilder("Removed web skins " + base_skins[0]);
                    for (int i = 1; i < base_skins.Count; i++)
                    {
                        builder.Append(", " + base_skins[i]);
                    }
                    changes.Add(builder.ToString());
                }
            }
            if (compared_skins.Count > 0)
            {
                if (compared_skins.Count == 1)
                {
                    changes.Add("Added web skin " + compared_skins[0]);
                }
                else
                {
                    StringBuilder builder = new StringBuilder("Added web skins " + compared_skins[0]);
                    for (int i = 1; i < compared_skins.Count; i++)
                    {
                        builder.Append(", " + compared_skins[i]);
                    }
                    changes.Add(builder.ToString());
                }
            }

            // default web skin
            compare_nullable_strings(Base.Default_Skin, Compared.Default_Skin, "default web skin", changes);

            // custom css
            if (String.IsNullOrEmpty(Base.CSS_File))
            {
                if (!String.IsNullOrEmpty(Compared.CSS_File))
                {
                    changes.Add("Enabled the aggregation-level stylesheet");
                }
            }
            else
            {
                if (String.IsNullOrEmpty(Compared.CSS_File))
                {
                    changes.Add("Disabled the aggregation-level stylesheet");
                }
            }

            // home pages (multilingual)
            List <Web_Language_Enum> removedLanguages = new List <Web_Language_Enum>();
            List <Web_Language_Enum> addedLanguages   = new List <Web_Language_Enum>();

            if (Base.Home_Page_File_Dictionary != null)
            {
                foreach (KeyValuePair <Web_Language_Enum, Complete_Item_Aggregation_Home_Page> thisHomePage in Base.Home_Page_File_Dictionary)
                {
                    // Look in compared for a match
                    if ((Compared.Home_Page_File_Dictionary == null) || (Compared.Home_Page_File_Dictionary.All(CompareHomePage => thisHomePage.Key != CompareHomePage.Key)))
                    {
                        removedLanguages.Add(thisHomePage.Key);
                    }
                }
            }
            if (Compared.Home_Page_File_Dictionary != null)
            {
                foreach (KeyValuePair <Web_Language_Enum, Complete_Item_Aggregation_Home_Page> thisHomePage in Compared.Home_Page_File_Dictionary)
                {
                    // Look in base for a match
                    if ((Base.Home_Page_File_Dictionary == null) || (Base.Home_Page_File_Dictionary.All(CompareHomePage => thisHomePage.Key != CompareHomePage.Key)))
                    {
                        addedLanguages.Add(thisHomePage.Key);
                    }
                }
            }
            if (removedLanguages.Count > 0)
            {
                if (removedLanguages.Count == 1)
                {
                    changes.Add("Removed " + Web_Language_Enum_Converter.Enum_To_Name(removedLanguages[0]) + " home page");
                }
                else
                {
                    StringBuilder builder = new StringBuilder("Removed " + Web_Language_Enum_Converter.Enum_To_Name(removedLanguages[0]));
                    for (int i = 1; i < removedLanguages.Count; i++)
                    {
                        builder.Append(", " + removedLanguages[i]);
                    }
                    changes.Add(builder + " home pages");
                }
            }
            if (addedLanguages.Count > 0)
            {
                if (addedLanguages.Count == 1)
                {
                    changes.Add("Added " + Web_Language_Enum_Converter.Enum_To_Name(addedLanguages[0]) + " home page");
                }
                else
                {
                    StringBuilder builder = new StringBuilder("Added " + Web_Language_Enum_Converter.Enum_To_Name(removedLanguages[0]));
                    for (int i = 1; i < addedLanguages.Count; i++)
                    {
                        builder.Append(", " + addedLanguages[i]);
                    }
                    changes.Add(builder + " home pages");
                }
            }


            // banners (multilingual)
            removedLanguages.Clear();
            addedLanguages.Clear();
            if (Base.Banner_Dictionary != null)
            {
                foreach (KeyValuePair <Web_Language_Enum, string> thisBanner in Base.Banner_Dictionary)
                {
                    // Look in compared for a match
                    bool match = false;
                    if (Compared.Banner_Dictionary != null)
                    {
                        foreach (KeyValuePair <Web_Language_Enum, string> compareBanner in Compared.Banner_Dictionary)
                        {
                            if (thisBanner.Key == compareBanner.Key)
                            {
                                match = true;

                                // Now, compare the source file as well
                                if (String.Compare(thisBanner.Value, compareBanner.Value, StringComparison.InvariantCultureIgnoreCase) != 0)
                                {
                                    changes.Add("Changed " + Web_Language_Enum_Converter.Enum_To_Name(thisBanner.Key) + " banner source file (" + thisBanner.Value + " --> " + compareBanner.Value + ")");
                                }

                                break;
                            }
                        }
                    }
                    if (!match)
                    {
                        removedLanguages.Add(thisBanner.Key);
                    }
                }
            }
            if (Compared.Banner_Dictionary != null)
            {
                foreach (KeyValuePair <Web_Language_Enum, string> thisBanner in Compared.Banner_Dictionary)
                {
                    // Look in base for a match
                    if ((Base.Banner_Dictionary == null) || (Base.Banner_Dictionary.All(CompareBanner => thisBanner.Key != CompareBanner.Key)))
                    {
                        addedLanguages.Add(thisBanner.Key);
                    }
                }
            }
            if (removedLanguages.Count > 0)
            {
                if (removedLanguages.Count == 1)
                {
                    changes.Add("Removed " + Web_Language_Enum_Converter.Enum_To_Name(removedLanguages[0]) + " banner");
                }
                else
                {
                    StringBuilder builder = new StringBuilder("Removed " + Web_Language_Enum_Converter.Enum_To_Name(removedLanguages[0]));
                    for (int i = 1; i < removedLanguages.Count; i++)
                    {
                        builder.Append(", " + removedLanguages[i]);
                    }
                    changes.Add(builder + " banners");
                }
            }
            if (addedLanguages.Count > 0)
            {
                if (addedLanguages.Count == 1)
                {
                    changes.Add("Added " + Web_Language_Enum_Converter.Enum_To_Name(addedLanguages[0]) + " banner");
                }
                else
                {
                    StringBuilder builder = new StringBuilder("Added " + Web_Language_Enum_Converter.Enum_To_Name(addedLanguages[0]));
                    for (int i = 1; i < addedLanguages.Count; i++)
                    {
                        builder.Append(", " + addedLanguages[i]);
                    }
                    changes.Add(builder + " banners");
                }
            }

            // search types
            List <Search_Type_Enum> removedSearches = new List <Search_Type_Enum>();
            List <Search_Type_Enum> addedSearches   = new List <Search_Type_Enum>();

            if (Base.Search_Types != null)
            {
                foreach (Search_Type_Enum thisSearch in Base.Search_Types)
                {
                    // Look in compared for a match
                    if ((Compared.Search_Types == null) || (Compared.Search_Types.All(CompareSearch => thisSearch != CompareSearch)))
                    {
                        removedSearches.Add(thisSearch);
                    }
                }
            }
            if (Compared.Search_Types != null)
            {
                foreach (Search_Type_Enum thisSearch in Compared.Search_Types)
                {
                    // Look in base for a match
                    if ((Base.Search_Types == null) || (Base.Search_Types.All(CompareSearch => thisSearch != CompareSearch)))
                    {
                        addedSearches.Add(thisSearch);
                    }
                }
            }
            if (removedSearches.Count > 0)
            {
                if (removedSearches.Count == 1)
                {
                    changes.Add("Removed " + removedSearches[0].ToString() + " search");
                }
                else
                {
                    StringBuilder builder = new StringBuilder("Removed " + removedSearches[0].ToString());
                    for (int i = 1; i < removedSearches.Count; i++)
                    {
                        builder.Append(", " + removedSearches[i].ToString());
                    }
                    changes.Add(builder + " searches");
                }
            }
            if (addedSearches.Count > 0)
            {
                if (addedSearches.Count == 1)
                {
                    changes.Add("Added " + addedSearches[0] + " search");
                }
                else
                {
                    StringBuilder builder = new StringBuilder("Added " + addedSearches[0]);
                    for (int i = 1; i < addedSearches.Count; i++)
                    {
                        builder.Append(", " + addedSearches[i]);
                    }
                    changes.Add(builder + " searches");
                }
            }

            // other display types? ( all/new item browse, map browse )

            // map search default area
            if ((Base.Map_Search_Display != null) || (Compared.Map_Search_Display != null))
            {
                if (Base.Map_Search_Display == null)
                {
                    changes.Add("Added default area for map search display");
                }
                else if (Compared.Map_Search_Display == null)
                {
                    changes.Add("Removed default area information for map search display");
                }
                else
                {
                    // Are these different?
                    bool different = false;
                    if (Base.Map_Search_Display.Type != Compared.Map_Search_Display.Type)
                    {
                        different = true;
                    }
                    else
                    {
                        if ((Base.Map_Search_Display.ZoomLevel.HasValue != Compared.Map_Search_Display.ZoomLevel.HasValue) ||
                            ((Base.Map_Search_Display.ZoomLevel.HasValue) && (Base.Map_Search_Display.ZoomLevel.Value != Compared.Map_Search_Display.ZoomLevel.Value)))
                        {
                            different = true;
                        }
                        if ((Base.Map_Search_Display.Latitude.HasValue != Compared.Map_Search_Display.Latitude.HasValue) ||
                            ((Base.Map_Search_Display.Latitude.HasValue) && (Base.Map_Search_Display.Latitude.Value != Compared.Map_Search_Display.Latitude.Value)))
                        {
                            different = true;
                        }
                        if ((Base.Map_Search_Display.Longitude.HasValue != Compared.Map_Search_Display.Longitude.HasValue) ||
                            ((Base.Map_Search_Display.Longitude.HasValue) && (Base.Map_Search_Display.Longitude.Value != Compared.Map_Search_Display.Longitude.Value)))
                        {
                            different = true;
                        }
                    }

                    if (different)
                    {
                        changes.Add("Changed default area for map search display");
                    }
                }
            }

            // map browse default area
            if ((Base.Map_Browse_Display != null) || (Compared.Map_Browse_Display != null))
            {
                if (Base.Map_Browse_Display == null)
                {
                    changes.Add("Added default area for map browse display");
                }
                else if (Compared.Map_Browse_Display == null)
                {
                    changes.Add("Removed default area information for map browse display");
                }
                else
                {
                    // Are these different?
                    bool different = false;
                    if (Base.Map_Browse_Display.Type != Compared.Map_Browse_Display.Type)
                    {
                        different = true;
                    }
                    else
                    {
                        if ((Base.Map_Browse_Display.ZoomLevel.HasValue != Compared.Map_Browse_Display.ZoomLevel.HasValue) ||
                            ((Base.Map_Browse_Display.ZoomLevel.HasValue) && (Base.Map_Browse_Display.ZoomLevel.Value != Compared.Map_Browse_Display.ZoomLevel.Value)))
                        {
                            different = true;
                        }
                        if ((Base.Map_Browse_Display.Latitude.HasValue != Compared.Map_Browse_Display.Latitude.HasValue) ||
                            ((Base.Map_Browse_Display.Latitude.HasValue) && (Base.Map_Browse_Display.Latitude.Value != Compared.Map_Browse_Display.Latitude.Value)))
                        {
                            different = true;
                        }
                        if ((Base.Map_Browse_Display.Longitude.HasValue != Compared.Map_Browse_Display.Longitude.HasValue) ||
                            ((Base.Map_Browse_Display.Longitude.HasValue) && (Base.Map_Browse_Display.Longitude.Value != Compared.Map_Browse_Display.Longitude.Value)))
                        {
                            different = true;
                        }
                    }

                    if (different)
                    {
                        changes.Add("Changed default area for map browse display");
                    }
                }
            }

            // facets
            List <Complete_Item_Aggregation_Metadata_Type> addedFacets   = new List <Complete_Item_Aggregation_Metadata_Type>();
            List <Complete_Item_Aggregation_Metadata_Type> removedFacets = new List <Complete_Item_Aggregation_Metadata_Type>();

            if (Base.Facets != null)
            {
                foreach (Complete_Item_Aggregation_Metadata_Type thisFacet in Base.Facets)
                {
                    // Look in compared for a match
                    if ((Compared.Facets == null) || (Compared.Facets.All(CompareFacet => thisFacet.ID != CompareFacet.ID)))
                    {
                        removedFacets.Add(thisFacet);
                    }
                }
            }
            if (Compared.Facets != null)
            {
                foreach (Complete_Item_Aggregation_Metadata_Type thisFacet in Compared.Facets)
                {
                    // Look in base for a match
                    if ((Base.Facets == null) || (Base.Facets.All(CompareFacet => thisFacet.ID != CompareFacet.ID)))
                    {
                        addedFacets.Add(thisFacet);
                    }
                }
            }
            if (removedFacets.Count > 0)
            {
                if (removedFacets.Count == 1)
                {
                    changes.Add("Removed facet " + removedFacets[0]);
                }
                else
                {
                    StringBuilder builder = new StringBuilder("Removed facets " + removedFacets[0]);
                    for (int i = 1; i < removedFacets.Count; i++)
                    {
                        builder.Append(", " + removedFacets[i]);
                    }
                    changes.Add(builder.ToString());
                }
            }
            if (addedFacets.Count > 0)
            {
                if (addedFacets.Count == 1)
                {
                    changes.Add("Added facet " + addedFacets[0]);
                }
                else
                {
                    StringBuilder builder = new StringBuilder("Added facets " + addedFacets[0]);
                    for (int i = 1; i < addedFacets.Count; i++)
                    {
                        builder.Append(", " + addedFacets[i]);
                    }
                    changes.Add(builder.ToString());
                }
            }

            // result views
            List <string> removedResultsDisplay = new List <string>();
            List <string> addedResultsDisplays  = new List <string>();

            if (Base.Result_Views != null)
            {
                foreach (string thisSearch in Base.Result_Views)
                {
                    // Look in compared for a match
                    if ((Compared.Result_Views == null) || (Compared.Result_Views.All(CompareSearch => thisSearch != CompareSearch)))
                    {
                        removedResultsDisplay.Add(thisSearch);
                    }
                }
            }
            if (Compared.Search_Types != null)
            {
                foreach (string thisSearch in Compared.Result_Views)
                {
                    // Look in base for a match
                    if ((Base.Result_Views == null) || (Base.Result_Views.All(CompareSearch => thisSearch != CompareSearch)))
                    {
                        addedResultsDisplays.Add(thisSearch);
                    }
                }
            }
            if (removedResultsDisplay.Count > 0)
            {
                if (removedResultsDisplay.Count == 1)
                {
                    changes.Add("Removed " + removedResultsDisplay[0].ToString() + " result display type");
                }
                else
                {
                    StringBuilder builder = new StringBuilder("Removed " + removedResultsDisplay[0]);
                    for (int i = 1; i < removedResultsDisplay.Count; i++)
                    {
                        builder.Append(", " + removedResultsDisplay[i]);
                    }
                    changes.Add(builder + " result display types");
                }
            }
            if (addedResultsDisplays.Count > 0)
            {
                if (addedResultsDisplays.Count == 1)
                {
                    changes.Add("Added " + addedResultsDisplays[0] + " result display type");
                }
                else
                {
                    StringBuilder builder = new StringBuilder("Added " + addedResultsDisplays[0]);
                    for (int i = 1; i < addedResultsDisplays.Count; i++)
                    {
                        builder.Append(", " + addedResultsDisplays[i]);
                    }
                    changes.Add(builder + " result display types");
                }
            }

            // default browse
            compare_nullable_strings(Base.Default_BrowseBy, Compared.Default_BrowseBy, "default browse", changes);

            // metadata browse


            // oai-pmh flag
            if (Base.OAI_Enabled != Compared.OAI_Enabled)
            {
                if (Compared.OAI_Enabled)
                {
                    changes.Add("OAI-PMH enabled");
                }
                else
                {
                    changes.Add("OAI-PMH disabled");
                }
            }

            // oai-pmh description
            compare_nullable_strings(Base.OAI_Metadata, Compared.OAI_Metadata, "additional OAI-PMH metadata", changes);

            // child pages


            return(changes);
        }
        private static void read_browse(bool Browse, XmlNodeReader NodeReader, Complete_Item_Aggregation HierarchyObject)
        {
            // Create a new browse/info object
            Complete_Item_Aggregation_Child_Page newBrowse = new Complete_Item_Aggregation_Child_Page
            {
                Browse_Type      = Item_Aggregation_Child_Visibility_Enum.Main_Menu,
                Source_Data_Type = Item_Aggregation_Child_Source_Data_Enum.Static_HTML
            };

            bool isDefault = false;

            // Determine which XML node name to look for and set browse v. info
            string lastName = "HI:BROWSE";

            if (!Browse)
            {
                lastName = "HI:INFO";
                newBrowse.Browse_Type = Item_Aggregation_Child_Visibility_Enum.None;
            }

            // Check for the attributes
            if (NodeReader.HasAttributes)
            {
                if (NodeReader.MoveToAttribute("location"))
                {
                    if (NodeReader.Value == "BROWSEBY")
                    {
                        newBrowse.Browse_Type = Item_Aggregation_Child_Visibility_Enum.Metadata_Browse_By;
                    }
                }
                if (NodeReader.MoveToAttribute("default"))
                {
                    if (NodeReader.Value == "DEFAULT")
                    {
                        isDefault = true;
                    }
                }
                if (NodeReader.MoveToAttribute("visibility"))
                {
                    switch (NodeReader.Value)
                    {
                    case "NONE":
                        newBrowse.Browse_Type = Item_Aggregation_Child_Visibility_Enum.None;
                        break;

                    case "MAIN_MENU":
                        newBrowse.Browse_Type = Item_Aggregation_Child_Visibility_Enum.Main_Menu;
                        break;

                    case "BROWSEBY":
                        newBrowse.Browse_Type = Item_Aggregation_Child_Visibility_Enum.Metadata_Browse_By;
                        break;
                    }
                }
                if (NodeReader.MoveToAttribute("parent"))
                {
                    newBrowse.Parent_Code = NodeReader.Value;
                }
            }

            // Step through the XML and build this browse/info object
            while (NodeReader.Read())
            {
                // If this is the beginning tag for an element, assign the next values accordingly
                if (NodeReader.NodeType == XmlNodeType.Element)
                {
                    // Get the node name, trimmed and to upper
                    string nodeName = NodeReader.Name.Trim().ToUpper();

                    // switch the rest based on the tag name
                    switch (nodeName)
                    {
                    case "HI:METADATA":
                        NodeReader.Read();
                        newBrowse.Code             = NodeReader.Value.ToLower();
                        newBrowse.Source_Data_Type = Item_Aggregation_Child_Source_Data_Enum.Database_Table;
                        break;

                    case "HI:CODE":
                        NodeReader.Read();
                        newBrowse.Code = NodeReader.Value.ToLower();
                        break;

                    case "HI:TITLE":
                        // Look for a language attached to this title
                        string titleLanguage = String.Empty;
                        if ((NodeReader.HasAttributes) && (NodeReader.MoveToAttribute("lang")))
                        {
                            titleLanguage = NodeReader.GetAttribute("lang");
                        }

                        // read and save the title
                        NodeReader.Read();
                        newBrowse.Add_Label(NodeReader.Value, Web_Language_Enum_Converter.Code_To_Enum(titleLanguage));
                        break;

                    case "HI:BODY":
                        // Look for a language attached to this title
                        string bodyLanguage = String.Empty;
                        if ((NodeReader.HasAttributes) && (NodeReader.MoveToAttribute("lang")))
                        {
                            bodyLanguage = NodeReader.GetAttribute("lang");
                        }

                        // read and save the title
                        NodeReader.Read();
                        string bodySource = NodeReader.Value;
                        newBrowse.Add_Static_HTML_Source(bodySource, Web_Language_Enum_Converter.Code_To_Enum(bodyLanguage));
                        break;
                    }
                }

                if (NodeReader.NodeType == XmlNodeType.EndElement)
                {
                    if (NodeReader.Name.Trim().ToUpper() == lastName)
                    {
                        // Don't add ALL or NEW here
                        if ((String.Compare(newBrowse.Code, "all", StringComparison.InvariantCultureIgnoreCase) != 0) && (String.Compare(newBrowse.Code, "new", StringComparison.InvariantCultureIgnoreCase) != 0))
                        {
                            HierarchyObject.Add_Child_Page(newBrowse);
                            //HierarchyObject.Add

                            // If this set the default browse by save that information
                            if ((newBrowse.Browse_Type == Item_Aggregation_Child_Visibility_Enum.Metadata_Browse_By) && (isDefault))
                            {
                                HierarchyObject.Default_BrowseBy = newBrowse.Code;
                            }
                        }

                        return;
                    }
                }
            }
        }
        private static void read_settings(XmlNodeReader NodeReader, Complete_Item_Aggregation HierarchyObject)
        {
            while (NodeReader.Read())
            {
                // If this is the beginning tag for an element, assign the next values accordingly
                if (NodeReader.NodeType == XmlNodeType.Element)
                {
                    // Get the node name, trimmed and to upper
                    string nodeName = NodeReader.Name.Trim().ToUpper();

                    // switch the rest based on the tag name
                    switch (nodeName)
                    {
                    case "HI:WEBSKINS":
                        NodeReader.Read();
                        string webskins = NodeReader.Value;
                        if (!String.IsNullOrEmpty(webskins))
                        {
                            string[] splitter = webskins.Split(",".ToCharArray());
                            foreach (string thisSplitter in splitter)
                            {
                                if (thisSplitter.Length > 0)
                                {
                                    HierarchyObject.Add_Web_Skin(thisSplitter.ToLower());
                                }
                            }
                        }
                        break;

                    case "HI:CSS":
                        NodeReader.Read();
                        if (!String.IsNullOrEmpty(NodeReader.Value))
                        {
                            HierarchyObject.CSS_File = NodeReader.Value.Trim();
                        }
                        break;

                    case "HI:CUSTOMHOME":
                        NodeReader.Read();
                        // No longer do anything with this tag
                        // HierarchyObject.Custom_Home_Page_Source_File = NodeReader.Value.Trim();
                        break;

                    case "HI:FACETS":
                        NodeReader.Read();
                        string facets = NodeReader.Value;
                        if (!String.IsNullOrEmpty(facets))
                        {
                            string[] splitter2 = facets.Split(",".ToCharArray());
                            HierarchyObject.Clear_Facets();
                            foreach (string thisSplitter2 in splitter2)
                            {
                                HierarchyObject.Add_Facet(Convert.ToInt16(thisSplitter2));
                            }
                        }
                        break;

                    case "HI:MAPSEARCH":
                        if (NodeReader.MoveToAttribute("type"))
                        {
                            switch (NodeReader.GetAttribute("type").ToLower())
                            {
                            case "extent":
                            case "computed":
                                // This should already be set, assuming there were values to be added
                                if (HierarchyObject.Map_Search_Display == null)
                                {
                                    HierarchyObject.Map_Search_Display = new Item_Aggregation_Map_Coverage_Info(Item_Aggregation_Map_Coverage_Type_Enum.COMPUTED);
                                }
                                break;

                            case "fixed":
                                decimal latitude  = 999;
                                decimal longitude = 999;
                                int     zoom      = 999;

                                if (NodeReader.MoveToAttribute("latitude"))
                                {
                                    Decimal.TryParse(NodeReader.GetAttribute("latitude"), out latitude);
                                }
                                if (NodeReader.MoveToAttribute("longitude"))
                                {
                                    Decimal.TryParse(NodeReader.GetAttribute("longitude"), out longitude);
                                }
                                if (NodeReader.MoveToAttribute("zoom"))
                                {
                                    Int32.TryParse(NodeReader.GetAttribute("zoom"), out zoom);
                                }

                                if ((latitude != 999) && (longitude != 999))
                                {
                                    HierarchyObject.Map_Search_Display = new Item_Aggregation_Map_Coverage_Info(Item_Aggregation_Map_Coverage_Type_Enum.FIXED, zoom, longitude, latitude);
                                }
                                break;
                            }
                        }
                        break;

                    case "HI:MAPBROWSE":
                        if (NodeReader.MoveToAttribute("type"))
                        {
                            switch (NodeReader.GetAttribute("type").ToLower())
                            {
                            case "extent":
                                HierarchyObject.Map_Browse_Display = new Item_Aggregation_Map_Coverage_Info(Item_Aggregation_Map_Coverage_Type_Enum.EXTENT);
                                break;

                            case "computed":
                                HierarchyObject.Map_Browse_Display = new Item_Aggregation_Map_Coverage_Info(Item_Aggregation_Map_Coverage_Type_Enum.COMPUTED);
                                break;

                            case "fixed":
                                decimal latitude  = 999;
                                decimal longitude = 999;
                                int     zoom      = 999;

                                if (NodeReader.MoveToAttribute("latitude"))
                                {
                                    Decimal.TryParse(NodeReader.GetAttribute("latitude"), out latitude);
                                }
                                if (NodeReader.MoveToAttribute("longitude"))
                                {
                                    Decimal.TryParse(NodeReader.GetAttribute("longitude"), out longitude);
                                }
                                if (NodeReader.MoveToAttribute("zoom"))
                                {
                                    Int32.TryParse(NodeReader.GetAttribute("zoom"), out zoom);
                                }

                                if ((latitude != 999) && (longitude != 999))
                                {
                                    HierarchyObject.Map_Browse_Display = new Item_Aggregation_Map_Coverage_Info(Item_Aggregation_Map_Coverage_Type_Enum.FIXED, zoom, longitude, latitude);
                                }
                                break;
                            }
                        }
                        break;
                    }
                }

                if (NodeReader.NodeType == XmlNodeType.EndElement)
                {
                    if (NodeReader.Name.Trim().ToUpper() == "HI:SETTINGS")
                    {
                        return;
                    }
                }
            }
        }
        private static void read_directives(XmlNodeReader NodeReader, Complete_Item_Aggregation HierarchyObject, string Directory)
        {
            string directiveCode = String.Empty;
            string directiveFile = String.Empty;

            while (NodeReader.Read())
            {
                // If this is the beginning tag for an element, assign the next values accordingly
                if (NodeReader.NodeType == XmlNodeType.Element)
                {
                    // Get the node name, trimmed and to upper
                    string nodeName = NodeReader.Name.Trim().ToUpper();

                    // switch the rest based on the tag name
                    switch (nodeName)
                    {
                    case "HI:CODE":
                        NodeReader.Read();
                        directiveCode = NodeReader.Value.Replace("<%", "").Replace("%>", "");
                        break;

                    case "HI:SOURCE":
                        NodeReader.Read();
                        directiveFile = NodeReader.Value;
                        break;
                    }
                }

                if (NodeReader.NodeType == XmlNodeType.EndElement)
                {
                    if (NodeReader.Name.Trim().ToUpper() == "HI:DIRECTIVE")
                    {
                        if ((directiveCode.Length > 0) && (directiveFile.Length > 0))
                        {
                            string contents;
                            try
                            {
                                // Look for the matching file
                                if (File.Exists(Directory + "\\" + directiveFile))
                                {
                                    StreamReader reader = new StreamReader(Directory + "\\" + directiveFile);
                                    contents = reader.ReadToEnd();
                                    reader.Close();
                                }
                                else
                                {
                                    contents = "MISSING DIRECTIVE SOURCE FILE ('" + directiveFile + "')";
                                }
                            }
                            catch
                            {
                                contents = "EXCEPTION WHILE READING DIRECTIVE SOURCE FILE ('" + directiveFile + "')";
                            }

                            // Create the custom derivative object
                            Item_Aggregation_Custom_Directive newDirective = new Item_Aggregation_Custom_Directive(directiveCode, directiveFile, contents);
                            if (HierarchyObject.Custom_Directives == null)
                            {
                                HierarchyObject.Custom_Directives = new Dictionary <string, Item_Aggregation_Custom_Directive>()
                                ;
                            }
                            HierarchyObject.Custom_Directives["<%" + directiveCode.ToUpper() + "%>"] = newDirective;
                        }
                        directiveCode = String.Empty;
                        directiveFile = String.Empty;
                    }

                    if (NodeReader.Name.Trim().ToUpper() == "HI:DIRECTIVES")
                    {
                        // Done with all the directives so return
                        return;
                    }
                }
            }
        }
        private static void read_highlights(XmlNodeReader NodeReader, Complete_Item_Aggregation HierarchyObject)
        {
            Complete_Item_Aggregation_Highlights highlight = new Complete_Item_Aggregation_Highlights();


            // Determine if this is a rotating type of highlight or not
            if (NodeReader.HasAttributes)
            {
                if (NodeReader.MoveToAttribute("type"))
                {
                    if (NodeReader.Value == "ROTATING")
                    {
                        HierarchyObject.Rotating_Highlights = true;
                    }
                }

                if (HierarchyObject.Front_Banner_Dictionary != null)
                {
                    // The following three values are for reading legacy XML files.  These
                    // data fields have been moved to be attached to the actual banner
                    if (NodeReader.MoveToAttribute("bannerSide"))
                    {
                        if (NodeReader.Value.Trim().ToUpper() == "RIGHT")
                        {
                            foreach (KeyValuePair <Web_Language_Enum, Item_Aggregation_Front_Banner> banners in HierarchyObject.Front_Banner_Dictionary)
                            {
                                banners.Value.Type = Item_Aggregation_Front_Banner_Type_Enum.Right;
                            }
                        }
                        else
                        {
                            foreach (KeyValuePair <Web_Language_Enum, Item_Aggregation_Front_Banner> banners in HierarchyObject.Front_Banner_Dictionary)
                            {
                                banners.Value.Type = Item_Aggregation_Front_Banner_Type_Enum.Left;
                            }
                        }
                    }
                    if (NodeReader.MoveToAttribute("bannerHeight"))
                    {
                        foreach (KeyValuePair <Web_Language_Enum, Item_Aggregation_Front_Banner> banners in HierarchyObject.Front_Banner_Dictionary)
                        {
                            banners.Value.Height = Convert.ToUInt16(NodeReader.Value);
                        }
                    }
                    if (NodeReader.MoveToAttribute("bannerWidth"))
                    {
                        foreach (KeyValuePair <Web_Language_Enum, Item_Aggregation_Front_Banner> banners in HierarchyObject.Front_Banner_Dictionary)
                        {
                            banners.Value.Width = Convert.ToUInt16(NodeReader.Value);
                        }
                    }
                }
            }

            while (NodeReader.Read())
            {
                // If this is the beginning tag for an element, assign the next values accordingly
                if (NodeReader.NodeType == XmlNodeType.Element)
                {
                    // Get the node name, trimmed and to upper
                    string nodeName = NodeReader.Name.Trim().ToUpper();

                    // switch the rest based on the tag name
                    string languageText;
                    switch (nodeName)
                    {
                    case "HI:SOURCE":
                        NodeReader.Read();
                        highlight.Image = NodeReader.Value.ToLower();
                        break;

                    case "HI:LINK":
                        NodeReader.Read();
                        highlight.Link = NodeReader.Value.ToLower();
                        break;

                    case "HI:TOOLTIP":
                        languageText = String.Empty;
                        if ((NodeReader.HasAttributes) && (NodeReader.MoveToAttribute("lang")))
                        {
                            languageText = NodeReader.Value.ToUpper();
                        }
                        NodeReader.Read();
                        highlight.Add_Tooltip(Web_Language_Enum_Converter.Code_To_Enum(languageText), NodeReader.Value);
                        break;

                    case "HI:TEXT":
                        languageText = String.Empty;
                        if ((NodeReader.HasAttributes) && (NodeReader.MoveToAttribute("lang")))
                        {
                            languageText = NodeReader.Value.ToUpper();
                        }
                        NodeReader.Read();
                        highlight.Add_Text(Web_Language_Enum_Converter.Code_To_Enum(languageText), NodeReader.Value);
                        break;
                    }
                }

                if (NodeReader.NodeType == XmlNodeType.EndElement)
                {
                    if (NodeReader.Name.Trim().ToUpper() == "HI:HIGHLIGHT")
                    {
                        if (HierarchyObject.Highlights == null)
                        {
                            HierarchyObject.Highlights = new List <Complete_Item_Aggregation_Highlights>();
                        }
                        HierarchyObject.Highlights.Add(highlight);
                        highlight = new Complete_Item_Aggregation_Highlights();
                    }

                    if (NodeReader.Name.Trim().ToUpper() == "HI:HIGHLIGHTS")
                    {
                        // Done with all the highlights so return
                        return;
                    }
                }
            }
        }
        private static void read_banners(XmlNodeReader NodeReader, Complete_Item_Aggregation HierarchyObject)
        {
            while (NodeReader.Read())
            {
                // If this is the beginning tag for an element, assign the next values accordingly
                if (NodeReader.NodeType == XmlNodeType.Element)
                {
                    // Get the node name, trimmed and to upper
                    string nodeName = NodeReader.Name.Trim().ToUpper();

                    // switch the rest based on the tag name
                    switch (nodeName)
                    {
                    case "HI:SOURCE":
                        // Check for any attributes to this banner node
                        string lang    = String.Empty;
                        bool   special = false;
                        Item_Aggregation_Front_Banner_Type_Enum type = Item_Aggregation_Front_Banner_Type_Enum.Left;
                        ushort width  = 550;
                        ushort height = 230;

                        if (NodeReader.HasAttributes)
                        {
                            if (NodeReader.MoveToAttribute("lang"))
                            {
                                lang = NodeReader.Value.Trim().ToUpper();
                            }
                            if (NodeReader.MoveToAttribute("type"))
                            {
                                if ((NodeReader.Value.Trim().ToUpper() == "HIGHLIGHT") || (NodeReader.Value.Trim().ToUpper() == "FRONT"))
                                {
                                    special = true;
                                }
                            }
                            if (NodeReader.MoveToAttribute("side"))
                            {
                                switch (NodeReader.Value.Trim().ToUpper())
                                {
                                case "RIGHT":
                                    type = Item_Aggregation_Front_Banner_Type_Enum.Right;
                                    break;

                                case "LEFT":
                                    type = Item_Aggregation_Front_Banner_Type_Enum.Left;
                                    break;

                                case "FULL":
                                    type = Item_Aggregation_Front_Banner_Type_Enum.Full;
                                    break;
                                }
                            }
                            if (NodeReader.MoveToAttribute("width"))
                            {
                                ushort.TryParse(NodeReader.Value, out width);
                            }
                            if (NodeReader.MoveToAttribute("height"))
                            {
                                ushort.TryParse(NodeReader.Value, out height);
                            }
                        }

                        // Now read the banner information and add to the aggregation object
                        NodeReader.Read();
                        if (special)
                        {
                            Item_Aggregation_Front_Banner bannerObj = HierarchyObject.Add_Front_Banner_Image(NodeReader.Value, Web_Language_Enum_Converter.Code_To_Enum(lang));
                            bannerObj.Width  = width;
                            bannerObj.Height = height;
                            bannerObj.Type   = type;
                        }
                        else
                        {
                            HierarchyObject.Add_Banner_Image(NodeReader.Value, Web_Language_Enum_Converter.Code_To_Enum(lang));
                        }


                        break;
                    }
                }

                if ((NodeReader.NodeType == XmlNodeType.EndElement) && (NodeReader.Name.Trim().ToUpper() == "HI:BANNER"))
                {
                    return;
                }
            }
        }
        /// <summary> Add a new aggregation to the system </summary>
        /// <param name="NewAggregation"> Information for the new aggregation </param>
        /// <returns> Message indicating success or any errors encountered </returns>
        public static RestResponseMessage add_new_aggregation(New_Aggregation_Arguments NewAggregation)
        {
            // Convert to the integer id for the parent and begin to do checking
            List <string> errors   = new List <string>();
            int           parentid = -1;

            if (NewAggregation.ParentCode.Length > 0)
            {
                Item_Aggregation_Related_Aggregations parentAggr = Engine_ApplicationCache_Gateway.Codes[NewAggregation.ParentCode];
                if (parentAggr != null)
                {
                    parentid = parentAggr.ID;
                }
                else
                {
                    errors.Add("Parent code is not valid");
                }
            }
            else
            {
                errors.Add("You must select a PARENT for this new aggregation");
            }

            // Validate the code

            if (NewAggregation.Code.Length > 20)
            {
                errors.Add("New aggregation code must be twenty characters long or less");
            }
            else if (NewAggregation.Code.Length == 0)
            {
                errors.Add("You must enter a CODE for this item aggregation");
            }
            else if (Engine_ApplicationCache_Gateway.Codes[NewAggregation.Code.ToUpper()] != null)
            {
                errors.Add("New code must be unique... <i>" + NewAggregation.Code + "</i> already exists");
            }
            else if (Engine_ApplicationCache_Gateway.Settings.Static.Reserved_Keywords.Contains(NewAggregation.Code.ToLower()))
            {
                errors.Add("That code is a system-reserved keyword.  Try a different code.");
            }
            else
            {
                bool alphaNumericTest = NewAggregation.Code.All(C => Char.IsLetterOrDigit(C) || C == '_' || C == '-');
                if (!alphaNumericTest)
                {
                    errors.Add("New aggregation code must be only letters and numbers");
                    NewAggregation.Code = NewAggregation.Code.Replace("\"", "");
                }
            }

            // Was there a type and name
            if (NewAggregation.Type.Length == 0)
            {
                errors.Add("You must select a TYPE for this new aggregation");
            }
            if (NewAggregation.Description.Length == 0)
            {
                errors.Add("You must enter a DESCRIPTION for this new aggregation");
            }
            if (NewAggregation.Name.Length == 0)
            {
                errors.Add("You must enter a NAME for this new aggregation");
            }
            else
            {
                if (NewAggregation.ShortName.Length == 0)
                {
                    NewAggregation.ShortName = NewAggregation.Name;
                }
            }

            // Check for the thematic heading
            int thematicHeadingId = -1;

            if (!String.IsNullOrEmpty(NewAggregation.Thematic_Heading))
            {
                // Look for the matching thematic heading
                foreach (Thematic_Heading thisHeading in Engine_ApplicationCache_Gateway.Thematic_Headings)
                {
                    if (String.Compare(thisHeading.Text, NewAggregation.Thematic_Heading, StringComparison.InvariantCultureIgnoreCase) == 0)
                    {
                        thematicHeadingId = thisHeading.ID;
                        break;
                    }
                }

                // If there was no match, the thematic heading was invalid, unless it was new
                if (thematicHeadingId < 0)
                {
                    if ((!NewAggregation.NewThematicHeading.HasValue) || (!NewAggregation.NewThematicHeading.Value))
                    {
                        errors.Add("Invalid thematic heading indicated");
                    }
                    else if (errors.Count == 0)
                    {
                        // Add the thematic heading first
                        if ((thematicHeadingId < 0) && (NewAggregation.NewThematicHeading.HasValue) && (NewAggregation.NewThematicHeading.Value))
                        {
                            thematicHeadingId = Engine_Database.Edit_Thematic_Heading(-1, 10, NewAggregation.Thematic_Heading, null);
                        }
                    }
                }
            }

            if (errors.Count > 0)
            {
                // Create the error message
                StringBuilder actionMessage = new StringBuilder("ERROR: Invalid entry for new item aggregation.<br />");
                foreach (string error in errors)
                {
                    actionMessage.Append("<br />" + error);
                }

                return(new RestResponseMessage(ErrorRestTypeEnum.InputError, actionMessage.ToString()));
            }



            string language = Web_Language_Enum_Converter.Enum_To_Code(Engine_ApplicationCache_Gateway.Settings.System.Default_UI_Language);

            // Try to save the new item aggregation
            if (!Engine_Database.Save_Item_Aggregation(NewAggregation.Code, NewAggregation.Name, NewAggregation.ShortName, NewAggregation.Description, thematicHeadingId, NewAggregation.Type, NewAggregation.Active, NewAggregation.Hidden, NewAggregation.External_Link, parentid, NewAggregation.User, language, null))
            {
                return(new RestResponseMessage(ErrorRestTypeEnum.Exception, "ERROR saving the new item aggregation to the database"));
            }
            // Ensure a folder exists for this, otherwise create one
            try
            {
                string folder = Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location + "aggregations\\" + NewAggregation.Code.ToLower();
                if (!Directory.Exists(folder))
                {
                    // Create this directory and all the subdirectories
                    Directory.CreateDirectory(folder);
                    Directory.CreateDirectory(folder + "/html");
                    Directory.CreateDirectory(folder + "/images");
                    Directory.CreateDirectory(folder + "/html/home");
                    Directory.CreateDirectory(folder + "/html/custom/home");
                    Directory.CreateDirectory(folder + "/images/buttons");
                    Directory.CreateDirectory(folder + "/images/banners");
                    Directory.CreateDirectory(folder + "/uploads");

                    // Get the parent name
                    string link_to_parent = String.Empty;
                    Item_Aggregation_Related_Aggregations parentAggr = Engine_ApplicationCache_Gateway.Codes.Aggregation_By_ID(parentid);
                    if (parentAggr != null)
                    {
                        if (String.Compare(parentAggr.Code, "all", StringComparison.InvariantCultureIgnoreCase) == 0)
                        {
                            link_to_parent = "<p>&larr; Back to <a href=\"<%BASEURL%>\" alt=\"Return to parent collection\">" + parentAggr.Name + "</a></p>" + Environment.NewLine;
                        }
                        else
                        {
                            link_to_parent = "<p>&larr; Back to <a href=\"<%BASEURL%>" + parentAggr.Code + "\" alt=\"Return to parent collection\">" + parentAggr.Name + "</a></p>" + Environment.NewLine;
                        }
                    }

                    // Create a default home text file
                    StreamWriter writer = new StreamWriter(folder + "/html/home/text.html");
                    writer.WriteLine(link_to_parent + "<h3>About " + NewAggregation.Name + "</h3>" + Environment.NewLine + "<p>" + NewAggregation.Description + "</p>" + Environment.NewLine + "<p>To edit this, log on as the aggregation admin and hover over this text to edit it.</p>" + Environment.NewLine);

                    writer.Flush();
                    writer.Close();

                    // Was a button indicated, and does it exist?
                    if ((!String.IsNullOrEmpty(NewAggregation.ButtonFile)) && (File.Exists(NewAggregation.ButtonFile)))
                    {
                        File.Copy(NewAggregation.ButtonFile, folder + "/images/buttons/coll.gif");
                    }
                    else
                    {
                        // Copy the default banner and buttons from images
                        if (File.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Directory + "design/aggregations/default_button.png"))
                        {
                            File.Copy(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Directory + "design/aggregations/default_button.png", folder + "/images/buttons/coll.png");
                        }
                        if (File.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Directory + "design/aggregations/default_button.gif"))
                        {
                            File.Copy(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Directory + "design/aggregations/default_button.gif", folder + "/images/buttons/coll.gif");
                        }
                    }

                    // Was a banner indicated, and does it exist?
                    string banner_file = String.Empty;
                    if ((!String.IsNullOrEmpty(NewAggregation.BannerFile)) && (File.Exists(NewAggregation.BannerFile)))
                    {
                        banner_file = "images/banners/" + Path.GetFileName(NewAggregation.BannerFile);
                        File.Copy(NewAggregation.BannerFile, folder + "//" + banner_file, true);
                    }
                    else
                    {
                        // Try to create a new custom banner
                        bool custom_banner_created = false;

                        // Create the banner with the name of the collection
                        if (Directory.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Application_Server_Network + "\\default\\banner_images"))
                        {
                            try
                            {
                                string[] banners = Directory.GetFiles(Engine_ApplicationCache_Gateway.Settings.Servers.Application_Server_Network + "\\default\\banner_images", "*.jpg");
                                if (banners.Length > 0)
                                {
                                    Random randomizer    = new Random();
                                    string banner_to_use = banners[randomizer.Next(0, banners.Length - 1)];
                                    Bitmap bitmap        = (Bitmap)(Image.FromFile(banner_to_use));

                                    RectangleF rectf = new RectangleF(30, bitmap.Height - 55, bitmap.Width - 40, 40);
                                    Graphics   g     = Graphics.FromImage(bitmap);
                                    g.SmoothingMode     = SmoothingMode.AntiAlias;
                                    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                                    g.PixelOffsetMode   = PixelOffsetMode.HighQuality;
                                    g.DrawString(NewAggregation.Name, new Font("Tahoma", 25, FontStyle.Bold), Brushes.Black, rectf);
                                    g.Flush();

                                    string new_file = folder + "/images/banners/coll.jpg";
                                    if (!File.Exists(new_file))
                                    {
                                        bitmap.Save(new_file, ImageFormat.Jpeg);
                                        custom_banner_created = true;
                                        banner_file           = "images/banners/coll.jpg";
                                    }
                                }
                            }
                            catch (Exception)
                            {
                                // Suppress this Error...
                            }
                        }

                        if ((!custom_banner_created) && (!File.Exists(folder + "/images/banners/coll.jpg")))
                        {
                            if (File.Exists(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Directory + "design/aggregations/default_banner.jpg"))
                            {
                                banner_file = "images/banners/coll.jpg";
                                File.Copy(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Directory + "design/aggregations/default_banner.jpg", folder + "/images/banners/coll.jpg", true);
                            }
                        }
                    }

                    // Now, try to create the item aggregation and write the configuration file
                    Custom_Tracer             tracer          = new Custom_Tracer();
                    Complete_Item_Aggregation itemAggregation = SobekEngineClient.Aggregations.Get_Complete_Aggregation(NewAggregation.Code, true, tracer);
                    if (banner_file.Length > 0)
                    {
                        itemAggregation.Banner_Dictionary.Clear();
                        itemAggregation.Add_Banner_Image(banner_file, Engine_ApplicationCache_Gateway.Settings.System.Default_UI_Language);
                    }
                    itemAggregation.Write_Configuration_File(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location + itemAggregation.ObjDirectory);

                    // If an email shoudl be sent, do that now
                    if (String.Compare(Engine_ApplicationCache_Gateway.Settings.Email.Send_On_Added_Aggregation, "always", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        string user = String.Empty;
                        if (!String.IsNullOrEmpty(NewAggregation.User))
                        {
                            user = NewAggregation.User;
                        }

                        string body = "New aggregation added to this system:\n\n\tCode:\t" + itemAggregation.Code + "\n\tType:\t" + itemAggregation.Type + "\n\tName:\t" + itemAggregation.Name + "\n\tShort:\t" + itemAggregation.ShortName + "\n\tUser:\t" + user + "\n\n" + Engine_ApplicationCache_Gateway.Settings.Servers.Application_Server_URL + "/" + itemAggregation.Code;
                        Email_Helper.SendEmail(Engine_ApplicationCache_Gateway.Settings.Email.System_Email, "New " + itemAggregation.Type + " - " + itemAggregation.ShortName, body, false, Engine_ApplicationCache_Gateway.Settings.System.System_Name);
                    }
                }
            }
            catch
            {
                // Reload the list of all codes, to include this new one and the new hierarchy
                lock (Engine_ApplicationCache_Gateway.Codes)
                {
                    Engine_Database.Populate_Code_Manager(Engine_ApplicationCache_Gateway.Codes, null);
                }

                return(new RestResponseMessage(ErrorRestTypeEnum.Exception, "ERROR completing the new aggregation add"));
            }

            // Reload the list of all codes, to include this new one and the new hierarchy
            lock (Engine_ApplicationCache_Gateway.Codes)
            {
                Engine_Database.Populate_Code_Manager(Engine_ApplicationCache_Gateway.Codes, null);
            }

            // Clear all aggregation information (and thematic heading info) from the cache as well
            CachedDataManager.Aggregations.Clear();

            return(new RestResponseMessage(ErrorRestTypeEnum.Successful, null));
        }
        /// <summary> Saves the information about this item aggregation to the database </summary>
        /// <param name="ItemAggr"> Item aggregation object with all the information to be saved </param>
        /// <param name="Username"> Name of the user performing this save, for the item aggregation milestones</param>
        /// <param name="Tracer">Trace object keeps a list of each method executed and important milestones in rendering</param>
        /// <returns>TRUE if successful, otherwise FALSE </returns>
        public static bool Save_To_Database(Complete_Item_Aggregation ItemAggr, string Username, Custom_Tracer Tracer)
        {
            // Build the list of language variants
            List <string> languageVariants = new List <string>
            {
                Web_Language_Enum_Converter.Enum_To_Code(Engine_ApplicationCache_Gateway.Settings.System.Default_UI_Language)
            };

            if (ItemAggr.Home_Page_File_Dictionary != null)
            {
                foreach (Web_Language_Enum language in ItemAggr.Home_Page_File_Dictionary.Keys)
                {
                    string code = Web_Language_Enum_Converter.Enum_To_Code(language);
                    if (!languageVariants.Contains(code))
                    {
                        languageVariants.Add(code);
                    }
                }
            }
            if (ItemAggr.Banner_Dictionary != null)
            {
                foreach (Web_Language_Enum language in ItemAggr.Banner_Dictionary.Keys)
                {
                    string code = Web_Language_Enum_Converter.Enum_To_Code(language);
                    if (!languageVariants.Contains(code))
                    {
                        languageVariants.Add(code);
                    }
                }
            }
            if (ItemAggr.Child_Pages != null)
            {
                foreach (Complete_Item_Aggregation_Child_Page childPage in ItemAggr.Child_Pages)
                {
                    if (childPage.Label_Dictionary != null)
                    {
                        foreach (Web_Language_Enum language in childPage.Label_Dictionary.Keys)
                        {
                            string code2 = Web_Language_Enum_Converter.Enum_To_Code(language);
                            if (!languageVariants.Contains(code2))
                            {
                                languageVariants.Add(code2);
                            }
                        }
                    }
                    if (childPage.Source_Dictionary != null)
                    {
                        foreach (Web_Language_Enum language in childPage.Source_Dictionary.Keys)
                        {
                            string code2 = Web_Language_Enum_Converter.Enum_To_Code(language);
                            if (!languageVariants.Contains(code2))
                            {
                                languageVariants.Add(code2);
                            }
                        }
                    }
                }
            }
            StringBuilder languageVariantsBuilder = new StringBuilder();

            foreach (string language in languageVariants)
            {
                if (language.Length > 0)
                {
                    if (languageVariantsBuilder.Length > 0)
                    {
                        languageVariantsBuilder.Append("|" + language);
                    }
                    else
                    {
                        languageVariantsBuilder.Append(language);
                    }
                }
            }


            return(Engine_Database.Save_Item_Aggregation(ItemAggr.ID, ItemAggr.Code, ItemAggr.Name, ItemAggr.ShortName,
                                                         ItemAggr.Description, ItemAggr.Thematic_Heading, ItemAggr.Type, ItemAggr.Active, ItemAggr.Hidden,
                                                         ItemAggr.Display_Options, 0, ItemAggr.Map_Search_Beta, 0, ItemAggr.Map_Display_Beta,
                                                         ItemAggr.OAI_Enabled, ItemAggr.OAI_Metadata, ItemAggr.Contact_Email, String.Empty, ItemAggr.External_Link, -1, Username,
                                                         languageVariantsBuilder.ToString(), Tracer));
        }
        public void Simple_Results_JSON(HttpResponse Response, List <string> UrlSegments, NameValueCollection QueryString, Microservice_Endpoint_Protocol_Enum Protocol, bool IsDebug)
        {
            Custom_Tracer tracer = new Custom_Tracer();

            tracer.Add_Trace("SimpleResultsEndpoints.Simple_Results_JSON", "Parse request to determine search requested");

            // Get all the searh field necessary from the query string
            Results_Arguments args = new Results_Arguments(QueryString);

            // Additional results arguments
            // limit number of results
            int     artificial_result_limitation = -1;
            Boolean isNumeric = false;

            if (!String.IsNullOrEmpty(QueryString["limit_results"]))
            {
                isNumeric = Int32.TryParse(QueryString["limit_results"], out artificial_result_limitation);

                if (!isNumeric)
                {
                    artificial_result_limitation = -1;
                }
                else if (artificial_result_limitation < 1)
                {
                    artificial_result_limitation = -1;
                }
            }

            int pagenum = 1;

            if (!String.IsNullOrEmpty(QueryString["page"]))
            {
                isNumeric = Int32.TryParse(QueryString["page"], out pagenum);

                if (!isNumeric)
                {
                    pagenum = 1;
                }
                else if (pagenum < 1)
                {
                    pagenum = 1;
                }
                else if (pagenum > 1)
                {
                    artificial_result_limitation = -1;
                }
            }

            // Was a collection indicated?
            if (UrlSegments.Count > 0)
            {
                args.Aggregation = UrlSegments[0];
            }

            // Get the aggregation object (we need to know which facets to use, etc.. )
            tracer.Add_Trace("SimpleResultsEndpoints.Simple_Results_JSON", "Get the '" + args.Aggregation + "' item aggregation (for facets, etc..)");
            Complete_Item_Aggregation aggr = AggregationServices.get_complete_aggregation(args.Aggregation, true, tracer);

            // If no aggregation was returned, that is an error
            if (aggr == null)
            {
                tracer.Add_Trace("SimpleResultsEndpoints.Simple_Results_JSON", "Returned aggregation was NULL... aggregation code may not be valid");

                if (IsDebug)
                {
                    Response.ContentType = "text/plain";
                    Response.Output.WriteLine("DEBUG MODE DETECTED");
                    Response.Output.WriteLine();
                    Response.Output.WriteLine(tracer.Text_Trace);
                    return;
                }

                Response.ContentType = "text/plain";
                Response.Output.WriteLine("Error occurred or aggregation '" + args.Aggregation + "' not valid");
                Response.StatusCode = 500;
                return;
            }

            // Perform the search
            tracer.Add_Trace("SimpleResultsEndpoints.Simple_Results_JSON", "Perform the search");
            Search_Results_Statistics   resultsStats;
            List <iSearch_Title_Result> resultsPage;
            ResultsEndpointErrorEnum    error = Get_Search_Results(args, aggr, false, tracer, out resultsStats, out resultsPage);


            // Was this in debug mode?
            // If this was debug mode, then just write the tracer
            if (IsDebug)
            {
                Response.ContentType = "text/plain";
                Response.Output.WriteLine("DEBUG MODE DETECTED");
                Response.Output.WriteLine();
                Response.Output.WriteLine(tracer.Text_Trace);
                return;
            }

            Response.Output.WriteLine("{\"stats\":{\"total_items\":\"" + resultsStats.Total_Items + "\",\"total_titles\":\"" + resultsStats.Total_Titles + "\"},");
            Response.Output.WriteLine(" \"results\":[");

            // Map to the results object title / item
            tracer.Add_Trace("SimpleResultsEndpoints.Simple_Results_JSON", "Map to the results object title / item");
            int items_counter = 0;
            int resultnum     = 0;

            if (resultsPage != null)
            {
                foreach (iSearch_Title_Result thisResult in resultsPage)
                {
                    // Every results should have an item
                    if (thisResult.Item_Count == 0)
                    {
                        continue;
                    }
                    else
                    {
                        resultnum++;
                    }

                    if (artificial_result_limitation != -1 && resultnum > artificial_result_limitation)
                    {
                        tracer.Add_Trace("SimpleResultsEndpoints.Simple_Results_XML", "Reached limit [" + artificial_result_limitation + "].");
                        break;
                    }
                    // Was this NOT the first item?
                    if (items_counter > 0)
                    {
                        Response.Output.WriteLine(",");
                    }

                    Response.Output.Write("        ");
                    items_counter++;

                    // add each descriptive field over
                    iSearch_Item_Result itemResult = thisResult.Get_Item(0);

                    string bibid     = thisResult.BibID;
                    string title     = thisResult.GroupTitle;
                    string vid       = itemResult.VID;
                    string thumbnail = itemResult.MainThumbnail;

                    // {"bibid":"1212", "vid":"00001", "title":"sdsd", "subjects":["subj1", "subj2", "subj3"] },

                    Response.Output.Write("{ \"bibid\":\"" + bibid + "\", \"vid\":\"" + vid + "\", ");
                    Response.Output.Write("\"title\":\"" + HttpUtility.HtmlEncode(title) + "\",");
                    Response.Output.Write("\"url_item\":\"" + Engine_ApplicationCache_Gateway.Settings.Servers.Application_Server_URL + bibid + "/" + vid + "/\",");
                    Response.Output.Write("\"url_thumbnail\":\"" + Engine_ApplicationCache_Gateway.Settings.Servers.Image_URL +
                                          SobekFileSystem.AssociFilePath(bibid, vid).Replace("\\", "/") + thumbnail + "\"");

                    int field_index = 0;

                    if (resultsStats.Metadata_Labels.Count > 0)
                    {
                        foreach (string metadataTerm in resultsStats.Metadata_Labels)
                        {
                            if (!String.IsNullOrWhiteSpace(thisResult.Metadata_Display_Values[field_index]))
                            {
                                // how to display this metadata field?
                                string metadataTermDisplay = metadataTerm;

                                string termString = thisResult.Metadata_Display_Values[field_index];
                                Response.Output.Write(",\"" + metadataTermDisplay + "\":[");

                                int individual_term_counter = 0;

                                if (termString.IndexOf("|") > 0)
                                {
                                    string[] splitter = termString.Split("|".ToCharArray());

                                    foreach (string thisSplit in splitter)
                                    {
                                        if (!String.IsNullOrWhiteSpace(thisSplit))
                                        {
                                            if (individual_term_counter > 0)
                                            {
                                                Response.Output.Write(", \"" + HttpUtility.HtmlEncode(thisSplit.Trim()) + "\"");
                                            }
                                            else
                                            {
                                                Response.Output.Write("\"" + HttpUtility.HtmlEncode(thisSplit.Trim()) + "\"");
                                            }

                                            individual_term_counter++;
                                        }
                                    }
                                }
                                else
                                {
                                    Response.Output.Write("\"" + HttpUtility.HtmlEncode(termString.Trim()) + "\"");
                                }

                                Response.Output.Write("]");
                            }

                            field_index++;
                        }
                    }

                    Response.Output.Write("}");
                }
            }

            Response.Output.WriteLine();
            Response.Output.WriteLine("    ]");
            Response.Output.WriteLine("} ");

            // If an error occurred, return the error
            switch (error)
            {
            case ResultsEndpointErrorEnum.Database_Exception:
                Response.ContentType = "text/plain";
                Response.Output.WriteLine("Database exception");
                Response.StatusCode = 500;
                return;

            case ResultsEndpointErrorEnum.Database_Timeout_Exception:
                Response.ContentType = "text/plain";
                Response.Output.WriteLine("Database timeout");
                Response.StatusCode = 500;
                return;

            case ResultsEndpointErrorEnum.Solr_Exception:
                Response.ContentType = "text/plain";
                Response.Output.WriteLine("Solr exception");
                Response.StatusCode = 500;
                return;

            case ResultsEndpointErrorEnum.Unknown:
                Response.ContentType = "text/plain";
                Response.Output.WriteLine("Unknown error");
                Response.StatusCode = 500;
                return;
            }
        }
        /// <summary> Get the language specific item aggregation, from the complete item aggregation object </summary>
        /// <param name="CompAggr"> Copmlete item aggregation object </param>
        /// <param name="RequestedLanguage"> Language version requested </param>
        /// <param name="Tracer"></param>
        /// <returns> The language-specific aggregation, built from the complete aggregation object, or NULL if an error occurred </returns>
        public static Item_Aggregation Get_Item_Aggregation(Complete_Item_Aggregation CompAggr, Web_Language_Enum RequestedLanguage, Custom_Tracer Tracer)
        {
            // If the complete aggregation was null, return null
            if (CompAggr == null)
            {
                if (Tracer != null)
                {
                    Tracer.Add_Trace("Item_Aggregation_Utilities.Get_Item_Aggregation", "Complete item aggregation was NULL.. aborting and returning NULL");
                }

                return(null);
            }

            if (Tracer != null)
            {
                Tracer.Add_Trace("Item_Aggregation_Utilities.Get_Item_Aggregation", "Building language-specific item aggregation from the complete object");
            }

            // Build the item aggregation
            Item_Aggregation returnValue = new Item_Aggregation(RequestedLanguage, CompAggr.ID, CompAggr.Code)
            {
                Active              = CompAggr.Active,
                BannerImage         = CompAggr.Banner_Image(RequestedLanguage, null),
                Child_Types         = CompAggr.Child_Types,
                Contact_Email       = CompAggr.Contact_Email,
                ContactForm         = CompAggr.ContactForm,
                CSS_File            = CompAggr.CSS_File,
                Default_BrowseBy    = CompAggr.Default_BrowseBy,
                Default_Result_View = CompAggr.Default_Result_View,
                Default_Skin        = CompAggr.Default_Skin,
                Description         = CompAggr.Description,
                Display_Options     = CompAggr.Display_Options,
                FrontBannerObj      = CompAggr.Front_Banner_Image(RequestedLanguage),
                Hidden              = CompAggr.Hidden,
                Last_Item_Added     = CompAggr.Last_Item_Added,
                Name = CompAggr.Name,
                Rotating_Highlights = CompAggr.Rotating_Highlights,
                ShortName           = CompAggr.ShortName,
                Statistics          = CompAggr.Statistics,
                Type = CompAggr.Type
            };

            // Copy the map search and browse information
            if (CompAggr.Map_Search_Display != null)
            {
                returnValue.Map_Search_Display = CompAggr.Map_Search_Display.Copy();
            }
            if (CompAggr.Map_Browse_Display != null)
            {
                returnValue.Map_Browse_Display = CompAggr.Map_Browse_Display.Copy();
            }

            // Copy any children aggregations over
            if (CompAggr.Active_Children_Count > 0)
            {
                if (Tracer != null)
                {
                    Tracer.Add_Trace("Item_Aggregation_Utilities.Get_Item_Aggregation", "...Copying children objects");
                }

                returnValue.Children = new List <Item_Aggregation_Related_Aggregations>();
                foreach (Item_Aggregation_Related_Aggregations thisAggr in CompAggr.Children)
                {
                    returnValue.Children.Add(thisAggr);
                }
            }

            // Copy any parent aggregations over
            if (CompAggr.Parent_Count > 0)
            {
                if (Tracer != null)
                {
                    Tracer.Add_Trace("Item_Aggregation_Utilities.Get_Item_Aggregation", "...Copying parent objects");
                }

                returnValue.Parents = new List <Item_Aggregation_Related_Aggregations>();
                foreach (Item_Aggregation_Related_Aggregations thisAggr in CompAggr.Parents)
                {
                    returnValue.Parents.Add(thisAggr);
                }
            }

            // Copy all the facet information over
            if (Tracer != null)
            {
                Tracer.Add_Trace("Item_Aggregation_Utilities.Get_Item_Aggregation", "...Copying facets");
            }
            foreach (short thisFacet in CompAggr.Facets)
            {
                returnValue.Facets.Add(thisFacet);
            }

            // Copy over all the results views
            if (Tracer != null)
            {
                Tracer.Add_Trace("Item_Aggregation_Utilities.Get_Item_Aggregation", "...Copying result views");
            }
            foreach (string display in CompAggr.Result_Views)
            {
                returnValue.Result_Views.Add(display);
            }

            // Copy all the views and searches over
            if (Tracer != null)
            {
                Tracer.Add_Trace("Item_Aggregation_Utilities.Get_Item_Aggregation", "...Copying views and searches");
            }
            if (CompAggr.Views_And_Searches != null)
            {
                foreach (Item_Aggregation_Views_Searches_Enum viewsSearches in CompAggr.Views_And_Searches)
                {
                    returnValue.Views_And_Searches.Add(viewsSearches);
                }
            }

            // Copy all the setting values
            if ((CompAggr.Settings != null) && (CompAggr.Settings.Count > 0))
            {
                foreach (StringKeyValuePair setting in CompAggr.Settings)
                {
                    returnValue.Add_Setting(setting.Key, setting.Value);
                }
            }

            // Copy over any web skin limitations
            if ((CompAggr.Web_Skins != null) && (CompAggr.Web_Skins.Count > 0))
            {
                if (Tracer != null)
                {
                    Tracer.Add_Trace("Item_Aggregation_Utilities.Get_Item_Aggregation", "...Copying web skins");
                }

                returnValue.Web_Skins = new List <string>();
                foreach (string thisSkin in CompAggr.Web_Skins)
                {
                    returnValue.Web_Skins.Add(thisSkin);
                }
            }

            // Language-specific (and simplified) metadata type info
            if (Tracer != null)
            {
                Tracer.Add_Trace("Item_Aggregation_Utilities.Get_Item_Aggregation", "...Copying search anbd browseable fields");
            }
            foreach (Complete_Item_Aggregation_Metadata_Type thisAdvSearchField in CompAggr.Search_Fields)
            {
                returnValue.Search_Fields.Add(new Item_Aggregation_Metadata_Type(thisAdvSearchField.DisplayTerm, thisAdvSearchField.SobekCode));
            }
            foreach (Complete_Item_Aggregation_Metadata_Type thisAdvSearchField in CompAggr.Browseable_Fields)
            {
                returnValue.Browseable_Fields.Add(new Item_Aggregation_Metadata_Type(thisAdvSearchField.DisplayTerm, thisAdvSearchField.SobekCode));
            }

            // Language-specific (and simplified) child pages information
            if ((CompAggr.Child_Pages != null) && (CompAggr.Child_Pages.Count > 0))
            {
                if (Tracer != null)
                {
                    Tracer.Add_Trace("Item_Aggregation_Utilities.Get_Item_Aggregation", "...Copying child pages");
                }

                returnValue.Child_Pages = new List <Item_Aggregation_Child_Page>();
                foreach (Complete_Item_Aggregation_Child_Page fullPage in CompAggr.Child_Pages)
                {
                    Item_Aggregation_Child_Page newPage = new Item_Aggregation_Child_Page
                    {
                        Browse_Type      = fullPage.Browse_Type,
                        Code             = fullPage.Code,
                        Parent_Code      = fullPage.Parent_Code,
                        Source_Data_Type = fullPage.Source_Data_Type
                    };

                    string label = fullPage.Get_Label(RequestedLanguage);
                    if (!String.IsNullOrEmpty(label))
                    {
                        newPage.Label = label;
                    }

                    string source = fullPage.Get_Static_HTML_Source(RequestedLanguage);
                    if (!String.IsNullOrEmpty(label))
                    {
                        newPage.Source = source;
                    }

                    returnValue.Child_Pages.Add(newPage);
                }
            }

            // Language-specific (and simplified) highlight information
            if ((CompAggr.Highlights != null) && (CompAggr.Highlights.Count > 0))
            {
                if (Tracer != null)
                {
                    Tracer.Add_Trace("Item_Aggregation_Utilities.Get_Item_Aggregation", "...Copying relevant highlights");
                }

                returnValue.Highlights = new List <Item_Aggregation_Highlights>();
                int day_integer      = DateTime.Now.DayOfYear + 1;
                int highlight_to_use = day_integer % CompAggr.Highlights.Count;

                // If this is for rotating highlights, show up to eight
                if ((CompAggr.Rotating_Highlights.HasValue) && (CompAggr.Rotating_Highlights.Value))
                {
                    // Copy over just the eight highlights we should use
                    int number = Math.Min(8, CompAggr.Highlights.Count);
                    for (int i = 0; i < number; i++)
                    {
                        Complete_Item_Aggregation_Highlights thisHighlight = CompAggr.Highlights[highlight_to_use];

                        Item_Aggregation_Highlights newHighlight = new Item_Aggregation_Highlights
                        {
                            Image = thisHighlight.Image,
                            Link  = thisHighlight.Link
                        };

                        string text = thisHighlight.Get_Text(RequestedLanguage);
                        if (!String.IsNullOrEmpty(text))
                        {
                            newHighlight.Text = text;
                        }

                        string tooltip = thisHighlight.Get_Tooltip(RequestedLanguage);
                        if (!String.IsNullOrEmpty(tooltip))
                        {
                            newHighlight.Tooltip = tooltip;
                        }

                        returnValue.Highlights.Add(newHighlight);

                        highlight_to_use++;
                        if (highlight_to_use >= CompAggr.Highlights.Count)
                        {
                            highlight_to_use = 0;
                        }
                    }
                }
                else
                {
                    Complete_Item_Aggregation_Highlights thisHighlight = CompAggr.Highlights[highlight_to_use];

                    Item_Aggregation_Highlights newHighlight = new Item_Aggregation_Highlights
                    {
                        Image = thisHighlight.Image,
                        Link  = thisHighlight.Link
                    };

                    string text = thisHighlight.Get_Text(RequestedLanguage);
                    if (!String.IsNullOrEmpty(text))
                    {
                        newHighlight.Text = text;
                    }

                    string tooltip = thisHighlight.Get_Tooltip(RequestedLanguage);
                    if (!String.IsNullOrEmpty(tooltip))
                    {
                        newHighlight.Tooltip = tooltip;
                    }

                    returnValue.Highlights.Add(newHighlight);
                }
            }

            // Language-specific source page
            if (Tracer != null)
            {
                Tracer.Add_Trace("Item_Aggregation_Utilities.Get_Item_Aggregation", "Getting the home page source");
            }
            returnValue.HomePageSource = String.Empty;
            HTML_Based_Content homeHtml = Get_Home_HTML(CompAggr, RequestedLanguage, null);

            returnValue.HomePageHtml     = homeHtml;
            returnValue.Custom_Home_Page = (CompAggr.Home_Page_File(RequestedLanguage) != null) && (CompAggr.Home_Page_File(RequestedLanguage).isCustomHome);

            if (Tracer != null)
            {
                Tracer.Add_Trace("Item_Aggregation_Utilities.Get_Item_Aggregation", "Returning fully built item aggregation object");
            }
            return(returnValue);
        }