/// <summary> Constructor for a new instance of the Static_Pages_Builder class </summary>
        /// <param name="Primary_Web_Server_URL"> URL for the primary web server </param>
        /// <param name="Static_Data_Location"> Network location for the data directory </param>
        /// <param name="Code_Manager"> Code manager contains the list of all valid aggregation codes </param>
        /// <param name="HTML_Skin_Collection"> HTML Web skin collection which controls the overall appearance of this digital library </param>
        /// <param name="Icon_Table"> Dictionary of all the wordmark/icons which can be tagged to the items </param>
        /// <param name="Translator"> Language support object which handles simple translational duties </param>
        /// <param name="Default_Skin"> Default skin code </param>
        public Static_Pages_Builder(string Primary_Web_Server_URL, string Static_Data_Location,
            Language_Support_Info Translator,
            Aggregation_Code_Manager Code_Manager,
            Dictionary<string, Wordmark_Icon> Icon_Table,
			SobekCM_Skin_Collection HTML_Skin_Collection,
			string Default_Skin)
        {
            primaryWebServerUrl = Primary_Web_Server_URL;
            staticSobekcmDataLocation = Static_Data_Location;
            staticSobekcmLocation = String.Empty;

            tracer = new Custom_Tracer();
            assistant = new SobekCM_Assistant();

            // Save all the objects needed by the SobekCM Library
            iconList = Icon_Table;
            translations = Translator;
            codeManager = Code_Manager;
            skinsCollection = HTML_Skin_Collection;
            defaultSkin = Default_Skin;

            // Create the mode object
            currentMode = new SobekCM_Navigation_Object
                              {
                                  ViewerCode = "citation",
                                  Skin = String.Empty,
                                  Mode = Display_Mode_Enum.Item_Display,
                                  Language = Web_Language_Enum.English,
                                  Base_URL = primaryWebServerUrl
                              };
        }
        /// <summary> Constructor for a new instance of the Static_Pages_Builder class </summary>
        /// <param name="Primary_Web_Server_URL"> URL for the primary web server </param>
        /// <param name="Static_Data_Location"> Network location for the data directory </param>
        /// <param name="All_Items_Lookup"> Allows individual items to be retrieved by various methods as <see cref="Application_State.Single_Item"/> objects.</param>
        /// <param name="Code_Manager"> Code manager contains the list of all valid aggregation codes </param>
        /// <param name="HTML_Skin"> HTML Web skin which controls the overall appearance of this digital library </param>
        /// <param name="Icon_Table"> Dictionary of all the wordmark/icons which can be tagged to the items </param>
        /// <param name="Translator"> Language support object which handles simple translational duties </param>
        public Static_Pages_Builder(string Primary_Web_Server_URL, string Static_Data_Location,
            Language_Support_Info Translator,
            Aggregation_Code_Manager Code_Manager,
            Item_Lookup_Object All_Items_Lookup,
            Dictionary<string, Wordmark_Icon> Icon_Table,
            SobekCM_Skin_Object HTML_Skin)
        {
            primaryWebServerUrl = Primary_Web_Server_URL;
            staticSobekcmDataLocation = Static_Data_Location;

            tracer = new Custom_Tracer();
            assistant = new SobekCM_Assistant();

               // marcWriter = new MARC_Writer();

            // Save all the objects needed by the UFDC Library
            iconList = Icon_Table;
            translations = Translator;
            codeManager = Code_Manager;
            itemList = All_Items_Lookup;
            ufdcInterface = HTML_Skin;
            dlocInterface = HTML_Skin;

            // Create the mode object
            currentMode = new SobekCM_Navigation_Object
                              {
                                  ViewerCode = "citation",
                                  Skin = "UFDC",
                                  Mode = Display_Mode_Enum.Item_Display,
                                  Language = Web_Language_Enum.English,
                                  Base_URL = primaryWebServerUrl
                              };
        }
 /// <summary> Constructor for a new instance of the SobekCM_Traced_Exception class </summary>
 /// <param name="Message"> The error message that explains the reason for the exception </param>
 /// <param name="Inner_Exception"> The exception which is the cause of the current exception </param>
 /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
 public SobekCM_Traced_Exception(string Message, Exception Inner_Exception, Custom_Tracer Tracer )
     : base(Message, Inner_Exception)
 {
     tracer = Tracer;
     if (tracer != null)
     {
         tracer.Add_Trace("SobekCM_Traced_Exception.Constructor", "Exception caught and bundled in the custom traced exception");
     }
 }
        /// <summary> Constructor for a new instance of the SobekCM_Log_Reader class </summary>
        /// <param name="Item_List"> List of all items </param>
        /// <param name="SobekCM_Web_App_Directory"></param>
        public SobekCM_Log_Reader(DataTable Item_List, string SobekCM_Web_App_Directory )
        {
            itemList = Item_List;

            // Build the application state
            Custom_Tracer tracer = new Custom_Tracer();

            // Make sure all the needed data is loaded into the Application State
            Application_State_Builder.Build_Application_State(tracer, false, ref Skins, ref Translation,
                                                              ref Codes, ref Item_Lookup_Object, ref Icon_List,
                                                              ref Stats_Date_Range, ref Thematic_Headings,
                                                              ref Collection_Aliases, ref IP_Restrictions,
                                                              ref URL_Portals, ref Mime_Types);

            // The cache needs to be disabled
            Cached_Data_Manager.Disabled = true;

            // Set the constant settings base directory value to the production location
            SobekCM_Library_Settings.Base_Directory = SobekCM_Web_App_Directory;
        }
        /// <summary> Find the static html file to display for an item view request, when requested by a search engine robot for indexing </summary>
        /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
        /// <param name="All_Items_Lookup"> Lookup object used to pull basic information about any item loaded into this library </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        /// <returns> Location for the static html file to display for this item view request </returns>
        public string Get_Item_Static_HTML(SobekCM_Navigation_Object Current_Mode, Item_Lookup_Object All_Items_Lookup, Custom_Tracer Tracer)
        {
            // Must at least have a bib id of the proper length
            if (Current_Mode.BibID.Length < 10)
            {
                Current_Mode.Invalid_Item = true;
                return String.Empty;
            }

            // Get the title object for this
            Multiple_Volume_Item dbTitle = All_Items_Lookup.Title_By_Bib(Current_Mode.BibID);
            if (dbTitle == null)
            {
                Current_Mode.Invalid_Item = true;
                return String.Empty;
            }

            // Try to get the very basic information about this item, to determine if the
            // bib / vid combination is valid
            Single_Item selected_item = null;
            if (Current_Mode.VID.Length > 0)
            {
                selected_item = All_Items_Lookup.Item_By_Bib_VID(Current_Mode.BibID, Current_Mode.VID, Tracer);
            }
            else
            {
                if (dbTitle.Item_Count == 1)
                {
                    selected_item = All_Items_Lookup.Item_By_Bib_Only(Current_Mode.BibID);
                }
            }

            // If no valid item and not a valid item group display either, return
            if (selected_item == null)
            {
                Current_Mode.Invalid_Item = true;
                return String.Empty;
            }

            // Set the title to the info browse, just to store it somewhere
            Current_Mode.Info_Browse_Mode = selected_item.Title;

            // Get the text for this item
            string bibid = Current_Mode.BibID;
            string vid = selected_item.VID.PadLeft(5, '0');
            Current_Mode.VID = vid;
            string base_image_url = SobekCM_Library_Settings.Base_Data_Directory + bibid.Substring(0, 2) + "\\" + bibid.Substring(2, 2) + "\\" + bibid.Substring(4, 2) + "\\" + bibid.Substring(6, 2) + "\\" + bibid.Substring(8, 2) + "\\" + bibid + "_" + vid + ".html";
            return base_image_url;
        }
        /// <summary> Get a digital resource for display or for editing </summary>
        /// <param name="Collection_Code"> Collection code to which this item must belong </param>
        /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
        /// <param name="All_Items_Lookup"> Lookup object used to pull basic information about any item loaded into this library </param>
        /// <param name="Base_URL"> Base URL for all the digital resource files for items to display </param>
        /// <param name="Icon_Table"> Dictionary of all the wordmark/icons which can be tagged to the items </param>
        /// <param name="Current_User"> Currently logged on user information (used when editing an item)</param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        /// <param name="Current_Item"> [OUT] Built single digital resource ready for displaying or editing </param>
        /// <param name="Current_Page"> [OUT] Build current page for display </param>
        /// <param name="Items_In_Title"> [OUT] List of all the items in this title </param>
        /// <returns> TRUE if successful, otherwise FALSE </returns>
        /// <remarks> This attempts to pull the objects from the cache.  If unsuccessful, it builds the objects from the
        /// database and hands off to the <see cref="Cached_Data_Manager" /> to store in the cache.  If the item must be 
        /// built from scratch, the <see cref="Items.SobekCM_Item_Factory"/> class is utilized. </remarks>
        public bool Get_Item(string Collection_Code, 
                             SobekCM_Navigation_Object Current_Mode, 
                             Item_Lookup_Object All_Items_Lookup, 
                             string Base_URL, 
                             Dictionary<string, Wordmark_Icon> Icon_Table, 
                             Custom_Tracer Tracer, 
                             User_Object Current_User,
                             out SobekCM_Item Current_Item,
                             out Page_TreeNode Current_Page,
                             out SobekCM_Items_In_Title Items_In_Title)
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("SobekCM_Assistant.Get_Item", String.Empty);
            }

            // Initially assign nulls
            Current_Item = null;
            Current_Page = null;
            Items_In_Title = null;

            // Check for legacy reference by itemid
            if ((Current_Mode.BibID.Length == 0) && (Current_Mode.ItemID_DEPRECATED > 0))
            {
                DataRow thisRowInfo = SobekCM_Database.Lookup_Item_By_ItemID(Current_Mode.ItemID_DEPRECATED, Tracer);
                if (thisRowInfo == null)
                {
                    Current_Mode.Invalid_Item = true;
                    return false;
                }

                Current_Mode.Mode = Display_Mode_Enum.Legacy_URL;
                Current_Mode.Error_Message = Current_Mode.Base_URL + thisRowInfo["BibID"] + "/" + thisRowInfo["VID"];
                return false;
            }

            // Must at least have a bib id of the proper length
            if (Current_Mode.BibID.Length < 10)
            {
                Current_Mode.Invalid_Item = true;
                return false;
            }

            // Get the title object for this
            bool item_group_display = false;
            Multiple_Volume_Item dbTitle = All_Items_Lookup.Title_By_Bib(Current_Mode.BibID);
            if (dbTitle == null)
            {
                Current_Mode.Invalid_Item = true;
                return false;
            }

            // Try to get the very basic information about this item, to determine if the
            // bib / vid combination is valid
            Single_Item selected_item = null;

            // Certain mySobek modes only need the item group
            if (( Current_Mode.Mode == Display_Mode_Enum.My_Sobek ) && (( Current_Mode.My_Sobek_Type == My_Sobek_Type_Enum.Edit_Group_Behaviors ) || ( Current_Mode.My_Sobek_Type == My_Sobek_Type_Enum.Edit_Group_Serial_Hierarchy ) || ( Current_Mode.My_Sobek_Type == My_Sobek_Type_Enum.Group_Add_Volume ) || ( Current_Mode.My_Sobek_Type == My_Sobek_Type_Enum.Group_AutoFill_Volumes ) || ( Current_Mode.My_Sobek_Type == My_Sobek_Type_Enum.Group_Mass_Update_Items )))
            {
                item_group_display = true;
            }

            // If this is not a mode that is only item group display, try to pull the item
            if (!item_group_display)
            {
                if ((Current_Mode.VID.Length > 0) && (Current_Mode.VID != "00000"))
                {
                    selected_item = All_Items_Lookup.Item_By_Bib_VID(Current_Mode.BibID, Current_Mode.VID, Tracer);
                }
                else
                {
                    if ((dbTitle.Item_Count == 1) && (Current_Mode.VID != "00000"))
                    {
                        selected_item = All_Items_Lookup.Item_By_Bib_Only(Current_Mode.BibID);
                    }
                    else
                    {
                        item_group_display = true;
                    }
                }
            }

            // If no valid item and not a valid item group display either, return
            if ((selected_item == null) && (!item_group_display))
            {
                Current_Mode.Invalid_Item = true;
                return false;
            }

            // If this is for a single item, return that
            if (selected_item != null)
            {
                // Make sure the VID is set
                Current_Mode.VID = selected_item.VID;

                // Try to get this from the cache
                if ((Current_Mode.Mode == Display_Mode_Enum.My_Sobek) && ( Current_Mode.My_Sobek_Type == My_Sobek_Type_Enum.Edit_Item_Metadata ) && (Current_User != null))
                    Current_Item = Cached_Data_Manager.Retrieve_Digital_Resource_Object(Current_User.UserID, Current_Mode.BibID, Current_Mode.VID, Tracer);
                else
                    Current_Item = Cached_Data_Manager.Retrieve_Digital_Resource_Object( Current_Mode.BibID, Current_Mode.VID, Tracer);

                // If not pulled from the cache, then we will have to build the item
                if (Current_Item == null)
                {
                    if (Tracer != null)
                    {
                        Tracer.Add_Trace("SobekCM_Assistant.Get_Item", "Build the item");
                    }

                    Current_Item = SobekCM_Item_Factory.Get_Item(Current_Mode.BibID, Current_Mode.VID, Icon_Table, Tracer);
                    if (Current_Item != null)
                    {
                        if ((Current_Mode.Mode == Display_Mode_Enum.My_Sobek) && (Current_Mode.My_Sobek_Type == My_Sobek_Type_Enum.Edit_Item_Metadata) && (Current_User != null))
                        {
                            string note_to_add = "Online edit by " + Current_User.Full_Name + " ( " + DateTime.Now.ToShortDateString() + " )";
                            Current_Item.METS_Header.Add_Creator_Individual_Notes( note_to_add );
                            Cached_Data_Manager.Store_Digital_Resource_Object(Current_User.UserID, Current_Mode.BibID, Current_Mode.VID, Current_Item, Tracer);
                        }
                        else
                            Cached_Data_Manager.Store_Digital_Resource_Object(Current_Mode.BibID, Current_Mode.VID, Current_Item, Tracer);
                    }
                }
                else
                {
                    if (Tracer != null)
                    {
                        Tracer.Add_Trace("SobekCM_Assistant.Get_Item", "Item found in the cache");
                    }
                }

                // If an item was requested and none was found, go to the current home
                if ((Current_Item == null))
                {
                    if (Tracer != null && !Tracer.Enabled)
                    {
                        Current_Mode.Mode = Display_Mode_Enum.Aggregation_Home;
                        return false;
                    }
                    return false;
                }

                // Get the page to display (printing has its own specification of page(s) to display)
                if (Current_Mode.Mode != Display_Mode_Enum.Item_Print)
                {
                    if (Tracer != null)
                    {
                        Tracer.Add_Trace("SobekCM_Assistant.Get_Item", "Get the current page");
                    }
                    Current_Page = SobekCM_Item_Factory.Get_Current_Page(Current_Item, Current_Mode.Page, Tracer);
                }
            }
            else if (item_group_display)
            {
                // Try to get this from the cache
                Current_Item = Cached_Data_Manager.Retrieve_Digital_Resource_Object(Current_Mode.BibID, Tracer);

                // Have to build this item group information then
                if (Current_Item == null)
                {
                    string bibID = Current_Mode.BibID;
                    SobekCM_Item_Factory.Get_Item_Group(bibID, Tracer, out Items_In_Title, out Current_Item );
                    if (Tracer != null)
                    {
                        Tracer.Add_Trace("SobekCM_Assistant.Get_Item", "TEST LOG ENTRY");
                    }

                    if (Current_Item == null)
                    {
                        Exception ee = SobekCM_Database.Last_Exception;
                        if (Tracer != null)
                            Tracer.Add_Trace("SobekCM_Assistant.Get_Item", ee != null ? ee.Message : "NO DATABASE EXCEPTION", Custom_Trace_Type_Enum.Error);

                        Current_Mode.Invalid_Item = true;
                        return false;
                    }

                    // Put this back on the cache
                    Current_Item.METS_Header.RecordStatus_Enum = METS_Record_Status.BIB_LEVEL;
                    Cached_Data_Manager.Store_Digital_Resource_Object(bibID, Current_Item, Tracer);
                    Cached_Data_Manager.Store_Items_In_Title(bibID, Items_In_Title, Tracer);
                }
            }

            return true;
        }
        /// <summary> Pulls an item aggregation object representing an item aggregation from the database (Collection Group or smaller) </summary>
        /// <param name="Aggregation_Code"> Code for the aggregation to pull </param>
        /// <param name="Language_Code"> Current language code (item aggregation instances are currently language-specific)</param>
        /// <param name="isRobot"> Flag indicates if this is a robot request (may cache differently)</param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        /// <returns> Fully-built object for the provided aggregation code</returns>
        /// <remarks> This attempts to pull the objects from the cache.  If unsuccessful, it builds the objects from the
        /// database and hands off to the <see cref="Cached_Data_Manager" /> to store in the cache. </remarks>
        public Item_Aggregation Get_Item_Aggregation(string Aggregation_Code, string Language_Code, bool isRobot, Custom_Tracer Tracer)
        {
            // Try to pull this from the cache
            Item_Aggregation cacheInstance = Cached_Data_Manager.Retrieve_Item_Aggregation(Aggregation_Code, Language_Code, !isRobot, Tracer);

            // Put into the builder regardless of whether his came from the cache.. need to confirm search fields as well
            Item_Aggregation returned = Item_Aggregation_Builder.Get_Item_Aggregation(Aggregation_Code, Language_Code, cacheInstance, isRobot, Tracer);

            // If the collection is null, then this subcollection code was invalid.
            if (returned == null)
            {
                return null;
            }

            // Return the object
            return returned;
        }
        /// <summary> Gets the HTML skin indicated in the current navigation mode </summary>
        /// <param name="Web_Skin_Code"> Web skin code </param>
        /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
        /// <param name="Skin_Collection"> Collection of the most common skins and source information for all the skins made on the fly </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        /// <returns> Fully-built object used to "skin" this digital library </returns>
        public SobekCM_Skin_Object Get_HTML_Skin( string Web_Skin_Code, SobekCM_Navigation_Object Current_Mode, SobekCM_Skin_Collection Skin_Collection, Custom_Tracer Tracer )
        {
            // Get the interface object
            SobekCM_Skin_Object htmlSkin = null;
            string webskin_code_language = Web_Skin_Code;
            if ( Current_Mode.Language_Code.Length > 0 )
                webskin_code_language = webskin_code_language + "_" + Current_Mode.Language_Code;
            if (Skin_Collection[webskin_code_language] != null)
            {
                htmlSkin = Skin_Collection[webskin_code_language];
                Current_Mode.Base_Skin = htmlSkin.Base_Skin_Code;
                Tracer.Add_Trace("SobekCM_Assistant.Get_HTML_Skin", "Web Skin '" + Web_Skin_Code + "' found in global values");
                return htmlSkin;
            }

            // If no interface yet, look in the cache
            if (Web_Skin_Code != "new")
            {
                htmlSkin = Cached_Data_Manager.Retrieve_Skin(Web_Skin_Code, Current_Mode.Language_Code, Tracer);
                if (htmlSkin != null)
                {
                    Tracer.Add_Trace("SobekCM_Assistant.Get_HTML_Skin", "Web skin '" + Web_Skin_Code + "' found in cache");
                    Current_Mode.Base_Skin = htmlSkin.Base_Skin_Code;
                    return htmlSkin;
                }
            }

            // If still not interface, build one
            DataRow skin_row = Skin_Collection.Skin_Row(Web_Skin_Code);
            if (skin_row != null)
            {
                Tracer.Add_Trace("SobekCM_Assistant.Get_HTML_Skin", "Building web skin '" + Web_Skin_Code + "'");

                SobekCM_Skin_Object new_skin = SobekCM_Skin_Collection_Builder.Build_Skin(skin_row, Current_Mode.Language_Code );

                // Look in the web skin row and see if it should be kept around, rather than momentarily cached
                if (new_skin != null)
                {
                    if ((skin_row.Table.Columns.Contains("Build_On_Launch")) && (Convert.ToBoolean(skin_row["Build_On_Launch"])))
                    {
                        // Save this semi-permanently in memory
                        Skin_Collection.Add(new_skin);
                    }
                    else
                    {
                        // Momentarily cache this web skin object
                        Cached_Data_Manager.Store_Skin(Web_Skin_Code, Current_Mode.Language_Code, new_skin, Tracer);
                    }

                    htmlSkin = new_skin;
                }
            }

            // If there is still no interface, this is an ERROR
            if (htmlSkin == null)
            {
                Current_Mode.Mode = Display_Mode_Enum.Error;
                Current_Mode.Error_Message = "Invalid web skin '" + Web_Skin_Code + "' requested.";
            }
            else
            {
                Current_Mode.Base_Skin = htmlSkin.Base_Skin_Code;
            }

            // Return the value
            return htmlSkin;
        }
 /// <summary> Get a digital resource for display or for editing </summary>
 /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
 /// <param name="All_Items_Lookup"> Lookup object used to pull basic information about any item loaded into this library </param>
 /// <param name="Base_URL"> Base URL for all the digital resource files for items to display </param>
 /// <param name="Icon_Table"> Dictionary of all the wordmark/icons which can be tagged to the items </param>
 /// <param name="Current_User"> Currently logged on user information (used when editing an item)</param>
 /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
 /// <param name="Current_Item"> [OUT] Built single digital resource ready for displaying or editing </param>
 /// <param name="Current_Page"> [OUT] Build current page for display </param>
 /// <param name="Items_In_Title"> [OUT] List of all the items in this title </param>
 /// <returns> TRUE if successful, otherwise FALSE </returns>
 /// <remarks> This attempts to pull the objects from the cache.  If unsuccessful, it builds the objects from the
 /// database and hands off to the <see cref="Cached_Data_Manager" /> to store in the cache.  If the item must be 
 /// built from scratch, the <see cref="Items.SobekCM_Item_Factory"/> class is utilized. </remarks>
 public bool Get_Item(SobekCM_Navigation_Object Current_Mode,
                      Item_Lookup_Object All_Items_Lookup,
                      string Base_URL, 
                      Dictionary<string, Wordmark_Icon> Icon_Table,
                      User_Object Current_User,
                      Custom_Tracer Tracer, 
                      out SobekCM_Item Current_Item, 
                      out Page_TreeNode Current_Page,
                      out SobekCM_Items_In_Title Items_In_Title )
 {
     return Get_Item(String.Empty, Current_Mode, All_Items_Lookup, Base_URL, Icon_Table, Tracer, Current_User, out Current_Item, out Current_Page, out Items_In_Title);
 }
        public SobekCM_Page_Globals(bool isPostBack, string page_name)
        {
            // Pull out the http request
            HttpRequest request = HttpContext.Current.Request;

            // Get the base url
            string base_url = request.Url.AbsoluteUri.ToLower().Replace("sobekcm.aspx", "");
            if (base_url.IndexOf("?") > 0)
                base_url = base_url.Substring(0, base_url.IndexOf("?"));

            try
            {
                tracer = new Custom_Tracer();
                tracer.Add_Trace("SobekCM_Page_Globals.Constructor", String.Empty);

                // Don't really need to *build* these, so just define them as a new ones if null
                if (Global.Checked_List == null)
                    Global.Checked_List = new Checked_Out_Items_List();
                if (Global.Search_History == null)
                    Global.Search_History = new Recent_Searches();

                // Make sure all the needed data is loaded into the Application State
                Application_State_Builder.Build_Application_State(tracer, false, ref Global.Skins, ref Global.Translation,
                                                                  ref Global.Codes, ref Global.Item_List, ref Global.Icon_List,
                                                                  ref Global.Stats_Date_Range, ref Global.Thematic_Headings, ref Global.Collection_Aliases, ref Global.IP_Restrictions,
                                                                  ref Global.URL_Portals, ref Global.Mime_Types, ref Global.Item_Viewer_Priority);

                tracer.Add_Trace("SobekCM_Page_Globals.Constructor", "Application State validated or built");

                // Check that something is saved for the original requested URL (may not exist if not forwarded)
                if (!HttpContext.Current.Items.Contains("Original_URL"))
                    HttpContext.Current.Items["Original_URL"] = request.Url.ToString();
            }
            catch (Exception ee)
            {
                // Send to the dashboard
                if ((HttpContext.Current.Request.UserHostAddress == "127.0.0.1") || (HttpContext.Current.Request.UserHostAddress == HttpContext.Current.Request.ServerVariables["LOCAL_ADDR"]) || (HttpContext.Current.Request.Url.ToString().IndexOf("localhost") >= 0))
                {
                    // Create an error message
                    string errorMessage = "Error caught while validating application state";
                    if ((SobekCM_Library_Settings.Database_Connections.Count == 0) || (String.IsNullOrEmpty(SobekCM_Library_Settings.Database_Connections[0].Connection_String)))
                    {
                        errorMessage = "No database connection string found!";
                        string configFileLocation = AppDomain.CurrentDomain.BaseDirectory + "config/sobekcm.xml";
                        try
                        {
                            if (!File.Exists(configFileLocation))
                            {
                                errorMessage = "Missing config/sobekcm.xml configuration file on the web server.<br />Ensure the configuration file 'sobekcm.xml' exists in a 'config' subfolder directly under the web application.<br />Example configuration is:" +
                                               "<div style=\"background-color: #bbbbbb; margin-left: 30px; margin-top:10px; padding: 3px;\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;  ?&gt;<br /> &lt;configuration&gt;<br /> &nbsp; &nbsp &lt;connection_string type=&quot;MSSQL&quot;&gt;data source=localhost\\instance;initial catalog=SobekCM;integrated security=Yes;&lt;/connection_string&gt;<br /> &nbsp; &nbsp &lt;error_emails&gt;[email protected]&lt;/error_emails&gt;<br /> &nbsp; &nbsp &lt;error_page&gt;http://ufdc.ufl.edu/error.html&lt;/error_page&gt;<br />&lt;/configuration&gt;</div>";
                            }
                        }
                        catch
                        {
                            errorMessage = "No database connection string found.<br />Likely an error reading the configuration file due to permissions on the web server.<br />Ensure the configuration file 'sobekcm.xml' exists in a 'config' subfolder directly under the web application.<br />Example configuration is:" +
                                           "<div style=\"background-color: #bbbbbb; margin-left: 30px; margin-top:10px; padding: 3px;\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;  ?&gt;<br /> &lt;configuration&gt;<br /> &nbsp; &nbsp &lt;connection_string type=&quot;MSSQL&quot;&gt;data source=localhost\\instance;initial catalog=SobekCM;integrated security=Yes;&lt;/connection_string&gt;<br /> &nbsp; &nbsp &lt;error_emails&gt;[email protected]&lt;/error_emails&gt;<br /> &nbsp; &nbsp &lt;error_page&gt;http://ufdc.ufl.edu/error.html&lt;/error_page&gt;<br />&lt;/configuration&gt;</div>";
                        }
                    }
                    else
                    {
                        if (ee.Message.IndexOf("The EXECUTE permission") >= 0)
                        {
                            errorMessage = "Permissions error while connecting to the database and pulling necessary data.<br /><br />Confirm the following:<ul><li>IIS is configured correctly to use anonymous authentication</li><li>Anonymous user (or service account) is part of the sobek_users role in the database.</li></ul>";
                        }
                        else
                        {
                            errorMessage = "Error connecting to the database and pulling necessary data.<br /><br />Confirm the following:<ul><li>Database connection string is correct ( " + SobekCM_Library_Settings.Database_Connections[0].Connection_String + ")</li><li>IIS is configured correctly to use anonymous authentication</li><li>Anonymous user (or service account) is part of the sobek_users role in the database.</li></ul>";
                        }
                    }
                    // Wrap this into the SobekCM Exception
                    SobekCM_Traced_Exception newException = new SobekCM_Traced_Exception(errorMessage, ee, tracer);

                    // Save this to the session state, and then forward to the dashboard
                    HttpContext.Current.Session["Last_Exception"] = newException;
                    HttpContext.Current.Response.Redirect("dashboard.aspx", false);
                    HttpContext.Current.ApplicationInstance.CompleteRequest();
                    return;
                }
                else
                {
                    throw ee;
                }
            }

            // Analyze the response and get the mode
            try
            {
                currentMode = new SobekCM_Navigation_Object(request.QueryString, base_url, request.UserLanguages, Global.Codes, Global.Collection_Aliases, ref Global.Item_List, Global.URL_Portals, tracer)
                    {
                        Base_URL = base_url,
                        isPostBack = isPostBack,
                        Browser_Type = request.Browser.Type.ToUpper()
                    };
                currentMode.Set_Robot_Flag(request.UserAgent, request.UserHostAddress);
            }
            catch
            {
                HttpContext.Current.Response.Status = "301 Moved Permanently";
                HttpContext.Current.Response.AddHeader("Location", base_url);
                HttpContext.Current.ApplicationInstance.CompleteRequest();
                return;
            }

            // If this was for HTML, but was at the data, just convert to XML
            if ((page_name == "SOBEKCM_DATA") && (currentMode.Writer_Type != Writer_Type_Enum.XML) && (currentMode.Writer_Type != Writer_Type_Enum.JSON) && (currentMode.Writer_Type != Writer_Type_Enum.DataSet) && (currentMode.Writer_Type != Writer_Type_Enum.Data_Provider))
                currentMode.Writer_Type = Writer_Type_Enum.XML;

            tracer.Add_Trace("SobekCM_Page_Globals.Constructor", "Navigation Object created from URI query string");

            // Need to ensure the list of items was pulled for several modes
            if (((currentMode.Writer_Type != Writer_Type_Enum.HTML) && (currentMode.Writer_Type != Writer_Type_Enum.HTML_Echo) && (currentMode.Writer_Type != Writer_Type_Enum.HTML_LoggedIn)) ||
                (currentMode.Mode == Display_Mode_Enum.Item_Display) ||
                (currentMode.Mode == Display_Mode_Enum.Item_Print) ||
                (currentMode.Mode == Display_Mode_Enum.Results) ||
                ((currentMode.Mode == Display_Mode_Enum.Aggregation) && ((currentMode.Aggregation_Type == Aggregation_Type_Enum.Browse_Info) || (currentMode.Aggregation_Type == Aggregation_Type_Enum.Child_Page_Edit) || (currentMode.Aggregation_Type == Aggregation_Type_Enum.Browse_Map))) ||
                (currentMode.Mode == Display_Mode_Enum.Public_Folder) ||
                ((currentMode.Mode == Display_Mode_Enum.My_Sobek) && ((currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Delete_Item) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Edit_Group_Behaviors) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Edit_Group_Serial_Hierarchy) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Edit_Item_Metadata) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.File_Management) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Folder_Management) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Group_Add_Volume) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Group_AutoFill_Volumes) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Group_Mass_Update_Items) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.New_Item) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Page_Images_Management))))
            {
                SobekCM_Database.Verify_Item_Lookup_Object(true, ref Global.Item_List, tracer);
            }

            try
            {
                if (currentMode.Aggregation.ToUpper() == "EPCSANB")
                {
                    HttpContext.Current.Response.Redirect(@"http://www.uflib.ufl.edu/epc/", false);
                    HttpContext.Current.ApplicationInstance.CompleteRequest();
                    currentMode.Request_Completed = true;
                    return;
                }

                // If this was an error, redirect now
                if (currentMode.Mode == Display_Mode_Enum.Error)
                {
                    return;
                }

                // All the user stuff can be skipped if this was from a robot
                if (!currentMode.Is_Robot)
                {
                    // Determine which IP Ranges this IP address belongs to, if not already determined.
                    if (HttpContext.Current.Session["IP_Range_Membership"] == null)
                    {
                        int ip_mask = Global.IP_Restrictions.Restrictive_Range_Membership(request.UserHostAddress);
                        HttpContext.Current.Session["IP_Range_Membership"] = ip_mask;
                    }

                    // Set the Session TOC, if provided
                    if (currentMode.TOC_Display != TOC_Display_Type_Enum.Undetermined)
                    {
                        if (currentMode.TOC_Display == TOC_Display_Type_Enum.Hide)
                        {
                            HttpContext.Current.Session["Show TOC"] = false;
                        }
                        else
                        {
                            HttpContext.Current.Session["Show TOC"] = true;
                        }
                    }

                    // Only do any of the user stuff if this is from the main SobekCM page
                    if (page_name == "SOBEKCM")
                    {
                        tracer.Add_Trace("SobekCM_Page_Globals.Constructor", "Checking for logged on user by cookie or session");
                        perform_user_checks(isPostBack);
                    }

                    // If this is a system admin, they can run as a different user actually
                    if ((currentUser != null) && (currentUser.Is_System_Admin) && (request.QueryString["userid"] != null))
                    {
                        try
                        {
                            int userid = Convert.ToInt32(request.QueryString["userid"]);
                            User_Object mirroredUser = SobekCM_Database.Get_User(userid, tracer);
                            if (mirroredUser != null)
                            {
                                // Replace the user information in the session state
                                HttpContext.Current.Session["user"] = mirroredUser;
                                currentUser = mirroredUser;
                            }
                        }
                        catch (Exception)
                        {
                            // Nothing to do here.. shouldn't ever really be here..
                        }
                    }

                    if (currentMode.Request_Completed)
                        return;

                    // If this was a call for RESET, clear the memory
                    if ((currentMode.Mode == Display_Mode_Enum.Administrative) && (currentMode.Admin_Type == Admin_Type_Enum.Reset))
                    {
                        Reset_Memory();

                        // Since this reset, send to the admin, memory management portion
                        currentMode.Mode = Display_Mode_Enum.Internal;
                        currentMode.Internal_Type = Internal_Type_Enum.Cache;
                    }
                }
                else // THIS IS A ROBOT REQUEST
                {
                    Perform_Search_Engine_Robot_Checks(currentMode, request.QueryString);
                }

                // If this is for a public folder, get the data
                if (currentMode.Mode == Display_Mode_Enum.Public_Folder)
                {
                    Public_Folder();
                }

                // Get the item now, so that you can set the collection code, if there was none listed
                if ((currentMode.Mode == Display_Mode_Enum.Item_Display) || (currentMode.Mode == Display_Mode_Enum.Item_Print) || ((currentMode.Mode == Display_Mode_Enum.My_Sobek) && ((currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Edit_Item_Metadata) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Edit_Item_Behaviors)))
                    || ((currentMode.Mode == Display_Mode_Enum.My_Sobek) && ((currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Edit_Group_Behaviors) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Edit_Group_Serial_Hierarchy) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Group_Add_Volume) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Group_AutoFill_Volumes) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Group_Mass_Update_Items) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.File_Management) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Page_Images_Management) || (currentMode.My_Sobek_Type == My_Sobek_Type_Enum.Delete_Item))))
                {
                    Display_Item();
                }

                // Was this a robot?
                if (currentMode.Request_Completed)
                    return;

                // Get the group, collection, or subcollection from the database or cache.
                // This also makes sure they are a proper hierarchy.
                Get_Entire_Collection_Hierarchy();

                // Run the search if this should be done now
                if (currentMode.Mode == Display_Mode_Enum.Results)
                {
                    Search_Block();
                }

                // Run the browse/info work if it is of those modes
                if ((currentMode.Mode == Display_Mode_Enum.Aggregation) && ((currentMode.Aggregation_Type == Aggregation_Type_Enum.Browse_Info) || (currentMode.Aggregation_Type == Aggregation_Type_Enum.Child_Page_Edit)))
                {
                    Browse_Info_Block();
                }

                if (currentMode.Mode == Display_Mode_Enum.My_Sobek)
                {
                    MySobekCM_Block();
                }

                // Run the simple text block if this is that mode
                if (currentMode.Mode == Display_Mode_Enum.Simple_HTML_CMS)
                {
                    Simple_Web_Content_Text_Block();
                }
            }
            catch (OutOfMemoryException ee)
            {
                if (currentMode != null)
                {
                    currentMode.Mode = Display_Mode_Enum.Error;
                    currentMode.Error_Message = "Out of memory exception caught";
                    currentMode.Caught_Exception = ee;
                }
                else
                {
                    Email_Information("Fatal Out of memory exception caught", ee);
                }
            }
            catch (Exception ee)
            {
                if (currentMode != null)
                {
                    currentMode.Mode = Display_Mode_Enum.Error;
                    currentMode.Error_Message = "Unknown error occurred";
                    currentMode.Caught_Exception = ee;
                }
                else
                {
                    Email_Information("Unknown Fatal Error Occurred", ee);
                }
            }
        }
        /// <summary> Constructor for a new instance of the Static_Pages_Builder class </summary>
        /// <param name="Primary_Web_Server_URL"> URL for the primary web server </param>
        /// <param name="Static_Data_Location"> Network location for the data directory </param>
        /// <param name="Base_Network_Location"> Location where the web application files site for this </param>
        /// <remarks> This constructor pulls all the needed information from the database</remarks>
        public Static_Pages_Builder(string Primary_Web_Server_URL, string Static_Data_Location, string Base_Network_Location )
        {
            primaryWebServerUrl = Primary_Web_Server_URL;
            staticSobekcmDataLocation = Static_Data_Location;
            staticSobekcmLocation = Base_Network_Location;

            tracer = new Custom_Tracer();
            assistant = new SobekCM_Assistant();

            // Build all the objects needed by the SobekCM Library
            iconList = new Dictionary<string, Wordmark_Icon>();
            SobekCM_Database.Populate_Icon_List(iconList, tracer);

            translations = new Language_Support_Info();
            SobekCM_Database.Populate_Translations(translations, tracer);

            codeManager = new Aggregation_Code_Manager();
            SobekCM_Database.Populate_Code_Manager(codeManager, tracer);

            Portal_List urlPortals = new Portal_List();
            SobekCM_Database.Populate_URL_Portals(urlPortals, tracer);
            defaultSkin = urlPortals.Default_Portal.Default_Web_Skin;

            skinsCollection = new SobekCM_Skin_Collection();
            SobekCM_Skin_Collection_Builder.Populate_Default_Skins(skinsCollection, null);

            // Set some constant settings
            // SobekCM.Library.SobekCM_Library_Settings.Watermarks_URL = primary_web_server_url + "/design/wordmarks/";
            SobekCM_Library_Settings.Base_SobekCM_Location_Relative = primaryWebServerUrl;

            // Create the mode object
            currentMode = new SobekCM_Navigation_Object
                              {
                                  ViewerCode = "FC",
                                  Skin = defaultSkin,
                                  Mode = Display_Mode_Enum.Item_Display,
                                  Language = Web_Language_Enum.English,
                                  Base_URL = primaryWebServerUrl
                              };

            // Ensure all the folders exist
            if (!Directory.Exists(staticSobekcmDataLocation))
                Directory.CreateDirectory(staticSobekcmDataLocation);
            if (!Directory.Exists(staticSobekcmDataLocation + "\\rss"))
                Directory.CreateDirectory(staticSobekcmDataLocation + "\\rss");

            // Disable the cached data manager
            Cached_Data_Manager.Disabled = true;
        }
 /// <summary> Pulls the static html url for a static html browse of all items in an aggregation, used for search engine robot requests </summary>
 /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
 /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
 /// <returns> File name to read for the static browse HTML to display </returns>
 public string Get_All_Browse_Static_HTML(SobekCM_Navigation_Object Current_Mode, Custom_Tracer Tracer)
 {
     string base_image_url = SobekCM_Library_Settings.Base_Data_Directory + Current_Mode.Aggregation + "_all.html";
     return base_image_url;
 }
        /// <summary> Constructor for a new instance of the Static_Pages_Builder class </summary>
        /// <param name="Primary_Web_Server_URL"> URL for the primary web server </param>
        /// <param name="Static_Data_Location"> Network location for the data directory </param>
        /// <remarks> This constructor pulls all the needed information from the database</remarks>
        public Static_Pages_Builder(string Primary_Web_Server_URL, string Static_Data_Location )
        {
            primaryWebServerUrl = Primary_Web_Server_URL;
            staticSobekcmDataLocation = Static_Data_Location;

            tracer = new Custom_Tracer();
            assistant = new SobekCM_Assistant();

               // marcWriter = new MARC_Writer();

            // Get the list of all items
            SobekCM_Database.Connection_String = SobekCM_Library_Settings.Database_Connection_String; ;

            // Build all the objects needed by the UFDC Library
            iconList = new Dictionary<string, Wordmark_Icon>();
            SobekCM_Database.Populate_Icon_List(iconList, tracer);

            translations = new Language_Support_Info();
            SobekCM_Database.Populate_Translations(translations, tracer);

            codeManager = new Aggregation_Code_Manager();
            SobekCM_Database.Populate_Code_Manager(codeManager, tracer);

            // Get the item list and build the hashtable
               //     DataSet tempSet = SobekCM.Library.Database.SobekCM_Database.Get_Item_List(false, tracer);
            itemList = new Item_Lookup_Object();
            SobekCM_Database.Populate_Item_Lookup_Object(false, itemList, tracer);

            // Set some constant settings
            // SobekCM.Library.SobekCM_Library_Settings.Watermarks_URL = primary_web_server_url + "/design/wordmarks/";
            SobekCM_Library_Settings.Base_SobekCM_Location_Relative = primaryWebServerUrl;

            // Create the mode object
            currentMode = new SobekCM_Navigation_Object
                              {
                                  ViewerCode = "FC",
                                  Skin = "UFDC",
                                  Mode = Display_Mode_Enum.Item_Display,
                                  Language = Web_Language_Enum.English,
                                  Base_URL = primaryWebServerUrl
                              };

            // Create the ufdc interface object
            ufdcInterface = new SobekCM_Skin_Object("ufdc", String.Empty, currentMode.Base_Design_URL + "skins/ufdc/ufdc.css")
                                {
                                    Header_Item_HTML =GetHtmlPage(primaryWebServerUrl + "/design/skins/UFDC/html/header_item.html").Replace("<%BREADCRUMBS%>","<a href=\"" + primaryWebServerUrl + "\">UFDC Home</a>").Replace("<%MYSOBEK%>","<a href=\"" + primaryWebServerUrl + "my\">myUFDC Home</a>"),
                                    Footer_Item_HTML = GetHtmlPage(primaryWebServerUrl + "/design/skins/UFDC/html/footer_item.html").Replace("<%VERSION%>", SobekCM_Library_Settings.CURRENT_WEB_VERSION).Replace("src=\"" + currentMode.Base_URL + "design/", "src=\"" + primaryWebServerUrl + "/design/"),
                                    Header_HTML = GetHtmlPage(primaryWebServerUrl + "/design/skins/UFDC/html/header.html").Replace("<%BREADCRUMBS%>", "<a href=\"" + primaryWebServerUrl + "\">UFDC Home</a>").Replace("<%MYSOBEK%>","<a href=\"" + primaryWebServerUrl + "my\">myUFDC Home</a>"),
                                    Footer_HTML = GetHtmlPage(primaryWebServerUrl + "/design/skins/UFDC/html/footer.html").Replace("<%VERSION%>", SobekCM_Library_Settings.CURRENT_WEB_VERSION).Replace("src=\"" + currentMode.Base_URL + "design/", "src=\"" + primaryWebServerUrl + "/design/"),
                                    Language_Code = "",
                                    Override_Banner = false
                                };

            // Create the dLOC_English interface
            dlocInterface = new SobekCM_Skin_Object("dloc", String.Empty, currentMode.Base_Design_URL + "skins/dloc/dloc.css", "<img id=\"mainBanner\" src=\"" + currentMode.Base_URL + "design/skins/dloc/banner.jpg\" alt=\"MISSING BANNER\" />")
                                {
                                    Header_Item_HTML = GetHtmlPage(primaryWebServerUrl + "/design/skins/dloc/html/header_item.html").Replace("<%BREADCRUMBS%>", "<a href=\"" + primaryWebServerUrl + "\">UFDC Home</a>").Replace("<%MYSOBEK%>", "<a href=\"" + primaryWebServerUrl + "my\">myUFDC Home</a>"),
                                    Footer_Item_HTML = GetHtmlPage(primaryWebServerUrl + "/design/skins/dloc/html/footer_item.html").Replace("<%VERSION%>", SobekCM_Library_Settings.CURRENT_WEB_VERSION).Replace("src=\"" + currentMode.Base_URL + "design/", "src=\"" + primaryWebServerUrl + "/design/"),
                                    Header_HTML = GetHtmlPage(primaryWebServerUrl + "/design/skins/dloc/html/header.html").Replace("<%BREADCRUMBS%>", "<a href=\"" + primaryWebServerUrl + "\">UFDC Home</a>").Replace("<%MYSOBEK%>", "<a href=\"" + primaryWebServerUrl + "my\">myUFDC Home</a>"),
                                    Footer_HTML = GetHtmlPage(primaryWebServerUrl + "/design/skins/dloc/html/footer.html").Replace("<%VERSION%>", SobekCM_Library_Settings.CURRENT_WEB_VERSION).Replace("src=\"" + currentMode.Base_URL + "design/", "src=\"" + primaryWebServerUrl + "/design/"),
                                    Language_Code = "",
                                    Override_Banner = false
                                };

            // Disable the cached data manager
            Cached_Data_Manager.Disabled = true;
        }
        private static void Perform_Solr_Search(Custom_Tracer Tracer, List<string> Terms, List<string> Web_Fields, int ActualCount, string Current_Aggregation, int Current_Page, int Current_Sort, int Results_Per_Page, out Search_Results_Statistics Complete_Result_Set_Info, out List<iSearch_Title_Result> Paged_Results)
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("SobekCM_Assistant.Perform_Solr_Search", "Build the Solr query");
            }

            // Step through all the terms and fields
            StringBuilder queryStringBuilder = new StringBuilder();
            for (int i = 0; i < ActualCount; i++)
            {
                string web_field = Web_Fields[i];
                string searchTerm = Terms[i];
                string solr_field;

                if (i == 0)
                {
                    // Skip any joiner for the very first field indicated
                    if ((web_field[0] == '+') || (web_field[0] == '=') || (web_field[0] == '-'))
                    {
                        web_field = web_field.Substring(1);
                    }

                    // Try to get the solr field
                    if (web_field == "TX")
                    {
                        solr_field = "fulltext:";
                    }
                    else
                    {
                        Metadata_Search_Field field = SobekCM_Library_Settings.Metadata_Search_Field_By_Code(web_field.ToUpper());
                        if (field != null)
                        {
                            solr_field = field.Solr_Field + ":";
                        }
                        else
                        {
                            solr_field = String.Empty;
                        }
                    }

                    // Add the solr search string
                    if (searchTerm.IndexOf(" ") > 0)
                    {
                        queryStringBuilder.Append("(" + solr_field + "\"" + searchTerm.Replace(":","") + "\")");
                    }
                    else
                    {
                        queryStringBuilder.Append("(" + solr_field + searchTerm.Replace(":", "") + ")");
                    }
                }
                else
                {
                    // Add the joiner for this subsequent terms
                    if ((web_field[0] == '+') || (web_field[0] == '=') || (web_field[0] == '-'))
                    {
                        switch (web_field[0])
                        {
                            case '=':
                                queryStringBuilder.Append(" OR ");
                                break;

                            case '+':
                                queryStringBuilder.Append(" AND ");
                                break;

                            case '-':
                                queryStringBuilder.Append(" NOT ");
                                break;

                            default:
                                queryStringBuilder.Append(" AND ");
                                break;
                        }
                        web_field = web_field.Substring(1);
                    }
                    else
                    {
                        queryStringBuilder.Append(" AND ");
                    }

                    // Try to get the solr field
                    if (web_field == "TX")
                    {
                        solr_field = "fulltext:";
                    }
                    else
                    {
                        Metadata_Search_Field field = SobekCM_Library_Settings.Metadata_Search_Field_By_Code(web_field.ToUpper());
                        if (field != null)
                        {
                            solr_field = field.Solr_Field + ":";
                        }
                        else
                        {
                            solr_field = String.Empty;
                        }
                    }

                    // Add the solr search string
                    if (searchTerm.IndexOf(" ") > 0)
                    {
                        queryStringBuilder.Append("(" + solr_field + "\"" + searchTerm.Replace(":", "") + "\")");
                    }
                    else
                    {
                        queryStringBuilder.Append("(" + solr_field + searchTerm.Replace(":", "") + ")");
                    }
                }
            }

            // Use this built query to query against Solr
            Solr_Documents_Searcher.Search(Current_Aggregation, queryStringBuilder.ToString(), Results_Per_Page, Current_Page, (ushort) Current_Sort, Tracer, out Complete_Result_Set_Info, out Paged_Results);
            return;
        }
        private void Perform_Database_Search(Custom_Tracer Tracer, List<string> Terms, List<string> Web_Fields, int ActualCount, SobekCM_Navigation_Object Current_Mode, int Current_Sort, Item_Aggregation Aggregation_Object, Item_Lookup_Object All_Items_Lookup, int Results_Per_Page, bool Potentially_Include_Facets, out Search_Results_Statistics Complete_Result_Set_Info, out List<List<iSearch_Title_Result>> Paged_Results, bool Need_Search_Statistics)
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("SobekCM_Assistant.Perform_Database_Sear`ch", "Query the database for search results");
            }

            // Get the list of facets first
            List<short> facetsList = Aggregation_Object.Facets;
            if (!Potentially_Include_Facets)
                facetsList.Clear();

            // Set the return values to NULL initially
            Complete_Result_Set_Info = null;

            const bool includePrivate = false;

            // Special code for searching by bibid, oclc, or aleph
            if (ActualCount == 1)
            {
                // Is this a BIBID search?
                if ((Web_Fields[0] == "BI") && ( Terms[0].IndexOf("*") < 0 ) && ( Terms[0].Length >= 10 ))
                {
                    string bibid = Terms[0].ToUpper();
                    string vid = String.Empty;
                    if (bibid.Length > 10)
                    {
                        if ((bibid.IndexOf("_") == 10) && ( bibid.Length > 11 ))
                        {
                            vid = bibid.Substring(11).PadLeft(5, '0');
                            bibid = bibid.Substring(0, 10);
                        }
                        else if ((bibid.IndexOf(":") == 10) && ( bibid.Length > 11 ))
                        {
                            vid = bibid.Substring(11).PadLeft(5, '0');
                            bibid = bibid.Substring(0, 10);
                        }
                        else if (bibid.Length == 15)
                        {
                            vid = bibid.Substring(10);
                            bibid = bibid.Substring(0, 10);
                        }
                    }

                    if (bibid.Length == 10)
                    {
                        if (vid.Length == 5)
                        {
                            if (All_Items_Lookup.Contains_BibID_VID(bibid, vid))
                            {
                                string redirect_url = Current_Mode.Base_URL + bibid + "/" + vid;
                                if ( Current_Mode.Writer_Type == Writer_Type_Enum.HTML_LoggedIn )
                                    redirect_url = Current_Mode.Base_URL + "l/" + bibid + "/" + vid;
                                HttpContext.Current.Response.Redirect(redirect_url);
                            }
                        }
                        else
                        {
                            if (All_Items_Lookup.Contains_BibID(bibid))
                            {
                                string redirect_url = Current_Mode.Base_URL + bibid;
                                if (Current_Mode.Writer_Type == Writer_Type_Enum.HTML_LoggedIn)
                                    redirect_url = Current_Mode.Base_URL + "l/" + bibid;
                                HttpContext.Current.Response.Redirect(redirect_url);
                            }
                        }
                    }
                }

                // Was this a OCLC search?
                if ((Web_Fields[0] == "OC") && (Terms[0].Length > 0))
                {
                    bool is_number = Terms[0].All(Char.IsNumber);

                    if (is_number)
                    {
                        long oclc = Convert.ToInt64(Terms[0]);
                        Multiple_Paged_Results_Args returnArgs = SobekCM_Database.Items_By_OCLC_Number(oclc, false, Results_Per_Page, Current_Sort, Need_Search_Statistics, Tracer);
                        if (Need_Search_Statistics)
                            Complete_Result_Set_Info = returnArgs.Statistics;
                        Paged_Results = returnArgs.Paged_Results;
                        return;
                    }
                }

                // Was this a ALEPH search?
                if ((Web_Fields[0] == "AL") && (Terms[0].Length > 0))
                {
                    bool is_number = Terms[0].All(Char.IsNumber);

                    if (is_number)
                    {
                        int aleph = Convert.ToInt32(Terms[0]);
                        Multiple_Paged_Results_Args returnArgs = SobekCM_Database.Items_By_ALEPH_Number(aleph, false, Results_Per_Page, Current_Sort, Need_Search_Statistics, Tracer);
                        if (Need_Search_Statistics)
                            Complete_Result_Set_Info = returnArgs.Statistics;
                        Paged_Results = returnArgs.Paged_Results;
                        return;
                    }
                }
            }

            List<short> links = new List<short>();
            List<short> db_fields = new List<short>();
            List<string> db_terms = Terms.ToList();

            // Step through all the web fields and convert to db fields
            for (int i = 0; i < ActualCount; i++)
            {
                if (Web_Fields[i].Length > 1)
                {
                    // Find the joiner
                    if ((Web_Fields[i][0] == '+') || (Web_Fields[i][0] == '=') || (Web_Fields[i][0] == '-'))
                    {
                        if (i != 0)
                        {
                            if (Web_Fields[i][0] == '+')
                                links.Add(0);
                            if (Web_Fields[i][0] == '=')
                                links.Add(1);
                            if (Web_Fields[i][0] == '-')
                                links.Add(2);
                        }
                        Web_Fields[i] = Web_Fields[i].Substring(1);
                    }
                    else
                    {
                        if (i != 0)
                        {
                            links.Add(0);
                        }
                    }

                    // Find the db field number
                    db_fields.Add(Metadata_Field_Number(Web_Fields[i]));
                }

                // Also add starting and ending quotes to all the valid searches
                if (db_terms[i].Length > 0)
                {
                    if ((db_terms[i].IndexOf("\"") < 0) && (db_terms[i].IndexOf(" ") < 0))
                    {
                        // Since this is a single word, see what type of special codes to include
                        switch (Current_Mode.Search_Precision)
                        {
                            case Search_Precision_Type_Enum.Contains:
                                db_terms[i] = "\"" + db_terms[i] + "\"";
                                break;

                            case Search_Precision_Type_Enum.Inflectional_Form:
                                // If there are any non-characters, don't use inflectional for this term
                                bool inflectional = db_terms[i].All(Char.IsLetter);
                                if (inflectional)
                                {
                                    db_terms[i] = "FORMSOF(inflectional," + db_terms[i] + ")";
                                }
                                else
                                {
                                    db_terms[i] = "\"" + db_terms[i] + "\"";
                                }
                                break;

                            case Search_Precision_Type_Enum.Synonmic_Form:
                                // If there are any non-characters, don't use thesaurus for this term
                                bool thesaurus = db_terms[i].All(Char.IsLetter);
                                if (thesaurus)
                                {
                                    db_terms[i] = "FORMSOF(thesaurus," + db_terms[i] + ")";
                                }
                                else
                                {
                                    db_terms[i] = "\"" + db_terms[i] + "\"";
                                }
                                break;
                        }
                    }
                    else
                    {
                        if (Current_Mode.Search_Precision != Search_Precision_Type_Enum.Exact_Match)
                        {
                            db_terms[i] = "\"" + db_terms[i] + "\"";
                        }
                    }
                }
            }

            // If this is an exact match, just do the search
            if (Current_Mode.Search_Precision == Search_Precision_Type_Enum.Exact_Match)
            {
                Multiple_Paged_Results_Args returnArgs = SobekCM_Database.Perform_Metadata_Exact_Search_Paged(db_terms[0], db_fields[0], includePrivate, Current_Mode.Aggregation, Results_Per_Page, Current_Mode.Page, Current_Sort, Need_Search_Statistics, facetsList, Need_Search_Statistics, Tracer);
                if (Need_Search_Statistics)
                    Complete_Result_Set_Info = returnArgs.Statistics;
                Paged_Results = returnArgs.Paged_Results;
            }
            else
            {
                // Finish filling up the fields and links
                while (links.Count < 9)
                    links.Add(0);
                while (db_fields.Count < 10)
                    db_fields.Add(-1);
                while (db_terms.Count < 10)
                    db_terms.Add(String.Empty);

                // See if this is a simple search, which can use a more optimized search routine
                bool simplified_search = db_fields.All(field => (field <= 0));

                // Perform either the simpler metadata search, or the more complex
                if (simplified_search)
                {
                    StringBuilder searchBuilder = new StringBuilder();
                    for (int i = 0; i < db_terms.Count; i++)
                    {
                        if (db_terms[i].Length > 0)
                        {
                            if (i > 0)
                            {
                                if (i > links.Count)
                                {
                                    searchBuilder.Append(" AND ");
                                }
                                else
                                {
                                    switch (links[i - 1])
                                    {
                                        case 0:
                                            searchBuilder.Append(" AND ");
                                            break;

                                        case 1:
                                            searchBuilder.Append(" OR ");
                                            break;

                                        case 2:
                                            searchBuilder.Append(" AND NOT ");
                                            break;
                                    }
                                }
                            }

                            searchBuilder.Append(db_terms[i]);
                        }
                    }

                    Multiple_Paged_Results_Args returnArgs = SobekCM_Database.Perform_Metadata_Search_Paged(searchBuilder.ToString(), includePrivate, Current_Mode.Aggregation, Results_Per_Page, Current_Mode.Page, Current_Sort, Need_Search_Statistics, facetsList, Need_Search_Statistics, Tracer);
                    if (Need_Search_Statistics)
                        Complete_Result_Set_Info = returnArgs.Statistics;
                    Paged_Results = returnArgs.Paged_Results;
                }
                else
                {
                    // Perform search in the database
                    Multiple_Paged_Results_Args returnArgs = SobekCM_Database.Perform_Metadata_Search_Paged(db_terms[0], db_fields[0], links[0], db_terms[1], db_fields[1], links[1], db_terms[2], db_fields[2], links[2], db_terms[3],
                                                                                                            db_fields[3], links[3], db_terms[4], db_fields[4], links[4], db_terms[5], db_fields[5], links[5], db_terms[6], db_fields[6], links[6], db_terms[7], db_fields[7], links[7], db_terms[8], db_fields[8],
                                                                                                            links[8], db_terms[9], db_fields[9], includePrivate, Current_Mode.Aggregation, Results_Per_Page, Current_Mode.Page, Current_Sort, Need_Search_Statistics, facetsList, Need_Search_Statistics, Tracer);
                    if (Need_Search_Statistics)
                        Complete_Result_Set_Info = returnArgs.Statistics;
                    Paged_Results = returnArgs.Paged_Results;
                }
            }
        }
        /// <summary> Retrieve the (assummed private) user folder browse by user and folder name </summary>
        /// <param name="Folder_Name"> Name of the folder to retieve the browse for </param>
        /// <param name="User_ID"> ID for the user </param>
        /// <param name="Results_Per_Page"> Number of results to display in this page (set higher if EXPORT is chosen)</param>
        /// <param name="ResultsPage">Which page of results to return ( one-based, so the first page is page number of one )</param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        /// <param name="Complete_Result_Set_Info"> [OUT] Information about the entire set of results </param>
        /// <param name="Paged_Results"> [OUT] List of search results for the requested page of results </param>
        /// <returns> TRUE if successful, otherwise FALSE </returns>
        /// <remarks> This attempts to pull the objects from the cache.  If unsuccessful, it builds the objects from the
        /// database and hands off to the <see cref="Cached_Data_Manager" /> to store in the cache </remarks>
        public bool Get_User_Folder( string Folder_Name, int User_ID, int Results_Per_Page, int ResultsPage, Custom_Tracer Tracer, out Search_Results_Statistics Complete_Result_Set_Info, out List<iSearch_Title_Result> Paged_Results )
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("SobekCM_Assistant.Get_User_Folder", String.Empty);
            }

            // Look to see if the browse statistics are available on any cache for this browse
            bool need_browse_statistics = true;
            Complete_Result_Set_Info = Cached_Data_Manager.Retrieve_User_Folder_Browse_Statistics(User_ID, Folder_Name, Tracer);
            if (Complete_Result_Set_Info != null)
                need_browse_statistics = false;

            // Look to see if the paged results are available on any cache..
            bool need_paged_results = true;
            Paged_Results = Cached_Data_Manager.Retrieve_User_Folder_Browse(User_ID, Folder_Name, ResultsPage, Results_Per_Page, Tracer);
            if (Paged_Results != null)
                need_paged_results = false;

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

                Single_Paged_Results_Args returnArgs = SobekCM_Database.Get_User_Folder_Browse(User_ID, Folder_Name, Results_Per_Page, ResultsPage, false, new List<short>(), need_browse_statistics, Tracer);
                if (need_browse_statistics)
                {
                    Complete_Result_Set_Info = returnArgs.Statistics;
                }
                Paged_Results = returnArgs.Paged_Results;

                // Save the overall result set statistics to the cache if something was pulled
                if ((need_browse_statistics) && (Complete_Result_Set_Info != null))
                {
                    Cached_Data_Manager.Store_User_Folder_Browse_Statistics(User_ID, Folder_Name, Complete_Result_Set_Info, Tracer);
                }

                // Save the overall result set statistics to the cache if something was pulled
                if ((need_paged_results) && (Paged_Results != null))
                {
                    Cached_Data_Manager.Store_User_Folder_Browse(User_ID, Folder_Name, ResultsPage, Results_Per_Page, Paged_Results, Tracer);
                }
            }

            return true;
        }
        /// <summary> Gets the simple CMS/info object and text to display </summary>
        /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
        /// <param name="Base_Directory"> Base directory location under which the the CMS/info source file will be found</param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        /// <param name="Simple_Web_Content"> [OUT] Built browse object which contains information like title, banner, etc.. and the entire text to be displayed </param>
        /// <param name="Site_Map"> [OUT] Optional navigational site map object related to this page </param>
        /// <returns>TRUE if successful, otherwise FALSE </returns>
        /// <remarks> This always pulls the data directly from disk; this text is not cached. </remarks>
        public bool Get_Simple_Web_Content_Text(SobekCM_Navigation_Object Current_Mode, string Base_Directory, Custom_Tracer Tracer, out HTML_Based_Content Simple_Web_Content, out SobekCM_SiteMap Site_Map )
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("SobekCM_Assistant.Get_Simple_Web_Content_Text", String.Empty);
            }

            Site_Map = null;

            string source = Current_Mode.Page_By_FileName;
            Simple_Web_Content = HTML_Based_Content_Reader.Read_HTML_File(source, true, Tracer);

            if (Simple_Web_Content == null)
            {
                Current_Mode.Error_Message = "Unable to retrieve simple text item '" + Current_Mode.Info_Browse_Mode.Replace("_","\\") + "'";
                return false;
            }

            if ( Simple_Web_Content.Static_Text.Length == 0 )
            {
                Current_Mode.Error_Message = "Unable to read the file for display";
                return false;
            }

            // Now, check for any "server-side include" directorives in the source text
            int include_index = Simple_Web_Content.Static_Text.IndexOf("<%INCLUDE");
            while(( include_index > 0 ) && ( Simple_Web_Content.Static_Text.IndexOf("%>", include_index ) > 0 ))
            {
                int include_finish_index = Simple_Web_Content.Static_Text.IndexOf("%>", include_index) + 2;
                string include_statement = Simple_Web_Content.Static_Text.Substring(include_index, include_finish_index - include_index);
                string include_statement_upper = include_statement.ToUpper();
                int file_index = include_statement_upper.IndexOf("FILE");
                string filename_to_include = String.Empty;
                if (file_index > 0)
                {
                    // Pull out the possible file name
                    string possible_file_name = include_statement.Substring(file_index + 4);
                    int file_start = -1;
                    int file_end = -1;
                    int char_index = 0;

                    // Find the start of the file information
                    while ((file_start < 0) && (char_index < possible_file_name.Length))
                    {
                        if ((possible_file_name[char_index] != '"') && (possible_file_name[char_index] != '=') && (possible_file_name[char_index] != ' '))
                        {
                            file_start = char_index;
                        }
                        else
                        {
                            char_index++;
                        }
                    }

                    // Find the end of the file information
                    if (file_start >= 0)
                    {
                        char_index++;
                        while ((file_end < 0) && (char_index < possible_file_name.Length))
                        {
                            if ((possible_file_name[char_index] == '"') || (possible_file_name[char_index] == ' ') || (possible_file_name[char_index] == '%'))
                            {
                                file_end = char_index;
                            }
                            else
                            {
                                char_index++;
                            }
                        }
                    }

                    // Get the filename
                    if ((file_start > 0) && (file_end > 0))
                    {
                        filename_to_include = possible_file_name.Substring(file_start, file_end - file_start);
                    }
                }

                // Remove the include and either place in the text from the indicated file,
                // or just remove
                if ((filename_to_include.Length > 0 ) && (File.Exists(SobekCM_Library_Settings.Base_Directory + "design\\webcontent\\" + filename_to_include)))
                {
                    // Define the value for the include text
                    string include_text;

                    // Look in the cache for this
                    object returnValue = HttpContext.Current.Cache.Get("INCLUDE_" + filename_to_include );
                    if (returnValue != null)
                    {
                        include_text = returnValue.ToString();
                    }
                    else
                    {
                        try
                        {
                            // Pull from the file
                            StreamReader reader = new StreamReader(SobekCM_Library_Settings.Base_Directory + "design\\webcontent\\" + filename_to_include);
                            include_text = reader.ReadToEnd();
                            reader.Close();

                            // Store on the cache for two minutes, if no indication not to
                            if ( include_statement_upper.IndexOf("NOCACHE") < 0 )
                                HttpContext.Current.Cache.Insert("INCLUDE_" + filename_to_include, include_text, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(2));
                        }
                        catch(Exception)
                        {
                            include_text = "Unable to read the soruce file ( " + filename_to_include + " )";
                        }
                    }

                    // Replace the text with the include file
                    Simple_Web_Content.Static_Text = Simple_Web_Content.Static_Text.Replace(include_statement, include_text);
                    include_index = Simple_Web_Content.Static_Text.IndexOf("<%INCLUDE", include_index + include_text.Length - 1 );
                }
                else
                {
                    // No suitable name was found, or it doesn't exist so just remove the INCLUDE completely
                    Simple_Web_Content.Static_Text = Simple_Web_Content.Static_Text.Replace(include_statement, "");
                    include_index = Simple_Web_Content.Static_Text.IndexOf("<%INCLUDE", include_index );
                }
            }

            // Look for a site map
            if (Simple_Web_Content.SiteMap.Length > 0)
            {
                // Look in the cache first
                Site_Map = Cached_Data_Manager.Retrieve_Site_Map(Simple_Web_Content.SiteMap, Tracer);

                // If this was NULL, pull it
                if (Site_Map == null)
                {
                    // Only continue if the file exists
                    if (File.Exists(SobekCM_Library_Settings.Base_Directory + "design\\webcontent\\" + Simple_Web_Content.SiteMap))
                    {
                        if (Tracer != null)
                        {
                            Tracer.Add_Trace("SobekCM_Assistant.Get_Simple_Web_Content_Text", "Reading site map file");
                        }

                        // Try to read this sitemap file
                        Site_Map = SobekCM_SiteMap_Reader.Read_SiteMap_File(SobekCM_Library_Settings.Base_Directory + "design\\webcontent\\" + Simple_Web_Content.SiteMap);

                        // If the sitemap file was succesfully read, cache it
                        if (Site_Map != null)
                        {
                            Cached_Data_Manager.Store_Site_Map(Site_Map, Simple_Web_Content.SiteMap, Tracer);
                        }
                    }
                }
            }

            // Since this is not cached, we can apply the individual user settings to the static text which was read right here
            Simple_Web_Content.Static_Text = Simple_Web_Content.Apply_Settings_To_Static_Text(Simple_Web_Content.Static_Text, null, Current_Mode.Skin, Current_Mode.Base_Skin, Current_Mode.Base_URL, Current_Mode.URL_Options(), Tracer);

            return true;
        }
        /// <summary> Pulls an item aggregation object representing all collections within this digital library  </summary>
        /// <param name="Language_Code"> Current language code (item aggregation instances are currently language-specific)</param>
        /// <param name="IsRobot"> Flag indicates if this is a robot request (may cache differently)</param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        /// <returns> Fully-built object representing all collections within this digital library </returns>
        /// <remarks> This attempts to pull the objects from the cache.  If unsuccessful, it builds the objects from the
        /// database and hands off to the <see cref="Cached_Data_Manager" /> to store in the cache. </remarks>
        public Item_Aggregation Get_All_Collections(string Language_Code, bool IsRobot, Custom_Tracer Tracer)
        {
            try
            {
                // Try to pull this from the cache
                Item_Aggregation cacheInstance = Cached_Data_Manager.Retrieve_Item_Aggregation("all", Language_Code, !IsRobot, Tracer);

                // Put into the builder regardless of whether his came from the cache.. need to confirm search fields as well
                Item_Aggregation returned = Item_Aggregation_Builder.Get_Item_Aggregation("all", Language_Code, cacheInstance, IsRobot, true, Tracer);

                // If the object is null, then this group code was invalid.
                if (returned == null)
                {
                    return null;
                }

                // Return the object
                return returned;
            }
            catch
            {
                return null;
            }
        }
        /// <summary> Retrieve the public user folder information and browse by user folder id </summary>
        /// <param name="UserFolderID"> Primary key for the public user folder to retrieve </param>
        /// <param name="ResultsPage">Which page of results to return ( one-based, so the first page is page number of one ) </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        /// <param name="Folder_Info"> [OUT] Information about this public user folder including name and owner</param>
        /// <param name="Complete_Result_Set_Info"> [OUT] Information about the entire set of results </param>
        /// <param name="Paged_Results"> [OUT] List of search results for the requested page of results </param>
        /// <returns> TRUE if successful, otherwise FALSE </returns>
        /// <remarks> This attempts to pull the objects from the cache.  If unsuccessful, it builds the objects from the
        /// database and hands off to the <see cref="Cached_Data_Manager" /> to store in the cache </remarks>
        public bool Get_Public_User_Folder(int UserFolderID, int ResultsPage, Custom_Tracer Tracer, out Public_User_Folder Folder_Info, out Search_Results_Statistics Complete_Result_Set_Info, out List<iSearch_Title_Result> Paged_Results)
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("SobekCM_Assistant.Get_Public_User_Folder", String.Empty);
            }

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

            // Try to get this from the cache first, otherwise get from database and store in cache
            Folder_Info = Cached_Data_Manager.Retrieve_Public_Folder_Info(UserFolderID, Tracer);
            if (Folder_Info == null)
            {
                Folder_Info = SobekCM_Database.Get_Public_User_Folder(UserFolderID, Tracer);
                if ((Folder_Info != null) && (Folder_Info.isPublic))
                {
                    Cached_Data_Manager.Store_Public_Folder_Info(Folder_Info, Tracer);
                }
            }

            // If this folder is invalid or private, return false
            if ((Folder_Info == null) || (!Folder_Info.isPublic))
            {
                return false;
            }

            // Look to see if the browse statistics are available on any cache for this browse
            bool need_browse_statistics = true;
            Complete_Result_Set_Info = Cached_Data_Manager.Retrieve_Public_Folder_Statistics(UserFolderID, Tracer);
            if (Complete_Result_Set_Info != null)
                need_browse_statistics = false;

            // Look to see if the paged results are available on any cache..
            bool need_paged_results = true;
            Paged_Results = Cached_Data_Manager.Retrieve_Public_Folder_Browse(UserFolderID, ResultsPage, Tracer);
            if (Paged_Results != null)
                need_paged_results = false;

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

                Single_Paged_Results_Args returnArgs = SobekCM_Database.Get_Public_Folder_Browse(UserFolderID, 20, ResultsPage, false, new List<short>(), need_browse_statistics, Tracer);
                if (need_browse_statistics)
                {
                    Complete_Result_Set_Info = returnArgs.Statistics;
                }
                Paged_Results = returnArgs.Paged_Results;

                // Save the overall result set statistics to the cache if something was pulled
                if ((need_browse_statistics) && (Complete_Result_Set_Info != null))
                {
                    Cached_Data_Manager.Store_Public_Folder_Statistics(UserFolderID, Complete_Result_Set_Info, Tracer);
                }

                // Save the overall result set statistics to the cache if something was pulled
                if ((need_paged_results) && (Paged_Results != null))
                {
                    Cached_Data_Manager.Store_Public_Folder_Browse(UserFolderID, ResultsPage, Paged_Results, Tracer);
                }
            }

            return true;
        }
        /// <summary> Gets the item aggregation and search fields for the current item aggregation </summary>
        /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
        /// <param name="Code_Manager"> List of valid collection codes, including mapping from the Sobek collections to Greenstone collections</param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering</param>
        /// <param name="Aggregation_Object"> [OUT] Fully-built object for the current aggregation object </param>
        /// <returns> TRUE if successful, otherwise FALSE </returns>
        /// <remarks> This attempts to pull the objects from the cache.  If unsuccessful, it builds the objects from the
        /// database and hands off to the <see cref="Cached_Data_Manager" /> to store in the cache. </remarks>
        public bool Get_Entire_Collection_Hierarchy(SobekCM_Navigation_Object Current_Mode, 
                                                    Aggregation_Code_Manager Code_Manager,
                                                    Custom_Tracer Tracer, out Item_Aggregation Aggregation_Object)
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("SobekCM_Assistant.Get_Entire_Collection_Hierarchy", String.Empty);
            }

            string languageCode = "en";
            if (Current_Mode.Language == Web_Language_Enum.Spanish)
                languageCode = "es";
            if (Current_Mode.Language == Web_Language_Enum.French)
                languageCode = "fr";

            // If there is an aggregation listed, try to get that now
            if ((Current_Mode.Aggregation.Length > 0) && (Current_Mode.Aggregation != "all"))
            {
                // Try to pull the aggregation information
                Aggregation_Object = Get_Item_Aggregation(Current_Mode.Aggregation, languageCode, Current_Mode.Is_Robot, Tracer );

                // Return if this was valid
                if (Aggregation_Object != null)
                {
                    if ((Current_Mode.Skin_in_URL != true) && ( Aggregation_Object.Default_Skin.Length > 0 ))
                    {
                        Current_Mode.Skin = Aggregation_Object.Default_Skin.ToLower();
                    }
                    return true;
                }

                Current_Mode.Error_Message = "Invalid item aggregation '" + Current_Mode.Aggregation + "' referenced.";
                return false;
            }
            // Get the collection group
            Aggregation_Object = Get_All_Collections(languageCode, Current_Mode.Is_Robot, Tracer );

            // If this is null, just stop
            if (Aggregation_Object == null)
            {
                Current_Mode.Error_Message = "Unable to pull the item aggregation corresponding to all collection groups";
                return false;
            }

            return true;
        }
        /// <summary> Performs a search ( or retrieves the search results from the cache ) and outputs the results and search url used  </summary>
        /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
        /// <param name="All_Items_Lookup"> Lookup object used to pull basic information about any item loaded into this library </param>
        /// <param name="Aggregation_Object"> Object for the current aggregation object, against which this search is performed </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        /// <param name="Complete_Result_Set_Info"> [OUT] Information about the entire set of results </param>
        /// <param name="Paged_Results"> [OUT] List of search results for the requested page of results </param>
        public void Get_Search_Results(SobekCM_Navigation_Object Current_Mode,
                                       Item_Lookup_Object All_Items_Lookup,
                                       Item_Aggregation Aggregation_Object,
                                       Custom_Tracer Tracer,
                                       out Search_Results_Statistics Complete_Result_Set_Info,
                                       out List<iSearch_Title_Result> Paged_Results )
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("SobekCM_Assistant.Get_Search_Results", String.Empty);
            }

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

            // Get the sort
            int sort = Current_Mode.Sort;
            if ((sort != 0) && (sort != 1) && (sort != 2) && (sort != 10) && (sort != 11))
                sort = 0;

            // Depending on type of search, either go to database or Greenstone
            if (Current_Mode.Search_Type == Search_Type_Enum.Map)
            {
                try
                {
                    double lat1 = 1000;
                    double long1 = 1000;
                    double lat2 = 1000;
                    double long2 = 1000;
                    string[] terms = Current_Mode.Coordinates.Split(",".ToCharArray());
                    if (terms.Length < 2)
                    {
                        Current_Mode.Mode = Display_Mode_Enum.Search;
                        HttpContext.Current.Response.Redirect(Current_Mode.Redirect_URL());
                    }
                    if (terms.Length < 4)
                    {
                        lat1 = Convert.ToDouble(terms[0]);
                        lat2 = lat1;
                        long1 = Convert.ToDouble(terms[1]);
                        long2 = long1;
                    }
                    if (terms.Length >= 4)
                    {
                        if (terms[0].Length > 0)
                            lat1 = Convert.ToDouble(terms[0]);
                        if (terms[1].Length > 0)
                            long1 = Convert.ToDouble(terms[1]);
                        if (terms[2].Length > 0)
                            lat2 = Convert.ToDouble(terms[2]);
                        if (terms[3].Length > 0)
                            long2 = Convert.ToDouble(terms[3]);
                    }

                    // If neither point is valid, return
                    if (((lat1 == 1000) || (long1 == 1000)) && ((lat2 == 1000) || (long2 == 1000)))
                    {
                        Current_Mode.Mode = Display_Mode_Enum.Search;
                        HttpContext.Current.Response.Redirect(Current_Mode.Redirect_URL());
                    }

                    // If just the first point is valid, use that
                    if ((lat2 == 1000) || (long2 == 1000))
                    {
                        lat2 = lat1;
                        long2 = long1;
                    }

                    // If just the second point is valid, use that
                    if ((lat1 == 1000) || (long1 == 1000))
                    {
                        lat1 = lat2;
                        long1 = long2;
                    }

                    // Perform the search against the database
                    try
                    {
                        // Try to pull more than one page, so we can cache the next page or so

                        Multiple_Paged_Results_Args returnArgs = SobekCM_Database.Get_Items_By_Coordinates(Current_Mode.Aggregation, lat1, long1, lat2, long2, false, 20, Current_Mode.Page, sort, false, new List<short>(), true, Tracer);
                        List<List<iSearch_Title_Result>> pagesOfResults = returnArgs.Paged_Results;
                        Complete_Result_Set_Info = returnArgs.Statistics;

                        if ((pagesOfResults != null) && (pagesOfResults.Count > 0))
                            Paged_Results = pagesOfResults[0];
                    }
                    catch (Exception ee)
                    {
                        // Next, show the message to the user
                        Current_Mode.Mode = Display_Mode_Enum.Error;
                        string error_message = ee.Message;
                        if (error_message.ToUpper().IndexOf("TIMEOUT") >= 0)
                        {
                            error_message = "Database Timeout Occurred<br /><br />Try again in a few minutes.<br /><br />";
                        }
                        Current_Mode.Error_Message = error_message;
                        Current_Mode.Caught_Exception = ee;
                    }
                }
                catch
                {
                    Current_Mode.Mode = Display_Mode_Enum.Search;
                    HttpContext.Current.Response.Redirect(Current_Mode.Redirect_URL());
                }
            }
            else
            {
                List<string> terms = new List<string>();
                List<string> web_fields = new List<string>();

                // Split the terms correctly ( only use the database stop words for the split if this will go to the database ultimately)
                if ((Current_Mode.Search_Type == Search_Type_Enum.Full_Text) || (Current_Mode.Search_Fields.IndexOf("TX") >= 0))
                {
                    Split_Clean_Search_Terms_Fields(Current_Mode.Search_String, Current_Mode.Search_Fields, Current_Mode.Search_Type, terms, web_fields, null, Current_Mode.Search_Precision, ',');
                }
                else
                {
                    Split_Clean_Search_Terms_Fields(Current_Mode.Search_String, Current_Mode.Search_Fields, Current_Mode.Search_Type, terms, web_fields, SobekCM_Library_Settings.Search_Stop_Words, Current_Mode.Search_Precision, ',');
                }

                // Get the count that will be used
                int actualCount = Math.Min(terms.Count, web_fields.Count);

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

                // Set the flags for how much data is needed.  (i.e., do we need to pull ANYTHING?  or
                // perhaps just the next page of results ( as opposed to pulling facets again).
                bool need_search_statistics = true;
                bool need_paged_results = true;
                if (!special_search_type)
                {
                    // Look to see if the search statistics are available on any cache..
                    Complete_Result_Set_Info = Cached_Data_Manager.Retrieve_Search_Result_Statistics(Current_Mode, actualCount, web_fields, terms, Tracer);
                    if (Complete_Result_Set_Info != null)
                        need_search_statistics = false;

                    // Look to see if the paged results are available on any cache..
                    Paged_Results = Cached_Data_Manager.Retrieve_Search_Results(Current_Mode, sort, actualCount, web_fields, terms, Tracer);
                    if (Paged_Results != null)
                        need_paged_results = false;
                }

                // If both were retrieved, do nothing else
                if ((need_paged_results) || (need_search_statistics))
                {
                    // Should this pull the search from the database, or from greenstone?
                    if ((Current_Mode.Search_Type == Search_Type_Enum.Full_Text) || (Current_Mode.Search_Fields.IndexOf("TX") >= 0))
                    {
                        try
                        {
                            // Perform the search against greenstone
                            Search_Results_Statistics recomputed_search_statistics;
                            Perform_Solr_Search(Tracer, terms, web_fields, actualCount, Current_Mode.Aggregation, Current_Mode.Page, sort, results_per_page, out recomputed_search_statistics, out Paged_Results);
                            if (need_search_statistics)
                                Complete_Result_Set_Info = recomputed_search_statistics;
                        }
                        catch (Exception ee)
                        {
                            Current_Mode.Mode = Display_Mode_Enum.Error;
                            Current_Mode.Error_Message = "Unable to perform search at this time";
                            Current_Mode.Caught_Exception = ee;
                        }

                        // If this was a special search, don't cache this
                        if (!special_search_type)
                        {
                            // Cache the search statistics, if it was needed
                            if ((need_search_statistics) && (Complete_Result_Set_Info != null))
                            {
                                Cached_Data_Manager.Store_Search_Result_Statistics(Current_Mode, actualCount, web_fields, terms, Complete_Result_Set_Info, Tracer);
                            }

                            // Cache the search results
                            if ((need_paged_results) && (Paged_Results != null))
                            {
                                Cached_Data_Manager.Store_Search_Results(Current_Mode, sort, actualCount, web_fields, terms, Paged_Results, Tracer);
                            }
                        }
                    }
                    else
                    {
                        // Try to pull more than one page, so we can cache the next page or so
                        List<List<iSearch_Title_Result>> pagesOfResults = new List<List<iSearch_Title_Result>>();

                        // Perform the search against the database
                        try
                        {
                            Search_Results_Statistics recomputed_search_statistics;
                            Perform_Database_Search(Tracer, terms, web_fields, actualCount, Current_Mode, sort, Aggregation_Object, All_Items_Lookup, results_per_page, !special_search_type, out recomputed_search_statistics, out pagesOfResults, need_search_statistics);
                            if (need_search_statistics)
                                Complete_Result_Set_Info = recomputed_search_statistics;

                            if ((pagesOfResults != null) && (pagesOfResults.Count > 0))
                                Paged_Results = pagesOfResults[0];
                        }
                        catch (Exception ee)
                        {
                            // Next, show the message to the user
                            Current_Mode.Mode = Display_Mode_Enum.Error;
                            string error_message = ee.Message;
                            if (error_message.ToUpper().IndexOf("TIMEOUT") >= 0)
                            {
                                error_message = "Database Timeout Occurred<br /><br />Try narrowing your search by adding more terms <br />or putting quotes around your search.<br /><br />";
                            }
                            Current_Mode.Error_Message = error_message;
                            Current_Mode.Caught_Exception = ee;
                        }

                        // If this was a special search, don't cache this
                        if (!special_search_type)
                        {
                            // Cache the search statistics, if it was needed
                            if ((need_search_statistics) && (Complete_Result_Set_Info != null))
                            {
                                Cached_Data_Manager.Store_Search_Result_Statistics(Current_Mode, actualCount, web_fields, terms, Complete_Result_Set_Info, Tracer);
                            }

                            // Cache the search results
                            if ((need_paged_results) && (pagesOfResults != null))
                            {
                                Cached_Data_Manager.Store_Search_Results(Current_Mode, sort, actualCount, web_fields, terms, pagesOfResults, Tracer);
                            }
                        }
                    }
                }
            }
        }
 /// <summary> Gets the HTML skin indicated in the current navigation mode </summary>
 /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
 /// <param name="Skin_Collection"> Collection of the most common skins and source information for all the skins made on the fly </param>
 /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
 /// <returns> Fully-built object used to "skin" this digital library </returns>
 public SobekCM_Skin_Object Get_HTML_Skin(SobekCM_Navigation_Object Current_Mode, SobekCM_Skin_Collection Skin_Collection, Custom_Tracer Tracer)
 {
     return Get_HTML_Skin(Current_Mode.Skin, Current_Mode, Skin_Collection, Tracer);
 }
        /// <summary> Gets the browse or info object and any other needed data for display ( resultset or text to display) </summary>
        /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
        /// <param name="Aggregation_Object"> Item Aggregation object</param>
        /// <param name="Base_Directory"> Base directory location under which the the CMS/info source file will be found</param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        /// <param name="Browse_Object"> [OUT] Stores all the information about this browse or info </param>
        /// <param name="Complete_Result_Set_Info"> [OUT] Information about the entire set of results </param>
        /// <param name="Paged_Results"> [OUT] List of search results for the requested page of results </param>
        /// <param name="Browse_Info_Display_Text"> [OUT] Static HTML-based content to be displayed if this is browing a staticly created html source file </param>
        /// <returns> TRUE if successful, otherwise FALSE </returns>
        /// <remarks> This attempts to pull the objects from the cache.  If unsuccessful, it builds the objects from the
        /// database and hands off to the <see cref="Cached_Data_Manager" /> to store in the cache </remarks>
        public bool Get_Browse_Info(SobekCM_Navigation_Object Current_Mode,
                                    Item_Aggregation Aggregation_Object,
                                    string Base_Directory,
                                    Custom_Tracer Tracer,
                                    out Item_Aggregation_Browse_Info Browse_Object,
                                    out Search_Results_Statistics Complete_Result_Set_Info,
                                    out List<iSearch_Title_Result> Paged_Results,
                                    out HTML_Based_Content Browse_Info_Display_Text )
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("SobekCM_Assistant.Get_Browse_Info", String.Empty);
            }

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

            // First, make sure the browse submode is valid
            if ((Aggregation_Object.Aggregation_ID == -1) && (Current_Mode.Mode == Display_Mode_Enum.Simple_HTML_CMS))
            {
                string source = Base_Directory + "design\\info";
                string[] matching_file = Directory.GetFiles(source, Current_Mode.Info_Browse_Mode + ".*");
                if (matching_file.Length > 0)
                {
                    Browse_Object = new Item_Aggregation_Browse_Info(Item_Aggregation_Browse_Info.Browse_Info_Type.Info, Item_Aggregation_Browse_Info.Source_Type.Static_HTML, Current_Mode.Info_Browse_Mode, matching_file[0], Current_Mode.Info_Browse_Mode);
                }
            }
            else
            {
                Browse_Object = Aggregation_Object.Get_Browse_Info_Object(Current_Mode.Info_Browse_Mode);
            }
            if (Browse_Object == null)
            {
                Current_Mode.Error_Message = "Unable to retrieve browse/info item '" + Current_Mode.Info_Browse_Mode + "'";
                return false;
            }

            // Is this a table result, or a string?
            switch (Browse_Object.Data_Type)
            {
                case Item_Aggregation_Browse_Info.Result_Data_Type.Table:

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

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

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

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

                        // Look to see if the paged results are available on any cache..
                        Paged_Results = Cached_Data_Manager.Retrieve_Browse_Results(Aggregation_Object.Code, browse_code, Current_Mode.Page, sort, Tracer);
                        if (Paged_Results != null)
                            need_paged_results = false;
                    }

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

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

                        // Get from the hierarchy object
                        if (Current_Mode.Writer_Type == Writer_Type_Enum.JSON)
                        {
                            Multiple_Paged_Results_Args returnArgs = SobekCM_Database.Get_Item_Aggregation_Browse_Paged(Current_Mode.Aggregation, "1900-01-01", false, 20, Current_Mode.Page, 0, need_browse_statistics, Aggregation_Object.Facets, need_browse_statistics, Tracer);
                            if (need_browse_statistics)
                            {
                                Complete_Result_Set_Info = returnArgs.Statistics;
                            }
                            pagesOfResults = returnArgs.Paged_Results;
                            if ((pagesOfResults != null) && (pagesOfResults.Count > 0))
                                Paged_Results = pagesOfResults[0];
                        }
                        else
                        {
                            Multiple_Paged_Results_Args returnArgs = Aggregation_Object.Get_Browse_Results(Browse_Object, Current_Mode.Page, sort, results_per_page, !special_search_type, need_browse_statistics, Tracer);
                            if (need_browse_statistics)
                            {
                                Complete_Result_Set_Info = returnArgs.Statistics;
                            }
                            pagesOfResults = returnArgs.Paged_Results;
                            if ((pagesOfResults != null) && (pagesOfResults.Count > 0))
                                Paged_Results = pagesOfResults[0];
                        }

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

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

                case Item_Aggregation_Browse_Info.Result_Data_Type.Text:
                    Browse_Info_Display_Text = Browse_Object.Get_Static_Content(Current_Mode.Language, Current_Mode.Base_URL, SobekCM_Library_Settings.Base_Design_Location + Aggregation_Object.objDirectory, Tracer);
                    break;
            }
            return true;
        }
        protected void Page_Load(object Sender, EventArgs E)
        {
            // Pull out the http request
            HttpRequest request = HttpContext.Current.Request;

            if (String.IsNullOrEmpty(SobekCM_Database.Connection_String))
            {
                Custom_Tracer tracer = new Custom_Tracer();
                try
                {

                    tracer.Add_Trace("SobekCM_Page_Globals.Constructor", String.Empty);

                    // Don't really need to *build* these, so just define them as a new ones if null
                    if (Global.Checked_List == null)
                        Global.Checked_List = new Checked_Out_Items_List();
                    if (Global.Search_History == null)
                        Global.Search_History = new Recent_Searches();

                    // Make sure all the needed data is loaded into the Application State
                    Application_State_Builder.Build_Application_State(tracer, false, ref Global.Skins, ref Global.Translation,
                                                                      ref Global.Codes, ref Global.Item_List, ref Global.Icon_List,
                                                                      ref Global.Stats_Date_Range, ref Global.Thematic_Headings, ref Global.Collection_Aliases, ref Global.IP_Restrictions,
                                                                      ref Global.URL_Portals, ref Global.Mime_Types, ref Global.Item_Viewer_Priority);

                    tracer.Add_Trace("SobekCM_Page_Globals.Constructor", "Application State validated or built");

                    // Check that something is saved for the original requested URL (may not exist if not forwarded)
                    if (!HttpContext.Current.Items.Contains("Original_URL"))
                        HttpContext.Current.Items["Original_URL"] = request.Url.ToString();
                }
                catch (Exception ee)
                {
                    // Send to the dashboard
                    if ((HttpContext.Current.Request.UserHostAddress == "127.0.0.1") || (HttpContext.Current.Request.UserHostAddress == HttpContext.Current.Request.ServerVariables["LOCAL_ADDR"]) || (HttpContext.Current.Request.Url.ToString().IndexOf("localhost") >= 0))
                    {
                        // Create an error message
                        string errorMessage;
                        if ((SobekCM_Library_Settings.Database_Connections.Count == 0) || (String.IsNullOrEmpty(SobekCM_Library_Settings.Database_Connections[0].Connection_String)))
                        {
                            errorMessage = "No database connection string found!";
                            string configFileLocation = AppDomain.CurrentDomain.BaseDirectory + "config/sobekcm.xml";
                            try
                            {
                                if (!File.Exists(configFileLocation))
                                {
                                    errorMessage = "Missing config/sobekcm.xml configuration file on the web server.<br />Ensure the configuration file 'sobekcm.xml' exists in a 'config' subfolder directly under the web application.<br />Example configuration is:" +
                                                   "<div style=\"background-color: #bbbbbb; margin-left: 30px; margin-top:10px; padding: 3px;\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;  ?&gt;<br /> &lt;configuration&gt;<br /> &nbsp; &nbsp &lt;connection_string type=&quot;MSSQL&quot;&gt;data source=localhost\\instance;initial catalog=SobekCM;integrated security=Yes;&lt;/connection_string&gt;<br /> &nbsp; &nbsp &lt;error_emails&gt;[email protected]&lt;/error_emails&gt;<br /> &nbsp; &nbsp &lt;error_page&gt;http://ufdc.ufl.edu/error.html&lt;/error_page&gt;<br />&lt;/configuration&gt;</div>";
                                }
                            }
                            catch
                            {
                                errorMessage = "No database connection string found.<br />Likely an error reading the configuration file due to permissions on the web server.<br />Ensure the configuration file 'sobekcm.xml' exists in a 'config' subfolder directly under the web application.<br />Example configuration is:" +
                                               "<div style=\"background-color: #bbbbbb; margin-left: 30px; margin-top:10px; padding: 3px;\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;  ?&gt;<br /> &lt;configuration&gt;<br /> &nbsp; &nbsp &lt;connection_string type=&quot;MSSQL&quot;&gt;data source=localhost\\instance;initial catalog=SobekCM;integrated security=Yes;&lt;/connection_string&gt;<br /> &nbsp; &nbsp &lt;error_emails&gt;[email protected]&lt;/error_emails&gt;<br /> &nbsp; &nbsp &lt;error_page&gt;http://ufdc.ufl.edu/error.html&lt;/error_page&gt;<br />&lt;/configuration&gt;</div>";
                            }
                        }
                        else
                        {
                            if (ee.Message.IndexOf("The EXECUTE permission") >= 0)
                            {
                                errorMessage = "Permissions error while connecting to the database and pulling necessary data.<br /><br />Confirm the following:<ul><li>IIS is configured correctly to use anonymous authentication</li><li>Anonymous user (or service account) is part of the sobek_users role in the database.</li></ul>";
                            }
                            else
                            {
                                errorMessage = "Error connecting to the database and pulling necessary data.<br /><br />Confirm the following:<ul><li>Database connection string is correct ( " + SobekCM_Library_Settings.Database_Connections[0].Connection_String + ")</li><li>IIS is configured correctly to use anonymous authentication</li><li>Anonymous user (or service account) is part of the sobek_users role in the database.</li></ul>";
                            }
                        }
                        // Wrap this into the SobekCM Exception
                        SobekCM_Traced_Exception newException = new SobekCM_Traced_Exception(errorMessage, ee, tracer);

                        // Save this to the session state, and then forward to the dashboard
                        HttpContext.Current.Session["Last_Exception"] = newException;
                        HttpContext.Current.Response.Redirect("dashboard.aspx", true);
                    }
                    else
                    {
                        throw ee;
                    }
                }
            }

            string bibID = null;
            string vid = null;

            // Is this a robot?  They should never get access to files this way
            if (SobekCM_Navigation_Object.Is_UserAgent_IP_Robot(request.UserAgent, request.UserHostAddress))
            {
                Response.Clear();
                Response.Output.WriteLine("RESTRICTED ITEM");
                return;
            }

            // Get any url rewrite which occurred
            if (Request.QueryString["urlrelative"] != null)
            {
                string urlrewrite = Request.QueryString["urlrelative"].ToLower();
                if (urlrewrite.Length > 4)
                {
                    // Split the url relative list
                    string[] url_relative_info = urlrewrite.Split("/".ToCharArray());
                    List<string> url_relative_list = (from thisPart in url_relative_info where thisPart.Length > 0 select thisPart.ToLower()).ToList();

                    // Now, look for BIBID and VID
                    //if ((SobekCM_Database.Verify_Item_Lookup_Object(true, ref Global.Item_List, null)) && (Global.Item_List.Contains_BibID(url_relative_list[2].ToUpper())))
                    if ((url_relative_list.Count > 2) && (url_relative_list[2].Length == 10))
                    {
                        // This is a BibID for an existing title with at least one public item
                        bibID = url_relative_list[2].ToUpper();

                        // Is the next part a VID?
                        if (url_relative_list.Count > 3)
                        {
                            string possible_vid = url_relative_list[3].Trim().PadLeft(5, '0');
                            int vid_as_int;
                            if (Int32.TryParse(possible_vid, out vid_as_int))
                                vid = possible_vid;
                        }
                    }

                    // Only continue if there is a BibID / VID
                    if ((!String.IsNullOrEmpty(bibID)) && (!String.IsNullOrEmpty(vid)))
                    {
                        // Determine the new URL
                        StringBuilder urlBuilder = new StringBuilder(SobekCM_Library_Settings.Image_Server_Network + bibID.Substring(0, 2) + "\\" + bibID.Substring(2, 2) + "\\" + bibID.Substring(4, 2) + "\\" + bibID.Substring(6, 2) + "\\" + bibID.Substring(8) + "\\" + vid + "\\" + url_relative_list[4], 250);
                        for (int i = 5; i < url_relative_list.Count; i++)
                        {
                            urlBuilder.Append("\\" + url_relative_list[i]);
                        }

                        file_url = urlBuilder.ToString();

                        // Get the extension
                        string extension = Path.GetExtension(file_url);
                        if (extension != null)
                        {
                            // Lookup the MIME type by extension
                            Mime_Type_Info mimeType = null;
                            if (Global.Mime_Types.ContainsKey(extension.ToLower()))
                                mimeType = Global.Mime_Types[extension.ToLower()];

                            if ((mimeType != null) && (!mimeType.isBlocked))
                            {
                                // Since everything is valid, check the database
                                bool isDark;
                                short restrictions;
                                SobekCM_Database.Get_Item_Restrictions(bibID, vid, null, out isDark, out restrictions);

                                // If not DARK, and is restricted, check for access here
                                if ((!isDark) && (restrictions > 0))
                                {
                                    // Does this user already have IP restriction mask determined?
                                    // Determine which IP Ranges this IP address belongs to, if not already determined.

                                    if (HttpContext.Current.Session["IP_Range_Membership"] == null)
                                    {
                                        int ip_mask = Global.IP_Restrictions.Restrictive_Range_Membership(request.UserHostAddress);
                                        HttpContext.Current.Session["IP_Range_Membership"] = ip_mask;
                                    }

                                    int current_user_mask = Convert.ToInt32(HttpContext.Current.Session["IP_Range_Membership"]);

                                    // Perform bitwise comparison
                                    int comparison = restrictions & current_user_mask;
                                    if (comparison == 0)
                                    {
                                        // If the user is Shibboleth authenticated, that is okay
                                        User_Object possible_user = HttpContext.Current.Session["user"] as User_Object;
                                        if (( possible_user == null ) || ( possible_user.Authentication_Type != User_Authentication_Type_Enum.Shibboleth ))
                                            isDark = true;
                                    }
                                }

                                if (!isDark)
                                {
                                    // Should this be forwarded for this mimetype?
                                    if (mimeType.shouldForward)
                                    {
                                        StringBuilder forwardBuilder = new StringBuilder(SobekCM_Library_Settings.Image_URL + bibID.Substring(0, 2) + "/" + bibID.Substring(2, 2) + "/" + bibID.Substring(4, 2) + "/" + bibID.Substring(6, 2) + "/" + bibID.Substring(8) + "/" + vid + "/" + url_relative_list[4], 250);
                                        for (int i = 5; i < url_relative_list.Count; i++)
                                        {
                                            forwardBuilder.Append("/" + url_relative_list[i]);
                                        }
                                        Response.Redirect(forwardBuilder.ToString());
                                    }
                                    else
                                    {
                                        Response.Clear();
                                        Response.ContentType = mimeType.MIME_Type;

                                        string filename = file_url;

                                        if (File.Exists(filename))
                                        {
                                            using (FileStream sourceStream = File.OpenRead(filename))
                                            {
                                                sourceStream.CopyTo(Response.OutputStream, 32768);
                                            }
                                        }

                                        Response.End();
                                    }
                                }
                                else
                                {
                                    Response.Clear();
                                    Response.Output.WriteLine("RESTRICTED ITEM");
                                }
                            }
                        }
                    }
                }
            }

            //public static async Task CopyToAsync(this Stream source, Stream destination)
            //{
            //    int i = 0;
            //    var buffers = new [] { new byte[0x1000], new byte[0x1000] };
            //    Task writeTask = null;
            //    while(true)
            //    {
            //        var readTask = source.ReadAsync(buffers[i], 0, buffers[i].Length))>0;
            //        if (writeTask != null) await Task.WhenAll(readTask, writeTask);
            //        int bytesRead = await readTask;
            //        if (bytesRead == 0) break;
            //        writeTask = destination.WriteAsync(buffers[i], 0, bytesRead);
            //        i ^= 1; // swap buffers
            //    }
            //}
        }