/// <summary> Constructor for a new instance of the RequestCache class </summary>
 /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
 /// <param name="Hierarchy_Object"> Current item aggregation object to display </param>
 /// <param name="Results_Statistics"> Information about the entire set of results for a search or browse </param>
 /// <param name="Paged_Results"> Single page of results for a search or browse, within the entire set </param>
 /// <param name="Browse_Object"> Object contains all the basic information about any browse or info display </param>
 /// <param name="Current_Item"> Current item to display </param>
 /// <param name="Current_Page"> Current page within the item</param>
 /// <param name="HTML_Skin"> HTML Web skin which controls the overall appearance of this digital library </param>
 /// <param name="Current_User"> Currently logged on user </param>
 /// <param name="Public_Folder"> Object contains the information about the public folder to display </param>
 /// <param name="Site_Map"> Optional site map object used to render a navigational tree-view on left side of static web content pages </param>
 /// <param name="Items_In_Title"> List of items within the current title ( used for the Item Group display )</param>
 /// <param name="Static_Web_Content"> HTML content-based browse, info, or imple CMS-style web content objects.  These are objects which are read from a static HTML file and much of the head information must be maintained </param>
 /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
 public RequestCache(Navigation_Object Current_Mode,
     Item_Aggregation Hierarchy_Object,
     Search_Results_Statistics Results_Statistics,
     List<iSearch_Title_Result> Paged_Results,
     Item_Aggregation_Child_Page Browse_Object,
     SobekCM_Item Current_Item,
     Page_TreeNode Current_Page,
     Web_Skin_Object HTML_Skin,
     User_Object Current_User,
     Public_User_Folder Public_Folder,
     SobekCM_SiteMap Site_Map,
     SobekCM_Items_In_Title Items_In_Title,
     HTML_Based_Content Static_Web_Content,
     Custom_Tracer Tracer)
 {
     this.Current_Mode = Current_Mode;
     this.Hierarchy_Object = Hierarchy_Object;
     this.Results_Statistics = Results_Statistics;
     this.Paged_Results = Paged_Results;
     this.Browse_Object = Browse_Object;
     this.Current_Item = Current_Item;
     this.Current_Page = Current_Page;
     this.HTML_Skin = HTML_Skin;
     this.Current_User = Current_User;
     this.Public_Folder = Public_Folder;
     this.Site_Map = Site_Map;
     this.Items_In_Title = Items_In_Title;
     this.Static_Web_Content = Static_Web_Content;
     this.Tracer = Tracer;
 }
 /// <summary> Constructor for a new instance of the RequestCache class </summary>
 /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
 /// <param name="Results_Statistics"> Information about the entire set of results for a search or browse </param>
 /// <param name="Paged_Results"> Single page of results for a search or browse, within the entire set </param>
 /// <param name="HTML_Skin"> HTML Web skin which controls the overall appearance of this digital library </param>
 /// <param name="Current_User"> Currently logged on user </param>
 /// <param name="Public_Folder"> Object contains the information about the public folder to display </param>
 /// <param name="Top_Collection"> Item aggregation for the top-level collection, which is used in a number of places, for example 
 /// showing the correct banner, even when it is not the "current" aggregation </param>
 /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
 public RequestCache(Navigation_Object Current_Mode,
     Search_Results_Statistics Results_Statistics,
     List<iSearch_Title_Result> Paged_Results,
     Web_Skin_Object HTML_Skin,
     User_Object Current_User,
     Public_User_Folder Public_Folder,
     Item_Aggregation Top_Collection,
     Custom_Tracer Tracer)
 {
     this.Current_Mode = Current_Mode;
     this.Results_Statistics = Results_Statistics;
     this.Paged_Results = Paged_Results;
     this.HTML_Skin = HTML_Skin;
     this.Current_User = Current_User;
     this.Public_Folder = Public_Folder;
     this.Top_Collection = Top_Collection;
     this.Tracer = Tracer;
 }
        /// <summary> Adds the banner to the response stream from either the html web skin
        /// or from the current item aggreagtion object, depending on flags in the web skin object </summary>
        /// <param name="Output"> Stream to which to write the HTML for the banner </param>
        /// <param name="Banner_Division_Name"> Name for the wrapper division around the banner </param>
        /// <param name="Hierarchy_Object"> Current item aggregation object to display </param>
        /// <param name="HTML_Skin"> HTML Web skin which controls the overall appearance of this digital library </param>
        /// <param name="Web_Page_Title"> Web page title to add behind the banner image </param>
        /// <param name="CurrentMode"> Mode / navigation information for the current request</param>
        /// <remarks> This is called by several html subwriters that otherwise tell this class to suppress writing the banner </remarks>
        public static void Add_Banner(TextWriter Output, string Banner_Division_Name, string Web_Page_Title, Navigation_Object CurrentMode, Web_Skin_Object HTML_Skin, Item_Aggregation Hierarchy_Object)
        {
            Output.WriteLine("<!-- Write the main collection, interface, or institution banner -->");
            if ((HTML_Skin != null) && (HTML_Skin.Override_Banner.HasValue) && (HTML_Skin.Override_Banner.Value))
            {
                if ( !String.IsNullOrEmpty(HTML_Skin.Banner_HTML))
                    Output.WriteLine(HTML_Skin.Banner_HTML);
            }
            else
            {
                string url_options = UrlWriterHelper.URL_Options(CurrentMode);
                if (url_options.Length > 0)
                    url_options = "?" + url_options;

                if ((Hierarchy_Object != null) && (Hierarchy_Object.Code != "all"))
                {
                    Output.WriteLine("<section id=\"sbkAhs_BannerDiv\" role=\"banner\" title=\"" + Hierarchy_Object.ShortName + "\">");
                    Output.WriteLine("  <h1 class=\"hidden-element\">" + Web_Page_Title + "</h1>");
                    Output.WriteLine("  <a alt=\"" + Hierarchy_Object.ShortName + "\" href=\"" + CurrentMode.Base_URL + Hierarchy_Object.Code + url_options + "\"><img id=\"mainBanner\" src=\"" + CurrentMode.Base_URL + Hierarchy_Object.Get_Banner_Image(HTML_Skin) + "\"  alt=\"" + Hierarchy_Object.ShortName + "\" /></a>");
                    Output.WriteLine("</section>");
                }
                else
                {
                    if ((Hierarchy_Object != null) && (Hierarchy_Object.Get_Banner_Image(HTML_Skin).Length > 0))
                    {
                        Output.WriteLine("<section id=\"sbkAhs_BannerDiv\" role=\"banner\" title=\"" + Hierarchy_Object.ShortName + "\">");
                        Output.WriteLine("  <h1 class=\"hidden-element\">" + Web_Page_Title + "</h1>");
                        Output.WriteLine("  <a alt=\"" + Hierarchy_Object.ShortName + "\" href=\"" + CurrentMode.Base_URL + url_options + "\"><img id=\"mainBanner\" src=\"" + CurrentMode.Base_URL + Hierarchy_Object.Get_Banner_Image(HTML_Skin) + "\"  alt=\"" + Hierarchy_Object.ShortName + "\" /></a>");
                        Output.WriteLine("</section>");
                    }
                    else
                    {
                        string skin_url = CurrentMode.Base_Design_URL + "skins/" + CurrentMode.Skin + "/";
                        Output.WriteLine("<section id=\"sbkAhs_BannerDiv\" role=\"banner\"><h1 class=\"hidden-element\">" + Web_Page_Title + "</h1><a href=\"" + CurrentMode.Base_URL + url_options + "\"><img id=\"mainBanner\" src=\"" + skin_url + "default.jpg\" alt=\"\" /></a></section>");
                    }
                }
            }
            Output.WriteLine();
        }
        /// <summary> Builds a language-specific <see cref="Web_Skin_Object"/> when needed by a user's request </summary>
        /// <param name="CompleteSkin"> Complete web skin object </param>
        /// <param name="Language_Code"> Code for the language, which determines which HTML to use </param>
        /// <param name="Tracer"></param>
        /// <returns> Completely built HTML interface object </returns>
        /// <remarks> The datarow for this method is retrieved from the database by calling the <see cref="Database.Engine_Database.Get_All_Web_Skins"/> method during 
        /// application startup and is then stored in the <see cref="Web_Skin_Collection"/> class until needed. </remarks>
        public static Web_Skin_Object Build_Skin(Complete_Web_Skin_Object CompleteSkin, string Language_Code, Custom_Tracer Tracer )
        {
            // Look for the language
            Web_Language_Enum language = Web_Language_Enum_Converter.Code_To_Enum(Language_Code);
            Web_Language_Enum original_language = language;
            if (!CompleteSkin.SourceFiles.ContainsKey(language))
            {
                if (Tracer != null) Tracer.Add_Trace("Web_Skin_Utilities.Build_Skin", "Language requested ( " + Web_Language_Enum_Converter.Enum_To_Name(language) + " ) not in language list");

                language = Engine_ApplicationCache_Gateway.Settings.System.Default_UI_Language;
                if (( original_language == language ) || ( !CompleteSkin.SourceFiles.ContainsKey(language)))
                {

                    if ((Tracer != null) && ( original_language != language ))
                        Tracer.Add_Trace("Web_Skin_Utilities.Build_Skin", "Default UI language ( " + Web_Language_Enum_Converter.Enum_To_Name(language) + " ) not in language list");

                    language = Web_Language_Enum.DEFAULT;
                    if (!CompleteSkin.SourceFiles.ContainsKey(language))
                    {
                        if (Tracer != null) Tracer.Add_Trace("Web_Skin_Utilities.Build_Skin", "DEFAULT language not in language list");

                        language = Web_Language_Enum.English;

                        if (!CompleteSkin.SourceFiles.ContainsKey(language))
                        {
                            if (Tracer != null) Tracer.Add_Trace("Web_Skin_Utilities.Build_Skin", "English language also not in language list");

                            if (CompleteSkin.SourceFiles.Count > 0)
                            {
                                language = CompleteSkin.SourceFiles.Keys.First();
                            }
                            else
                            {
                                if (Tracer != null) Tracer.Add_Trace("Web_Skin_Utilities.Build_Skin", "Apparently there are NO source files.. returning NULL");
                                language = Web_Language_Enum.UNDEFINED;
                            }
                        }
                    }
                }
            }

            if (Tracer != null) Tracer.Add_Trace("Web_Skin_Utilities.Build_Skin", "Will build language-specific web skin for '" + Web_Language_Enum_Converter.Enum_To_Name(language)  + "'");

            // Now, look in the cache for this
            if (language != Web_Language_Enum.UNDEFINED)
            {
                Web_Skin_Object cacheObject = CachedDataManager.WebSkins.Retrieve_Skin(CompleteSkin.Skin_Code, Web_Language_Enum_Converter.Enum_To_Code(language), null);
                if (cacheObject != null)
                {
                    if (Tracer != null) Tracer.Add_Trace("Web_Skin_Utilities.Build_Skin", "Web skin found in the memory cache");

                    return cacheObject;
                }
            }

            if (Tracer != null) Tracer.Add_Trace("Web_Skin_Utilities.Build_Skin", "Web skin not found in the memory cache, so building it now");

            // Build this then
            Web_Skin_Object returnValue = new Web_Skin_Object(CompleteSkin.Skin_Code, CompleteSkin.Base_Skin_Code, "design/skins/" + CompleteSkin.Skin_Code + "/" + CompleteSkin.CSS_Style);

            // Set the language code
            if ( language == Web_Language_Enum.DEFAULT )
                returnValue.Language_Code = Web_Language_Enum_Converter.Enum_To_Code(Engine_ApplicationCache_Gateway.Settings.System.Default_UI_Language);
            else if ( language == Web_Language_Enum.UNDEFINED )
                returnValue.Language_Code = Web_Language_Enum_Converter.Enum_To_Code(language);

            // Set some optional (nullable) flags
            if ( CompleteSkin.Override_Banner ) returnValue.Override_Banner = true;
            if ( CompleteSkin.Suppress_Top_Navigation ) returnValue.Suppress_Top_Navigation = true;

            // If no suitable language was found, probably an error (no source files at all)
            if (language == Web_Language_Enum.UNDEFINED)
            {
                if (!String.IsNullOrEmpty(CompleteSkin.Exception))
                    returnValue.Exception = CompleteSkin.Exception;
                else
                    returnValue.Exception = "No valid source files found";

                // Also set the headers and footers to the exception
                returnValue.Header_HTML = returnValue.Exception;
                returnValue.Footer_HTML = returnValue.Exception;
                returnValue.Header_Item_HTML = returnValue.Exception;
                returnValue.Footer_Item_HTML = returnValue.Exception;

                return returnValue;
            }

            // Get the source file
            Complete_Web_Skin_Source_Files sourceFiles = CompleteSkin.SourceFiles[language];

            // Build the banner
            if ((returnValue.Override_Banner.HasValue) && (returnValue.Override_Banner.Value))
            {
                if (Tracer != null) Tracer.Add_Trace("Web_Skin_Utilities.Build_Skin", "Skin overrides the banner, so build the banner HTML");

                // Find the LANGUAGE-SPECIFIC high-bandwidth banner image
                if ( !String.IsNullOrEmpty(sourceFiles.Banner))
                {
                    if ( !String.IsNullOrEmpty(CompleteSkin.Banner_Link))
                    {
                        returnValue.Banner_HTML = "<a href=\"" + CompleteSkin.Banner_Link + "\"><img border=\"0\" src=\"<%BASEURL%>skins/" + CompleteSkin.Skin_Code + "/" + sourceFiles.Banner + "\" alt=\"MISSING BANNER\" /></a>";
                    }
                    else
                    {
                        returnValue.Banner_HTML = "<img border=\"0\" src=\"<%BASEURL%>skins/" + CompleteSkin.Skin_Code + "/" + sourceFiles.Banner + "\" alt=\"MISSING BANNER\" />";
                    }
                }
            }

            // Now, set the header and footer html
            if (Tracer != null) Tracer.Add_Trace("Web_Skin_Utilities.Build_Skin", "Determine the header footer source HTML files");
            string this_header = Path.Combine(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location, "skins", CompleteSkin.Skin_Code, sourceFiles.Header_Source_File);
            string this_footer = Path.Combine(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location, "skins", CompleteSkin.Skin_Code, sourceFiles.Footer_Source_File);
            string this_item_header = Path.Combine(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location, "skins", CompleteSkin.Skin_Code, sourceFiles.Header_Item_Source_File);
            string this_item_footer = Path.Combine(Engine_ApplicationCache_Gateway.Settings.Servers.Base_Design_Location, "skins", CompleteSkin.Skin_Code, sourceFiles.Footer_Item_Source_File);

            // If the item specific stuff doesn't exist, use the regular
            if (!File.Exists(this_item_header))
                this_item_header = this_header;
            if (!File.Exists(this_item_footer))
                this_item_footer = this_footer;

            // Now, assign all of these
            if (Tracer != null) Tracer.Add_Trace("Web_Skin_Utilities.Build_Skin", "Get the HTML source for all the headers and footers");
            returnValue.Set_Header_Footer_Source(this_header, this_footer, this_item_header, this_item_footer);

            if (Tracer != null) Tracer.Add_Trace("Web_Skin_Utilities.Build_Skin", "Returning the fully built web skin");
            return returnValue;
        }
        /// <summary> Stores the language-specific html skin object to the cache  </summary>
        /// <param name="Skin_Code"> Code for this html display skin </param>
        /// <param name="Language_Code"> Current language code for the user interface ( skins are language-specific)</param>
        /// <param name="StoreObject"> Language-specific HTML Skin object </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering</param>
        public void Store_Skin(string Skin_Code, string Language_Code, Web_Skin_Object StoreObject, Custom_Tracer Tracer)
        {
            // If the cache is disabled, just return before even tracing
            if ((settings.Disabled) || (StoreObject == null))
                return;

            // Determine the key
            string key = "SKIN|" + Skin_Code.ToLower() + "|";
            if (Language_Code.Length > 0)
                key = key + Language_Code;

            // Log
            if (Tracer != null)
            {
                Tracer.Add_Trace("CachedDataManager.Store_Skin", "Adding object '" + key + "' to the local cache with expiration of 1 minute");
            }

            // Add to the cache with five minute expiration
            HttpContext.Current.Cache.Insert(key, StoreObject, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(5));
        }
        public void Set_Main_Writer()
        {
            // If this is for HTML or HTML logged in, try to get the web skin object
            string current_skin_code = currentMode.Skin.ToUpper();
            if ((currentMode.Writer_Type == Writer_Type_Enum.HTML) || (currentMode.Writer_Type == Writer_Type_Enum.HTML_LoggedIn))
            {
                // Check if a different skin should be used if this is an item display
                if ((currentMode.Mode == Display_Mode_Enum.Item_Display) || (currentMode.Mode == Display_Mode_Enum.Item_Print))
                {
                    if ((currentItem != null) && (currentItem.Behaviors.Web_Skin_Count > 0))
                    {
                        if (!currentItem.Behaviors.Web_Skins.Contains(current_skin_code))
                        {
                            string new_skin_code = currentItem.Behaviors.Web_Skins[0];
                            current_skin_code = new_skin_code;
                        }
                    }
                }

                // Check if a differente skin should be used if this is a collection display
                if ((hierarchyObject != null) && ( hierarchyObject.Web_Skins != null ) && (hierarchyObject.Web_Skins.Count > 0))
                {
                    // Do NOT do this replacement if the web skin is in the URL and this is admin mode
                    if ((!currentMode.Skin_In_URL) || (currentMode.Mode != Display_Mode_Enum.Administrative))
                    {
                        if (!hierarchyObject.Web_Skins.Contains(current_skin_code.ToLower()))
                        {
                            current_skin_code = hierarchyObject.Web_Skins[0];
                        }
                    }
                }

                SobekCM_Assistant assistant = new SobekCM_Assistant();

                // Try to get the web skin from the cache or skin collection, otherwise build it
                htmlSkin = assistant.Get_HTML_Skin(current_skin_code, currentMode, UI_ApplicationCache_Gateway.Web_Skin_Collection, true, tracer);

                // If the skin was somehow overriden, default back to the default skin
                if (( htmlSkin == null ) && ( !String.IsNullOrEmpty(defaultSkin)))
                {
                    if (String.Compare(current_skin_code, defaultSkin, StringComparison.InvariantCultureIgnoreCase) != 0)
                    {
                        currentMode.Skin = defaultSkin;
                        htmlSkin = assistant.Get_HTML_Skin(defaultSkin, currentMode, UI_ApplicationCache_Gateway.Web_Skin_Collection, true, tracer);
                    }
                }

                // If there was no web skin returned, forward user to URL with no web skin.
                // This happens if the web skin code is invalid.  If a robot, just return a bad request
                // value though.
                if (htmlSkin == null)
                {

                        HttpContext.Current.Response.StatusCode = 404;
                        HttpContext.Current.Response.Output.WriteLine("404 - INVALID URL");
                        HttpContext.Current.Response.Output.WriteLine("Web skin indicated is invalid, default web skin invalid - line 1029");

                    HttpContext.Current.Response.Output.WriteLine(tracer.Text_Trace);
                        HttpContext.Current.ApplicationInstance.CompleteRequest();
                        currentMode.Request_Completed = true;

                    return;
                }
            }

            // Build the RequestCache object
            RequestCache RequestSpecificValues = new RequestCache(currentMode, hierarchyObject, searchResultStatistics, pagedSearchResults, thisBrowseObject, currentItem, currentPage, htmlSkin, currentUser, publicFolder, siteMap, itemsInTitle, staticWebContent, tracer);

            if ((currentMode.Writer_Type == Writer_Type_Enum.HTML) || (currentMode.Writer_Type == Writer_Type_Enum.HTML_LoggedIn))
            {
                mainWriter = new Html_MainWriter(RequestSpecificValues);
            }

            // Load the OAI writer
            if (currentMode.Writer_Type == Writer_Type_Enum.OAI)
            {
                mainWriter = new Oai_MainWriter(HttpContext.Current.Request.QueryString, RequestSpecificValues);
            }

            // Load the DataSet writer
            if (currentMode.Writer_Type == Writer_Type_Enum.DataSet)
            {
                mainWriter = new Dataset_MainWriter(RequestSpecificValues);
            }

            // Load the DataProvider writer
            if (currentMode.Writer_Type == Writer_Type_Enum.Data_Provider)
            {
                mainWriter = new DataProvider_MainWriter(RequestSpecificValues);
            }

            // Load the XML writer
            if (currentMode.Writer_Type == Writer_Type_Enum.XML)
            {
                mainWriter = new Xml_MainWriter(RequestSpecificValues);
            }

            // Load the JSON writer
            if (currentMode.Writer_Type == Writer_Type_Enum.JSON)
            {
                mainWriter = new Json_MainWriter(RequestSpecificValues, UI_ApplicationCache_Gateway.Settings.Servers.Image_URL);
            }

            // Load the HTML ECHO writer
            if (currentMode.Writer_Type == Writer_Type_Enum.HTML_Echo)
            {
                mainWriter = new Html_Echo_MainWriter(RequestSpecificValues, browse_info_display_text);
            }

            // Default to HTML
            if (mainWriter == null)
            {
                mainWriter = new Html_MainWriter(RequestSpecificValues);
            }
        }
 /// <summary> Writes the static header to go at the top of the static digital resource page </summary>
 /// <param name="Writer"> Open stream to write the HTML header to </param>
 /// <param name="HTMLSkin"> Default html web skin/interface</param>
 /// <param name="Banner"> Banner HTML</param>
 public void Display_Header(TextWriter Writer, Web_Skin_Object HTMLSkin, string Banner)
 {
     string breadcrumbs = "<a href=\"" + currentMode.Base_URL + "\">" + UI_ApplicationCache_Gateway.Settings.System.System_Name + " Home</a>";
     Writer.WriteLine(HTMLSkin.Header_Item_HTML.Replace("<%URLOPTS%>", "").Replace("<%?URLOPTS%>", "").Replace("<%&URLOPTS%>", "").Replace("<%BREADCRUMBS%>", breadcrumbs).Replace("<%MYSOBEK%>", "").Replace("<%ENGLISH%>", "").Replace("<%FRENCH%>", "").Replace("<%SPANISH%>", "").Replace("<%LOWGRAPHICS%>", "").Replace("<%HIGHGRAPHICS%>", "").Replace("<%BASEURL%>", currentMode.Base_URL).Replace("<%BANNER%>", Banner));
     Writer.WriteLine(String.Empty);
 }
        /// <summary> Writes the static header to go at the top of the static digital resource page </summary>
        /// <param name="Writer"> Open stream to write the HTML header to </param>
        /// <param name="HTMLSkin"> Default html web skin/interface</param>
        /// <param name="CurrentItem"> Current item, to include the aggregationPermissions in the breadcrumbs </param>
        public void Display_Header(TextWriter Writer, Web_Skin_Object HTMLSkin, SobekCM_Item CurrentItem )
        {
            StringBuilder breadcrumb_builder = new StringBuilder("<a href=\"" + currentMode.Base_URL + "\">" + UI_ApplicationCache_Gateway.Settings.System.System_Abbreviation + " Home</a>");

            int codes_added = 0;
                if (CurrentItem.Behaviors.Aggregation_Count > 0)
                {
                    foreach (Aggregation_Info aggregation in CurrentItem.Behaviors.Aggregations)
                    {
                        string aggrCode = aggregation.Code;
                        if (aggrCode.ToLower() != currentMode.Aggregation)
                        {
                            if ((aggrCode.ToUpper() != "I" + CurrentItem.Bib_Info.Source.Code.ToUpper()) &&
                                (aggrCode.ToUpper() != "I" + CurrentItem.Bib_Info.Location.Holding_Code.ToUpper()))
                            {
                                Item_Aggregation_Related_Aggregations thisAggr = UI_ApplicationCache_Gateway.Aggregations[aggrCode];
                                if ((thisAggr != null) && (thisAggr.Active))
                                {
                                    breadcrumb_builder.Append(" &nbsp;|&nbsp; <a href=\"" + currentMode.Base_URL +
                                                              aggrCode.ToLower() + "\">" +
                                                              thisAggr.ShortName +
                                                              "</a>");
                                    codes_added++;
                                }
                            }
                        }
                        if (codes_added == 5)
                            break;
                    }
                }

            if (codes_added < 5)
            {
                if (CurrentItem.Bib_Info.Source.Code.Length > 0)
                {
                    // Add source code
                    string source_code = CurrentItem.Bib_Info.Source.Code;
                    if ((source_code[0] != 'i') && (source_code[0] != 'I'))
                        source_code = "I" + source_code;
                    Item_Aggregation_Related_Aggregations thisSourceAggr = UI_ApplicationCache_Gateway.Aggregations[source_code];
                    if ((thisSourceAggr != null) && (!thisSourceAggr.Hidden) && (thisSourceAggr.Active))
                    {
                        string source_name = thisSourceAggr.ShortName;
                        if (source_name.ToUpper() != "ADDED AUTOMATICALLY")
                        {
                            breadcrumb_builder.Append(" &nbsp;|&nbsp; <a href=\"" + currentMode.Base_URL +
                                                      source_code.ToLower() + "\">" +
                                                      source_name + "</a>");
                        }
                    }

                    // Add the holding code
                    if ((CurrentItem.Bib_Info.Location.Holding_Code.Length > 0) &&
                        (CurrentItem.Bib_Info.Location.Holding_Code != CurrentItem.Bib_Info.Source.Code))
                    {
                        // Add holding code
                        string holding_code = CurrentItem.Bib_Info.Location.Holding_Code;
                        if ((holding_code[0] != 'i') && (holding_code[0] != 'I'))
                            holding_code = "I" + holding_code;

                        Item_Aggregation_Related_Aggregations thisAggr = UI_ApplicationCache_Gateway.Aggregations[holding_code];
                        if ((thisAggr != null) && (!thisAggr.Hidden) && (thisAggr.Active))
                        {
                            string holding_name = thisAggr.ShortName;

                            if (holding_name.ToUpper() != "ADDED AUTOMATICALLY")
                            {
                                breadcrumb_builder.Append(" &nbsp;|&nbsp; <a href=\"" + currentMode.Base_URL +
                                                          holding_code.ToLower() + "\">" +
                                                          holding_name + "</a>");
                            }
                        }
                    }
                }
                else
                {
                    if (CurrentItem.Bib_Info.Location.Holding_Code.Length > 0)
                    {
                        // Add holding code
                        string holding_code = CurrentItem.Bib_Info.Location.Holding_Code;
                        if ((holding_code[0] != 'i') && (holding_code[0] != 'I'))
                            holding_code = "I" + holding_code;
                        string holding_name = UI_ApplicationCache_Gateway.Aggregations.Get_Collection_Short_Name(holding_code);
                        if (holding_name.ToUpper() != "ADDED AUTOMATICALLY")
                        {
                            breadcrumb_builder.Append(" &nbsp;|&nbsp; <a href=\"" + currentMode.Base_URL +
                                                      holding_code.ToLower() + "\">" +
                                                      holding_name + "</a>");
                        }
                    }
                }
            }
            string breadcrumbs = breadcrumb_builder.ToString();

            Writer.WriteLine(HTMLSkin.Header_Item_HTML.Replace("<%URLOPTS%>", "").Replace("<%?URLOPTS%>", "").Replace("<%&URLOPTS%>", "").Replace("<%BREADCRUMBS%>", breadcrumbs).Replace("<%MYSOBEK%>", "").Replace("<%ENGLISH%>", "").Replace("<%FRENCH%>", "").Replace("<%SPANISH%>", "").Replace("<%LOWGRAPHICS%>", "").Replace("<%HIGHGRAPHICS%>", "").Replace("<%BASEURL%>", currentMode.Base_URL).Replace("<%BANNER%>",String.Empty));
            Writer.WriteLine(String.Empty);
        }
        /// <summary> Writes the static footer to go at the bottom of the static digital resource page </summary>
        /// <param name="Writer"> Open stream to write the HTML footer to </param>
        /// <param name="HTMLSkin"> Default html web skin/interface</param>
        public void Display_Footer(TextWriter Writer, Web_Skin_Object HTMLSkin)
        {
            // Get the current contact URL
            Display_Mode_Enum thisMode = currentMode.Mode;
            currentMode.Mode = Display_Mode_Enum.Contact;
            string contact = UrlWriterHelper.Redirect_URL(currentMode);

            // Restore the old mode
            currentMode.Mode = thisMode;

            Writer.WriteLine(currentMode.Mode == Display_Mode_Enum.Item_Display
                                 ? HTMLSkin.Footer_Item_HTML.Replace("<%CONTACT%>", contact).Replace("<%URLOPTS%>", "").Replace("<%?URLOPTS%>", "").Replace("<%&URLOPTS%>", "").Replace("<%VERSION%>", "").Replace("<%BASEURL%>", currentMode.Base_URL).Trim()
                                 : HTMLSkin.Footer_HTML.Replace("<%CONTACT%>", contact).Replace("<%URLOPTS%>", "").Replace("<%?URLOPTS%>", "").Replace("<%&URLOPTS%>", "").Replace("<%VERSION%>", "").Replace("<%BASEURL%>", currentMode.Base_URL).Trim());
        }
        /// <summary>
        ///   Gets the banner image for this aggregation, by language
        /// </summary>
        /// <param name = "Language"> Language code </param>
        /// <param name = "ThisWebSkin"> Web skin object which may override the banner</param>
        /// <returns> Either the language-specific banner image, or else the default banner image</returns>
        /// <remarks>
        ///   If NO banner images were included in the aggregation XML, then this could be the empty string.<br /><br />
        ///   If the provided web skin overrides the banner, then use that web skin's banner.
        /// </remarks>
        public string Banner_Image(Web_Language_Enum Language, Web_Skin_Object ThisWebSkin)
        {
            // Does the web skin exist and override the banner?  For non-institutional agggregations
            // use the web skin banner HTML instead of the aggregation's banner
            if ((ThisWebSkin != null) && (ThisWebSkin.Override_Banner.HasValue) && (ThisWebSkin.Override_Banner.Value) && (Type.ToLower().IndexOf("institution") < 0))
            {
                return !String.IsNullOrEmpty(ThisWebSkin.Banner_HTML) ? ThisWebSkin.Banner_HTML : String.Empty;
            }

            if (Banner_Dictionary == null)
                return String.Empty;

            // Does this language exist in the banner image lookup dictionary?
            if (Banner_Dictionary.ContainsKey(Language))
            {
                return "design/" + ObjDirectory + Banner_Dictionary[Language];
            }

            // Default to the system language then
            if (Banner_Dictionary.ContainsKey(defaultUiLanguage))
            {
                return "design/" + ObjDirectory + Banner_Dictionary[defaultUiLanguage];
            }

            // Just return the first, assuming one exists
            return Banner_Dictionary.Count > 0 ? Banner_Dictionary.ElementAt(0).Value : String.Empty;
        }
        /// <summary> Get the banner image for this aggregation, possibly returning the web skin banner if it overrides
        /// the aggregation banner  </summary>
        /// <param name="ThisWebSkin"> Web skin object, which may override the banner from this aggregation </param>
        /// <returns> String for the banner to use for this aggregation </returns>
        public string Get_Banner_Image(Web_Skin_Object ThisWebSkin)
        {
            // Does the web skin exist and override the banner?  For non-institutional agggregations
            // use the web skin banner HTML instead of the aggregation's banner
            if ((ThisWebSkin != null) && (ThisWebSkin.Override_Banner.HasValue) && ( ThisWebSkin.Override_Banner.Value ) && (Type.ToLower().IndexOf("institution") < 0))
            {
                return !String.IsNullOrEmpty(ThisWebSkin.Banner_HTML) ? ThisWebSkin.Banner_HTML : String.Empty;
            }

            return BannerImage;
        }