/// <summary> Constructor for a new instance of the Xml_MainWriter class </summary>
 /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
 /// <param name="Hierarchy_Object"> Current item aggregation object to display </param>
 /// <param name="Results_Statistics"> Information about the entire set of results for a search or browse </param>
 /// <param name="Paged_Results"> Single page of results for a search or browse, within the entire set </param>
 /// <param name="Browse_Object"> Object contains all the basic information about any browse or info display </param>
 /// <param name="Current_Item"> Current item to display </param>
 /// <param name="Current_Page"> Current page within the item</param>
 public Xml_MainWriter(SobekCM_Navigation_Object Current_Mode, 
     Item_Aggregation Hierarchy_Object,
     Search_Results_Statistics Results_Statistics,
     List<iSearch_Title_Result> Paged_Results,
     Item_Aggregation_Browse_Info Browse_Object,
     SobekCM_Item Current_Item,
     Page_TreeNode Current_Page)
     : base(Current_Mode, Hierarchy_Object, Results_Statistics, Paged_Results, Browse_Object, Current_Item, Current_Page, null)
 {
 }
 /// <summary> Constructor for a new instance of the Dataset_MainWriter class </summary>
 /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
 /// <param name="Hierarchy_Object"> Current item aggregation object to display </param>
 /// <param name="Results_Statistics"> Information about the entire set of results for a search or browse </param>
 /// <param name="Paged_Results"> Single page of results for a search or browse, within the entire set </param>
 /// <param name="Browse_Object"> Object contains all the basic information about any browse or info display </param>
 /// <param name="Current_Item"> Current item to display </param>
 /// <param name="Current_Page"> Current page within the item</param>
 public Dataset_MainWriter(SobekCM_Navigation_Object Current_Mode,
     Item_Aggregation Hierarchy_Object,
     Search_Results_Statistics Results_Statistics,
     List<iSearch_Title_Result> Paged_Results,
     Item_Aggregation_Child_Page Browse_Object,
     SobekCM_Item Current_Item,
     Page_TreeNode Current_Page)
     : base(Current_Mode, Hierarchy_Object, Results_Statistics, Paged_Results, Browse_Object,  Current_Item, Current_Page, null)
 {
     // All work done in base class
 }
 /// <summary> Constructor for a new instance of the Text_MainWriter class </summary>
 /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
 /// <param name="Hierarchy_Object"> Current item aggregation object to display </param>
 /// <param name="Results_Statistics"> Information about the entire set of results for a search or browse </param>
 /// <param name="Paged_Results"> Single page of results for a search or browse, within the entire set </param>
 /// <param name="Browse_Object"> Object contains all the basic information about any browse or info display </param>
 /// <param name="Current_Item"> Current item to display </param>
 /// <param name="Current_Page"> Current page within the item</param>
 /// <param name="Static_Web_Content"> HTML content-based browse, info, or imple CMS-style web content objects.  These are objects which are read from a static HTML file and much of the head information must be maintained </param>
 public Text_MainWriter(SobekCM_Navigation_Object Current_Mode,
      Item_Aggregation Hierarchy_Object,
     Search_Results_Statistics Results_Statistics,
     List<iSearch_Title_Result> Paged_Results,
     Item_Aggregation_Browse_Info Browse_Object,
     SobekCM_Item Current_Item,
     Page_TreeNode Current_Page,
     HTML_Based_Content Static_Web_Content)
     : base(Current_Mode, Hierarchy_Object, Results_Statistics, Paged_Results, Browse_Object, Current_Item, Current_Page, Static_Web_Content)
 {
     // All work done in base class
 }
 /// <summary> Constructor for a new instance of the Search_Results_HtmlSubwriter class </summary>
 /// <param name="Results_Statistics"> Information about the entire set of results for a search or browse </param>
 /// <param name="Paged_Results"> Single page of results for a search or browse, within the entire set </param>
 /// <param name="Code_Manager"> List of valid collection codes, including mapping from the Sobek collections to Greenstone collections</param>
 /// <param name="Translator"> Language support object which handles simple translational duties </param>
 /// <param name="All_Items_Lookup"> Lookup object used to pull basic information about any item loaded into this library </param>
 /// <param name="Current_User"> Currently logged on user </param>
 public Search_Results_HtmlSubwriter(Search_Results_Statistics Results_Statistics,
     List<iSearch_Title_Result> Paged_Results,
     Aggregation_Code_Manager Code_Manager, Language_Support_Info Translator,
     Item_Lookup_Object All_Items_Lookup, 
     User_Object Current_User)
 {
     currentUser = Current_User;
     pagedResults = Paged_Results;
     resultsStatistics = Results_Statistics;
     translations = Translator;
     codeManager = Code_Manager;
     allItemsTable = All_Items_Lookup;
 }
 /// <summary> Constructor for a new instance of the Json_MainWriter class </summary>
 /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
 /// <param name="Hierarchy_Object"> Current item aggregation object to display </param>
 /// <param name="Results_Statistics"> Information about the entire set of results for a search or browse </param>
 /// <param name="Paged_Results"> Single page of results for a search or browse, within the entire set </param>
 /// <param name="Browse_Object"> Object contains all the basic information about any browse or info display </param>
 /// <param name="Current_Item"> Current item to display </param>
 /// <param name="Current_Page"> Current page within the item</param>
 /// <param name="All_Items_Lookup"> Lookup object used to pull basic information about any item loaded into this library </param>
 /// <param name="Current_Image_Root"> Current root directory to pull images and metadata for digital resources </param>
 public Json_MainWriter(SobekCM_Navigation_Object Current_Mode,
     Item_Aggregation Hierarchy_Object,
     Search_Results_Statistics Results_Statistics,
     List<iSearch_Title_Result> Paged_Results,
     Item_Aggregation_Browse_Info Browse_Object,
     SobekCM_Item Current_Item,
     Page_TreeNode Current_Page,
     Item_Lookup_Object All_Items_Lookup,
     string Current_Image_Root)
     : base(Current_Mode, Hierarchy_Object, Results_Statistics, Paged_Results, Browse_Object,   Current_Item, Current_Page, null)
 {
     allItems = All_Items_Lookup;
     currentGreenstoneImageRoot = Current_Image_Root;
 }
 /// <summary> Constructor for a new instance of the DataSet_Browse_Info_AggregationViewer class </summary>
 /// <param name="Browse_Object"> Browse or information object to be displayed </param>
 /// <param name="Results_Statistics"> Information about the entire set of results for a search or browse </param>
 /// <param name="Paged_Results"> Single page of results for a search or browse, within the entire set </param>
 /// <param name="Code_Manager"> Code manager object maintains mapping between SobekCM codes and greenstone codes (used by result_dataset_html_subwriter)</param>
 /// <param name="Item_List"> Object for pulling additional information about each item during display </param>
 /// <param name="Current_User"> Currently logged on user, or NULL </param>
 public DataSet_Browse_Info_AggregationViewer(Item_Aggregation_Browse_Info Browse_Object,
     Search_Results_Statistics Results_Statistics,
     List<iSearch_Title_Result> Paged_Results,
     Aggregation_Code_Manager Code_Manager,
     Item_Lookup_Object Item_List,
     User_Object Current_User)
     : base(null, null)
 {
     browseObject = Browse_Object;
     codeManager = Code_Manager;
     itemList = Item_List;
     currentUser = Current_User;
     resultsStatistics = Results_Statistics;
     pagedResults = Paged_Results;
 }
 /// <summary> Constructor for a new instance of the abstractMainWriter abstract class </summary>
 /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
 /// <param name="Hierarchy_Object"> Current item aggregation object to display </param>
 /// <param name="Results_Statistics"> Information about the entire set of results for a search or browse </param>
 /// <param name="Paged_Results"> Single page of results for a search or browse, within the entire set </param>
 /// <param name="Browse_Object"> Object contains all the basic information about any browse or info display </param>
 /// <param name="Current_Item"> Current item to display </param>
 /// <param name="Current_Page"> Current page within the item</param>
 /// <param name="Static_Web_Content"> HTML content-based browse, info, or imple CMS-style web content objects.  These are objects which are read from a static HTML file and much of the head information must be maintained </param>
 protected abstractMainWriter(SobekCM_Navigation_Object Current_Mode,
     Item_Aggregation Hierarchy_Object,
     Search_Results_Statistics Results_Statistics,
     List<iSearch_Title_Result> Paged_Results,
     Item_Aggregation_Child_Page Browse_Object,
     SobekCM_Item Current_Item,
     Page_TreeNode Current_Page,
     HTML_Based_Content Static_Web_Content )
 {
     currentMode = Current_Mode;
     hierarchyObject = Hierarchy_Object;
     results_statistics = Results_Statistics;
     paged_results = Paged_Results;
     thisBrowseObject = Browse_Object;
     currentItem = Current_Item;
     currentPage = Current_Page;
     htmlBasedContent = Static_Web_Content;
 }
        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;
                }
            }
        }
        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;
        }
        /// <summary> Gets the collection of all (public) items linked to an item aggregation </summary>
        /// <param name="AggregationCode"> Code for the item aggregation of interest </param>
        /// <param name="Since_Date"> Date from which to pull the data </param>
        /// <param name="Include_Private_Items"> Flag indicates whether to include private items in the result set </param>
        /// <param name="ResultsPerPage"> Number of results to return per "page" of results </param>
        /// <param name="ResultsPage"> Which page of results to return ( one-based, so the first page is page number of one )</param>
        /// <param name="Sort"> Current sort to use ( 0 = default by search or browse, 1 = title, 10 = date asc, 11 = date desc )</param>
        /// <param name="Include_Facets"> Flag indicates if facets should be included in the final result set</param>
        /// <param name="Facet_Types"> Primary key for the metadata types to include as facets (up to eight)</param>
        /// <param name="Return_Search_Statistics"> Flag indicates whether to create and return statistics about the overall search results, generally set to TRUE for the first page requested and subsequently set to FALSE </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering</param>
        /// <returns> Table with all of the item and item group information </returns>
        /// <remarks> This calls the 'SobekCM_Get_Aggregation_Browse_Paged' stored procedure </remarks>
        public static Multiple_Paged_Results_Args Get_Item_Aggregation_Browse_Paged(string AggregationCode, string Since_Date, bool Include_Private_Items, int ResultsPerPage, int ResultsPage, int Sort, bool Include_Facets, List<short> Facet_Types, bool Return_Search_Statistics, Custom_Tracer Tracer)
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("SobekCM_Database.Get_Item_Aggregation_Browse_Paged", "Pulling browse from database");
            }

            Multiple_Paged_Results_Args returnArgs;

            // Create the connection
            using (SqlConnection connect = new SqlConnection(connectionString + "Connection Timeout=45"))
            {

                // Create the command
                SqlCommand executeCommand = new SqlCommand("SobekCM_Get_Aggregation_Browse_Paged2", connect)
                                                {CommandTimeout = 45, CommandType = CommandType.StoredProcedure};

                executeCommand.Parameters.AddWithValue("@code", AggregationCode);
                executeCommand.Parameters.AddWithValue("@date", Since_Date);
                executeCommand.Parameters.AddWithValue("@include_private", Include_Private_Items);
                executeCommand.Parameters.AddWithValue("@pagesize", ResultsPerPage);
                executeCommand.Parameters.AddWithValue("@pagenumber", ResultsPage);
                executeCommand.Parameters.AddWithValue("@sort", Sort);

                if (ResultsPerPage > 100)
                {
                    executeCommand.Parameters.AddWithValue("@minpagelookahead", 1);
                    executeCommand.Parameters.AddWithValue("@maxpagelookahead", 1);
                    executeCommand.Parameters.AddWithValue("@lookahead_factor", LOOKAHEAD_FACTOR);
                }
                else
                {
                    executeCommand.Parameters.AddWithValue("@minpagelookahead", MIN_PAGE_LOOKAHEAD);
                    executeCommand.Parameters.AddWithValue("@maxpagelookahead", MAX_PAGE_LOOKAHEAD);
                    executeCommand.Parameters.AddWithValue("@lookahead_factor", LOOKAHEAD_FACTOR);
                }

                if ((Include_Facets) && (Facet_Types != null))
                {
                    executeCommand.Parameters.AddWithValue("@include_facets", true);
                    if (Facet_Types.Count > 0)
                        executeCommand.Parameters.AddWithValue("@facettype1", Facet_Types[0]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype1", -1);
                    if (Facet_Types.Count > 1)
                        executeCommand.Parameters.AddWithValue("@facettype2", Facet_Types[1]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype2", -1);
                    if (Facet_Types.Count > 2)
                        executeCommand.Parameters.AddWithValue("@facettype3", Facet_Types[2]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype3", -1);
                    if (Facet_Types.Count > 3)
                        executeCommand.Parameters.AddWithValue("@facettype4", Facet_Types[3]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype4", -1);
                    if (Facet_Types.Count > 4)
                        executeCommand.Parameters.AddWithValue("@facettype5", Facet_Types[4]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype5", -1);
                    if (Facet_Types.Count > 5)
                        executeCommand.Parameters.AddWithValue("@facettype6", Facet_Types[5]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype6", -1);
                    if (Facet_Types.Count > 6)
                        executeCommand.Parameters.AddWithValue("@facettype7", Facet_Types[6]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype7", -1);
                    if (Facet_Types.Count > 7)
                        executeCommand.Parameters.AddWithValue("@facettype8", Facet_Types[7]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype8", -1);
                }
                else
                {
                    executeCommand.Parameters.AddWithValue("@include_facets", false);
                    executeCommand.Parameters.AddWithValue("@facettype1", -1);
                    executeCommand.Parameters.AddWithValue("@facettype2", -1);
                    executeCommand.Parameters.AddWithValue("@facettype3", -1);
                    executeCommand.Parameters.AddWithValue("@facettype4", -1);
                    executeCommand.Parameters.AddWithValue("@facettype5", -1);
                    executeCommand.Parameters.AddWithValue("@facettype6", -1);
                    executeCommand.Parameters.AddWithValue("@facettype7", -1);
                    executeCommand.Parameters.AddWithValue("@facettype8", -1);
                }
                executeCommand.Parameters.AddWithValue("@item_count_to_use_cached", 1000);

                // Add parameters for total items and total titles
                SqlParameter totalItemsParameter = executeCommand.Parameters.AddWithValue("@total_items", 0);
                totalItemsParameter.Direction = ParameterDirection.InputOutput;

                SqlParameter totalTitlesParameter = executeCommand.Parameters.AddWithValue("@total_titles", 0);
                totalTitlesParameter.Direction = ParameterDirection.InputOutput;

                // Create the data reader
                connect.Open();
                using (SqlDataReader reader = executeCommand.ExecuteReader())
                {

                    // Create the return argument object
                    List<string> metadataLabels = new List<string>();
                    returnArgs = new Multiple_Paged_Results_Args { Paged_Results = DataReader_To_Result_List_With_LookAhead2(reader, ResultsPerPage, metadataLabels) };

                    // Create the overall search statistics?
                    if (Return_Search_Statistics)
                    {
                        Search_Results_Statistics stats = new Search_Results_Statistics(reader, Facet_Types, metadataLabels);
                        returnArgs.Statistics = stats;
                        reader.Close();
                        stats.Total_Items = Convert.ToInt32(totalItemsParameter.Value);
                        stats.Total_Titles = Convert.ToInt32(totalTitlesParameter.Value);
                    }
                    else
                    {
                        reader.Close();
                    }
                }
                connect.Close();
            }

            // Return the built result arguments
            return returnArgs;
        }
        /// <summary> Stores a (assumed private) user's folder browse into the cache or caching server </summary>
        /// <param name="User_ID"> Primary key for the user </param>
        /// <param name="Folder_Name"> Name of the folder to store </param>
        /// <param name="StoreObject"> Object to store  </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering</param>
        public static void Store_User_Folder_Browse_Statistics(int User_ID, string Folder_Name, Search_Results_Statistics StoreObject, Custom_Tracer Tracer)
        {
            // If the cache is disabled, just return before even tracing
            if (Disabled)
                return;

            string key = "USER_FOLDER_" + User_ID + "_" + Folder_Name.ToLower() + "_STATISTICS";

            if (Tracer != null)
            {
                Tracer.Add_Trace("Cached_Data_Manager.Store_User_Folder_Browse_Statistics", "Adding object '" + key + "' to the cache with expiration of 1 minute");
            }

            if (HttpContext.Current.Cache[key] == null)
            {
                HttpContext.Current.Cache.Insert(key, StoreObject, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(1));
            }
        }
        /// <summary> Stores the table of search results to the cache or caching server </summary>
        /// <param name="Aggregation_Code"> Aggregation code for the browse statistics to store in the cache </param>
        /// <param name="Browse_Name"> Name of the browse to store the browse statistics in the cache</param>
        /// <param name="StoreObject"> Search results item/title list </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering</param>
        public static void Store_Browse_Result_Statistics(string Aggregation_Code, string Browse_Name, Search_Results_Statistics StoreObject, Custom_Tracer Tracer)
        {
            // If the cache is disabled, just return before even tracing
            if (Disabled)
                return;

            // Determine the key
            string key = "TOTALBROWSE_" + Aggregation_Code.ToUpper() + "_" + Browse_Name.ToUpper();

            // try to store in the caching server, if enabled
            if (caching_serving_enabled)
            {
                if (Tracer != null)
                {
                    Tracer.Add_Trace("Cached_Data_Manager.Store_Browse_Result_Statistics", "Adding object '" + key + "' to the caching server");
                }

                if (AppFabric_Manager.Add(key, StoreObject, Tracer))
                    return;
            }

            // Store this on the local cache, if not there and storing on the cache server failed
            if (HttpContext.Current.Cache[key] == null)
            {
                if (Tracer != null)
                {
                    Tracer.Add_Trace("Cached_Data_Manager.Store_Browse_Result_Statistics", "Adding object '" + key + "' to the local cache with expiration of 3 minutes");
                }

                HttpContext.Current.Cache.Insert(key, StoreObject, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(3));
            }
        }
        /// <summary> Constructor for a new instance of the Folder_Mgmt_MySobekViewer class </summary>
        /// <param name="User"> Authenticated user information </param>
        /// <param name="Results_Statistics"> Information about the entire set of results for the current folder </param>
        /// <param name="Paged_Results"> Single page of results for the current folder, within the entire set </param>
        /// <param name="Code_Manager"> Code manager object maintains mapping between SobekCM codes and greenstone codes (used by result_dataset_html_subwriter)</param>
        /// <param name="Item_List"> Object for pulling additional information about each item during display </param>
        /// <param name="currentCollection"> Current item aggregation [UNUSED?] </param>
        /// <param name="htmlSkin"> HTML interface, which determines the header, footer, stylesheet, and other design elements for the rendered HTML</param>
        /// <param name="Translator"> Translation / language support object for writing the user interface is multiple languages</param>
        /// <param name="currentMode"> 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>
        public Folder_Mgmt_MySobekViewer(User_Object User,
            Search_Results_Statistics Results_Statistics,
            List<iSearch_Title_Result> Paged_Results,
            Aggregation_Code_Manager Code_Manager,
            Item_Lookup_Object Item_List,
            Item_Aggregation currentCollection, 
            SobekCM_Skin_Object htmlSkin,
            Language_Support_Info Translator, 
            SobekCM_Navigation_Object currentMode,
            Custom_Tracer Tracer)
            : base(User)
        {
            Tracer.Add_Trace("Folder_Mgmt_MySobekViewer.Constructor", String.Empty);

            user = User;
            pagedResults = Paged_Results;
            resultsStatistics = Results_Statistics;
            codeManager = Code_Manager;
            itemList = Item_List;
            this.htmlSkin = htmlSkin;
            base.Translator = Translator;
            this.currentCollection = currentCollection;

            properFolderName = String.Empty;
            int current_folder_id = -1;
            if (currentMode.My_Sobek_SubMode.Length > 0)
            {
                // Try to get this user folder from the user object
                User_Folder userFolder = user.Get_Folder( currentMode.My_Sobek_SubMode );

                // If the user folder is null, then this folder is not in the current user object
                // This may still be a valid folder though.  Check this by pulling folder list for this
                // user again
                if (userFolder == null)
                {
                    // Get the user from the database again
                    User_Object checkFolderUser = SobekCM_Database.Get_User(user.UserID, Tracer);

                    // Look for this folder in the new user object
                    userFolder = checkFolderUser.Get_Folder(currentMode.My_Sobek_SubMode);
                    if (userFolder == null)
                    {
                        // Invalid folder.. should not have gotten this far though
                        HttpContext.Current.Response.Redirect(currentMode.Base_URL);
                    }
                    else
                    {
                        // Save this to the user so this does not have to happen again
                        user.Add_Folder(userFolder);
                    }
                }

                // Get the proper name and folder id
                Debug.Assert(userFolder != null, "userFolder != null");
                properFolderName = userFolder.Folder_Name;
                current_folder_id = userFolder.Folder_ID;
            }

            if ((currentMode.isPostBack) || ((HttpContext.Current.Request.Form["item_action"] != null) && (HttpContext.Current.Request.Form["item_action"].Length > 0 )))
            {
                try
                {
                    // Pull the standard values
                    NameValueCollection form = HttpContext.Current.Request.Form;

                    string item_action = form["item_action"].Replace(",","").ToUpper().Trim();
                    string bookshelf_items = form["bookshelf_items"].Trim().Replace("%22", "\"").Replace("%27", "'").Replace("%3D", "=").Replace("%26", "&");
                    string bookshelf_params = form["bookshelf_params"].Trim();
                    string add_bookshelf = String.Empty;
                    if ( form["add_bookshelf"] != null )
                        add_bookshelf = form["add_bookshelf"].Trim();

                    if (item_action == "REFRESH_FOLDER")
                    {
                         refresh_user_folders(user, Tracer);
                         Cached_Data_Manager.Remove_All_User_Folder_Browses(user.UserID, Tracer);
                    }

                    if (item_action == "DELETE_FOLDER")
                    {
                        int folder_id = Convert.ToInt32(bookshelf_items);

                        SobekCM_Database.Delete_User_Folder(user.UserID, folder_id, Tracer);
                        Cached_Data_Manager.Clear_Public_Folder_Info(folder_id, Tracer);
                        refresh_user_folders(user, Tracer);
                    }

                    if (item_action == "NEW_BOOKSHELF")
                    {
                        string folder_name = form["new_bookshelf_name"].Trim().Replace("<", "(").Replace(">", ")");
                        int parent_id = Convert.ToInt32(form["new_bookshelf_parent"]);

                        if (SobekCM_Database.Edit_User_Folder(-1, user.UserID, parent_id, folder_name, false, String.Empty, Tracer) > 0)
                        {
                            refresh_user_folders(user, Tracer);
                        }
                    }

                    if ( item_action == "FOLDER_VISIBILITY" )
                    {
                        User_Folder thisFolder = user.Get_Folder(bookshelf_items);
                        if (bookshelf_params.ToUpper() == "PRIVATE")
                        {
                            if (SobekCM_Database.Edit_User_Folder(thisFolder.Folder_ID, user.UserID, -1, thisFolder.Folder_Name, false, String.Empty, Tracer) >= 0)
                                thisFolder.isPublic = false;

                            Cached_Data_Manager.Clear_Public_Folder_Info(thisFolder.Folder_ID, Tracer);
                        }

                        if (bookshelf_params.ToUpper() == "PUBLIC")
                        {
                            if (SobekCM_Database.Edit_User_Folder(thisFolder.Folder_ID, user.UserID, -1, thisFolder.Folder_Name, true, String.Empty, Tracer) >= 0 )
                                thisFolder.isPublic = true;
                        }
                    }

                    if ((item_action == "REMOVE") || ( item_action == "MOVE" ))
                    {
                        if (bookshelf_items.IndexOf("|") > 0)
                        {
                            string[] split_multi_items = bookshelf_items.Split("|".ToCharArray());
                            foreach (string[] split in split_multi_items.Select(thisItem => thisItem.Split("_".ToCharArray())).Where(split => split.Length == 2))
                            {
                                SobekCM_Database.Delete_Item_From_User_Folder(user.UserID, properFolderName, split[0], split[1], Tracer);
                                if (item_action == "MOVE")
                                {
                                    SobekCM_Database.Add_Item_To_User_Folder(user.UserID, add_bookshelf, split[0], split[1], 0, String.Empty, Tracer);
                                }
                            }

                            // Ensure this user folder is not sitting in the cache
                            Cached_Data_Manager.Remove_User_Folder_Browse(user.UserID, properFolderName, Tracer);
                            Cached_Data_Manager.Clear_Public_Folder_Info(current_folder_id, Tracer);
                            if (item_action == "MOVE")
                            {
                                Cached_Data_Manager.Remove_User_Folder_Browse(user.UserID, add_bookshelf, Tracer);
                                User_Folder moved_to_folder = user.Get_Folder(add_bookshelf);
                                if (moved_to_folder != null)
                                {
                                    Cached_Data_Manager.Clear_Public_Folder_Info(moved_to_folder.Folder_ID, Tracer);
                                }
                            }
                        }
                        else
                        {
                                string[] split = bookshelf_items.Split("_".ToCharArray());
                                if (split.Length == 2)
                                {
                                    SobekCM_Database.Delete_Item_From_User_Folder(user.UserID, properFolderName, split[0], split[1], Tracer);
                                    if (item_action == "MOVE")
                                    {
                                        SobekCM_Database.Add_Item_To_User_Folder(user.UserID, add_bookshelf, split[0], split[1], 1, String.Empty, Tracer);
                                    }
                                }

                            // Ensure this user folder is not sitting in the cache
                            Cached_Data_Manager.Remove_User_Folder_Browse(user.UserID, properFolderName, Tracer);
                            Cached_Data_Manager.Clear_Public_Folder_Info(current_folder_id, Tracer);
                            if (item_action == "MOVE")
                            {
                                Cached_Data_Manager.Remove_User_Folder_Browse(user.UserID, add_bookshelf, Tracer);
                                User_Folder moved_to_folder = user.Get_Folder(add_bookshelf);
                                if (moved_to_folder != null)
                                {
                                    Cached_Data_Manager.Clear_Public_Folder_Info(moved_to_folder.Folder_ID, Tracer);
                                }
                            }
                        }
                    }

                    if ( item_action == "EMAIL" )
                    {
                        string comments = form["email_comments"].Trim().Replace(">",")").Replace("<","(");
                        string email = form["email_address"].Trim();
                        string format = HttpContext.Current.Request.Form["email_format"].Trim().ToUpper();

                            string[] split = bookshelf_items.Split("_".ToCharArray());
                            if (split.Length == 2)
                            {
                                SobekCM_Assistant newAssistant = new SobekCM_Assistant();
                                SobekCM_Item newItem;
                                Page_TreeNode newPage;
                                SobekCM_Items_In_Title itemsInTitle;
                                newAssistant.Get_Item(currentMode, Item_List, SobekCM_Library_Settings.Image_URL, null, user, Tracer, out newItem, out newPage, out itemsInTitle );
                                SobekCM_Database.Add_Item_To_User_Folder(user.UserID, add_bookshelf, split[0], split[1], 1, comments, Tracer);

                                // Determine the email format
                                bool is_html_format = (format != "TEXT");

                                // Send this email
                                Item_Email_Helper.Send_Email(email, String.Empty, comments, user.Full_Name, currentMode.SobekCM_Instance_Abbreviation, newItem, is_html_format, currentMode.Base_URL + newItem.BibID + "/" + newItem.VID);
                            }
                    }

                    if ( item_action == "EDIT_NOTES" )
                    {
                        string notes = form["add_notes"].Trim().Replace(">",")").Replace("<","(");

                            string[] split = bookshelf_items.Split("_".ToCharArray());
                            if (split.Length == 2)
                            {
                                SobekCM_Database.Add_Item_To_User_Folder(user.UserID, add_bookshelf, split[0], split[1], 1, notes, Tracer);
                                Cached_Data_Manager.Remove_User_Folder_Browse(user.UserID, add_bookshelf, Tracer);
                            }

                    }
                }
                catch(Exception)
                {
                    // Catches any errors which may occur.  User will be sent back to the same URL,
                    // so any error that occurs should be obvious to the user
                }

                string return_url = HttpContext.Current.Items["Original_URL"].ToString();
                HttpContext.Current.Response.Redirect(return_url, false);

            }
        }
        /// <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> Perform an search for documents with matching parameters </summary>
        /// <param name="AggregationCode"> Aggregation code within which to search </param>
        /// <param name="QueryString"> Quert string for the actual search to perform aggainst the Solr/Lucene engine </param>
        /// <param name="ResultsPerPage"> Number of results to display per a "page" of results </param>
        /// <param name="Page_Number"> Which page of results to return ( one-based, so the first page is page number of one )</param>
        /// <param name="Sort"> Sort to apply before returning the results of the search </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> Page search result object with all relevant result information </returns>
        public static bool Search(string AggregationCode, string QueryString, int ResultsPerPage, int Page_Number, ushort Sort, Custom_Tracer Tracer, out Search_Results_Statistics Complete_Result_Set_Info, out List<iSearch_Title_Result> Paged_Results)
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("Solr_Documents_Searcher.Search", String.Empty);
            }

            // Set output initially to null
            Paged_Results = new List<iSearch_Title_Result>();
            Complete_Result_Set_Info = null;

            try
            {
                // Ensure page is not erroneously set to zero or negative
                if (Page_Number <= 0)
                    Page_Number = 1;

                // Create the solr worker to query the document index
                var solrWorker = Solr_Operations_Cache<Solr_Document_Result>.GetSolrOperations(SobekCM_Library_Settings.Document_Solr_Index_URL);

                // Create the query options
                QueryOptions options = new QueryOptions
                                           {
                                               Rows = ResultsPerPage,
                                               Start = (Page_Number - 1) * ResultsPerPage,
                                               Fields = new[] { "did", "score","url","aleph","donor","edition","format","holdinglocation","sourceinstitution","maintitle","materialtype","oclc","pubdate_display","author_display","publisher_display","mainthumbnail"  },
                                               Highlight = new HighlightingParameters { Fields = new[] { "fulltext" }, },
                                               ExtraParams = new Dictionary<string, string> { { "hl.useFastVectorHighlighter", "true" } }
                                           };

                // Set the sort value
                if (Sort != 0)
                {
                    options.OrderBy.Clear();
                    switch (Sort)
                    {
                        case 1:
                            options.OrderBy.Add(new SortOrder("maintitle_sort"));
                            break;

                        case 2:
                            options.OrderBy.Add(new SortOrder("bibid", Order.ASC) );
                            break;

                        case 3:
                            options.OrderBy.Add(new SortOrder("bibid", Order.DESC));
                            break;

                        case 10:
                            options.OrderBy.Add(new SortOrder("pubdate", Order.ASC));
                            break;

                        case 11:
                            options.OrderBy.Add(new SortOrder("pubdate", Order.DESC));
                            break;

                    }
                }

                // If there was an aggregation code included, put that at the beginning of the search
                if ((AggregationCode.Length > 0) && (AggregationCode.ToUpper() != "ALL"))
                {
                    QueryString = "(aggregation_code:" + AggregationCode.ToUpper() + ")AND(" + QueryString + ")";
                }

                // Perform this search
                SolrQueryResults<Solr_Document_Result> results = solrWorker.Query(QueryString, options);

                // Create the search statistcs
                List<string> metadataLabels = new List<string> {"Author", "Publisher", "Format", "Edition", "Institution", "Donor"};

                Complete_Result_Set_Info = new Search_Results_Statistics(metadataLabels)
                                               {
                                                   Total_Titles = results.NumFound,
                                                   Total_Items = results.NumFound,
                                                   QueryTime = results.Header.QTime
                                               };

                // Pass all the results into the List and add the highlighted text to each result as well
                foreach (Solr_Document_Result thisResult in results)
                {
                    // Add the highlight snipper
                    if ((results.Highlights.ContainsKey(thisResult.DID)) && (results.Highlights[thisResult.DID].Count > 0) && (results.Highlights[thisResult.DID].ElementAt(0).Value.Count > 0))
                    {
                        thisResult.Snippet = results.Highlights[thisResult.DID].ElementAt(0).Value.ElementAt(0);
                    }

                    // Add this results
                    Paged_Results.Add(thisResult);
                }

                return true;
            }
            catch ( Exception ee )
            {
                return false;
            }
        }
        /// <summary> Constructor for a new instance of the Admin_HtmlSubwriter class </summary>
        /// <param name="Results_Statistics"> Information about the entire set of results for a browse of a user's bookshelf folder </param>
        /// <param name="Paged_Results"> Single page of results for a browse of a user's bookshelf folder, within the entire set </param>
        /// <param name="Code_Manager"> List of valid collection codes, including mapping from the Sobek collections to Greenstone collections</param>
        /// <param name="All_Items_Lookup"> Lookup object used to pull basic information about any item loaded into this library </param>
        /// <param name="Hierarchy_Object"> Current item aggregation object to display </param>
        /// <param name="HTML_Skin"> HTML Web skin which controls the overall appearance of this digital library </param>
        /// <param name="Translator"> Language support object which handles simple translational duties </param>
        /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
        /// <param name="Current_Item">Current item to edit, if the user is requesting to edit an item</param>
        /// <param name="Aggregation_Aliases"> List of all existing aliases for existing aggregations </param>
        /// <param name="Web_Skin_Collection"> Collection of all the web skins </param>
        /// <param name="Current_User"> Currently logged on user </param>
        /// <param name="Icon_Table"> Dictionary of all the wordmark/icons which can be tagged to the items </param>
        /// <param name="IP_Restrictions"> List of all IP Restriction ranges in use by this digital library </param>
        /// <param name="URL_Portals"> List of all web portals into this system </param>
        /// <param name="Stats_Date_Range"> Object contains the start and end dates for the statistical data in the database </param>
        /// <param name="Thematic_Headings"> Headings under which all the highlighted collections on the home page are organized </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        public Admin_HtmlSubwriter(Search_Results_Statistics Results_Statistics,
                                     List<iSearch_Title_Result> Paged_Results,
                                     Aggregation_Code_Manager Code_Manager,
                                     Item_Lookup_Object All_Items_Lookup,
                                     Item_Aggregation Hierarchy_Object,
                                     SobekCM_Skin_Object HTML_Skin,
                                     Language_Support_Info Translator,
                                     SobekCM_Navigation_Object Current_Mode,
                                     SobekCM_Item Current_Item,
                                     Dictionary<string,string> Aggregation_Aliases,
                                     SobekCM_Skin_Collection Web_Skin_Collection,
                                     User_Object Current_User,
                                     IP_Restriction_Ranges IP_Restrictions,
                                     Dictionary<string, Wordmark_Icon> Icon_Table,
                                     Portal_List URL_Portals,
                                     Statistics_Dates Stats_Date_Range,
                                     List<Thematic_Heading> Thematic_Headings,
                                     Custom_Tracer Tracer )
        {
            Tracer.Add_Trace("Admin_HtmlSubwriter.Constructor", "Saving values and geting user object back from the session");

            resultsStatistics = Results_Statistics;
            pagedResults = Paged_Results;
            codeManager = Code_Manager;
            itemList = All_Items_Lookup;
            htmlSkin = HTML_Skin;
            translator = Translator;
            currentCollection = Hierarchy_Object;
            currentItem = Current_Item;
            user = Current_User;
            ipRestrictions = IP_Restrictions;
            iconTable = Icon_Table;
            statsDates = Stats_Date_Range;

            if (Current_Mode.My_Sobek_Type == My_Sobek_Type_Enum.Log_Out)
            {
                Tracer.Add_Trace("Admin_HtmlSubwriter.Constructor", "Performing logout");

                HttpContext.Current.Session["user"] = null;
                HttpContext.Current.Response.Redirect("?");
            }

            if ((Current_Mode.My_Sobek_Type != My_Sobek_Type_Enum.Logon) && (user != null) && (user.Is_Temporary_Password))
            {
                Current_Mode.My_Sobek_Type = My_Sobek_Type_Enum.New_Password;
            }

            if (Current_Mode.Logon_Required)
                Current_Mode.My_Sobek_Type = My_Sobek_Type_Enum.Logon;

            // If the user is not an admin, and admin was selected, reroute this
            if ((!Current_User.Is_System_Admin) && (!Current_User.Is_Portal_Admin))
            {
                Current_Mode.Mode = Display_Mode_Enum.My_Sobek;
                Current_Mode.My_Sobek_Type = My_Sobek_Type_Enum.Home;
                Current_Mode.My_Sobek_SubMode = String.Empty;
                HttpContext.Current.Response.Redirect(Current_Mode.Redirect_URL());
            }

            Tracer.Add_Trace("Admin_HtmlSubwriter.Constructor", "Building the my sobek viewer object");
            switch (Current_Mode.Admin_Type)
            {
                case Admin_Type_Enum.Aggregation_Single:
                    adminViewer = new Aggregation_Single_AdminViewer(user, Current_Mode, codeManager, Thematic_Headings, Web_Skin_Collection, Tracer);
                    break;

                case Admin_Type_Enum.Home:
                    adminViewer = new Home_AdminViewer(user, Current_Mode, Tracer);
                    break;

                case Admin_Type_Enum.Builder_Status:
                    adminViewer = new Builder_AdminViewer(user, Current_Mode);
                    break;

                case Admin_Type_Enum.Interfaces:
                    adminViewer = new Skins_AdminViewer(user, Current_Mode, Web_Skin_Collection, Tracer);
                    break;

                case Admin_Type_Enum.Forwarding:
                    adminViewer = new Aliases_AdminViewer(user, Current_Mode, Aggregation_Aliases, Tracer);
                    break;

                case Admin_Type_Enum.Wordmarks:
                    adminViewer = new Wordmarks_AdminViewer(user, Current_Mode, Tracer);
                    break;

                case Admin_Type_Enum.URL_Portals:
                    adminViewer = new Portals_AdminViewer(user, Current_Mode, URL_Portals, Tracer);
                    break;

                case Admin_Type_Enum.Users:
                    adminViewer = new Users_AdminViewer(user, Current_Mode, codeManager, Tracer);
                    break;

                case Admin_Type_Enum.User_Groups:
                    adminViewer = new User_Group_AdminViewer(user, Current_Mode, codeManager, Tracer);
                    break;

                case Admin_Type_Enum.Aggregations_Mgmt:
                    adminViewer = new Aggregations_Mgmt_AdminViewer(user, Current_Mode, codeManager, Tracer);
                    break;

                case Admin_Type_Enum.IP_Restrictions:
                    adminViewer = new IP_Restrictions_AdminViewer(user, Current_Mode, ipRestrictions, Tracer);
                    break;

                case Admin_Type_Enum.Thematic_Headings:
                    adminViewer = new Thematic_Headings_AdminViewer(user, Current_Mode, Thematic_Headings, Tracer);
                    break;

                case Admin_Type_Enum.Settings:
                    adminViewer = new Settings_AdminViewer(user, Current_Mode, Tracer);
                    break;

                case Admin_Type_Enum.Projects:
                    if (Current_Mode.My_Sobek_SubMode.Length > 1)
                    {
                        string project_code = Current_Mode.My_Sobek_SubMode.Substring(1);
                        Tracer.Add_Trace("MySobek_HtmlSubwriter.Constructor", "Checking cache for valid project file");
                        if (user != null)
                        {
                            SobekCM_Item projectObject = Cached_Data_Manager.Retrieve_Project(user.UserID, project_code, Tracer);
                            if (projectObject != null)
                            {
                                Tracer.Add_Trace("MySobek_HtmlSubwriter.Constructor", "Valid project file found in cache");
                                adminViewer = new Edit_Item_Metadata_MySobekViewer(user, Current_Mode, itemList, projectObject, codeManager, iconTable, htmlSkin, Tracer);
                            }
                            else
                            {
                                if (SobekCM_Database.Get_All_Projects_Templates(Tracer).Tables[0].Select("ProjectCode='" + project_code + "'").Length > 0)
                                {
                                    Tracer.Add_Trace("MySobek_HtmlSubwriter.Constructor", "Building project file from (possible) PMETS");
                                    string pmets_file = SobekCM_Library_Settings.Base_MySobek_Directory + "projects\\" + Current_Mode.My_Sobek_SubMode.Substring(1) + ".pmets";
                                    SobekCM_Item pmets_item = File.Exists(pmets_file) ? SobekCM_Item.Read_METS(pmets_file) : new SobekCM_Item();
                                    pmets_item.Bib_Info.Main_Title.Title = "Project level metadata for '" + project_code + "'";
                                    pmets_item.Bib_Info.SobekCM_Type = TypeOfResource_SobekCM_Enum.Project;
                                    pmets_item.BibID = project_code.ToUpper();
                                    pmets_item.VID = "00001";
                                    pmets_item.Source_Directory = SobekCM_Library_Settings.Base_MySobek_Directory +  "projects\\";

                                    Tracer.Add_Trace("MySobek_HtmlSubwriter.Constructor", "Adding project file to cache");

                                    Cached_Data_Manager.Store_Project(user.UserID, project_code, pmets_item, Tracer);

                                    adminViewer = new Edit_Item_Metadata_MySobekViewer(user, Current_Mode, itemList, pmets_item, codeManager, iconTable, htmlSkin, Tracer);
                                }
                            }
                        }
                    }

                    if (adminViewer == null)
                        adminViewer = new Projects_AdminViewer(user, Current_Mode, Tracer);
                    break;
            }

            // Pass in the navigation and translator information
            adminViewer.CurrentMode = Current_Mode;
            adminViewer.Translator = translator;
        }
        /// <summary> Constructor creates a new instance of the Aggregation_HtmlSubwriter class </summary>
        /// <param name="Current_Aggregation"> Current item aggregation object to display </param>
        /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
        /// <param name="HTML_Skin"> HTML Web skin which controls the overall appearance of this digital library </param>
        /// <param name="Translator"> Language support object which handles simple translational duties </param>
        /// <param name="Browse_Object"> Object contains all the basic information about any browse or info display </param>
        /// <param name="Paged_Results"> Paged results to display within a browse or search result </param>
        /// <param name="Results_Statistics"> Information about the entire set of results for a search or browse </param>
        /// <param name="Code_Manager"> List of valid collection codes, including mapping from the Sobek collections to Greenstone collections</param>
        /// <param name="All_Items_Lookup"> Lookup object used to pull basic information about any item loaded into this library </param>
        /// <param name="Thematic_Headings"> Headings under which all the highlighted collections on the home page are organized </param>
        /// <param name="Current_User"> Currently logged on user (or object representing the unlogged on user's preferences) </param>
        /// <param name="Static_Web_Content"> HTML content-based browse, info, or imple CMS-style web content objects.  These are objects which are read from a static HTML file and much of the head information must be maintained </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        public Aggregation_HtmlSubwriter(Item_Aggregation Current_Aggregation, 
            SobekCM_Navigation_Object Current_Mode, SobekCM_Skin_Object HTML_Skin, 
            Language_Support_Info Translator, 
            Item_Aggregation_Child_Page Browse_Object,
            Search_Results_Statistics Results_Statistics,
            List<iSearch_Title_Result> Paged_Results,
            Aggregation_Code_Manager Code_Manager, Item_Lookup_Object All_Items_Lookup,
            List<Thematic_Heading> Thematic_Headings, User_Object Current_User,
            HTML_Based_Content Static_Web_Content,
            Custom_Tracer Tracer )
        {
            currentUser = Current_User;
            base.Current_Aggregation = Current_Aggregation;
            currentMode = Current_Mode;
            Skin = HTML_Skin;
            translator = Translator;
            thisBrowseObject = Browse_Object;
            thisStaticBrowseObject = Static_Web_Content;
            codeManager = Code_Manager;
            itemList = All_Items_Lookup;
            thematicHeadings = Thematic_Headings;
            resultsStatistics = Results_Statistics;
            pagedResults = Paged_Results;
            leftButtons = String.Empty;
            rightButtons = String.Empty;

            // Check to see if the user should be able to edit the home page
            if ((currentMode.Mode == Display_Mode_Enum.Aggregation) && (currentMode.Aggregation_Type == Aggregation_Type_Enum.Home_Edit))
            {
                if ( currentUser == null )
                    currentMode.Aggregation_Type = Aggregation_Type_Enum.Home;
                else
                {
                    if ((!currentUser.Is_System_Admin) && (!currentUser.Is_Portal_Admin) && (!currentUser.Is_Aggregation_Admin(Current_Aggregation.Code)))
                    {
                        currentMode.Aggregation_Type = Aggregation_Type_Enum.Home;
                    }
                }
            }
            else if ( currentMode.Aggregation_Type == Aggregation_Type_Enum.Home_Edit )
                currentMode.Aggregation_Type = Aggregation_Type_Enum.Home;

            NameValueCollection form = HttpContext.Current.Request.Form;
            if ( form["item_action"] != null)
            {
                string action = form["item_action"].ToLower().Trim();

                if ((action == "add_aggregation") && ( currentUser != null ))
                {
                    SobekCM_Database.User_Set_Aggregation_Home_Page_Flag(currentUser.UserID, base.Current_Aggregation.Aggregation_ID, true, Tracer);
                    currentUser.Set_Aggregation_Home_Page_Flag(base.Current_Aggregation.Code, base.Current_Aggregation.Name, true);
                    HttpContext.Current.Session.Add("ON_LOAD_MESSAGE", "Added aggregation to your home page");
                }

                if (( action == "remove_aggregation") && ( currentUser != null ))
                {
                    int removeAggregationID = base.Current_Aggregation.Aggregation_ID;
                    string remove_code = base.Current_Aggregation.Code;
                    string remove_name = base.Current_Aggregation.Name;

                    if ((form["aggregation"] != null) && (form["aggregation"].Length > 0))
                    {
                        Item_Aggregation_Related_Aggregations aggrInfo = codeManager[form["aggregation"]];
                        if (aggrInfo != null)
                        {
                            remove_code = aggrInfo.Code;
                            removeAggregationID = aggrInfo.ID;
                        }
                    }

                    SobekCM_Database.User_Set_Aggregation_Home_Page_Flag(currentUser.UserID, removeAggregationID, false, Tracer);
                    currentUser.Set_Aggregation_Home_Page_Flag(remove_code, remove_name, false);

                    if (currentMode.Home_Type != Home_Type_Enum.Personalized)
                    {
                        HttpContext.Current.Session.Add("ON_LOAD_MESSAGE", "Removed aggregation from your home page");
                    }
                }

                if ((action == "private_folder") && ( currentUser != null ))
                {
                    User_Folder thisFolder = currentUser.Get_Folder(form["aggregation"]);
                    if (SobekCM_Database.Edit_User_Folder(thisFolder.Folder_ID, currentUser.UserID, -1, thisFolder.Folder_Name, false, String.Empty, Tracer) >= 0)
                        thisFolder.isPublic = false;
                }

                if ((action == "email") && ( currentUser != null ))
                {
                    string address = form["email_address"].Replace(";", ",").Trim();
                    string comments = form["email_comments"].Trim();
                    string format = form["email_format"].Trim().ToUpper();

                    if (address.Length > 0)
                    {
                        // Determine the email format
                        bool is_html_format = format != "TEXT";

                        // CC: the user, unless they are already on the list
                        string cc_list = currentUser.Email;
                        if (address.ToUpper().IndexOf(currentUser.Email.ToUpper()) >= 0)
                            cc_list = String.Empty;

                        // Send the email
                        string any_error = URL_Email_Helper.Send_Email(address, cc_list, comments, currentUser.Full_Name, currentMode.SobekCM_Instance_Abbreviation, is_html_format, HttpContext.Current.Items["Original_URL"].ToString(), base.Current_Aggregation.Name, "Collection", currentUser.UserID);
                        HttpContext.Current.Session.Add("ON_LOAD_MESSAGE", any_error.Length > 0 ? any_error : "Your email has been sent");

                        currentMode.isPostBack = true;

                        // Do this to force a return trip (cirumnavigate cacheing)
                        string original_url = HttpContext.Current.Items["Original_URL"].ToString();
                        if (original_url.IndexOf("?") < 0)
                            HttpContext.Current.Response.Redirect(original_url + "?p=" + DateTime.Now.Millisecond, false);
                        else
                            HttpContext.Current.Response.Redirect(original_url + "&p=" + DateTime.Now.Millisecond, false);

                        HttpContext.Current.ApplicationInstance.CompleteRequest();
                        Current_Mode.Request_Completed = true;
                        return;
                    }
                }
            }

            if (( currentMode.Aggregation_Type == Aggregation_Type_Enum.Home_Edit ) && ( form["sbkAghsw_HomeTextEdit"] != null))
            {
                string aggregation_folder = SobekCM_Library_Settings.Base_Design_Location + "aggregations\\" + Current_Aggregation.Code + "\\";
                string file = aggregation_folder + Current_Aggregation.Home_Page_File(currentMode.Language);

                // Make a backup from today, if none made yet
                if (File.Exists(file))
                {
                    DateTime lastWrite = (new FileInfo(file)).LastWriteTime;
                    string new_file = file.ToLower().Replace(".txt", "").Replace(".html", "").Replace(".htm", "") + lastWrite.Year + lastWrite.Month.ToString().PadLeft(2, '0') + lastWrite.Day.ToString() .PadLeft(2, '0')+ ".bak";
                    if (File.Exists(new_file))
                        File.Delete(new_file);
                    File.Move(file, new_file);
                }

                // Write to the file now
                StreamWriter homeWriter = new StreamWriter(file, false);
                homeWriter.WriteLine(form["sbkAghsw_HomeTextEdit"]);
                homeWriter.Flush();
                homeWriter.Close();

                // Also save this change
                SobekCM_Database.Save_Item_Aggregation_Milestone(Current_Aggregation.Code, "Home page edited (" + Web_Language_Enum_Converter.Enum_To_Name(currentMode.Language) + ")", currentUser.Full_Name);

                // Clear this aggreation from the cache
                Cached_Data_Manager.Remove_Item_Aggregation(Current_Aggregation.Code, Tracer);

                // If this is all, save the new text as well.
                if (String.Compare("all", Current_Aggregation.Code, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    HttpContext.Current.Application["SobekCM_Home"] = form["sbkAghsw_HomeTextEdit"];
                }

                // Forward along
                currentMode.Aggregation_Type = Aggregation_Type_Enum.Home;
                string redirect_url = currentMode.Redirect_URL();
                if (redirect_url.IndexOf("?") > 0)
                    redirect_url = redirect_url + "&refresh=always";
                else
                    redirect_url = redirect_url + "?refresh=always";
                currentMode.Request_Completed = true;
                HttpContext.Current.Response.Redirect(redirect_url, false);
                HttpContext.Current.ApplicationInstance.CompleteRequest();

                return;
            }

            // If this is a search, verify it is a valid search type
            if (currentMode.Mode == Display_Mode_Enum.Search)
            {
                // Not every collection has every search type...
                ReadOnlyCollection<Search_Type_Enum> possibleSearches = base.Current_Aggregation.Search_Types;
                if (!possibleSearches.Contains(currentMode.Search_Type))
                {
                    bool found_valid = false;

                    if ((currentMode.Search_Type == Search_Type_Enum.Full_Text) && (possibleSearches.Contains(Search_Type_Enum.dLOC_Full_Text)))
                    {
                        found_valid = true;
                        currentMode.Search_Type = Search_Type_Enum.dLOC_Full_Text;
                    }

                    if ((!found_valid) && (currentMode.Search_Type == Search_Type_Enum.Basic) && (possibleSearches.Contains(Search_Type_Enum.Newspaper)))
                    {
                        found_valid = true;
                        currentMode.Search_Type = Search_Type_Enum.Newspaper;
                    }

                    if (( !found_valid ) && ( possibleSearches.Count > 0 ))
                    {
                        found_valid = true;
                        currentMode.Search_Type = possibleSearches[0];
                    }

                    if ( !found_valid )
                    {
                        currentMode.Mode = Display_Mode_Enum.Aggregation;
                        currentMode.Aggregation_Type = Aggregation_Type_Enum.Home;
                    }
                }
            }

            if (currentMode.Mode == Display_Mode_Enum.Search)
            {
                collectionViewer = AggregationViewer_Factory.Get_Viewer(currentMode.Search_Type, base.Current_Aggregation, currentMode, currentUser);
            }

            if (currentMode.Mode == Display_Mode_Enum.Aggregation)
            {
                switch (currentMode.Aggregation_Type)
                {
                    case Aggregation_Type_Enum.Home:
                    case Aggregation_Type_Enum.Home_Edit:
                        collectionViewer = AggregationViewer_Factory.Get_Viewer(base.Current_Aggregation.Views_And_Searches[0], base.Current_Aggregation, currentMode);
                        break;

                    case Aggregation_Type_Enum.Browse_Info:
                        if (resultsStatistics == null)
                        {
                            collectionViewer = new Static_Browse_Info_AggregationViewer(thisBrowseObject, thisStaticBrowseObject, Current_Aggregation, currentMode, Current_User);
                        }
                        else
                        {
                            collectionViewer = new DataSet_Browse_Info_AggregationViewer(thisBrowseObject, resultsStatistics, pagedResults, codeManager, itemList, currentUser);
                        }
                        break;

                    case Aggregation_Type_Enum.Child_Page_Edit:
                        collectionViewer = new Static_Browse_Info_AggregationViewer(thisBrowseObject, thisStaticBrowseObject, Current_Aggregation, currentMode, Current_User);
                        break;

                    case Aggregation_Type_Enum.Browse_By:
                        collectionViewer = new Metadata_Browse_AggregationViewer(Current_Mode, Current_Aggregation, Tracer);
                        break;

                    case Aggregation_Type_Enum.Browse_Map:
                        collectionViewer = new Map_Browse_AggregationViewer(Current_Mode, Current_Aggregation, Tracer);
                        break;

                    case Aggregation_Type_Enum.Browse_Map_Beta:
                        collectionViewer = new Map_Browse_AggregationViewer_Beta(Current_Mode, Current_Aggregation, Tracer);
                        break;

                    case Aggregation_Type_Enum.Item_Count:
                        collectionViewer = new Item_Count_AggregationViewer(Current_Mode, Current_Aggregation);
                        break;

                    case Aggregation_Type_Enum.Usage_Statistics:
                        collectionViewer = new Usage_Statistics_AggregationViewer(Current_Mode, Current_Aggregation);
                        break;

                    case Aggregation_Type_Enum.Private_Items:
                        collectionViewer = new Private_Items_AggregationViewer(Current_Mode, Current_Aggregation, Tracer);
                        break;
                }
            }

            // If execution should end, do it now
            if (currentMode.Request_Completed)
                return;

            if (collectionViewer != null)
            {
                collectionViewer.Translator = translator;
                collectionViewer.HTML_Skin = HTML_Skin;
                collectionViewer.CurrentMode = Current_Mode;
                collectionViewer.CurrentObject = Current_Aggregation;
                collectionViewer.Current_User = Current_User;

                // Pull the standard values
                switch (collectionViewer.Selection_Panel_Display)
                {
                    case Selection_Panel_Display_Enum.Selectable:
                        if (form["show_subaggrs"] != null)
                        {
                            string show_subaggrs = form["show_subaggrs"].ToUpper();
                            if (show_subaggrs == "TRUE")
                                currentMode.Show_Selection_Panel = true;
                        }
                        break;

                    case Selection_Panel_Display_Enum.Always:
                        currentMode.Show_Selection_Panel = true;
                        break;
                }
            }
        }
        /// <summary> Performs a basic metadata search over the entire citation, given a search condition, and returns one page of results </summary>
        /// <param name="Search_Condition"> Search condition string to be run against the databasse </param>
        /// <param name="Include_Private_Items"> Flag indicates whether to include private items in the result set </param>
        /// <param name="AggregationCode"> Code for the aggregation of interest ( or empty string to search all aggregations )</param>
        /// <param name="DateRange_Start"> If this search includes a date range search, start of the date range, or -1</param>
        /// <param name="DateRange_End"> If this search includes a date range search, end of the date range, or -1</param>
        /// <param name="ResultsPerPage"> Number of results to return per "page" of results </param>
        /// <param name="ResultsPage"> Which page of results to return ( one-based, so the first page is page number of one )</param>
        /// <param name="Sort"> Current sort to use ( 0 = default by search or browse, 1 = title, 10 = date asc, 11 = date desc )</param>
        /// <param name="Include_Facets"> Flag indicates whether to include facets in the result set </param>
        /// <param name="Facet_Types"> Primary key for the metadata types to include as facets (up to eight)</param>
        /// <param name="Return_Search_Statistics"> Flag indicates whether to create and return statistics about the overall search results, generally set to TRUE for the first page requested and subsequently set to FALSE </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering</param>
        /// <returns> Small arguments object which contains the page of results and optionally statistics about results for the entire search, including complete counts and facet information </returns>
        /// <remarks> This calls the 'SobekCM_Metadata_Basic_Search_Paged' stored procedure </remarks>
        public static Multiple_Paged_Results_Args Perform_Metadata_Search_Paged( string Search_Condition, bool Include_Private_Items, string AggregationCode, long DateRange_Start, long DateRange_End, int ResultsPerPage, int ResultsPage, int Sort, bool Include_Facets, List<short> Facet_Types, bool Return_Search_Statistics, Custom_Tracer Tracer)
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("SobekCM_Database.Perform_Basic_Search_Paged", "Performing basic search in database");
            }

            Multiple_Paged_Results_Args returnArgs;

            // Create the connection
            using (SqlConnection connect = new SqlConnection(connectionString + "Connection Timeout=45"))
            {

                // Create the command
                SqlCommand executeCommand = new SqlCommand("SobekCM_Metadata_Basic_Search_Paged2", connect)
                                                {CommandTimeout = 45, CommandType = CommandType.StoredProcedure};

                executeCommand.Parameters.AddWithValue("@searchcondition", Search_Condition.Replace("''","'"));
                executeCommand.Parameters.AddWithValue("@include_private", Include_Private_Items);
                if (AggregationCode.ToUpper() == "ALL")
                    AggregationCode = String.Empty;
                executeCommand.Parameters.AddWithValue("@aggregationcode", AggregationCode);
                executeCommand.Parameters.AddWithValue("@daterange_start", DateRange_Start);
                executeCommand.Parameters.AddWithValue("@daterange_end", DateRange_End);
                executeCommand.Parameters.AddWithValue("@pagesize", ResultsPerPage);
                executeCommand.Parameters.AddWithValue("@pagenumber", ResultsPage);
                executeCommand.Parameters.AddWithValue("@sort", Sort);

                // If this is for more than 100 results, don't look ahead
                if (ResultsPerPage > 100)
                {
                    executeCommand.Parameters.AddWithValue("@minpagelookahead", 1);
                    executeCommand.Parameters.AddWithValue("@maxpagelookahead", 1);
                    executeCommand.Parameters.AddWithValue("@lookahead_factor", LOOKAHEAD_FACTOR);
                }
                else
                {
                    executeCommand.Parameters.AddWithValue("@minpagelookahead", MIN_PAGE_LOOKAHEAD);
                    executeCommand.Parameters.AddWithValue("@maxpagelookahead", MAX_PAGE_LOOKAHEAD);
                    executeCommand.Parameters.AddWithValue("@lookahead_factor", LOOKAHEAD_FACTOR);
                }

                if ((Include_Facets) && (Facet_Types != null) && ( Facet_Types.Count > 0 ) && (Return_Search_Statistics))
                {
                    executeCommand.Parameters.AddWithValue("@include_facets", true);
                    if (Facet_Types.Count > 0)
                        executeCommand.Parameters.AddWithValue("@facettype1", Facet_Types[0]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype1", -1);
                    if (Facet_Types.Count > 1)
                        executeCommand.Parameters.AddWithValue("@facettype2", Facet_Types[1]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype2", -1);
                    if (Facet_Types.Count > 2)
                        executeCommand.Parameters.AddWithValue("@facettype3", Facet_Types[2]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype3", -1);
                    if (Facet_Types.Count > 3)
                        executeCommand.Parameters.AddWithValue("@facettype4", Facet_Types[3]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype4", -1);
                    if (Facet_Types.Count > 4)
                        executeCommand.Parameters.AddWithValue("@facettype5", Facet_Types[4]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype5", -1);
                    if (Facet_Types.Count > 5)
                        executeCommand.Parameters.AddWithValue("@facettype6", Facet_Types[5]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype6", -1);
                    if (Facet_Types.Count > 6)
                        executeCommand.Parameters.AddWithValue("@facettype7", Facet_Types[6]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype7", -1);
                    if (Facet_Types.Count > 7)
                        executeCommand.Parameters.AddWithValue("@facettype8", Facet_Types[7]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype8", -1);
                }
                else
                {
                    executeCommand.Parameters.AddWithValue("@include_facets", false);
                    executeCommand.Parameters.AddWithValue("@facettype1", -1);
                    executeCommand.Parameters.AddWithValue("@facettype2", -1);
                    executeCommand.Parameters.AddWithValue("@facettype3", -1);
                    executeCommand.Parameters.AddWithValue("@facettype4", -1);
                    executeCommand.Parameters.AddWithValue("@facettype5", -1);
                    executeCommand.Parameters.AddWithValue("@facettype6", -1);
                    executeCommand.Parameters.AddWithValue("@facettype7", -1);
                    executeCommand.Parameters.AddWithValue("@facettype8", -1);
                }

                // Add parameters for total items and total titles
                SqlParameter totalItemsParameter = executeCommand.Parameters.AddWithValue("@total_items", 0);
                totalItemsParameter.Direction = ParameterDirection.InputOutput;

                SqlParameter totalTitlesParameter = executeCommand.Parameters.AddWithValue("@total_titles", 0);
                totalTitlesParameter.Direction = ParameterDirection.InputOutput;

                // Add parameters for items and titles if this search is expanded to include all aggregations
                SqlParameter expandedItemsParameter = executeCommand.Parameters.AddWithValue("@all_collections_items", 0);
                expandedItemsParameter.Direction = ParameterDirection.InputOutput;

                SqlParameter expandedTitlesParameter = executeCommand.Parameters.AddWithValue("@all_collections_titles", 0);
                expandedTitlesParameter.Direction = ParameterDirection.InputOutput;

                // Create the data reader
                connect.Open();
                using (SqlDataReader reader = executeCommand.ExecuteReader())
                {
                    // Create the return argument object
                    List<string> metadataLabels = new List<string>();
                    returnArgs = new Multiple_Paged_Results_Args
                                     {Paged_Results = DataReader_To_Result_List_With_LookAhead2(reader, ResultsPerPage, metadataLabels)};

                    // Create the overall search statistics?
                    if (Return_Search_Statistics)
                    {
                        Search_Results_Statistics stats = new Search_Results_Statistics(reader, Facet_Types, metadataLabels);
                        returnArgs.Statistics = stats;
                        reader.Close();
                        stats.Total_Items = Convert.ToInt32(totalItemsParameter.Value);
                        stats.Total_Titles = Convert.ToInt32(totalTitlesParameter.Value);
                        stats.All_Collections_Items = Convert.ToInt32(expandedItemsParameter.Value);
                        stats.All_Collections_Titles = Convert.ToInt32(expandedTitlesParameter.Value);
                    }
                    else
                    {
                        reader.Close();
                    }
                }
                connect.Close();
            }

            // Return the built result arguments
            return returnArgs;
        }
        /// <summary> Returns the list of all items/titles which match a given OCLC number </summary>
        /// <param name="OCLC_Number"> OCLC number to look for matching items </param>
        /// <param name="Include_Private_Items"> Flag indicates whether to include private items in the result set </param>
        /// <param name="ResultsPerPage"> Number of results to return per "page" of results </param>
        /// <param name="Sort"> Current sort to use ( 0 = default by search or browse, 1 = title, 10 = date asc, 11 = date desc )</param>
        /// <param name="Return_Search_Statistics"> Flag indicates whether to create and return statistics about the overall search results, generally set to TRUE for the first page requested and subsequently set to FALSE </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering</param>
        /// <returns> Table with all of the item and item group information which matches the OCLC number </returns>
        /// <remarks> This calls the 'SobekCM_Items_By_OCLC' stored procedure </remarks>
        public static Multiple_Paged_Results_Args Items_By_OCLC_Number(long OCLC_Number, bool Include_Private_Items, int ResultsPerPage, int Sort, bool Return_Search_Statistics, Custom_Tracer Tracer)
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("SobekCM_Database.Items_By_OCLC_Number", "Searching by OCLC in the database");
            }

            // Build the parameter list
            SqlParameter[] paramList = new SqlParameter[5];
            paramList[0] = new SqlParameter("@oclc_number", OCLC_Number);
            paramList[1] = new SqlParameter("@include_private", Include_Private_Items);
            paramList[2] = new SqlParameter("@sort", Sort);
            paramList[3] = new SqlParameter("@total_items", 0) {Direction = ParameterDirection.InputOutput};
            paramList[4] = new SqlParameter("@total_titles", 0) {Direction = ParameterDirection.InputOutput};

            // Get the matching reader
            Multiple_Paged_Results_Args returnArgs;
            using (SqlDataReader reader = SqlHelper.ExecuteReader(connectionString, CommandType.StoredProcedure, "SobekCM_Items_By_OCLC", paramList))
            {
                List<string>  metadataFields = new List<string>();

                // Create the return argument object
                returnArgs = new Multiple_Paged_Results_Args { Paged_Results = DataReader_To_Result_List_With_LookAhead2(reader, ResultsPerPage, metadataFields) };

                // Create the overall search statistics?
                if (Return_Search_Statistics)
                {
                    Search_Results_Statistics stats = new Search_Results_Statistics(reader, null, metadataFields);
                    returnArgs.Statistics = stats;
                    reader.Close();
                    stats.Total_Items = Convert.ToInt32(paramList[3].Value);
                    stats.Total_Titles = Convert.ToInt32(paramList[4].Value);
                }
                else
                {
                    reader.Close();
                }
            }

            // Return the built results
            return returnArgs;
        }
        /// <summary> Get a browse of all items in a user's folder </summary>
        /// <param name="UserID"> Primary key for this user in the database </param>
        /// <param name="FolderName"> Name of this user's folder </param>
        /// <param name="ResultsPerPage"> Number of results to return per "page" of results </param>
        /// <param name="ResultsPage"> Which page of results to return ( one-based, so the first page is page number of one )</param>
        /// <param name="Include_Facets"> Flag indicates if facets should be included in the final result set</param>
        /// <param name="Facet_Types"> Primary key for the metadata types to include as facets (up to eight)</param>
        /// <param name="Return_Search_Statistics"> Flag indicates whether to create and return statistics about the overall search results, generally set to TRUE for the first page requested and subsequently set to FALSE </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering</param>
        /// <returns> List of items matching search </returns>
        /// <remarks> This calls the 'mySobek_Get_User_Folder_Browse' stored procedure</remarks> 
        public static Single_Paged_Results_Args Get_User_Folder_Browse(int UserID, string FolderName, int ResultsPerPage, int ResultsPage, bool Include_Facets, List<short> Facet_Types, bool Return_Search_Statistics, Custom_Tracer Tracer)
        {
            if (Tracer != null)
            {
                Tracer.Add_Trace("SobekCM_Database.Get_User_Folder_Browse", String.Empty);
            }

            Single_Paged_Results_Args returnArgs;

            // Create the connection
            using (SqlConnection connect = new SqlConnection(connectionString + "Connection Timeout=45"))
            {

                // Create the command
                SqlCommand executeCommand = new SqlCommand("mySobek_Get_User_Folder_Browse", connect)
                                                {CommandTimeout = 45, CommandType = CommandType.StoredProcedure};

                executeCommand.Parameters.AddWithValue("@userid", UserID);
                executeCommand.Parameters.AddWithValue("@foldername", FolderName);
                executeCommand.Parameters.AddWithValue("@pagesize", ResultsPerPage);
                executeCommand.Parameters.AddWithValue("@pagenumber", ResultsPage);
                executeCommand.Parameters.AddWithValue("@include_facets", Include_Facets);
                if ((Include_Facets) && (Facet_Types != null))
                {
                    if (Facet_Types.Count > 0)
                        executeCommand.Parameters.AddWithValue("@facettype1", Facet_Types[0]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype1", -1);
                    if (Facet_Types.Count > 1)
                        executeCommand.Parameters.AddWithValue("@facettype2", Facet_Types[1]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype2", -1);
                    if (Facet_Types.Count > 2)
                        executeCommand.Parameters.AddWithValue("@facettype3", Facet_Types[2]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype3", -1);
                    if (Facet_Types.Count > 3)
                        executeCommand.Parameters.AddWithValue("@facettype4", Facet_Types[3]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype4", -1);
                    if (Facet_Types.Count > 4)
                        executeCommand.Parameters.AddWithValue("@facettype5", Facet_Types[4]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype5", -1);
                    if (Facet_Types.Count > 5)
                        executeCommand.Parameters.AddWithValue("@facettype6", Facet_Types[5]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype6", -1);
                    if (Facet_Types.Count > 6)
                        executeCommand.Parameters.AddWithValue("@facettype7", Facet_Types[6]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype7", -1);
                    if (Facet_Types.Count > 7)
                        executeCommand.Parameters.AddWithValue("@facettype8", Facet_Types[7]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype8", -1);
                }
                else
                {
                    executeCommand.Parameters.AddWithValue("@facettype1", -1);
                    executeCommand.Parameters.AddWithValue("@facettype2", -1);
                    executeCommand.Parameters.AddWithValue("@facettype3", -1);
                    executeCommand.Parameters.AddWithValue("@facettype4", -1);
                    executeCommand.Parameters.AddWithValue("@facettype5", -1);
                    executeCommand.Parameters.AddWithValue("@facettype6", -1);
                    executeCommand.Parameters.AddWithValue("@facettype7", -1);
                    executeCommand.Parameters.AddWithValue("@facettype8", -1);
                }

                // Add parameters for total items and total titles
                SqlParameter totalItemsParameter = executeCommand.Parameters.AddWithValue("@total_items", 0);
                totalItemsParameter.Direction = ParameterDirection.InputOutput;

                SqlParameter totalTitlesParameter = executeCommand.Parameters.AddWithValue("@total_titles", 0);
                totalTitlesParameter.Direction = ParameterDirection.InputOutput;

                // Create the data reader
                connect.Open();
                using (SqlDataReader reader = executeCommand.ExecuteReader())
                {
                    // Create the return argument object
                    List<string> metadataLabels = new List<string>();
                    returnArgs = new Single_Paged_Results_Args
                                     {Paged_Results = DataReader_To_Simple_Result_List2(reader, metadataLabels)};

                    // Create the overall search statistics?
                    if (Return_Search_Statistics)
                    {
                        Search_Results_Statistics stats = new Search_Results_Statistics(reader, Facet_Types, metadataLabels);
                        returnArgs.Statistics = stats;
                        reader.Close();
                        stats.Total_Items = Convert.ToInt32(totalItemsParameter.Value);
                        stats.Total_Titles = Convert.ToInt32(totalTitlesParameter.Value);
                    }
                    else
                    {
                        reader.Close();
                    }
                }
                connect.Close();
            }

            // Return the built result arguments
            return returnArgs;
        }
        /// <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;
        }
        /// <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> Perform a metadata search against items in the database and return one page of results </summary>
        /// <param name="Term1"> First search term for this metadata search </param>
        /// <param name="Field1"> Field number to search for (or -1 to search all fields)</param>
        /// <param name="Link2"> Link between the first and second terms ( 0=AND, 1=OR, 2=AND NOT )</param>
        /// <param name="Term2"> Second search term for this metadata search </param>
        /// <param name="Field2"> Field number to search for (or -1 to search all fields)</param>
        /// <param name="Link3">Link between the second and third search terms ( 0=AND, 1=OR, 2=AND NOT )</param>
        /// <param name="Term3"> Third search term for this metadata search </param>
        /// <param name="Field3"> Field number to search for (or -1 to search all fields)</param>
        /// <param name="Link4">Link between the third and fourth search terms ( 0=AND, 1=OR, 2=AND NOT )</param>
        /// <param name="Term4"> Fourth search term for this metadata search </param>
        /// <param name="Field4"> Field number to search for (or -1 to search all fields)</param>
        /// <param name="Link5">Link between the fourth and fifth search terms ( 0=AND, 1=OR, 2=AND NOT )</param>
        /// <param name="Term5"> Fifth search term for this metadata search </param>
        /// <param name="Field5"> Field number to search for (or -1 to search all fields)</param>
        /// <param name="Link6">Link between the fifth and sixth search terms ( 0=AND, 1=OR, 2=AND NOT )</param>
        /// <param name="Term6"> Sixth search term for this metadata search </param>
        /// <param name="Field6"> Field number to search for (or -1 to search all fields)</param>
        /// <param name="Link7">Link between the sixth and seventh search terms ( 0=AND, 1=OR, 2=AND NOT )</param>
        /// <param name="Term7"> Seventh search term for this metadata search </param>
        /// <param name="Field7"> Field number to search for (or -1 to search all fields)</param>
        /// <param name="Link8">Link between the seventh and eighth search terms ( 0=AND, 1=OR, 2=AND NOT )</param>
        /// <param name="Term8"> Eighth search term for this metadata search </param>
        /// <param name="Field8"> Field number to search for (or -1 to search all fields)</param>
        /// <param name="Link9">Link between the eighth and ninth search terms ( 0=AND, 1=OR, 2=AND NOT )</param>
        /// <param name="Term9"> Ninth search term for this metadata search </param>
        /// <param name="Field9"> FIeld number to search for (or -1 to search all fields)</param>
        /// <param name="Link10">Link between the ninth and tenth search terms ( 0=AND, 1=OR, 2=AND NOT )</param>
        /// <param name="Term10"> Tenth search term for this metadata search </param>
        /// <param name="Field10"> Field number to search for (or -1 to search all fields)</param>
        /// <param name="Include_Private_Items"> Flag indicates whether to include private items in the result set </param>
        /// <param name="ResultsPerPage"> Number of results to return per "page" of results </param>
        /// <param name="ResultsPage"> Which page of results to return ( one-based, so the first page is page number of one )</param>
        /// <param name="Sort"> Current sort to use ( 0 = default by search or browse, 1 = title, 10 = date asc, 11 = date desc )</param>
        /// <param name="AggregationCode"> Code for the aggregation of interest ( or empty string to search all aggregations )</param>
        /// <param name="Include_Facets"> Flag indicates whether to include facets </param>
        /// <param name="Facet_Types"> Primary key for the metadata types to include as facets (up to eight)</param>
        /// <param name="Return_Search_Statistics"> Flag indicates whether to create and return statistics about the overall search results, generally set to TRUE for the first page requested and subsequently set to FALSE </param>
        /// <param name="tracer"> Trace object keeps a list of each method executed and important milestones in rendering</param>
        /// <returns> Small arguments object which contains the page of results and optionally statistics about results for the entire search, including complete counts and facet information </returns>
        /// <remarks> This calls the 'SobekCM_Metadata_Search_Paged' stored procedure </remarks>
        public static Multiple_Paged_Results_Args Perform_Metadata_Search_Paged(string Term1, int Field1,
																				int Link2, string Term2, int Field2, int Link3, string Term3, int Field3, int Link4, string Term4, int Field4,
																				int Link5, string Term5, int Field5, int Link6, string Term6, int Field6, int Link7, string Term7, int Field7,
																				int Link8, string Term8, int Field8, int Link9, string Term9, int Field9, int Link10, string Term10, int Field10,
																				bool Include_Private_Items, string AggregationCode, int ResultsPerPage, int ResultsPage, int Sort, bool Include_Facets, 
																				List<short> Facet_Types, bool Return_Search_Statistics, Custom_Tracer tracer)
        {
            if (tracer != null)
            {
                tracer.Add_Trace("SobekCM_Database.Perform_Metadata_Search_Paged", "Performing search in database");
            }

            Multiple_Paged_Results_Args returnArgs;

            // Create the connection
            using (SqlConnection connect = new SqlConnection(connectionString + "Connection Timeout=45"))
            {

                // Create the command
                SqlCommand executeCommand = new SqlCommand("SobekCM_Metadata_Search_Paged", connect)
                                                {CommandTimeout = 45, CommandType = CommandType.StoredProcedure};

                executeCommand.Parameters.AddWithValue("@term1", Term1);
                executeCommand.Parameters.AddWithValue("@field1", Field1);
                executeCommand.Parameters.AddWithValue("@link2", Link2);
                executeCommand.Parameters.AddWithValue("@term2", Term2);
                executeCommand.Parameters.AddWithValue("@field2", Field2);
                executeCommand.Parameters.AddWithValue("@link3", Link3);
                executeCommand.Parameters.AddWithValue("@term3", Term3);
                executeCommand.Parameters.AddWithValue("@field3", Field3);
                executeCommand.Parameters.AddWithValue("@link4", Link4);
                executeCommand.Parameters.AddWithValue("@term4", Term4);
                executeCommand.Parameters.AddWithValue("@field4", Field4);
                executeCommand.Parameters.AddWithValue("@link5", Link5);
                executeCommand.Parameters.AddWithValue("@term5", Term5);
                executeCommand.Parameters.AddWithValue("@field5", Field5);
                executeCommand.Parameters.AddWithValue("@link6", Link6);
                executeCommand.Parameters.AddWithValue("@term6", Term6);
                executeCommand.Parameters.AddWithValue("@field6", Field6);
                executeCommand.Parameters.AddWithValue("@link7", Link7);
                executeCommand.Parameters.AddWithValue("@term7", Term7);
                executeCommand.Parameters.AddWithValue("@field7", Field7);
                executeCommand.Parameters.AddWithValue("@link8", Link8);
                executeCommand.Parameters.AddWithValue("@term8", Term8);
                executeCommand.Parameters.AddWithValue("@field8", Field8);
                executeCommand.Parameters.AddWithValue("@link9", Link9);
                executeCommand.Parameters.AddWithValue("@term9", Term9);
                executeCommand.Parameters.AddWithValue("@field9", Field9);
                executeCommand.Parameters.AddWithValue("@link10", Link10);
                executeCommand.Parameters.AddWithValue("@term10", Term10);
                executeCommand.Parameters.AddWithValue("@field10", Field10);
                executeCommand.Parameters.AddWithValue("@include_private", Include_Private_Items);
                if (AggregationCode.ToUpper() == "ALL")
                    AggregationCode = String.Empty;
                executeCommand.Parameters.AddWithValue("@aggregationcode", AggregationCode);
                executeCommand.Parameters.AddWithValue("@pagesize", ResultsPerPage);
                executeCommand.Parameters.AddWithValue("@pagenumber", ResultsPage);
                executeCommand.Parameters.AddWithValue("@sort", Sort);

                // If this is for more than 100 results, don't look ahead
                if (ResultsPerPage > 100)
                {
                    executeCommand.Parameters.AddWithValue("@minpagelookahead", 1);
                    executeCommand.Parameters.AddWithValue("@maxpagelookahead", 1);
                    executeCommand.Parameters.AddWithValue("@lookahead_factor", LOOKAHEAD_FACTOR);
                }
                else
                {
                    executeCommand.Parameters.AddWithValue("@minpagelookahead", MIN_PAGE_LOOKAHEAD);
                    executeCommand.Parameters.AddWithValue("@maxpagelookahead", MAX_PAGE_LOOKAHEAD);
                    executeCommand.Parameters.AddWithValue("@lookahead_factor", LOOKAHEAD_FACTOR);
                }

                if ((Include_Facets) && (Facet_Types != null) && ( Facet_Types.Count > 0 ) && (Return_Search_Statistics))
                {
                    executeCommand.Parameters.AddWithValue("@include_facets", Include_Facets);
                    if (Facet_Types.Count > 0)
                        executeCommand.Parameters.AddWithValue("@facettype1", Facet_Types[0]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype1", -1);
                    if (Facet_Types.Count > 1)
                        executeCommand.Parameters.AddWithValue("@facettype2", Facet_Types[1]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype2", -1);
                    if (Facet_Types.Count > 2)
                        executeCommand.Parameters.AddWithValue("@facettype3", Facet_Types[2]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype3", -1);
                    if (Facet_Types.Count > 3)
                        executeCommand.Parameters.AddWithValue("@facettype4", Facet_Types[3]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype4", -1);
                    if (Facet_Types.Count > 4)
                        executeCommand.Parameters.AddWithValue("@facettype5", Facet_Types[4]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype5", -1);
                    if (Facet_Types.Count > 5)
                        executeCommand.Parameters.AddWithValue("@facettype6", Facet_Types[5]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype6", -1);
                    if (Facet_Types.Count > 6)
                        executeCommand.Parameters.AddWithValue("@facettype7", Facet_Types[6]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype7", -1);
                    if (Facet_Types.Count > 7)
                        executeCommand.Parameters.AddWithValue("@facettype8", Facet_Types[7]);
                    else
                        executeCommand.Parameters.AddWithValue("@facettype8", -1);
                }
                else
                {
                    executeCommand.Parameters.AddWithValue("@include_facets", false);
                    executeCommand.Parameters.AddWithValue("@facettype1", -1);
                    executeCommand.Parameters.AddWithValue("@facettype2", -1);
                    executeCommand.Parameters.AddWithValue("@facettype3", -1);
                    executeCommand.Parameters.AddWithValue("@facettype4", -1);
                    executeCommand.Parameters.AddWithValue("@facettype5", -1);
                    executeCommand.Parameters.AddWithValue("@facettype6", -1);
                    executeCommand.Parameters.AddWithValue("@facettype7", -1);
                    executeCommand.Parameters.AddWithValue("@facettype8", -1);
                }

                // Add parameters for total items and total titles
                SqlParameter totalItemsParameter = executeCommand.Parameters.AddWithValue("@total_items", 0);
                totalItemsParameter.Direction = ParameterDirection.InputOutput;

                SqlParameter totalTitlesParameter = executeCommand.Parameters.AddWithValue("@total_titles", 0);
                totalTitlesParameter.Direction = ParameterDirection.InputOutput;

                // Add parameters for items and titles if this search is expanded to include all aggregations
                SqlParameter expandedItemsParameter = executeCommand.Parameters.AddWithValue("@all_collections_items", 0);
                expandedItemsParameter.Direction = ParameterDirection.InputOutput;

                SqlParameter expandedTitlesParameter = executeCommand.Parameters.AddWithValue("@all_collections_titles", 0);
                expandedTitlesParameter.Direction = ParameterDirection.InputOutput;

                // Create the data reader
                connect.Open();
                using (SqlDataReader reader = executeCommand.ExecuteReader())
                {

                    // Create the return argument object
                    returnArgs = new Multiple_Paged_Results_Args
                                     {Paged_Results = DataReader_To_Result_List_With_LookAhead(reader, ResultsPerPage)};

                    // Create the overall search statistics?
                    if (Return_Search_Statistics)
                    {
                        Search_Results_Statistics stats = new Search_Results_Statistics(reader, Facet_Types);
                        returnArgs.Statistics = stats;
                        reader.Close();
                        stats.Total_Items = Convert.ToInt32(totalItemsParameter.Value);
                        stats.Total_Titles = Convert.ToInt32(totalTitlesParameter.Value);
                        stats.All_Collections_Items = Convert.ToInt32(expandedItemsParameter.Value);
                        stats.All_Collections_Titles = Convert.ToInt32(expandedTitlesParameter.Value);
                    }
                    else
                    {
                        reader.Close();
                    }
                }
                connect.Close();
            }

            // Return the built result arguments
            return returnArgs;
        }
        /// <summary> Constructor creates a new instance of the Aggregation_HtmlSubwriter class </summary>
        /// <param name="Hierarchy_Object"> Current item aggregation object to display </param>
        /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
        /// <param name="HTML_Skin"> HTML Web skin which controls the overall appearance of this digital library </param>
        /// <param name="Translator"> Language support object which handles simple translational duties </param>
        /// <param name="Browse_Object"> Object contains all the basic information about any browse or info display </param>
        /// <param name="Paged_Results"> Paged results to display within a browse or search result </param>
        /// <param name="Results_Statistics"> Information about the entire set of results for a search or browse </param>
        /// <param name="Code_Manager"> List of valid collection codes, including mapping from the Sobek collections to Greenstone collections</param>
        /// <param name="All_Items_Lookup"> Lookup object used to pull basic information about any item loaded into this library </param>
        /// <param name="Thematic_Headings"> Headings under which all the highlighted collections on the home page are organized </param>
        /// <param name="Current_User"> Currently logged on user </param>
        /// <param name="IP_Restrictions"> IP restrictions, used to determine if a user has access to a particular item </param>
        /// <param name="Static_Web_Content"> HTML content-based browse, info, or imple CMS-style web content objects.  These are objects which are read from a static HTML file and much of the head information must be maintained </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        public Aggregation_HtmlSubwriter(Item_Aggregation Hierarchy_Object, 
            SobekCM_Navigation_Object Current_Mode, SobekCM_Skin_Object HTML_Skin, 
            Language_Support_Info Translator, 
            Item_Aggregation_Browse_Info Browse_Object,
            Search_Results_Statistics Results_Statistics,
            List<iSearch_Title_Result> Paged_Results,
            Aggregation_Code_Manager Code_Manager, Item_Lookup_Object All_Items_Lookup,
            List<Thematic_Heading> Thematic_Headings, User_Object Current_User,
            IP_Restriction_Ranges IP_Restrictions,
            HTML_Based_Content Static_Web_Content,
            Custom_Tracer Tracer )
        {
            currentUser = Current_User;
            base.Hierarchy_Object = Hierarchy_Object;
            currentMode = Current_Mode;
            Skin = HTML_Skin;
            translator = Translator;
            thisBrowseObject = Browse_Object;
            thisStaticBrowseObject = Static_Web_Content;
            codeManager = Code_Manager;
            itemList = All_Items_Lookup;
            thematicHeadings = Thematic_Headings;
            ipRestrictions = IP_Restrictions;
            resultsStatistics = Results_Statistics;
            pagedResults = Paged_Results;

            NameValueCollection form = HttpContext.Current.Request.Form;
            if (form["item_action"] != null)
            {
                string action = form["item_action"].ToLower().Trim();

                if (action == "add_aggregation")
                {
                    SobekCM_Database.User_Set_Aggregation_Home_Page_Flag(currentUser.UserID, base.Hierarchy_Object.Aggregation_ID, true, Tracer);
                    currentUser.Set_Aggregation_Home_Page_Flag(base.Hierarchy_Object.Code, base.Hierarchy_Object.Name, true);
                    HttpContext.Current.Session.Add("ON_LOAD_MESSAGE", "Added aggregation to your home page");
                }

                if (action == "remove_aggregation")
                {
                    int removeAggregationID = base.Hierarchy_Object.Aggregation_ID;
                    string remove_code = base.Hierarchy_Object.Code;
                    string remove_name = base.Hierarchy_Object.Name;

                    if ((form["aggregation"] != null) && (form["aggregation"].Length > 0))
                    {
                        Item_Aggregation_Related_Aggregations aggrInfo = codeManager[form["aggregation"]];
                        if (aggrInfo != null)
                        {
                            remove_code = aggrInfo.Code;
                            removeAggregationID = aggrInfo.ID;
                        }
                    }

                    SobekCM_Database.User_Set_Aggregation_Home_Page_Flag(currentUser.UserID, removeAggregationID, false, Tracer);
                    currentUser.Set_Aggregation_Home_Page_Flag(remove_code, remove_name, false);

                    if (currentMode.Home_Type != Home_Type_Enum.Personalized)
                    {
                        HttpContext.Current.Session.Add("ON_LOAD_MESSAGE", "Removed aggregation from your home page");
                    }
                }

                if (action == "private_folder")
                {
                    User_Folder thisFolder = currentUser.Get_Folder(form["aggregation"]);
                    if (SobekCM_Database.Edit_User_Folder(thisFolder.Folder_ID, currentUser.UserID, -1, thisFolder.Folder_Name, false, String.Empty, Tracer) >= 0)
                        thisFolder.isPublic = false;
                }

                if (action == "email")
                {
                    string address = form["email_address"].Replace(";", ",").Trim();
                    string comments = form["email_comments"].Trim();
                    string format = form["email_format"].Trim().ToUpper();

                    if (address.Length > 0)
                    {
                        // Determine the email format
                        bool is_html_format = true;
                        if (format == "TEXT")
                            is_html_format = false;

                        // CC: the user, unless they are already on the list
                        string cc_list = currentUser.Email;
                        if (address.ToUpper().IndexOf(currentUser.Email.ToUpper()) >= 0)
                            cc_list = String.Empty;

                        // Send the email
                        string any_error = URL_Email_Helper.Send_Email(address, cc_list, comments, currentUser.Full_Name, currentMode.SobekCM_Instance_Abbreviation, is_html_format, HttpContext.Current.Items["Original_URL"].ToString(), base.Hierarchy_Object.Name, "home");
                        HttpContext.Current.Session.Add("ON_LOAD_MESSAGE", any_error.Length > 0 ? any_error : "Your email has been sent");

                        currentMode.isPostBack = true;

                        // Do this to force a return trip (cirumnavigate cacheing)
                        string original_url = HttpContext.Current.Items["Original_URL"].ToString();
                        if (original_url.IndexOf("?") < 0)
                            HttpContext.Current.Response.Redirect(original_url + "?p=" + DateTime.Now.Millisecond, false);
                        else
                            HttpContext.Current.Response.Redirect(original_url + "&p=" + DateTime.Now.Millisecond, false);
                    }
                }
            }

            // If this is a search, verify it is a valid search type
            if (currentMode.Mode == Display_Mode_Enum.Search)
            {
                // Not every collection has every search type...
                ReadOnlyCollection<Search_Type_Enum> possibleSearches = base.Hierarchy_Object.Search_Types;
                if (!possibleSearches.Contains(currentMode.Search_Type))
                {
                    bool found_valid = false;

                    if ((currentMode.Search_Type == Search_Type_Enum.Full_Text) && (possibleSearches.Contains(Search_Type_Enum.dLOC_Full_Text)))
                    {
                        found_valid = true;
                        currentMode.Search_Type = Search_Type_Enum.dLOC_Full_Text;
                    }

                    if ((!found_valid) && (currentMode.Search_Type == Search_Type_Enum.Basic) && (possibleSearches.Contains(Search_Type_Enum.Newspaper)))
                    {
                        found_valid = true;
                        currentMode.Search_Type = Search_Type_Enum.Newspaper;
                    }

                    if (( !found_valid ) && ( possibleSearches.Count > 0 ))
                    {
                        found_valid = true;
                        currentMode.Search_Type = possibleSearches[0];
                    }

                    if ( !found_valid )
                    {
                        currentMode.Mode = Display_Mode_Enum.Aggregation_Home;
                    }
                }
            }

            if (currentMode.Mode == Display_Mode_Enum.Search)
            {
                collectionViewer = AggregationViewer_Factory.Get_Viewer(currentMode.Search_Type, base.Hierarchy_Object, currentMode, currentUser);
            }

            if (currentMode.Mode == Display_Mode_Enum.Aggregation_Home)
            {
                collectionViewer = AggregationViewer_Factory.Get_Viewer(base.Hierarchy_Object.Views_And_Searches[0], base.Hierarchy_Object, currentMode);
            }

            if (currentMode.Mode == Display_Mode_Enum.Aggregation_Browse_Info)
            {
                if ( resultsStatistics == null )
                {
                    collectionViewer = new Static_Browse_Info_AggregationViewer(thisBrowseObject, thisStaticBrowseObject);
                }
                else
                {
                    collectionViewer = new DataSet_Browse_Info_AggregationViewer(thisBrowseObject, resultsStatistics, pagedResults, codeManager, itemList, currentUser );
                }
            }

            if (currentMode.Mode == Display_Mode_Enum.Aggregation_Browse_By)
            {
                collectionViewer = new Metadata_Browse_AggregationViewer( Current_Mode, Hierarchy_Object, Tracer );
            }

            if (currentMode.Mode == Display_Mode_Enum.Aggregation_Browse_Map)
            {
                collectionViewer = new Map_Browse_AggregationViewer(Current_Mode, Hierarchy_Object, Tracer);
            }

            if (currentMode.Mode == Display_Mode_Enum.Aggregation_Item_Count)
            {
                collectionViewer = new Item_Count_AggregationViewer(Current_Mode, Hierarchy_Object);
            }

            if (currentMode.Mode == Display_Mode_Enum.Aggregation_Usage_Statistics)
            {
                collectionViewer = new Usage_Statistics_AggregationViewer(Current_Mode, Hierarchy_Object);
            }

            if (currentMode.Mode == Display_Mode_Enum.Aggregation_Private_Items)
            {
                collectionViewer = new Private_Items_AggregationViewer(Current_Mode, Hierarchy_Object, Tracer);
            }

            if (currentMode.Mode == Display_Mode_Enum.Aggregation_Admin_View)
            {
                collectionViewer = new Admin_AggregationViewer(Hierarchy_Object);
            }

            if (collectionViewer != null)
            {
                collectionViewer.Translator = translator;
                collectionViewer.HTML_Skin = HTML_Skin;
                collectionViewer.CurrentMode = Current_Mode;
                collectionViewer.CurrentObject = Hierarchy_Object;
                collectionViewer.Current_User = Current_User;

                // Pull the standard values
                switch (collectionViewer.Selection_Panel_Display)
                {
                    case Selection_Panel_Display_Enum.Selectable:
                        if (form["show_subaggrs"] != null)
                        {
                            string show_subaggrs = form["show_subaggrs"].ToUpper();
                            if (show_subaggrs == "TRUE")
                                currentMode.Show_Selection_Panel = true;
                        }
                        break;

                    case Selection_Panel_Display_Enum.Always:
                        currentMode.Show_Selection_Panel = true;
                        break;
                }
            }
        }
        /// <summary> Constructor for a new instance of the MySobek_HtmlSubwriter class </summary>
        /// <param name="Results_Statistics"> Information about the entire set of results for a browse of a user's bookshelf folder </param>
        /// <param name="Paged_Results"> Single page of results for a browse of a user's bookshelf folder, within the entire set </param>
        /// <param name="Code_Manager"> List of valid collection codes, including mapping from the Sobek collections to Greenstone collections</param>
        /// <param name="All_Items_Lookup"> Lookup object used to pull basic information about any item loaded into this library </param>
        /// <param name="Hierarchy_Object"> Current item aggregation object to display </param>
        /// <param name="HTML_Skin"> HTML Web skin which controls the overall appearance of this digital library </param>
        /// <param name="Translator"> Language support object which handles simple translational duties </param>
        /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
        /// <param name="Current_Item">Current item to edit, if the user is requesting to edit an item</param>
        /// <param name="Current_User"> Currently logged on user </param>
        /// <param name="Icon_Table"> Dictionary of all the wordmark/icons which can be tagged to the items </param>
        /// <param name="Stats_Date_Range"> Object contains the start and end dates for the statistical data in the database </param>
        /// <param name="HTML_Skin_Collection"> HTML Web skin collection which controls the overall appearance of this digital library </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        public MySobek_HtmlSubwriter(Search_Results_Statistics Results_Statistics,
                                     List<iSearch_Title_Result> Paged_Results,
                                     Aggregation_Code_Manager Code_Manager,
                                     Item_Lookup_Object All_Items_Lookup,
                                     Item_Aggregation Hierarchy_Object,
                                     SobekCM_Skin_Object HTML_Skin,
                                     Language_Support_Info Translator,
                                     SobekCM_Navigation_Object Current_Mode,
                                     SobekCM_Item Current_Item,
                                     User_Object Current_User,
                                     Dictionary<string, Wordmark_Icon> Icon_Table,
                                     Statistics_Dates Stats_Date_Range,
									 SobekCM_Skin_Collection HTML_Skin_Collection,
                                     Custom_Tracer Tracer )
        {
            Tracer.Add_Trace("MySobek_HtmlSubwriter.Constructor", "Saving values and geting user object back from the session");

            resultsStatistics = Results_Statistics;
            pagedResults = Paged_Results;
            codeManager = Code_Manager;
            itemList = All_Items_Lookup;
            htmlSkin = HTML_Skin;
            translator = Translator;
            currentCollection = Hierarchy_Object;
            currentItem = Current_Item;
            user = Current_User;
            iconTable = Icon_Table;
            statsDates = Stats_Date_Range;

            if (Current_Mode.My_Sobek_Type == My_Sobek_Type_Enum.Log_Out)
            {
                Tracer.Add_Trace("MySobek_HtmlSubwriter.Constructor", "Performing logout");

                HttpContext.Current.Session["user"] = null;
                HttpContext.Current.Response.Redirect("?", false);
                HttpContext.Current.ApplicationInstance.CompleteRequest();
                Current_Mode.Request_Completed = true;
                return;
            }

            if ((Current_Mode.My_Sobek_Type != My_Sobek_Type_Enum.Logon) && (user != null) && (user.Is_Temporary_Password))
            {
                Current_Mode.My_Sobek_Type = My_Sobek_Type_Enum.New_Password;
            }

            if (Current_Mode.Logon_Required)
                Current_Mode.My_Sobek_Type = My_Sobek_Type_Enum.Logon;

            Tracer.Add_Trace("MySobek_HtmlSubwriter.Constructor", "Building the my sobek viewer object");
            switch (Current_Mode.My_Sobek_Type)
            {
                case My_Sobek_Type_Enum.Home:
                    mySobekViewer = new Home_MySobekViewer(user, Tracer);
                    break;

                case My_Sobek_Type_Enum.New_Item:
                    mySobekViewer = new New_Group_And_Item_MySobekViewer(user, Current_Mode, itemList, codeManager, iconTable, htmlSkin, translator, HTML_Skin_Collection, Tracer);
                    break;

                case My_Sobek_Type_Enum.Folder_Management:
                    mySobekViewer = new Folder_Mgmt_MySobekViewer(user, resultsStatistics, pagedResults, codeManager, itemList, currentCollection, htmlSkin, translator, Current_Mode, Tracer);
                    break;

                case My_Sobek_Type_Enum.Saved_Searches:
                    mySobekViewer = new Saved_Searches_MySobekViewer(user, translator, Current_Mode, Tracer);
                    break;

                case My_Sobek_Type_Enum.Preferences:
                    mySobekViewer = new Preferences_MySobekViewer(user, Current_Mode, Tracer);
                    break;

                case My_Sobek_Type_Enum.Logon:
                    mySobekViewer = new Logon_MySobekViewer(Current_Mode, Tracer);
                    break;

                case My_Sobek_Type_Enum.New_Password:
                    mySobekViewer = new NewPassword_MySobekViewer(user, Tracer);
                    break;

                case My_Sobek_Type_Enum.Delete_Item:
                    mySobekViewer = new Delete_Item_MySobekViewer(user, Current_Mode, currentItem, All_Items_Lookup, Tracer);
                    break;

                case My_Sobek_Type_Enum.Edit_Item_Behaviors:
                    mySobekViewer = new Edit_Item_Behaviors_MySobekViewer(user, Current_Mode, currentItem, codeManager, Tracer);
                    break;

                case My_Sobek_Type_Enum.Edit_Item_Metadata:
                    mySobekViewer = new Edit_Item_Metadata_MySobekViewer(user, Current_Mode, itemList, currentItem, codeManager, iconTable, htmlSkin, translator, HTML_Skin_Collection, Tracer);
                    break;

                case My_Sobek_Type_Enum.File_Management:
                    mySobekViewer = new File_Management_MySobekViewer(user, Current_Mode, Current_Item, itemList, codeManager, iconTable, htmlSkin, translator, HTML_Skin_Collection, Tracer);
                    break;

                case My_Sobek_Type_Enum.Edit_Group_Behaviors:
                    mySobekViewer = new Edit_Group_Behaviors_MySobekViewer(user, Current_Mode, currentItem, codeManager, Tracer);
                    break;

                case My_Sobek_Type_Enum.Edit_Group_Serial_Hierarchy:
                    mySobekViewer = new Edit_Serial_Hierarchy_MySobekViewer(user);
                    break;

                case My_Sobek_Type_Enum.Item_Tracking:
                    mySobekViewer = new Track_Item_MySobekViewer(user, Current_Mode, Tracer);
                    break;

                case My_Sobek_Type_Enum.Group_Add_Volume:
                    // Pull the list of items tied to this group
                    SobekCM_Items_In_Title itemsInTitle = Cached_Data_Manager.Retrieve_Items_In_Title(currentItem.BibID, Tracer);
                    if (itemsInTitle == null)
                    {
                        // Get list of information about this item group and save the item list
                        DataSet itemDetails = SobekCM_Database.Get_Item_Group_Details(currentItem.BibID, Tracer);
                        itemsInTitle = new SobekCM_Items_In_Title(itemDetails.Tables[1]);

                        // Store in cache if retrieved
                        Cached_Data_Manager.Store_Items_In_Title(currentItem.BibID, itemsInTitle, Tracer);
                    }
                    mySobekViewer = new Group_Add_Volume_MySobekViewer(user, Current_Mode, itemList, currentItem, codeManager, iconTable, htmlSkin, itemsInTitle, translator, HTML_Skin_Collection, Tracer);
                    break;

                case My_Sobek_Type_Enum.Group_AutoFill_Volumes:
                    mySobekViewer = new Group_AutoFill_Volume_MySobekViewer(user);
                    break;

                case My_Sobek_Type_Enum.Group_Mass_Update_Items:
                    mySobekViewer = new Mass_Update_Items_MySobekViewer(user, Current_Mode, currentItem, codeManager, Tracer);
                    break;

                case My_Sobek_Type_Enum.Page_Images_Management:
                    mySobekViewer = new Page_Image_Upload_MySobekViewer(user, Current_Mode, Current_Item, itemList, codeManager, iconTable, htmlSkin, translator, Tracer );
                    break;

                case My_Sobek_Type_Enum.User_Tags:
                    mySobekViewer = new User_Tags_MySobekViewer(user, Tracer);
                    break;

                case My_Sobek_Type_Enum.User_Usage_Stats:
                    mySobekViewer = new User_Usage_Stats_MySobekViewer(user, Current_Mode, statsDates, Tracer);
                    break;
            }

            // Pass in the navigation and translator information
            mySobekViewer.CurrentMode = Current_Mode;
            mySobekViewer.Translator = translator;
        }
        /// <summary> Constructor for a new instance of the Text_MainWriter class </summary>
        /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
        /// <param name="Hierarchy_Object"> Current item aggregation object to display </param>
        /// <param name="Results_Statistics"> Information about the entire set of results for a search or browse </param>
        /// <param name="Paged_Results"> Single page of results for a search or browse, within the entire set </param>
        /// <param name="Browse_Object"> Object contains all the basic information about any browse or info display </param>
        /// <param name="Current_Item"> Current item to display </param>
        /// <param name="Current_Page"> Current page within the item</param>
        /// <param name="HTML_Skin"> HTML Web skin which controls the overall appearance of this digital library </param>
        /// <param name="Current_User"> Currently logged on user </param>
        /// <param name="Translator"> Language support object which handles simple translational duties </param>
        /// <param name="Code_Manager"> List of valid collection codes, including mapping from the Sobek collections to Greenstone collections</param>
        /// <param name="Item_List"> Lookup object used to pull basic information about any item loaded into this library </param>
        /// <param name="Stats_Date_Range"> Object contains the start and end dates for the statistical data in the database </param>
        /// <param name="Search_History"> List of recent searches performed against this digital library </param>
        /// <param name="Icon_Dictionary"> Dictionary of information about every wordmark/icon in this digital library, used to build the wordmarks subpage </param>
        /// <param name="Thematic_Headings"> Headings under which all the highlighted collections on the main home page are organized </param>
        /// <param name="Public_Folder"> Object contains the information about the public folder to display </param>
        /// <param name="Aggregation_Aliases"> List of all existing aliases for existing aggregations </param>
        /// <param name="Web_Skin_Collection"> Collection of all the web skins </param>
        /// <param name="Checked_Items"> List of all items which are currently checked out for single fair use and the IP address currently viewing the item</param>
        /// <param name="IP_Restrictions"> Any possible restriction on item access by IP ranges </param>
        /// <param name="URL_Portals"> List of all web portals into this system </param>
        /// <param name="Site_Map"> Optional site map object used to render a navigational tree-view on left side of static web content pages </param>
        /// <param name="Items_In_Title"> List of items within the current title ( used for the Item Group display )</param>
        /// <param name="Static_Web_Content"> HTML content-based browse, info, or imple CMS-style web content objects.  These are objects which are read from a static HTML file and much of the head information must be maintained </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        public Html_MainWriter(SobekCM_Navigation_Object Current_Mode,
            Item_Aggregation Hierarchy_Object,
            Search_Results_Statistics Results_Statistics,
            List<iSearch_Title_Result> Paged_Results,
            Item_Aggregation_Child_Page Browse_Object,
            SobekCM_Item Current_Item,
            Page_TreeNode Current_Page,
            SobekCM_Skin_Object HTML_Skin,
            User_Object Current_User,
            Language_Support_Info Translator,
            Aggregation_Code_Manager Code_Manager,
            Item_Lookup_Object Item_List,
            Statistics_Dates Stats_Date_Range,
            Recent_Searches Search_History,
            Dictionary<string, Wordmark_Icon> Icon_Dictionary,
            List<Thematic_Heading> Thematic_Headings,
            Public_User_Folder Public_Folder,
            Dictionary<string, string> Aggregation_Aliases,
            SobekCM_Skin_Collection Web_Skin_Collection,
            Checked_Out_Items_List Checked_Items,
            IP_Restriction_Ranges IP_Restrictions,
            Portal_List URL_Portals,
            SobekCM_SiteMap Site_Map,
            SobekCM_Items_In_Title Items_In_Title,
            HTML_Based_Content Static_Web_Content,
            Custom_Tracer Tracer )
            : base(Current_Mode, Hierarchy_Object, Results_Statistics, Paged_Results, Browse_Object,  Current_Item, Current_Page, Static_Web_Content)
        {
            // Save parameters
            htmlSkin = HTML_Skin;
            translator = Translator;
            codeManager = Code_Manager;
            itemList = Item_List;
            statsDateRange = Stats_Date_Range;
            searchHistory = Search_History;
            currentUser = Current_User;
            iconList = Icon_Dictionary;
            thematicHeadings = Thematic_Headings;
            publicFolder = Public_Folder;
            aggregationAliases = Aggregation_Aliases;
            webSkins = Web_Skin_Collection;
            checkedItems = Checked_Items;
            ipRestrictionInfo = IP_Restrictions;
            urlPortals = URL_Portals;
            siteMap = Site_Map;
            itemsInTitle = Items_In_Title;

            // Set some defaults

            // Handle basic events which may be fired by the internal header
            if (HttpContext.Current.Request.Form["internal_header_action"] != null)
            {
                // Pull the action value
                string internalHeaderAction = HttpContext.Current.Request.Form["internal_header_action"].Trim();

                // Was this to hide or show the header?
                if ((internalHeaderAction == "hide") || (internalHeaderAction == "show"))
                {
                    // Pull the current visibility from the session
                    bool shown = !((HttpContext.Current.Session["internal_header"] != null) && (HttpContext.Current.Session["internal_header"].ToString() == "hidden"));
                    if ((internalHeaderAction == "hide") && (shown))
                    {
                        HttpContext.Current.Session["internal_header"] = "hidden";
                        currentMode.Redirect();
                        return;
                    }
                    if ((internalHeaderAction == "show") && (!shown))
                    {
                        HttpContext.Current.Session["internal_header"] = "shown";
                        currentMode.Redirect();
                        return;
                    }
                }
            }

            try
            {

                // Create the html sub writer now
                switch (Current_Mode.Mode)
                {
                    case Display_Mode_Enum.Internal:
                        subwriter = new Internal_HtmlSubwriter(iconList, currentUser, codeManager);
                        break;

                    case Display_Mode_Enum.Statistics:
                        subwriter = new Statistics_HtmlSubwriter(searchHistory, codeManager, statsDateRange);
                        break;

                    case Display_Mode_Enum.Preferences:
                        subwriter = new Preferences_HtmlSubwriter(currentMode);
                        break;

                    case Display_Mode_Enum.Error:
                        subwriter = new Error_HtmlSubwriter(false);
                        // Send the email now
                        if (currentMode.Caught_Exception != null)
                        {
                            if (currentMode.Error_Message.Length == 0)
                                currentMode.Error_Message = "Unknown exception caught";
                            Email_Information(currentMode.Error_Message, currentMode.Caught_Exception, Tracer, false);
                        }
                        break;

                    case Display_Mode_Enum.Legacy_URL:
                        subwriter = new LegacyUrl_HtmlSubwriter();
                        break;

                    case Display_Mode_Enum.Item_Print:
                        subwriter = new Print_Item_HtmlSubwriter(currentItem, codeManager, translator, currentMode);
                        break;

                    case Display_Mode_Enum.Contact:

                        StringBuilder builder = new StringBuilder();
                        builder.Append("\n\nSUBMISSION INFORMATION\n");
                        builder.Append("\tDate:\t\t\t\t" + DateTime.Now.ToString() + "\n");
                        string lastMode = String.Empty;
                        try
                        {
                            if (HttpContext.Current.Session["Last_Mode"] != null)
                                lastMode = HttpContext.Current.Session["Last_Mode"].ToString();
                            builder.Append("\tIP Address:\t\t\t" + HttpContext.Current.Request.UserHostAddress + "\n");
                            builder.Append("\tHost Name:\t\t\t" + HttpContext.Current.Request.UserHostName + "\n");
                            builder.Append("\tBrowser:\t\t\t" + HttpContext.Current.Request.Browser.Browser + "\n");
                            builder.Append("\tBrowser Platform:\t\t" + HttpContext.Current.Request.Browser.Platform + "\n");
                            builder.Append("\tBrowser Version:\t\t" + HttpContext.Current.Request.Browser.Version + "\n");
                            builder.Append("\tBrowser Language:\t\t");
                            bool first = true;
                            string[] languages = HttpContext.Current.Request.UserLanguages;
                            if (languages != null)
                                foreach (string thisLanguage in languages)
                                {
                                    if (first)
                                    {
                                        builder.Append(thisLanguage);
                                        first = false;
                                    }
                                    else
                                    {
                                        builder.Append(", " + thisLanguage);
                                    }
                                }

                            builder.Append("\n\nHISTORY\n");
                            if (HttpContext.Current.Session["LastSearch"] != null)
                                builder.Append("\tLast Search:\t\t" + HttpContext.Current.Session["LastSearch"] + "\n");
                            if (HttpContext.Current.Session["LastResults"] != null)
                                builder.Append("\tLast Results:\t\t" + HttpContext.Current.Session["LastResults"] + "\n");
                            if (HttpContext.Current.Session["Last_Mode"] != null)
                                builder.Append("\tLast Mode:\t\t\t" + HttpContext.Current.Session["Last_Mode"] + "\n");
                            builder.Append("\tURL:\t\t\t\t" + HttpContext.Current.Items["Original_URL"]);
                        }
                        catch
                        {

                        }
                        subwriter = new Contact_HtmlSubwriter(lastMode, builder.ToString(), currentMode, hierarchyObject);
                        break;

                    case Display_Mode_Enum.Contact_Sent:
                        subwriter = new Contact_HtmlSubwriter(String.Empty, String.Empty, currentMode, hierarchyObject);
                        break;

                    case Display_Mode_Enum.Simple_HTML_CMS:
                        subwriter = new Web_Content_HtmlSubwriter(hierarchyObject, currentMode, htmlSkin, htmlBasedContent, siteMap);
                        break;

                    case Display_Mode_Enum.My_Sobek:
                        subwriter = new MySobek_HtmlSubwriter(results_statistics, paged_results, codeManager, itemList, hierarchyObject, htmlSkin, translator, currentMode, currentItem, currentUser, iconList, statsDateRange, webSkins, Tracer);
                        break;

                    case Display_Mode_Enum.Administrative:
                        subwriter = new Admin_HtmlSubwriter(codeManager, itemList, hierarchyObject, htmlSkin, translator, currentMode, aggregationAliases, webSkins, currentUser, ipRestrictionInfo, iconList, urlPortals, thematicHeadings, Tracer);
                        break;

                    case Display_Mode_Enum.Results:
                        subwriter = new Search_Results_HtmlSubwriter(results_statistics, paged_results, codeManager, translator, itemList, currentUser);
                        break;

                    case Display_Mode_Enum.Public_Folder:
                        subwriter = new Public_Folder_HtmlSubwriter(results_statistics, paged_results, codeManager, translator, itemList, currentUser, publicFolder);
                        break;

                    case Display_Mode_Enum.Search:
                    case Display_Mode_Enum.Aggregation:
                        subwriter = new Aggregation_HtmlSubwriter(hierarchyObject, currentMode, htmlSkin, translator, thisBrowseObject, results_statistics, paged_results, codeManager, itemList, thematicHeadings, currentUser, htmlBasedContent, Tracer);
                        break;

                    case Display_Mode_Enum.Item_Display:
                        if ((!currentMode.Invalid_Item) && (currentItem != null))
                        {
                            bool show_toc = false;
                            if (HttpContext.Current.Session["Show TOC"] != null)
                            {
                                Boolean.TryParse(HttpContext.Current.Session["Show TOC"].ToString(), out show_toc);
                            }

                            // Check that this item is not checked out by another user
                            bool itemCheckedOutByOtherUser = false;
                            if (currentItem.Behaviors.CheckOut_Required)
                            {
                                if (!checkedItems.Check_Out(currentItem.Web.ItemID, HttpContext.Current.Request.UserHostAddress))
                                {
                                    itemCheckedOutByOtherUser = true;
                                }
                            }

                            // Check to see if this is IP restricted
                            string restriction_message = String.Empty;
                            if (currentItem.Behaviors.IP_Restriction_Membership > 0)
                            {
                                if (HttpContext.Current != null)
                                {
                                    int user_mask = (int)HttpContext.Current.Session["IP_Range_Membership"];
                                    int comparison = currentItem.Behaviors.IP_Restriction_Membership & user_mask;
                                    if (comparison == 0)
                                    {
                                        int restriction = currentItem.Behaviors.IP_Restriction_Membership;
                                        int restriction_counter = 0;
                                        while (restriction % 2 != 1)
                                        {
                                            restriction = restriction >> 1;
                                            restriction_counter++;
                                        }
                                        restriction_message = ipRestrictionInfo[restriction_counter].Item_Restricted_Statement;
                                    }
                                }
                            }

                            // Create the item viewer writer
                            subwriter = new Item_HtmlSubwriter(currentItem, currentPage, currentUser, codeManager, translator, show_toc, (SobekCM_Library_Settings.JP2ServerUrl.Length > 0), currentMode, hierarchyObject, restriction_message, itemsInTitle, Tracer);
                            ((Item_HtmlSubwriter)subwriter).Item_Checked_Out_By_Other_User = itemCheckedOutByOtherUser;
                        }
                        else
                        {
                            // Create the invalid item html subwrite and write the HTML
                            subwriter = new Error_HtmlSubwriter(true);
                        }
                        break;

                }
            }
            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))
                {
                    Tracer.Add_Trace("Html_MainWriter.Constructor", "Exception caught!", Custom_Trace_Type_Enum.Error);
                    Tracer.Add_Trace("Html_MainWriter.Constructor", ee.Message, Custom_Trace_Type_Enum.Error);
                    Tracer.Add_Trace("Html_MainWriter.Constructor", ee.StackTrace, Custom_Trace_Type_Enum.Error);

                    // Wrap this into the SobekCM Exception
                    SobekCM_Traced_Exception newException = new SobekCM_Traced_Exception("Exception caught while building the mode-specific HTML Subwriter", 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);
                    Current_Mode.Request_Completed = true;

                    return;
                }
                else
                {
                    subwriter = new Error_HtmlSubwriter(false);
                }
            }

            if (subwriter != null)
            {
                subwriter.Mode = currentMode;
                subwriter.Skin = htmlSkin;
                subwriter.Current_Aggregation = hierarchyObject;
            }
        }
 /// <summary> Constructor for a new instance of the Multiple_Paged_Results_Args class </summary>
 /// <param name="Statistics"> Statistics/information about the overall search or browse, including initial query time, complete results counts, and facets </param>
 /// <param name="Paged_Results"> Collection of paged results, which are themselves a collection of search title results </param>
 public Multiple_Paged_Results_Args(Search_Results_Statistics Statistics, List <List <iSearch_Title_Result> > Paged_Results)
 {
     this.Statistics    = Statistics;
     this.Paged_Results = Paged_Results;
 }
        /// <summary> Stores the table of search results to the cache or caching server </summary>
        /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
        /// <param name="Terms"> List of all search terms for the search result statistics to store </param>
        /// <param name="Fields"> List of all search fields for the search result statistics to store </param>
        /// <param name="Count"> Number of fields or terms to include in the key for this result </param>
        /// <param name="DateRange_Start"> Beginning of a date range search, or -1 </param>
        /// <param name="DateRange_End"> End of a date range search, or -1 </param>
        /// <param name="StoreObject"> Search results item/title list </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering</param>
        public static void Store_Search_Result_Statistics(SobekCM_Navigation_Object Current_Mode, int Count, List<string> Fields, List<string> Terms, long DateRange_Start, long DateRange_End, Search_Results_Statistics StoreObject, Custom_Tracer Tracer)
        {
            // If the cache is disabled, just return before even tracing
            if (Disabled)
                return;
            // Determine the key
            // If there is no aggregation listed, use 'all'
            string aggregation_code = Current_Mode.Aggregation.ToLower();
            if (aggregation_code.Length == 0)
                aggregation_code = "all";

            // Determine the search precision
            string precision = "results";
            switch (Current_Mode.Search_Precision)
            {
                case Search_Precision_Type_Enum.Contains:
                    precision = "contains";
                    break;

                case Search_Precision_Type_Enum.Exact_Match:
                    precision = "exact";
                    break;

                case Search_Precision_Type_Enum.Synonmic_Form:
                    precision = "like";
                    break;
            }

            // Start to build the key
            StringBuilder keyBuilder = new StringBuilder("TOTALRESULTS_" + precision + "_" + aggregation_code + "_T_");
            for (int i = 0; i < Count; i++)
            {
                keyBuilder.Append(Terms[i].ToLower() + "_");
            }
            keyBuilder.Append("F_");
            for (int i = 0; i < Count; i++)
            {
                keyBuilder.Append(Fields[i] + "_");
            }

            // Add possivle date range search restrction to the key
            if (DateRange_Start >= 0)
            {
                keyBuilder.Append("_DATE" + DateRange_Start);
                if (DateRange_End >= 0)
                {
                    keyBuilder.Append("-" + DateRange_End);
                }
            }

            string key = keyBuilder.ToString();

            //if (Current_Mode.SubAggregation.Length > 0)
            //{
            //    key = "a_" + precision + "_" + aggregation_code + "s_" + Current_Mode.SubAggregation + "t_" + Current_Mode.Search_String + "f_" + search_fields;
            //}
            if ((Current_Mode.Search_String.Length == 0) && (Current_Mode.Coordinates.Length > 0))
            {
                key = "TOTALRESULTS_" + precision + "_" + aggregation_code + "coord_" + Current_Mode.Coordinates;
            }

            // try to store in the caching server, if enabled
            if (caching_serving_enabled)
            {
                if (Tracer != null)
                {
                    Tracer.Add_Trace("Cached_Data_Manager.Store_Search_Result_Statistics", "Adding object '" + key + "' to the caching server");
                }

                if (AppFabric_Manager.Add(key, StoreObject, Tracer))
                    return;
            }

            // Store this on the local cache, if not there and storing on the cache server failed
            if (HttpContext.Current.Cache[key] == null)
            {
                if (Tracer != null)
                {
                    Tracer.Add_Trace("Cached_Data_Manager.Store_Search_Result_Statistics", "Adding object '" + key + "' to the local cache with expiration of 3 minutes");
                }

                HttpContext.Current.Cache.Insert(key, StoreObject, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(3));
            }
        }
        /// <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> Constructor for a new instance of the Single_Paged_Results_Args class </summary>
 /// <param name="Statistics"> Statistics/information about the overall search or browse, including initial query time, complete results counts, and facets </param>
 /// <param name="Paged_Results"> Single  page of results, which is collection of search title results </param>
 public Single_Paged_Results_Args(Search_Results_Statistics Statistics, List<iSearch_Title_Result> Paged_Results)
 {
     this.Statistics = Statistics;
     this.Paged_Results = Paged_Results;
 }
        /// <summary> Constructor for a new instance of the Text_MainWriter class </summary>
        /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
        /// <param name="Hierarchy_Object"> Current item aggregation object to display </param>
        /// <param name="Results_Statistics"> Information about the entire set of results for a search or browse </param>
        /// <param name="Paged_Results"> Single page of results for a search or browse, within the entire set </param>
        /// <param name="Browse_Object"> Object contains all the basic information about any browse or info display </param>
        /// <param name="Current_Item"> Current item to display </param>
        /// <param name="Current_Page"> Current page within the item</param>
        /// <param name="HTML_Skin"> HTML Web skin which controls the overall appearance of this digital library </param>
        /// <param name="Current_User"> Currently logged on user </param>
        /// <param name="Translator"> Language support object which handles simple translational duties </param>
        /// <param name="Code_Manager"> List of valid collection codes, including mapping from the Sobek collections to Greenstone collections</param>
        /// <param name="Item_List"> Lookup object used to pull basic information about any item loaded into this library </param>
        /// <param name="Stats_Date_Range"> Object contains the start and end dates for the statistical data in the database </param>
        /// <param name="Search_History"> List of recent searches performed against this digital library </param>
        /// <param name="Icon_Dictionary"> Dictionary of information about every wordmark/icon in this digital library, used to build the wordmarks subpage </param>
        /// <param name="Thematic_Headings"> Headings under which all the highlighted collections on the main home page are organized </param>
        /// <param name="Public_Folder"> Object contains the information about the public folder to display </param>
        /// <param name="Aggregation_Aliases"> List of all existing aliases for existing aggregations </param>
        /// <param name="Web_Skin_Collection"> Collection of all the web skins </param>
        /// <param name="Checked_Items"> List of all items which are currently checked out for single fair use and the IP address currently viewing the item</param>
        /// <param name="IP_Restrictions"> Any possible restriction on item access by IP ranges </param>
        /// <param name="URL_Portals"> List of all web portals into this system </param>
        /// <param name="Site_Map"> Optional site map object used to render a navigational tree-view on left side of static web content pages </param>
        /// <param name="Items_In_Title"> List of items within the current title ( used for the Item Group display )</param>
        /// <param name="Static_Web_Content"> HTML content-based browse, info, or imple CMS-style web content objects.  These are objects which are read from a static HTML file and much of the head information must be maintained </param>
        public Html_MainWriter(SobekCM_Navigation_Object Current_Mode,
            Item_Aggregation Hierarchy_Object,
            Search_Results_Statistics Results_Statistics,
            List<iSearch_Title_Result> Paged_Results,
            Item_Aggregation_Browse_Info Browse_Object,
            SobekCM_Item Current_Item,
            Page_TreeNode Current_Page,
            SobekCM_Skin_Object HTML_Skin,
            User_Object Current_User,
            Language_Support_Info Translator,
            Aggregation_Code_Manager Code_Manager,
            Item_Lookup_Object Item_List,
            Statistics_Dates Stats_Date_Range,
            Recent_Searches Search_History,
            Dictionary<string, Wordmark_Icon> Icon_Dictionary,
            List<Thematic_Heading> Thematic_Headings,
            Public_User_Folder Public_Folder,
            Dictionary<string, string> Aggregation_Aliases,
            SobekCM_Skin_Collection Web_Skin_Collection,
            Checked_Out_Items_List Checked_Items,
            IP_Restriction_Ranges IP_Restrictions,
            Portal_List URL_Portals,
            SobekCM_SiteMap Site_Map,
            SobekCM_Items_In_Title Items_In_Title,
            HTML_Based_Content Static_Web_Content )
            : base(Current_Mode, Hierarchy_Object, Results_Statistics, Paged_Results, Browse_Object,  Current_Item, Current_Page, Static_Web_Content)
        {
            // Save parameters
            htmlSkin = HTML_Skin;
            translator = Translator;
            codeManager = Code_Manager;
            itemList = Item_List;
            statsDateRange = Stats_Date_Range;
            searchHistory = Search_History;
            currentUser = Current_User;
            iconList = Icon_Dictionary;
            thematicHeadings = Thematic_Headings;
            publicFolder = Public_Folder;
            aggregationAliases = Aggregation_Aliases;
            webSkins = Web_Skin_Collection;
            checkedItems = Checked_Items;
            ipRestrictionInfo = IP_Restrictions;
            urlPortals = URL_Portals;
            siteMap = Site_Map;
            itemsInTitle = Items_In_Title;

            // Set some defaults
            finishPageInAddFinalHtmlMethod = false;

            // Handle basic events which may be fired by the internal header

            if (HttpContext.Current.Request.Form["internal_header_action"] != null)
            {
                // Pull the action value
                string internalHeaderAction = HttpContext.Current.Request.Form["internal_header_action"].Trim();

                // Was this to hide or show the header?
                if ((internalHeaderAction == "hide") || (internalHeaderAction == "show"))
                {
                    // Pull the current visibility from the session
                    bool shown = true;
                    if ((HttpContext.Current.Session["internal_header"] != null) && (HttpContext.Current.Session["internal_header"].ToString() == "hidden"))
                    {
                        shown = false;
                    }
                    if ((internalHeaderAction == "hide") && (shown))
                    {
                        HttpContext.Current.Session["internal_header"] = "hidden";
                        HttpContext.Current.Response.Redirect(currentMode.Redirect_URL(), true);
                    }
                    if ((internalHeaderAction == "show") && (!shown))
                    {
                        HttpContext.Current.Session["internal_header"] = "shown";
                        HttpContext.Current.Response.Redirect(currentMode.Redirect_URL(), true);
                    }
                }
            }
        }