Example #1
0
        private void recursively_build_all_files_list(List <SobekCM_File_Info> returnValue, List <Page_TreeNode> handledPages, abstract_TreeNode thisNode)
        {
            // Since this is pre-order, first 'visit' this
            if (thisNode.Page)
            {
                Page_TreeNode pageNode = (Page_TreeNode)thisNode;
                if (!handledPages.Contains(pageNode))
                {
                    foreach (SobekCM_File_Info file in pageNode.Files)
                    {
                        returnValue.Add(file);
                    }
                    handledPages.Add(pageNode);
                }
            }

            // is this a division node? .. which can have children ..
            if (!thisNode.Page)
            {
                Division_TreeNode thisDivNode = (Division_TreeNode)thisNode;

                // Do the same for all the children
                foreach (abstract_TreeNode childNode in thisDivNode.Nodes)
                {
                    recursively_build_all_files_list(returnValue, handledPages, childNode);
                }
            }
        }
Example #2
0
        /// <summary> Method removes many of the string values that are loaded while reading the metadata
        /// but are not needed for general use of the item in the SobekCM web application  </summary>
        public void Minimize_File_Size()
        {
            // First clear the extraneous checksum information on the physical division tree
            List <abstract_TreeNode> allNodes = physicalDivisionTree.Divisions_PreOrder;

            foreach (abstract_TreeNode thisNode in allNodes)
            {
                if (thisNode.Page)
                {
                    Page_TreeNode pageNode = (Page_TreeNode)thisNode;
                    foreach (SobekCM_File_Info thisFile in pageNode.Files)
                    {
                        thisFile.Checksum_Type = null;
                        thisFile.Checksum      = null;
                    }
                }
            }

            // Next clear the extraneous checksum information on the download tree
            allNodes = downloadDivisionTree.Divisions_PreOrder;
            foreach (abstract_TreeNode thisNode in allNodes)
            {
                if (thisNode.Page)
                {
                    Page_TreeNode pageNode = (Page_TreeNode)thisNode;
                    foreach (SobekCM_File_Info thisFile in pageNode.Files)
                    {
                        thisFile.Checksum_Type = null;
                        thisFile.Checksum      = null;
                    }
                }
            }
        }
 /// <summary> Constructor for a new instance of the RequestCache class </summary>
 /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
 /// <param name="Hierarchy_Object"> Current item aggregation object to display </param>
 /// <param name="Results_Statistics"> Information about the entire set of results for a search or browse </param>
 /// <param name="Paged_Results"> Single page of results for a search or browse, within the entire set </param>
 /// <param name="Browse_Object"> Object contains all the basic information about any browse or info display </param>
 /// <param name="Current_Item"> Current item to display </param>
 /// <param name="Current_Page"> Current page within the item</param>
 /// <param name="HTML_Skin"> HTML Web skin which controls the overall appearance of this digital library </param>
 /// <param name="Current_User"> Currently logged on user </param>
 /// <param name="Public_Folder"> Object contains the information about the public folder to display </param>
 /// <param name="Site_Map"> Optional site map object used to render a navigational tree-view on left side of static web content pages </param>
 /// <param name="Items_In_Title"> List of items within the current title ( used for the Item Group display )</param>
 /// <param name="Static_Web_Content"> HTML content-based browse, info, or imple CMS-style web content objects.  These are objects which are read from a static HTML file and much of the head information must be maintained </param>
 /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
 public RequestCache(Navigation_Object Current_Mode,
     Item_Aggregation Hierarchy_Object,
     Search_Results_Statistics Results_Statistics,
     List<iSearch_Title_Result> Paged_Results,
     Item_Aggregation_Child_Page Browse_Object,
     SobekCM_Item Current_Item,
     Page_TreeNode Current_Page,
     Web_Skin_Object HTML_Skin,
     User_Object Current_User,
     Public_User_Folder Public_Folder,
     SobekCM_SiteMap Site_Map,
     SobekCM_Items_In_Title Items_In_Title,
     HTML_Based_Content Static_Web_Content,
     Custom_Tracer Tracer)
 {
     this.Current_Mode = Current_Mode;
     this.Hierarchy_Object = Hierarchy_Object;
     this.Results_Statistics = Results_Statistics;
     this.Paged_Results = Paged_Results;
     this.Browse_Object = Browse_Object;
     this.Current_Item = Current_Item;
     this.Current_Page = Current_Page;
     this.HTML_Skin = HTML_Skin;
     this.Current_User = Current_User;
     this.Public_Folder = Public_Folder;
     this.Site_Map = Site_Map;
     this.Items_In_Title = Items_In_Title;
     this.Static_Web_Content = Static_Web_Content;
     this.Tracer = Tracer;
 }
Example #4
0
        /// <summary> Adds a file  object (with the appropriate divisions and pages) to this tree </summary>
        /// <param name="New_File"> New file object to add </param>
        /// <param name="Label"> Label for the page containing this file, if it is a new page </param>
        /// <remarks> This is generally used to add just a single file.  To add many files, better logic should be implemented </remarks>
        public void Add_File(SobekCM_File_Info New_File, string Label)
        {
            // Determine the upper case name
            string systemname_upper = New_File.File_Name_Sans_Extension;

            // Look for a page/entity which has the same file name, else it will be added to the last division
            foreach (abstract_TreeNode rootNode in Roots)
            {
                if (recursively_add_file(rootNode, New_File, systemname_upper))
                {
                    return;
                }
            }

            // If not found, find the last division
            if (Roots.Count > 0)
            {
                if (!Roots[Roots.Count - 1].Page)
                {
                    // Get his last division
                    Division_TreeNode lastDivision = (Division_TreeNode)Roots[Roots.Count - 1];

                    // Find the last division then
                    while ((lastDivision.Nodes.Count > 0) && (!lastDivision.Nodes[lastDivision.Nodes.Count - 1].Page))
                    {
                        lastDivision = (Division_TreeNode)lastDivision.Nodes[lastDivision.Nodes.Count - 1];
                    }

                    // Add this as a new page on the last division
                    Page_TreeNode newPage = new Page_TreeNode(Label);
                    lastDivision.Add_Child(newPage);

                    // Now, add this file to the page
                    newPage.Files.Add(New_File);
                }
                else
                {
                    // No divisions at all, but pages exist at the top level, which is okay
                    Page_TreeNode pageNode = (Page_TreeNode)Roots[Roots.Count - 1];

                    // Now, add this file to the page
                    pageNode.Files.Add(New_File);
                }
            }
            else
            {
                // No nodes exist, so add a MAIN division node
                Division_TreeNode newDivNode = new Division_TreeNode("Main", String.Empty);
                Roots.Add(newDivNode);

                // Add this as a new page on the new division
                Page_TreeNode newPage = new Page_TreeNode(Label);
                newDivNode.Add_Child(newPage);

                // Now, add this file to the page
                newPage.Files.Add(New_File);
            }
        }
 /// <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 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 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;
 }
Example #10
0
        private void preorder_build(List <abstract_TreeNode> Collection, abstract_TreeNode ThisNode, bool OnlyAddPages, bool PagesMustHaveFiles)
        {
            // Since this is pre-order, first 'visit' this
            if (!OnlyAddPages)
            {
                Collection.Add(ThisNode);
            }
            else
            {
                // If we are just getting pages, only add if it is not already added
                if ((ThisNode.Page) && (!Collection.Contains(ThisNode)))
                {
                    // If you just add all files, just add it here
                    if (!PagesMustHaveFiles)
                    {
                        Collection.Add(ThisNode);
                    }
                    else
                    {
                        // Must ensure this page has files to add it
                        Page_TreeNode asPage = ThisNode as Page_TreeNode;
                        if (asPage != null)
                        {
                            if ((asPage.Files != null) && (asPage.Files.Count > 0))
                            {
                                Collection.Add(asPage);
                            }
                        }
                    }
                }
            }

            // is this a division node? .. which can have children ..
            if (!ThisNode.Page)
            {
                Division_TreeNode thisDivNode = (Division_TreeNode)ThisNode;

                // Do the same for all the children
                foreach (abstract_TreeNode childNode in thisDivNode.Nodes)
                {
                    preorder_build(Collection, childNode, OnlyAddPages, PagesMustHaveFiles);
                }
            }
        }
Example #11
0
        private bool recursively_add_file(abstract_TreeNode Node, SobekCM_File_Info New_File, string SystemName_Upper)
        {
            // If this is a page, check for a match first
            if (Node.Page)
            {
                Page_TreeNode pageNode = (Page_TreeNode)Node;
                if (pageNode.Files.Count >= 1)
                {
                    if (pageNode.Files[0].File_Name_Sans_Extension == SystemName_Upper)
                    {
                        // Belongs to this page.  Now, just make sure it doesn't already exist
                        foreach (SobekCM_File_Info thisFile in pageNode.Files)
                        {
                            if (thisFile.System_Name.ToUpper() == New_File.System_Name.ToUpper())
                            {
                                return(true);
                            }
                        }

                        // Not found, so add it to this page
                        pageNode.Files.Add(New_File);
                        return(true);
                    }
                }
            }

            // If this was a division, check all pages
            if (!Node.Page)
            {
                Division_TreeNode divNode = (Division_TreeNode)Node;
                foreach (abstract_TreeNode childNodes in divNode.Nodes)
                {
                    if (recursively_add_file(childNodes, New_File, SystemName_Upper))
                    {
                        return(true);
                    }
                }
            }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                        Current_Mode.Invalid_Item = true;
                        return false;
                    }

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

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

            bool mainDivisionFound = false;
            Division_Tree thisDivTree = null;

            // Loop through reading each XML node
            do
            {
                // get the right division information based on node type
                switch (R.NodeType)
                {
                        // if EndElement, move up tree
                    case XmlNodeType.EndElement:
                        if ((R.Name == "METS:structMap") || ( R.Name == "structMap" ))
                        {
                            return;
                        }

                        if ((R.Name == "METS:div") || (R.Name == "div"))
                        {
                            // If there are more than one parent on the "parent stack" pop one off
                            if (parentNodes.Count > 0)
                                parentNodes.Pop();
                        }
                        break;

                        // if new element, add name and traverse tree
                    case XmlNodeType.Element:

                        // Is this the beginning of a structure map
                        if ((R.Name == "METS:structMap") || (R.Name == "structMap"))
                        {
                            thisDivTree = Package.Divisions.Physical_Tree;
                            if (R.MoveToAttribute("TYPE"))
                            {
                                if (R.Value.ToUpper() == "OTHER")
                                    thisDivTree = Package.Divisions.Download_Tree;
                            }
                        }

                        // Is this a new division?
                        if (((R.Name == "METS:div") || ( R.Name == "div" )) && (R.HasAttributes))
                        {
                            // Since this is a new division, get all the possible attribute values or set to empty string
                            string dmdid = (R.MoveToAttribute("DMDID") ? R.Value : String.Empty);
                            string amdid = (R.MoveToAttribute("AMDID") ? R.Value : String.Empty);
                            string divID = (R.MoveToAttribute("DMDID") ? R.Value : String.Empty);
                            string divType = (R.MoveToAttribute("TYPE") ? R.Value : String.Empty);
                            string divLabel = (R.MoveToAttribute("LABEL") ? R.Value : String.Empty);

                            // Get the order
                            ushort divOrder;
                            if (R.MoveToAttribute("ORDER"))
                            {
                                if (!UInt16.TryParse(R.Value, out divOrder)) divOrder = 0;
                            }
                            else if (R.MoveToAttribute("ORDERLABEL"))
                            {
                                if (!UInt16.TryParse(R.Value, out divOrder)) divOrder = 0;
                            }
                            else
                            {
                                divOrder = 0;
                            }

                            // Was this an outer division, or the main division?
                            if (!mainDivisionFound) 
                            {
                                // This is an outer wrapper and NOT the MAIN division, so save this as an
                                // outer division (division greater than current digital resources), such as 
                                // used sometimes for serials or journals.
                                if (divType.ToUpper() != "MAIN")
                                {
                                    if (!Package.Divisions.Contains_Outer_Division(divLabel, divType))
                                    {
                                        Package.Divisions.Add_Outer_Division(divLabel, divOrder, divType);
                                    }
                                }
                                else
                                {
                                    mainDivisionFound = true;
                                }
                            }
                            else
                            {
                                // Get the parent node, if there is one
                                abstract_TreeNode parentNode = parentNodes.Count > 0 ? parentNodes.Peek() : null;

                                // Create this division
                                abstract_TreeNode bibNode;
                                if (divType.ToUpper() == "PAGE")
                                    bibNode = new Page_TreeNode(divLabel);
                                else
                                    bibNode = new Division_TreeNode(divType, divLabel);

                                // Check to make sure no repeat here                               
                                if (divID.IndexOf("_repeat") > 0)
                                {
                                    divID = divID.Substring(0, divID.IndexOf("_repeat"));
                                    if (divisions_by_id.ContainsKey(divID))
                                    {
                                        bibNode = divisions_by_id[divID];
                                    }
                                }
                                
                                // Get the DMD sec or AMD sec's 
                                if (dmdid.Length > 0)
                                {
                                    string[] divDmdSecIds = dmdid.Split(" ".ToCharArray());
                                    foreach( string thisId in divDmdSecIds )
                                    {
                                        DivisionDmdids[thisId] = bibNode;
                                    }                                        
                                }
                                if (amdid.Length > 0)
                                {
                                    string[] divAmdSecIds = amdid.Split(" ".ToCharArray());
                                    foreach (string thisId in divAmdSecIds)
                                    {
                                        DivisionAmdids[thisId] = bibNode;
                                    }
                                }

                                // If there is a parent, add to it
                                if (parentNode != null)
                                {
                                    ((Division_TreeNode) parentNode).Nodes.Add(bibNode);
                                }
                                else
                                {
                                    // No parent, so add this to the root
                                    thisDivTree.Roots.Add(bibNode);
                                }

                                // Now, add this to the end of the parent list, in case it has children
                                if (!R.IsEmptyElement)
                                {
                                    parentNodes.Push(bibNode);
                                }
                            }

                            R.MoveToElement();
                        }

                        // Is this a new file pointer applying to the last division?
                        if (((R.Name == "METS:fptr") || (R.Name == "fptr")) && (R.MoveToAttribute("FILEID")))
                        {
                            // Get this file id
                            string fileID = R.Value;

                            // Get the file from the files by id dictionary
                            if (FilesByFileid.ContainsKey(fileID))
                            {
                                SobekCM_File_Info thisFile = FilesByFileid[fileID];

                                abstract_TreeNode pageParentNode = null;
                                if (parentNodes.Count > 0)
                                    pageParentNode = parentNodes.Peek();


                                if ((pageParentNode != null) && (pageParentNode.Page))
                                {
                                    Page_TreeNode asPageNode = (Page_TreeNode) pageParentNode;
                                    if (!asPageNode.Files.Contains(thisFile))
                                        asPageNode.Files.Add(thisFile);
                                }
                                else
                                {
                                    if (pageParentNode == null)
                                    {
                                        thisDivTree.Add_File(thisFile);
                                    }
                                    else
                                    {
                                        Division_TreeNode asDivNode = (Division_TreeNode) pageParentNode;

                                        Page_TreeNode newPage = new Page_TreeNode();
                                        asDivNode.Add_Child(newPage);

                                        //parentNodes.Push(newPage);

                                        newPage.Files.Add(thisFile);
                                    }
                                }
                            }
                        }

                        // Is this a new METS pointer, often seen when importing from DSpace
                        if ((R.Name == "METS:mptr") || (R.Name == "mptr")) 
                        {
                            // Get the parent label
                            string parentLabel = String.Empty;

                            // Look for a parent node (should be one)
                            if (parentNodes.Count > 0)
                            {
                                abstract_TreeNode pageParentNode = parentNodes.Peek();
                                parentLabel = pageParentNode.Label;
                            }
                            else if (Package.Divisions.Outer_Division_Count > 0)
                            {
                                parentLabel = Package.Divisions.Outer_Divisions[Package.Divisions.Outer_Division_Count - 1].Label;
                            }

                            if ((!String.IsNullOrEmpty(parentLabel)) && (String.Compare(parentLabel, "Parent of this DSpace Object", StringComparison.OrdinalIgnoreCase) == 0))
                            {
                                // Is this a HANDLE reference?
                                string locType = (R.MoveToAttribute("LOCTYPE") ? R.Value : String.Empty).ToUpper();
                                string href = (R.MoveToAttribute("xlink:href") ? R.Value : String.Empty);

                                // If this has a handle href, make that the aggregation
                                if ((locType == "HANDLE") && (href.Length > 0))
                                {
                                    Package.Behaviors.Add_Aggregation(href);
                                }
                            }
                        }

                        break;

                } // end switch
            } while (R.Read());
        }
        /// <summary> Reads metadata from an open stream and saves to the provided item/package </summary>
        /// <param name="Input_Stream"> Open stream to read metadata from </param>
        /// <param name="Return_Package"> Package into which to read the metadata </param>
        /// <param name="Options"> Dictionary of any options which this metadata reader/writer may utilize </param>
        /// <param name="Error_Message">[OUTPUT] Explanation of the error, if an error occurs during reading </param>
        /// <returns>TRUE if successful, otherwise FALSE </returns>
        /// <remarks> Accepts two options: (1) 'METS_File_ReaderWriter:Minimize_File_Info' which tells whether the reader 
        /// should just skip the file reading portion completely, and just read the bibliographic data ( Default is FALSE).
        /// (2) 'METS_File_ReaderWriter:Support_Divisional_dmdSec_amdSec' </remarks>
        public bool Read_Metadata(Stream Input_Stream, SobekCM_Item Return_Package, Dictionary<string, object> Options, out string Error_Message)
        {
            Error_Message = String.Empty;

            // Read the options from the dictionary of options
            bool minimizeFileInfo = false;
            if (Options != null)
            {
                if (Options.ContainsKey("METS_File_ReaderWriter:Minimize_File_Info"))
                    bool.TryParse(Options["METS_File_ReaderWriter:Minimize_File_Info"].ToString(), out minimizeFileInfo);

                if (Options.ContainsKey("METS_File_ReaderWriter:Support_Divisional_dmdSec_amdSec"))
                {
                    bool supportDivisionalDmdSecAmdSec;
                    bool.TryParse(Options["METS_File_ReaderWriter:Support_Divisional_dmdSec_amdSec"].ToString(), out supportDivisionalDmdSecAmdSec);
                }
            }

            // Keep a list of all the files created, by file id, as additional data is gathered
            // from the different locations ( amdSec, fileSec, structmap )
            Dictionary<string, SobekCM_File_Info> files_by_fileid = new Dictionary<string, SobekCM_File_Info>();

            // For now, to do support for old way of doing downloads, build a list to hold
            // the deprecated download files
            List<Download_Info_DEPRECATED> deprecatedDownloads = new List<Download_Info_DEPRECATED>();

            // Need to store the unanalyzed sections of dmdSec and amdSec until we determine if 
            // the scope is the whole package, or the top-level div.  We use lists as the value since
            // several sections may have NO id and the METS may even (incorrectly) have multiple sections
            // with the same ID
            Dictionary<string, List<Unanalyzed_METS_Section>> dmdSec = new Dictionary<string, List<Unanalyzed_METS_Section>>();
            Dictionary<string, List<Unanalyzed_METS_Section>> amdSec = new Dictionary<string, List<Unanalyzed_METS_Section>>();

            // Dictionaries store the link between dmdSec and amdSec id's to single divisions
            Dictionary<string, abstract_TreeNode> division_dmdids = new Dictionary<string, abstract_TreeNode>();
            Dictionary<string, abstract_TreeNode> division_amdids = new Dictionary<string, abstract_TreeNode>();


            try
            {
                // Try to read the XML
                XmlReader r = new XmlTextReader(Input_Stream);

                // Begin stepping through each of the XML nodes
                while (r.Read())
                {
                    #region Handle some processing instructions requested by Florida SUS's / FLVC (hope to deprecate)

                    // Handle some processing instructions requested by Florida SUS's / FLVC
                    if (r.NodeType == XmlNodeType.ProcessingInstruction)
                    {
                        if (r.Name.ToLower() == "fcla")
                        {
                            string value = r.Value.ToLower();
                            if (value.IndexOf("fda=\"yes\"") >= 0)
                            {
                                DAITSS_Info daitssInfo = Return_Package.Get_Metadata_Module(GlobalVar.DAITSS_METADATA_MODULE_KEY) as DAITSS_Info;
                                if (daitssInfo == null)
                                {
                                    daitssInfo = new DAITSS_Info();
                                    Return_Package.Add_Metadata_Module(GlobalVar.DAITSS_METADATA_MODULE_KEY, daitssInfo);
                                }
                                daitssInfo.toArchive = true;
                            }
                            if (value.IndexOf("fda=\"no\"") >= 0)
                            {
                                DAITSS_Info daitssInfo2 = Return_Package.Get_Metadata_Module(GlobalVar.DAITSS_METADATA_MODULE_KEY) as DAITSS_Info;
                                if (daitssInfo2 == null)
                                {
                                    daitssInfo2 = new DAITSS_Info();
                                    Return_Package.Add_Metadata_Module(GlobalVar.DAITSS_METADATA_MODULE_KEY, daitssInfo2);
                                }
                                daitssInfo2.toArchive = false;
                            }
                        }
                    }

                    #endregion

                    if (r.NodeType == XmlNodeType.Element)
                    {
                        switch (r.Name.Replace("METS:", ""))
                        {
                            case "mets":
                                if (r.MoveToAttribute("OBJID"))
                                    Return_Package.METS_Header.ObjectID = r.Value;
                                break;

                            case "metsHdr":
                                read_mets_header(r.ReadSubtree(), Return_Package);
                                break;

                            case "dmdSec":
                            case "dmdSecFedora":
                                Unanalyzed_METS_Section thisDmdSec = store_dmd_sec(r.ReadSubtree());
                                if ( dmdSec.ContainsKey(thisDmdSec.ID))
                                    dmdSec[thisDmdSec.ID].Add(thisDmdSec);
                                else
                                {
                                    List<Unanalyzed_METS_Section> newDmdSecList = new List<Unanalyzed_METS_Section>();
                                    newDmdSecList.Add(thisDmdSec);
                                    dmdSec[thisDmdSec.ID] = newDmdSecList;
                                }
                                
                                break;

                            case "amdSec":
                                Unanalyzed_METS_Section thisAmdSec = store_amd_sec(r.ReadSubtree());
                                if (amdSec.ContainsKey(thisAmdSec.ID))
                                    amdSec[thisAmdSec.ID].Add(thisAmdSec);
                                else
                                {
                                    List<Unanalyzed_METS_Section> newAmdSecList = new List<Unanalyzed_METS_Section> {thisAmdSec};
                                    amdSec[thisAmdSec.ID] = newAmdSecList;
                                }
                                break;

                            case "fileSec":
                                read_file_sec(r.ReadSubtree(), minimizeFileInfo, files_by_fileid);
                                break;

                            case "structMap":
                                if (!r.IsEmptyElement)
                                {
                                    read_struct_map(r.ReadSubtree(), Return_Package, files_by_fileid, division_dmdids, division_amdids);
                                }
                                break;

                            case "behaviorSec":
                                read_behavior_sec(r.ReadSubtree(), Return_Package);
                                break;
                        }
                    }
                }

                // writer.Close();
                r.Close();

            }
            catch 
            {
                // Do nothinh
            }

            Input_Stream.Close();

            // Load some options for interoperability
            Dictionary<string, object> options = new Dictionary<string, object>();
            options.Add("SobekCM_FileInfo_METS_amdSec_ReaderWriter:Files_By_FileID", files_by_fileid);

            #region Process the previously stored dmd sections

            // Now, process the previously stored dmd sections
            foreach (string thisDmdSecId in dmdSec.Keys)
            {
                // Could be multiple stored sections with the same (or no) ID
                foreach (Unanalyzed_METS_Section metsSection in dmdSec[thisDmdSecId])
                {
                    XmlReader reader = XmlReader.Create(new StringReader(metsSection.Inner_XML));
                    string mdtype = String.Empty;
                    string othermdtype = String.Empty;
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element)
                        {
                            if (reader.Name.ToLower().Replace("mets:", "") == "mdwrap")
                            {

                                if (reader.MoveToAttribute("MDTYPE"))
                                    mdtype = reader.Value;
                                if (reader.MoveToAttribute("OTHERMDTYPE"))
                                    othermdtype = reader.Value;

                                // NOt crazy about this part, but sometimes people do not use the OTHERMDTYPE
                                // tag correctly, and just use the LABEL to differentiate the types
                                if ((mdtype == "OTHER") && (othermdtype.Length == 0) && (reader.MoveToAttribute("LABEL")))
                                    othermdtype = reader.Value;

                                // Now, determine if this was a division-level read, or a package-wide
                                if (division_dmdids.ContainsKey(thisDmdSecId))
                                {
                                    // Division level dmdSec
                                    // Get the division
                                    abstract_TreeNode node = division_dmdids[thisDmdSecId];

                                    // Get an appropriate reader from the metadata configuration
                                    iDivision_dmdSec_ReaderWriter rw = ResourceObjectSettings.MetadataConfig.Get_Division_DmdSec_ReaderWriter(mdtype, othermdtype);

                                    // Is this dmdSec analyzable? (i.e., did we find an appropriate reader/writer?)
                                    if (rw == null)
                                    {
                                        node.Add_Unanalyzed_DMDSEC(metsSection);
                                    }
                                    else
                                    {
                                        rw.Read_dmdSec(reader, node, options);
                                    }
                                }
                                else
                                {
                                    // Package-level dmdSec 
                                    // Get an appropriate reader from the metadata configuration
                                    iPackage_dmdSec_ReaderWriter rw = ResourceObjectSettings.MetadataConfig.Get_Package_DmdSec_ReaderWriter(mdtype, othermdtype);

                                    // Is this dmdSec analyzable? (i.e., did we find an appropriate reader/writer?)
                                    if (rw == null)
                                    {
                                        Return_Package.Add_Unanalyzed_DMDSEC(metsSection);
                                    }
                                    else
                                    {
                                        rw.Read_dmdSec(reader, Return_Package, options);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            #endregion

            #region Process the previously stored amd sections

            // Now, process the previously stored amd sections
            foreach (string thisAmdSecId in amdSec.Keys)
            {
                // Could be multiple stored sections with the same (or no) ID
                foreach (Unanalyzed_METS_Section metsSection in amdSec[thisAmdSecId])
                {
                    XmlReader reader = XmlReader.Create(new StringReader(metsSection.Inner_XML));
                    string mdtype = String.Empty;
                    string othermdtype = String.Empty;
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element)
                        {
                            if (reader.Name.ToLower().Replace("mets:", "") == "mdwrap")
                            {

                                if (reader.MoveToAttribute("MDTYPE"))
                                    mdtype = reader.Value;
                                if (reader.MoveToAttribute("OTHERMDTYPE"))
                                    othermdtype = reader.Value;

                                // Package-level amdSec 
                                // Get an appropriate reader from the metadata configuration
                                iPackage_amdSec_ReaderWriter rw = ResourceObjectSettings.MetadataConfig.Get_Package_AmdSec_ReaderWriter(mdtype, othermdtype);

                                // Is this amdSec analyzable? (i.e., did we find an appropriate reader/writer?)
                                if (rw == null)
                                {
                                    Return_Package.Add_Unanalyzed_AMDSEC(metsSection);
                                }
                                else
                                {
                                    rw.Read_amdSec(reader, Return_Package, options);
                                }
                            }
                        }
                    }
                }
            }

            #endregion

            #region Special code used for moving downloads into the structure map system, and out of the old SobekCM METS section 

            // For backward compatability, move from the old download system to the
            // new structure.  This has to happen here at the end so that we have access

            // Were there some downloads added here?
            if (deprecatedDownloads.Count > 0)
            {
                // Get the list of downloads from the download tree
                List<SobekCM_File_Info> newStructureDownloads = Return_Package.Divisions.Download_Tree.All_Files;

                // Step through each download in the old system
                foreach (Download_Info_DEPRECATED thisDownload in deprecatedDownloads)
                {
                    // Get the label (if there is one)
                    string label = thisDownload.Label;
                    string filename = thisDownload.FileName;
                    bool found = false;
                    if ((filename.Length == 0) && (thisDownload.File_ID.Length > 0))
                    {
                        if (files_by_fileid.ContainsKey(thisDownload.File_ID))
                        {
                            SobekCM_File_Info thisDownloadFile = files_by_fileid[thisDownload.File_ID];
                            filename = thisDownloadFile.System_Name;

                            // Ensure a file of this name doesn't already exist
                            foreach (SobekCM_File_Info existingFile in newStructureDownloads)
                            {
                                if (existingFile.System_Name.ToUpper().Trim() == filename.ToUpper().Trim())
                                {
                                    found = true;
                                    break;
                                }
                            }

                            // Not found, so add it
                            if (!found)
                            {
                                // Determine the label if it was missing or identical to file name
                                if ((label.Length == 0) || (label == filename))
                                {
                                    label = filename;
                                    int first_period_index = label.IndexOf('.');
                                    if (first_period_index > 0)
                                    {
                                        label = label.Substring(0, first_period_index);
                                    }
                                }

                                // Add the root to the download tree, if not existing
                                Division_TreeNode newRoot;
                                if (Return_Package.Divisions.Download_Tree.Roots.Count == 0)
                                {
                                    newRoot = new Division_TreeNode("Main", String.Empty);
                                    Return_Package.Divisions.Download_Tree.Roots.Add(newRoot);
                                }
                                else
                                {
                                    newRoot = (Division_TreeNode) Return_Package.Divisions.Download_Tree.Roots[0];
                                }

                                // Add a page for this, with the provided label if there was one
                                Page_TreeNode newPage = new Page_TreeNode(label);
                                newRoot.Nodes.Add(newPage);

                                // Now, add this existing file
                                newPage.Files.Add(thisDownloadFile);

                                // Add to the list of files added (in case it appears twice)
                                newStructureDownloads.Add(thisDownloadFile);
                            }
                        }
                    }
                    else
                    {
                        // Ensure a file of this name doesn't already exist
                        foreach (SobekCM_File_Info existingFile in newStructureDownloads)
                        {
                            if (existingFile.System_Name.ToUpper().Trim() == filename.ToUpper().Trim())
                            {
                                found = true;
                                break;
                            }
                        }

                        // Not found, so add it
                        if (!found)
                        {
                            // Determine the label if it was missing or identical to file name
                            if ((label.Length == 0) || (label == filename))
                            {
                                label = filename;
                                int first_period_index = label.IndexOf('.');
                                if (first_period_index > 0)
                                {
                                    label = label.Substring(0, first_period_index);
                                }
                            }

                            // Add the root to the download tree, if not existing
                            Division_TreeNode newRoot;
                            if (Return_Package.Divisions.Download_Tree.Roots.Count == 0)
                            {
                                newRoot = new Division_TreeNode("Main", String.Empty);
                                Return_Package.Divisions.Download_Tree.Roots.Add(newRoot);
                            }
                            else
                            {
                                newRoot = (Division_TreeNode) Return_Package.Divisions.Download_Tree.Roots[0];
                            }

                            // Add a page for this, with the provided label if there was one
                            Page_TreeNode newPage = new Page_TreeNode(label);
                            newRoot.Nodes.Add(newPage);

                            // Now, add this existing file
                            SobekCM_File_Info thisDownloadFile = new SobekCM_File_Info(filename);
                            newPage.Files.Add(thisDownloadFile);

                            // Add to the list of files added (in case it appears twice)
                            newStructureDownloads.Add(thisDownloadFile);
                        }
                    }
                }
            }

            #endregion

            #region Special code for distributing any page-level coordinate information read from the old SobekCM coordinate metadata

            // Get the geospatial data
            GeoSpatial_Information geoSpatial = Return_Package.Get_Metadata_Module(GlobalVar.GEOSPATIAL_METADATA_MODULE_KEY) as GeoSpatial_Information;
            if ((geoSpatial != null) && ( geoSpatial.Polygon_Count > 0 ))
            {
                // See if any has the page sequence filled out, which means it came from the old metadata system
                bool redistribute = false;
                foreach (Coordinate_Polygon thisPolygon in geoSpatial.Polygons)
                {
                    if (thisPolygon.Page_Sequence > 0)
                    {
                        redistribute = true;
                        break;
                    }
                }

                // If we need to redistribute, get started!
                if (redistribute)
                {
                    // Get the pages, by sequence
                    List<abstract_TreeNode> pagesBySequence = Return_Package.Divisions.Physical_Tree.Pages_PreOrder;
                    List<Coordinate_Polygon> polygonsToRemove = new List<Coordinate_Polygon>();

                    // Step through each polygon
                    foreach (Coordinate_Polygon thisPolygon in geoSpatial.Polygons)
                    {
                        if ((thisPolygon.Page_Sequence > 0) && ( thisPolygon.Page_Sequence <= pagesBySequence.Count ))
                        {
                            // Get the page
                            abstract_TreeNode thisPageFromSequence = pagesBySequence[thisPolygon.Page_Sequence - 1];

                            // We can assume this page does not already have the coordiantes
                            GeoSpatial_Information thisPageCoord = new GeoSpatial_Information();
                            thisPageFromSequence.Add_Metadata_Module( GlobalVar.GEOSPATIAL_METADATA_MODULE_KEY, thisPageCoord );
                            thisPageCoord.Add_Polygon( thisPolygon);

                            // Remove this from the package-level coordinates
                            polygonsToRemove.Add(thisPolygon);
                        }
                    }

                    // Now, remove all polygons flagged to be removed
                    foreach (Coordinate_Polygon thisPolygon in polygonsToRemove)
                    {
                        geoSpatial.Remove_Polygon(thisPolygon);
                    }
                }
            }

            #endregion

            #region Copy any serial hierarchy in the Behaviors.Serial_Info part into the bib portion, if not there

            // Do some final cleanup on the SERIAL HIERARCHY
            if ((Return_Package.Behaviors.hasSerialInformation) && (Return_Package.Behaviors.Serial_Info.Count > 0))
            {
                if ((Return_Package.Bib_Info.Series_Part_Info.Enum1.Length == 0) && (Return_Package.Bib_Info.Series_Part_Info.Year.Length == 0))
                {
                    if (Return_Package.Bib_Info.SobekCM_Type == TypeOfResource_SobekCM_Enum.Newspaper)
                    {
                        Return_Package.Bib_Info.Series_Part_Info.Year = Return_Package.Behaviors.Serial_Info[0].Display;
                        Return_Package.Bib_Info.Series_Part_Info.Year_Index = Return_Package.Behaviors.Serial_Info[0].Order;

                        if (Return_Package.Behaviors.Serial_Info.Count > 1)
                        {
                            Return_Package.Bib_Info.Series_Part_Info.Month = Return_Package.Behaviors.Serial_Info[1].Display;
                            Return_Package.Bib_Info.Series_Part_Info.Month_Index = Return_Package.Behaviors.Serial_Info[1].Order;
                        }
                    }

                    if (Return_Package.Behaviors.Serial_Info.Count > 2)
                    {
                        Return_Package.Bib_Info.Series_Part_Info.Day = Return_Package.Behaviors.Serial_Info[2].Display;
                        Return_Package.Bib_Info.Series_Part_Info.Day_Index = Return_Package.Behaviors.Serial_Info[2].Order;
                    }
                }
                else
                {
                    Return_Package.Bib_Info.Series_Part_Info.Enum1 = Return_Package.Behaviors.Serial_Info[0].Display;
                    Return_Package.Bib_Info.Series_Part_Info.Enum1_Index = Return_Package.Behaviors.Serial_Info[0].Order;

                    if (Return_Package.Behaviors.Serial_Info.Count > 1)
                    {
                        Return_Package.Bib_Info.Series_Part_Info.Enum2 = Return_Package.Behaviors.Serial_Info[1].Display;
                        Return_Package.Bib_Info.Series_Part_Info.Enum2_Index = Return_Package.Behaviors.Serial_Info[1].Order;
                    }

                    if (Return_Package.Behaviors.Serial_Info.Count > 2)
                    {
                        Return_Package.Bib_Info.Series_Part_Info.Enum3 = Return_Package.Behaviors.Serial_Info[2].Display;
                        Return_Package.Bib_Info.Series_Part_Info.Enum3_Index = Return_Package.Behaviors.Serial_Info[2].Order;
                    }
                }
            }

            #endregion

            return true;
        }
        private void read_struct_map(XmlReader r, SobekCM_Item package, Dictionary<string, SobekCM_File_Info> files_by_fileid, Dictionary<string, abstract_TreeNode> division_dmdids, Dictionary<string, abstract_TreeNode> division_amdids )
        {
            Stack<abstract_TreeNode> parentNodes = new Stack<abstract_TreeNode>();
            Dictionary<string, abstract_TreeNode> divisions_by_id = new Dictionary<string, abstract_TreeNode>();

            string divID;
            string divType = String.Empty;
            string divLabel = String.Empty;
            string fileID = String.Empty;
            string dmdid = String.Empty;
            string amdid = String.Empty;
            ushort divOrder = 0;
            bool mainDivisionFound = false;
            abstract_TreeNode parentNode;
            Division_Tree thisDivTree = null;

            // Loop through reading each XML node
            do
            {
                // get the right division information based on node type
                switch (r.NodeType)
                {
                        // if EndElement, move up tree
                    case XmlNodeType.EndElement:
                        if (r.Name == "METS:structMap")
                        {
                            return;
                        }

                        if (r.Name == "METS:div")
                        {
                            // If there are more than one parent on the "parent stack" pop one off
                            if (parentNodes.Count > 0)
                                parentNodes.Pop();
                        }
                        break;

                        // if new element, add name and traverse tree
                    case XmlNodeType.Element:

                        // Is this the beginning of a structure map
                        if (r.Name == "METS:structMap")
                        {
                            thisDivTree = package.Divisions.Physical_Tree;
                            if (r.MoveToAttribute("TYPE"))
                            {
                                if (r.Value.ToUpper() == "OTHER")
                                    thisDivTree = package.Divisions.Download_Tree;
                            }
                        }

                        // Is this a new division?
                        if ((r.Name == "METS:div") && (r.HasAttributes))
                        {
                            // Since this is a new division, get all the possible attribute values or set to empty string
                            dmdid = (r.MoveToAttribute("DMDID") ? r.Value : String.Empty);
                            amdid = (r.MoveToAttribute("AMDID") ? r.Value : String.Empty);
                            divID = (r.MoveToAttribute("DMDID") ? r.Value : String.Empty);
                            divType = (r.MoveToAttribute("TYPE") ? r.Value : String.Empty);
                            divLabel = (r.MoveToAttribute("LABEL") ? r.Value : String.Empty);

                            // Get the order
                            if (r.MoveToAttribute("ORDER"))
                            {
                                if (!UInt16.TryParse(r.Value, out divOrder)) divOrder = 0;
                            }
                            else if (r.MoveToAttribute("ORDERLABEL"))
                            {
                                if (!UInt16.TryParse(r.Value, out divOrder)) divOrder = 0;
                            }
                            else
                            {
                                divOrder = 0;
                            }

                            // Was this an outer division, or the main division?
                            if (!mainDivisionFound) 
                            {
                                // This is an outer wrapper and NOT the MAIN division, so save this as an
                                // outer division (division greater than current digital resources), such as 
                                // used sometimes for serials or journals.
                                if (divType.ToUpper() != "MAIN")
                                {
                                    if (!package.Divisions.Contains_Outer_Division(divLabel, divType))
                                    {
                                        package.Divisions.Add_Outer_Division(divLabel, divOrder, divType);
                                    }
                                }
                                else
                                {
                                    mainDivisionFound = true;
                                }
                            }
                            else
                            {
                                // Get the parent node, if there is one
                                parentNode = parentNodes.Count > 0 ? parentNodes.Peek() : null;

                                // Create this division
                                abstract_TreeNode bibNode;
                                if (divType.ToUpper() == "PAGE")
                                    bibNode = new Page_TreeNode(divLabel);
                                else
                                    bibNode = new Division_TreeNode(divType, divLabel);

                                // Check to make sure no repeat here                               
                                if (divID.IndexOf("_repeat") > 0)
                                {
                                    divID = divID.Substring(0, divID.IndexOf("_repeat"));
                                    if (divisions_by_id.ContainsKey(divID))
                                    {
                                        bibNode = divisions_by_id[divID];
                                    }
                                }
                                
                                // Get the DMD sec or AMD sec's 
                                if (dmdid.Length > 0)
                                {
                                    string[] divDmdSecIds = dmdid.Split(" ".ToCharArray());
                                    foreach( string thisId in divDmdSecIds )
                                    {
                                        division_dmdids[thisId] = bibNode;
                                    }                                        
                                }
                                if (amdid.Length > 0)
                                {
                                    string[] divAmdSecIds = amdid.Split(" ".ToCharArray());
                                    foreach (string thisId in divAmdSecIds)
                                    {
                                        division_amdids[thisId] = bibNode;
                                    }
                                }

                                // If there is a parent, add to it
                                if (parentNode != null)
                                {
                                    ((Division_TreeNode) parentNode).Nodes.Add(bibNode);
                                }
                                else
                                {
                                    // No parent, so add this to the root
                                    thisDivTree.Roots.Add(bibNode);
                                }

                                // Now, add this to the end of the parent list, in case it has children
                                if (!r.IsEmptyElement)
                                {
                                    parentNodes.Push(bibNode);
                                }
                            }

                            r.MoveToElement();
                        }

                        // Is this a new file pointer applying to the last division?
                        if ((r.Name == "METS:fptr") && (r.MoveToAttribute("FILEID")))
                        {
                            // Get this file id
                            fileID = r.Value;

                            // Get the file from the files by id dictionary
                            if (files_by_fileid.ContainsKey(fileID))
                            {
                                SobekCM_File_Info thisFile = files_by_fileid[fileID];

                                abstract_TreeNode pageParentNode = null;
                                if (parentNodes.Count > 0)
                                    pageParentNode = parentNodes.Peek();


                                if ((pageParentNode != null) && (pageParentNode.Page))
                                {
                                    Page_TreeNode asPageNode = (Page_TreeNode) pageParentNode;
                                    if (!asPageNode.Files.Contains(thisFile))
                                        asPageNode.Files.Add(thisFile);
                                }
                                else
                                {
                                    if (pageParentNode == null)
                                    {
                                        thisDivTree.Add_File(thisFile);
                                    }
                                    else
                                    {
                                        Division_TreeNode asDivNode = (Division_TreeNode) pageParentNode;

                                        Page_TreeNode newPage = new Page_TreeNode();
                                        asDivNode.Add_Child(newPage);

                                        //parentNodes.Push(newPage);

                                        newPage.Files.Add(thisFile);
                                    }
                                }
                            }
                        }
                        break;
                } // end switch
            } while (r.Read());
        }
        //public void Set_Text_Language(Application_State.Language_Enum Language)
        //{
        //    switch (Language)
        //    {
        //        case Application_State.Language_Enum.French:
        //            search = "RECHERCHE";
        //            search_doc = "Recherche Ce Document";
        //            view = "VUE";
        //            full_citation = "Notice"; // "Citation Complètes";
        //            browse_images = "Revue des Images";
        //            view_image = "Revue l'Image";
        //            browse_text = "Revue la Texte";
        //            language = "LANGUE";
        //            english = "Anglais";
        //            french = "Français";
        //            spanish = "Espagñol";
        //            download = "TÉLÉCHARGEMENT";
        //            help = "AIDE";
        //            using_site = "Navigation";
        //            contact = "Assistance";
        //            contents = "TABLE DES MATIÈRES";
        //            break;
        //        case Application_State.Language_Enum.Spanish:
        //            search = "BUSCAR";
        //            search_all = "Busque Todas las Colecciones";
        //            search_this = "Busque Esta Colección";
        //            last_search = "Resultados Anteriores";
        //            search_doc = "Busque Este Documento";
        //            view = "VER";
        //            full_citation = "Cita Completa";
        //            browse_images = "Navegar Imagenes";
        //            view_image = "Ver Imagen";
        //            browse_text = "Navegar Texto";
        //            language = "IDIOMA";
        //            english = "Inglés";
        //            french = "Francés";
        //            spanish = "Español";
        //            download = "TRANSFERENCIA DIRECTA";
        //            help = "AYUDA";
        //            using_site = "Usando este sitio";
        //            contact = "Contacto";
        //            contents = "INDICE";
        //            break;
        //    }
        //}
        /// <summary> Writes the HTML generated by this item html subwriter directly to the response stream </summary>
        /// <param name="Output"> Stream to which to write the HTML for this subwriter </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        /// <returns> Value indicating if html writer should finish the page immediately after this, or if there are other controls or routines which need to be called first </returns>
        /// <remarks> This begins writing this page, up to the item-level main menu</remarks>
        public override bool Write_HTML(TextWriter Output, Custom_Tracer Tracer)
        {
            Tracer.Add_Trace("Item_HtmlSubwriter.Write_HTML", "Begin writing the item viewer, up to the item-level main menu");

            // If this is for a fragment, do nothing
            if (!String.IsNullOrEmpty(currentMode.Fragment))
                return false;

            Output.WriteLine();

            // Just return if this is the pageviewer
            if (PageViewer.ItemViewer_Type == ItemViewer_Type_Enum.GnuBooks_PageTurner)
            {
                return true;
            }

            // Put an itemscope div around here for micro-data purposes
            Output.WriteLine("<!-- Unstyled div placed around entire item information to support schema.org microdata -->");
            Output.WriteLine("<div itemscope itemtype=\"http:schema.org/ItemPage\">");
            Output.WriteLine();

            // The item viewer can choose to override the standard item titlebar
            if (!behaviors.Contains(HtmlSubwriter_Behaviors_Enum.Item_Subwriter_Suppress_Titlebar))
            {
                Output.WriteLine("<!-- Show the title and any other important item information -->");
                Output.WriteLine("<div id=\"sbkIsw_Titlebar\">");
                if (currentItem.METS_Header.RecordStatus_Enum == METS_Record_Status.BIB_LEVEL)
                {
                    string grouptitle = currentItem.Behaviors.GroupTitle;
                    if (grouptitle.Length > 125)
                    {
                        Output.WriteLine("\t<h1 itemprop=\"name\"><abbr title=\"" + grouptitle + "\">" + grouptitle.Substring(0, 120) + "...</abbr></h1>");
                    }
                    else
                    {
                        Output.WriteLine("\t<h1 itemprop=\"name\">" + grouptitle + "</h1>");
                    }
                }
                else
                {
                    string final_title = currentItem.Bib_Info.Main_Title.Title;
                    if (currentItem.Bib_Info.Main_Title.NonSort.Length > 0)
                    {
                        if (currentItem.Bib_Info.Main_Title.NonSort[currentItem.Bib_Info.Main_Title.NonSort.Length - 1] == ' ')
                            final_title = currentItem.Bib_Info.Main_Title.NonSort + currentItem.Bib_Info.Main_Title.Title;
                        else
                        {
                            if (currentItem.Bib_Info.Main_Title.NonSort[currentItem.Bib_Info.Main_Title.NonSort.Length - 1] == '\'')
                            {
                                final_title = currentItem.Bib_Info.Main_Title.NonSort + currentItem.Bib_Info.Main_Title.Title;
                            }
                            else
                            {
                                final_title = currentItem.Bib_Info.Main_Title.NonSort + " " + currentItem.Bib_Info.Main_Title.Title;
                            }
                        }
                    }

                    // Add the Title if there is one
                    if (final_title.Length > 0)
                    {
                        // Is this a newspaper?
                        bool newspaper = currentItem.Behaviors.GroupType.ToUpper() == "NEWSPAPER";

                        // Does a custom setting override the default behavior to add a date?
                        if ((newspaper) && (SobekCM_Library_Settings.Additional_Settings.ContainsKey("Item Viewer.Include Date In Title")) && (SobekCM_Library_Settings.Additional_Settings["Item Viewer.Include Date In Title"].ToUpper() == "NEVER"))
                            newspaper = false;

                        // Add the date if it should be added
                        if ((newspaper) && ((currentItem.Bib_Info.Origin_Info.Date_Created.Length > 0) || (currentItem.Bib_Info.Origin_Info.Date_Issued.Length > 0)))
                        {
                            string date = currentItem.Bib_Info.Origin_Info.Date_Created;
                            if (currentItem.Bib_Info.Origin_Info.Date_Created.Length == 0)
                                date = currentItem.Bib_Info.Origin_Info.Date_Issued;

                            if (final_title.Length > 125)
                            {
                                Output.WriteLine("\t<h1 itemprop=\"name\"><abbr title=\"" + final_title + "\">" + final_title.Substring(0, 120) + "...</abbr> ( " + date + " )</h1>");
                            }
                            else
                            {
                                Output.WriteLine("\t<h1 itemprop=\"name\">" + final_title + " ( " + date + " )</h1>");
                            }
                        }
                        else
                        {
                            if (final_title.Length > 125)
                            {
                                Output.WriteLine("\t<h1 itemprop=\"name\"><abbr title=\"" + final_title + "\">" + final_title.Substring(0, 120) + "...</abbr></h1>");
                            }
                            else
                            {
                                Output.WriteLine("\t<h1 itemprop=\"name\">" + final_title + "</h1>");
                            }
                        }
                    }

                    // Add the link if there is one
                    if ((currentItem.Bib_Info.hasLocationInformation) && (currentItem.Bib_Info.Location.Other_URL.Length > 0))
                    {
                        if (currentItem.Bib_Info.Location.Other_URL.ToLower().IndexOf("www.youtube.com") < 0)
                        {

                            // Determine the type of link
                            string type = translations.Get_Translation("Related Link", currentMode.Language);
                            if (currentItem.Bib_Info.Location.Other_URL_Display_Label.Length > 0)
                            {
                                type = translations.Get_Translation(currentItem.Bib_Info.Location.Other_URL_Display_Label, currentMode.Language);
                            }

                            // Determine the display value
                            string note = currentItem.Bib_Info.Location.Other_URL;
                            if (currentItem.Bib_Info.Location.Other_URL_Note.Length > 0)
                            {
                                note = currentItem.Bib_Info.Location.Other_URL_Note;
                            }

                            // Add the link
                            Output.WriteLine("\t<a href=\"" + currentItem.Bib_Info.Location.Other_URL + "\">" + note + " ( " + type + " )</a><br />");
                        }
                    }

                    // If there is an ACCESSION number and this is an ARTIFACT, include that at the top
                    //EDIT: Removing the condition for checking if this is an ARTIFACT. Always display the ACCESSION number if available (6/18/2014 - SY)
              //      if ((currentItem.Bib_Info.SobekCM_Type == TypeOfResource_SobekCM_Enum.Artifact) && (currentItem.Bib_Info.Identifiers_Count > 0))
                    if (currentItem.Bib_Info.Identifiers_Count > 0)
                    {
                        foreach (Identifier_Info thisIdentifier in currentItem.Bib_Info.Identifiers)
                        {
                            if (thisIdentifier.Type.ToUpper().IndexOf("ACCESSION") >= 0)
                            {
                                Output.WriteLine("\t" + translations.Get_Translation("Accession number", currentMode.Language) + " " + thisIdentifier.Identifier + "<br />");
                                break;
                            }
                        }
                    }
                }

                Output.WriteLine("</div>");
                Output.WriteLine();
            }

            // The item viewer can choose to override the standard item menu
            if (!behaviors.Contains(HtmlSubwriter_Behaviors_Enum.Item_Subwriter_Suppress_Item_Menu))
            {
                // Can this user (if there is one) edit this item?
                bool canManage = (currentUser != null) && (currentUser.Can_Edit_This_Item(currentItem));

                // Add the item views
                Output.WriteLine("<!-- Add the different view and social options -->");
                Output.WriteLine("<nav class=\"sbkMenu_Bar\" id=\"sbkIsw_MenuBar\">");

                // Add the sharing buttons if this is not restricted by IP address or checked out
                if ((!itemRestrictedFromUserByIp) && (!itemCheckedOutByOtherUser) && (!currentMode.Is_Robot))
                {
                    string add_text = "Add";
                    string remove_text = "Remove";
                    string send_text = "Send";
                    string print_text = "Print";
                    if (canManage)
                    {
                        add_text = String.Empty;
                        remove_text = String.Empty;
                        send_text = String.Empty;
                        print_text = String.Empty;
                    }

                    Output.WriteLine("\t<div id=\"menu-right-actions\">");

                    if (currentItem.Web.ItemID > 0)
                    {
                        Output.WriteLine("\t\t<span id=\"printbuttonitem\" class=\"action-sf-menu-item\" onclick=\"print_form_open();\"><img src=\"" + currentMode.Base_URL + "default/images/printer.png\" alt=\"\" style=\"vertical-align:middle\" /><span id=\"printbuttonspan\">" + print_text + "</span></span>");
                    }
                    else
                    {
                        Output.WriteLine("\t\t<span id=\"printbuttonitem\" class=\"action-sf-menu-item\" onclick=\"window.print();return false;\"><img src=\"" + currentMode.Base_URL + "default/images/printer.png\" alt=\"\" style=\"vertical-align:middle\" /><span id=\"printbuttonspan\">" + print_text + "</span></span>");
                    }

                    //if (currentItem.Behaviors.Can_Be_Described)
                    //{
                    //    if (currentUser != null)
                    //    {
                    //        Output.Write("<a href=\"?m=hmh\" onmouseover=\"document.getElementById('describe_button').src='" + currentMode.Base_URL + "design/skins/" + htmlSkin.Base_Skin_Code + "/buttons/describe_rect_button_h.gif'\" onmouseout=\"document.getElementById('describe_button').src='" + currentMode.Base_URL + "design/skins/" + htmlSkin.Base_Skin_Code + "/buttons/describe_rect_button.gif'\"  onclick=\"return describe_item_form_open( 'describe_button' );\"><img class=\"ResultSavePrintButtons\" border=\"0px\" name=\"describe_button\" id=\"describe_button\" src=\"" + currentMode.Base_URL + "design/skins/" + htmlSkin.Base_Skin_Code + "/buttons/describe_rect_button.gif\" title=\"Add a description to this item\" alt=\"DESCRIBE\" /></a>");
                    //    }
                    //    else
                    //    {
                    //        Output.Write("<a href=\"?m=hmh\" onmouseover=\"document.getElementById('describe_button').src='" + currentMode.Base_URL + "design/skins/" + htmlSkin.Base_Skin_Code + "/buttons/describe_rect_button_h.gif'\" onmouseout=\"document.getElementById('describe_button').src='" + currentMode.Base_URL + "design/skins/" + htmlSkin.Base_Skin_Code + "/buttons/describe_rect_button.gif'\"><img class=\"ResultSavePrintButtons\" border=\"0px\" name=\"describe_button\" id=\"describe_button\" src=\"" + currentMode.Base_URL + "design/skins/" + htmlSkin.Base_Skin_Code + "/buttons/describe_rect_button.gif\" title=\"Add a description to this item\" alt=\"DESCRIBE\" /></a>");
                    //    }
                    //}

                    if ((currentUser != null))
                    {
                        Output.WriteLine("\t\t<span id=\"sendbuttonitem\" class=\"action-sf-menu-item\" onclick=\"email_form_open();\"><img src=\"" + currentMode.Base_URL + "default/images/email.png\" alt=\"\" style=\"vertical-align:middle\" /><span id=\"sendbuttonspan\">" + send_text + "</span></span>");

                        if (currentItem.Web.ItemID > 0)
                        {
                            if (currentUser.Is_In_Bookshelf(currentItem.BibID, currentItem.VID))
                            {
                                Output.WriteLine("\t\t<span id=\"addbuttonitem\" class=\"action-sf-menu-item\" onclick=\"return remove_item_itemviewer();\"><img src=\"" + currentMode.Base_URL + "default/images/minussign.png\" alt=\"\" style=\"vertical-align:middle\" /><span id=\"addbuttonspan\">" + remove_text + "</span></span>");
                            }
                            else
                            {
                                Output.WriteLine("\t\t<span id=\"addbuttonitem\" class=\"action-sf-menu-item\" onclick=\"add_item_form_open();\"><img src=\"" + currentMode.Base_URL + "default/images/plussign.png\" alt=\"\" style=\"vertical-align:middle\" /><span id=\"addbuttonspan\">" + add_text + "</span></span>");
                            }
                        }
                    }
                    else
                    {

                        Output.WriteLine("\t\t<span id=\"sendbuttonitem\" class=\"action-sf-menu-item\" onclick=\"window.location='?m=hmh';\"><img src=\"" + currentMode.Base_URL + "default/images/email.png\" alt=\"\" style=\"vertical-align:middle\" /><span id=\"sendbuttonspan\">" + send_text + "</span></span>");

                        if (currentItem.Web.ItemID > 0)
                            Output.WriteLine("\t\t<span id=\"addbuttonitem\" class=\"action-sf-menu-item\" onclick=\"window.location='?m=hmh';\"><img src=\"" + currentMode.Base_URL + "default/images/plussign.png\" alt=\"\" style=\"vertical-align:middle\" /><span id=\"addbuttonspan\">" + add_text + "</span></span>");

                    }

                    Output.WriteLine("\t\t<span id=\"sharebuttonitem\" class=\"action-sf-menu-item\" onclick=\"toggle_share_form('share_button');\"><span id=\"sharebuttonspan\">Share</span></span>");

                    Output.WriteLine("\t</div>");
                    Output.WriteLine();
                }

                Output.WriteLine("\t<ul class=\"sf-menu\" id=\"sbkIhs_Menu\">");

                // Save the current view type
                ushort page = currentMode.Page;
                ushort subpage = currentMode.SubPage;
                string viewerCode = currentMode.ViewerCode;
                currentMode.SubPage = 0;

                // Add any PRE-MENU instance options
                string first_pre_menu_option = String.Empty;
                string second_pre_menu_option = String.Empty;
                string third_pre_menu_option = String.Empty;
                if (SobekCM_Library_Settings.Additional_Settings.ContainsKey("Item Viewer.Static First Menu Item"))
                    first_pre_menu_option = SobekCM_Library_Settings.Additional_Settings["Item Viewer.Static First Menu Item"];
                if (SobekCM_Library_Settings.Additional_Settings.ContainsKey("Item Viewer.Static Second Menu Item"))
                    second_pre_menu_option = SobekCM_Library_Settings.Additional_Settings["Item Viewer.Static Second Menu Item"];
                if (SobekCM_Library_Settings.Additional_Settings.ContainsKey("Item Viewer.Static Third Menu Item"))
                    third_pre_menu_option = SobekCM_Library_Settings.Additional_Settings["Item Viewer.Static Third Menu Item"];
                if ((first_pre_menu_option.Length > 0) || (second_pre_menu_option.Length > 0) || ( third_pre_menu_option.Length > 0 ))
                {
                    if (first_pre_menu_option.Length > 0)
                    {
                        string[] first_splitter = first_pre_menu_option.Replace("[", "").Replace("]", "").Split(";".ToCharArray());
                        if (first_splitter.Length > 0)
                        {
                            Output.WriteLine("\t\t<li><a href=\"" + first_splitter[1] + "\" title=\"" + HttpUtility.HtmlEncode(first_splitter[0]) + "\">" + HttpUtility.HtmlEncode(first_splitter[0]) + "</a></li>");
                        }
                    }
                    if (second_pre_menu_option.Length > 0)
                    {
                        string[] second_splitter = second_pre_menu_option.Replace("[", "").Replace("]", "").Split(";".ToCharArray());
                        if (second_splitter.Length > 0)
                        {
                            Output.WriteLine("\t\t<li><a href=\"" + second_splitter[1] + "\" title=\"" + HttpUtility.HtmlEncode(second_splitter[0]) + "\">" + HttpUtility.HtmlEncode(second_splitter[0]) + "</a></li>");
                        }
                    }
                    if (third_pre_menu_option.Length > 0)
                    {
                        string[] third_splitter = third_pre_menu_option.Replace("[", "").Replace("]", "").Split(";".ToCharArray());
                        if (third_splitter.Length > 0)
                        {
                            Output.WriteLine("\t\t<li><a href=\"" + third_splitter[1] + "\" title=\"" + HttpUtility.HtmlEncode(third_splitter[0]) + "\">" + HttpUtility.HtmlEncode(third_splitter[0]) + "</a></li>");
                        }
                    }
                }

                // Add the item level views
                foreach (View_Object thisView in currentItem.Behaviors.Views)
                {
                    if (((!itemRestrictedFromUserByIp) && (!currentItem.Behaviors.Dark_Flag)) || (thisView.View_Type == View_Enum.CITATION) ||
                        (thisView.View_Type == View_Enum.ALL_VOLUMES) ||
                        (thisView.View_Type == View_Enum.RELATED_IMAGES))
                    {
                        // Special code for the CITATION view (TEMPORARY - v.3.2)
                        if (thisView.View_Type == View_Enum.CITATION)
                        {
                            if (currentMode.Is_Robot)
                            {
                                Output.Write("\t\t<li id=\"selected-sf-menu-item-link\"><a href=\"\">Description</a></li>");
                            }
                            else
                            {
                                currentMode.ViewerCode = "citation";
                                if (currentItem.Bib_Info.SobekCM_Type == TypeOfResource_SobekCM_Enum.EAD)
                                    currentMode.ViewerCode = "description";
                                if ((viewerCode == "citation") || (viewerCode == "marc") || (viewerCode == "metadata") ||
                                    (viewerCode == "usage") || (viewerCode == "description"))
                                {
                                    Output.Write("\t\t<li id=\"selected-sf-menu-item-link\"><a href=\"" + currentMode.Redirect_URL() + "\">Description</a>");
                                }
                                else
                                {
                                    Output.Write("\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">Description</a>");
                                }
                                Output.WriteLine("<ul>");

                                if (currentItem.Bib_Info.SobekCM_Type == TypeOfResource_SobekCM_Enum.EAD)
                                    Output.WriteLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">Archival Description</a></li>");
                                else
                                    Output.WriteLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">Standard View</a></li>");

                                currentMode.ViewerCode = "marc";
                                Output.WriteLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">MARC View</a></li>");

                                currentMode.ViewerCode = "metadata";
                                Output.WriteLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">Metadata</a></li>");

                                currentMode.ViewerCode = "usage";
                                Output.WriteLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">Usage Statistics</a></li>");

                                Output.WriteLine("\t\t</ul></li>");
                                currentMode.ViewerCode = viewerCode;
                            }
                        }
                        else if (thisView.View_Type == View_Enum.ALL_VOLUMES)
                        {
                            string resource_type_upper = currentItem.Bib_Info.SobekCM_Type_String.ToUpper();
                            string all_volumes = "All Volumes";
                            if (resource_type_upper.IndexOf("NEWSPAPER") >= 0)
                            {
                                all_volumes = "All Issues";
                            }
                            else if (resource_type_upper.IndexOf("MAP") >= 0)
                            {
                                all_volumes = "Related Maps";
                            }
                            else if (resource_type_upper.IndexOf("AERIAL") >= 0)
                            {
                                all_volumes = "Related Flights";
                            }

                            if (currentMode.Is_Robot)
                            {
                                Output.Write("\t\t<li><a href=\"" + SobekCM_Library_Settings.Base_URL + "\\" + currentItem.BibID + "\">" + all_volumes + "</a></li>");
                            }
                            else
                            {

                                currentMode.ViewerCode = "allvolumes";
                                if ((viewerCode == "allvolumes") || (viewerCode == "allvolumes2") ||
                                    (viewerCode == "allvolumes3"))
                                {
                                    Output.Write("\t\t<li id=\"selected-sf-menu-item-link\"><a href=\"" + currentMode.Redirect_URL() + "\">" + all_volumes + "</a>");
                                }
                                else
                                {
                                    Output.Write("\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">" + all_volumes + "</a>");
                                }
                                Output.WriteLine("<ul>");

                                currentMode.ViewerCode = "allvolumes";
                                Output.WriteLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">Tree View</a></li>");

                                currentMode.ViewerCode = "allvolumes2";
                                Output.WriteLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">Thumbnails</a></li>");

                                if (currentMode.Internal_User)
                                {
                                    currentMode.ViewerCode = "allvolumes3";
                                    Output.WriteLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">List View</a></li>");
                                }

                                Output.WriteLine("\t\t</ul></li>");
                                currentMode.ViewerCode = viewerCode;
                            }
                        }
                        else
                        {
                            List<string> item_nav_bar_link = Item_Nav_Bar_HTML_Factory.Get_Nav_Bar_HTML(thisView, currentItem.Bib_Info.SobekCM_Type_String, htmlSkin.Base_Skin_Code, currentMode, -1, translations, showZoomable, currentItem);

                            // Add each nav bar link
                            foreach (string this_link in item_nav_bar_link)
                            {
                                Output.WriteLine("\t\t" + this_link + "");
                            }
                        }
                    }
                }

                // If this is citation or index mode, the number may be an invalid page sequence
                if ((page <= 0) ||
                    (currentMode.ViewerCode == View_Object.Viewer_Code_By_Type(View_Enum.RELATED_IMAGES)[0]))
                {
                    currentMode.Page = 1;
                }

                if ((currentItem.Web.Static_PageCount > 0) && (currentPage == null))
                {
                    currentPage = currentItem.Web.Pages_By_Sequence[0];
                }

                // Add each page display type
                if ((currentPage != null) && (!itemRestrictedFromUserByIp))
                {
                    int page_seq = currentMode.Page;
                    string resourceType = currentItem.Bib_Info.SobekCM_Type_String.ToUpper();
                    if (currentItem.Behaviors.Item_Level_Page_Views_Count > 0)
                    {
                        List<string> pageViewLinks = new List<string>();

                        foreach (View_Object thisPageView in currentItem.Behaviors.Item_Level_Page_Views)
                        {
                            View_Enum thisViewType = thisPageView.View_Type;
                            foreach (SobekCM_File_Info thisFile in currentPage.Files)
                            {
                                View_Object fileObject = thisFile.Get_Viewer();
                                if ((fileObject != null) && (fileObject.View_Type == thisViewType))
                                {
                                    pageViewLinks.AddRange(Item_Nav_Bar_HTML_Factory.Get_Nav_Bar_HTML(thisFile.Get_Viewer(), resourceType, htmlSkin.Base_Skin_Code, currentMode, page_seq, translations, showZoomable, currentItem));
                                }
                            }
                        }

                        if (currentItem.BibID == "UF00001672")
                        {
                            string filename = currentPage.Files[0].File_Name_Sans_Extension + ".txt";
                            SobekCM_File_Info newFile = new SobekCM_File_Info(filename);
                            pageViewLinks.AddRange(Item_Nav_Bar_HTML_Factory.Get_Nav_Bar_HTML(newFile.Get_Viewer(), resourceType, htmlSkin.Base_Skin_Code, currentMode, page_seq, translations, showZoomable, currentItem));
                        }

                        // Only continue if there were views
                        if (pageViewLinks.Count > 0)
                        {
                            // Determine the name for this menu item
                            string menu_title = "Page Image";
                            if (resourceType.IndexOf("MAP") >= 0)
                            {
                                menu_title = "Map Image";
                            }
                            else if ((resourceType.IndexOf("AERIAL") >= 0) || (resourceType.IndexOf("PHOTOGRAPH") >= 0))
                            {
                                menu_title = "Image";
                            }
                            if (currentItem.Web.Static_PageCount > 1)
                                menu_title = menu_title + "s";

                            // Get the link for the first page view
                            string link = pageViewLinks[0].Substring(pageViewLinks[0].IndexOf("href=\"") + 6);
                            link = link.Substring(0, link.IndexOf("\""));

                            // Was this a match?
                            if ((currentMode.ViewerCode == page_seq + "t") || (currentMode.ViewerCode == page_seq + "x") || (currentMode.ViewerCode == page_seq + "j"))
                            {
                                Output.Write("\t\t<li id=\"selected-sf-menu-item-link\"><a href=\"" + link + "\">" + menu_title + "</a>");
                            }
                            else
                            {
                                Output.Write("\t\t<li><a href=\"" + link + "\">" + menu_title + "</a>");
                            }
                            Output.WriteLine("<ul>");

                            foreach (string pageLink in pageViewLinks)
                            {
                                Output.WriteLine("\t\t\t<li>" + pageLink + "</li>");
                            }

                            Output.WriteLine("\t\t</ul></li>");
                        }
                    }
                }

                if (itemRestrictedFromUserByIp)
                {
                    List<string> restricted_nav_bar_link = Item_Nav_Bar_HTML_Factory.Get_Nav_Bar_HTML(new View_Object(View_Enum.RESTRICTED), currentItem.Bib_Info.SobekCM_Type_String.ToUpper(), htmlSkin.Base_Skin_Code, currentMode, 0, translations, showZoomable, currentItem);
                    Output.WriteLine("\t\t" + restricted_nav_bar_link[0] + "");
                }

                // Add the MANAGE button?
                if (userCanEditItem)
                {
                    // Get the MANAGE URL (which is actually an item view)
                    currentMode.ViewerCode = "manage";
                    string manage_menu_url = currentMode.Redirect_URL();

                    if (currentItem.METS_Header.RecordStatus_Enum != METS_Record_Status.BIB_LEVEL)
                    {

                        // Get all the mySObek URLs
                        currentMode.Mode = Display_Mode_Enum.My_Sobek;
                        currentMode.My_Sobek_Type = My_Sobek_Type_Enum.Edit_Item_Metadata;
                        string edit_metadata_url = currentMode.Redirect_URL();
                        currentMode.My_Sobek_Type = My_Sobek_Type_Enum.Edit_Item_Behaviors;
                        string edit_behaviors_url = currentMode.Redirect_URL();
                        currentMode.My_Sobek_Type = My_Sobek_Type_Enum.Page_Images_Management;
                        string page_images_url = currentMode.Redirect_URL();
                        currentMode.My_Sobek_Type = My_Sobek_Type_Enum.File_Management;
                        string manage_downloads = currentMode.Redirect_URL();

                        currentMode.Mode = Display_Mode_Enum.Item_Display;

                        Output.WriteLine("\t\t<li><a href=\"" + manage_menu_url + "\">Manage</a><ul>");

                        Output.WriteLine("\t\t\t<li><a href=\"" + edit_metadata_url + "\">Edit Metadata</a></li>");
                        Output.WriteLine("\t\t\t<li><a href=\"" + edit_behaviors_url + "\">Edit Item Behaviors</a></li>");
                        Output.WriteLine("\t\t\t<li><a href=\"" + manage_downloads + "\">Manage Download Files</a></li>");

                        if (currentItem.Web.Static_PageCount == 0)
                            Output.WriteLine("\t\t\t<li><a href=\"" + page_images_url + "\">Manage Pages and Divisions</a></li>");
                        else
                        {
                            currentMode.ViewerCode = "qc";
                            Output.WriteLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">Manage Pages and Divisions</a></li>");
                        }

                        currentMode.ViewerCode = "mapedit";
                        Output.WriteLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">Manage Geo-Spatial Data (beta)</a></li>");

                        currentMode.ViewerCode = "ts";
                        Output.WriteLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">View Tracking Sheet</a></li>");

                        Output.WriteLine("\t\t</ul></li>");
                    }
                    else
                    {
                        // Get all the mySObek URLs
                        currentMode.Mode = Display_Mode_Enum.My_Sobek;
                        currentMode.My_Sobek_Type = My_Sobek_Type_Enum.Edit_Group_Behaviors;
                        string edit_behaviors_url = currentMode.Redirect_URL();
                        currentMode.My_Sobek_Type = My_Sobek_Type_Enum.Group_Add_Volume;
                        string add_volume_url = currentMode.Redirect_URL();
                        currentMode.My_Sobek_Type = My_Sobek_Type_Enum.Group_Mass_Update_Items;
                        string mass_update_url = currentMode.Redirect_URL();

                        currentMode.Mode = Display_Mode_Enum.Item_Display;

                        Output.WriteLine("\t\t<li><a href=\"" + manage_menu_url + "\">Manage</a><ul>");

                        Output.WriteLine("\t\t\t<li><a href=\"" + edit_behaviors_url + "\">Edit Item Group Behaviors</a></li>");
                        Output.WriteLine("\t\t\t<li><a href=\"" + add_volume_url + "\">Add New Volume</a></li>");
                        Output.WriteLine("\t\t\t<li><a href=\"" + mass_update_url + "\">Mass Update Item Behaviors</a></li>");

                        Output.WriteLine("\t\t</ul></li>");
                    }
                }

                // Set current submode back
                currentMode.Page = page;
                currentMode.ViewerCode = viewerCode;
                currentMode.SubPage = subpage;

                Output.WriteLine("\t</ul>");
                Output.WriteLine("</nav>");
                Output.WriteLine();

                Output.WriteLine("<!-- Initialize the main item menu -->");
                Output.WriteLine("<script>");
                Output.WriteLine("\tjQuery(document).ready(function () { jQuery('ul.sf-menu').superfish(); });");
                Output.WriteLine("</script>");
                Output.WriteLine();
            }

            return true;
        }
 /// <summary> Adds to the collection of pages by sequence </summary>
 /// <param name="Next_Page"> Next page in sequence to add </param>
 public void Add_Pages_By_Sequence(Page_TreeNode Next_Page)
 {
     if (pages_by_seq == null)
         pages_by_seq = new List<Page_TreeNode>();
     pages_by_seq.Add(Next_Page);
 }
        /// <summary> Adds a file  object (with the appropriate divisions and pages) to this tree </summary>
        /// <param name="New_File"> New file object to add </param>
        /// <param name="Label"> Label for the page containing this file, if it is a new page </param>
        /// <remarks> This is generally used to add just a single file.  To add many files, better logic should be implemented </remarks>
        public void Add_File(SobekCM_File_Info New_File, string Label)
        {
            // Determine the upper case name
            string systemname_upper = New_File.File_Name_Sans_Extension;

            // Look for a page/entity which has the same file name, else it will be added to the last division
            foreach (abstract_TreeNode rootNode in Roots)
            {
                if (recursively_add_file(rootNode, New_File, systemname_upper))
                {
                    return;
                }
            }

            // If not found, find the last division
            if (Roots.Count > 0)
            {
                if (!Roots[Roots.Count - 1].Page)
                {
                    // Get his last division
                    Division_TreeNode lastDivision = (Division_TreeNode) Roots[Roots.Count - 1];

                    // Find the last division then
                    while ((lastDivision.Nodes.Count > 0) && (!lastDivision.Nodes[lastDivision.Nodes.Count - 1].Page))
                    {
                        lastDivision = (Division_TreeNode) lastDivision.Nodes[lastDivision.Nodes.Count - 1];
                    }

                    // Add this as a new page on the last division
                    Page_TreeNode newPage = new Page_TreeNode(Label);
                    lastDivision.Add_Child(newPage);

                    // Now, add this file to the page
                    newPage.Files.Add(New_File);
                }
                else
                {
                    // No divisions at all, but pages exist at the top level, which is okay
                    Page_TreeNode pageNode = (Page_TreeNode) Roots[Roots.Count - 1];

                    // Now, add this file to the page
                    pageNode.Files.Add(New_File);
                }
            }
            else
            {
                // No nodes exist, so add a MAIN division node
                Division_TreeNode newDivNode = new Division_TreeNode("Main", String.Empty);
                Roots.Add(newDivNode);

                // Add this as a new page on the new division
                Page_TreeNode newPage = new Page_TreeNode(Label);
                newDivNode.Add_Child(newPage);

                // Now, add this file to the page
                newPage.Files.Add(New_File);
            }
        }
        private void Finish_writing_html(SobekCM_Item currentItem, Page_TreeNode currentPage, string filename, string text_file_location )
        {
            string bibid = currentItem.BibID;
            currentItem.Behaviors.Text_Searchable = false;

            // Create the HTML writer
            Item_HtmlSubwriter itemWriter = new Item_HtmlSubwriter(currentItem, currentPage, null, codeManager, translations, true, true, currentMode, null, String.Empty, null, tracer)
                                                 {Mode = currentMode, Skin = ufdcInterface};
            SobekCM_Library_Settings.Base_SobekCM_Location_Relative = currentMode.Base_URL;
            if ((SobekCM_Library_Settings.Base_SobekCM_Location_Relative.Length == 0) || (SobekCM_Library_Settings.Base_SobekCM_Location_Relative.Contains("localhost")))
            {
                SobekCM_Library_Settings.Base_SobekCM_Location_Relative = primaryWebServerUrl;
                if (bibid.IndexOf("CA") == 0)
                {
                    currentMode.Skin = "dloc";
                    itemWriter.Skin = dlocInterface;
                    SobekCM_Library_Settings.Base_SobekCM_Location_Relative = "http://www.dloc.com/";
                }
                currentMode.Base_URL = SobekCM_Library_Settings.Base_SobekCM_Location_Relative;
            }

            // Now that the item viewer is built, set the robot flag to suppress some checks
            currentMode.Is_Robot = true;

            // Create the TextWriter
            StreamWriter writer = new StreamWriter(filename, false, Encoding.UTF8);

            // Add the header
            Display_Header(writer, itemWriter.Skin);

            // Begin to write the item view
            itemWriter.Write_HTML(writer, tracer);

            // Write the table of contents as static HTML, rather than the TreeView web control
            if ((currentItem.Web.Static_PageCount > 1) && (currentItem.Web.Static_Division_Count > 1))
            {
                writer.WriteLine("        <ul class=\"SobekNavBarMenu\">" + Environment.NewLine + "          <li class=\"SobekNavBarHeader\"> TABLE OF CONTENTS </li>" + Environment.NewLine + "        </ul>" + Environment.NewLine  +
                                 "        <div class=\"HideTocRow\">" + Environment.NewLine + "          <img src=\"" + SobekCM_Library_Settings.Base_SobekCM_Location_Relative + "design/skins/" + itemWriter.Skin.Skin_Code + "/tabs/cLG.gif\" border=\"0\" alt=\"\" /><img src=\"" + SobekCM_Library_Settings.Base_SobekCM_Location_Relative + "design/skins/" + itemWriter.Skin.Skin_Code + "/tabs/AU.gif\" border=\"0\" alt=\"\" /><span class=\"tab\">HIDE</span><img src=\"" + SobekCM_Library_Settings.Base_SobekCM_Location_Relative + "design/skins/" + itemWriter.Skin.Skin_Code + "/tabs/cRG.gif\" border=\"0\" alt=\"\" />" + Environment.NewLine + "        </div>");
                writer.WriteLine("<div class=\"SobekTocTreeView\">");

                // load the table of contents in the tree
                TreeView treeView1 = new TreeView();
                itemWriter.Create_TreeView_From_Divisions(treeView1);

                // Step through all the parent nodes
                writer.WriteLine("<table cellspacing=\"4px\" >");
                foreach (TreeNode thisNode in treeView1.Nodes)
                {
                    writer.WriteLine("  <tr><td width=\"9px\">&nbsp;</td><td>" + thisNode.Text.Replace("ufdcSelectedTocTreeViewItem", "ufdcTocTreeViewItem") + "</td></tr>");
                }
                writer.WriteLine("</table>");
                writer.WriteLine("</div>");
            }

            itemWriter.Write_Additional_HTML(writer, tracer);
            PlaceHolder placeHolder = new PlaceHolder();
            itemWriter.PageViewer.Add_Main_Viewer_Section(placeHolder, tracer);
            Literal citationLiteral = (Literal)placeHolder.Controls[0];
            writer.WriteLine(citationLiteral.Text);
            placeHolder.Controls.Clear();

            writer.WriteLine("<!-- COMMENT HERE -->");

            // Close out this tables and form
            writer.WriteLine("       </tr>");

            // Add the download list if there are some
            if ( currentItem.Divisions.Download_Tree.Has_Files )
            {
                writer.WriteLine("       <tr>");
                // Create the downloads viewer to ouput the html
                Download_ItemViewer downloadViewer = new Download_ItemViewer
                                                         {CurrentItem = currentItem, CurrentMode = currentMode};

                // Add the HTML for this now
                downloadViewer.Add_Main_Viewer_Section(placeHolder, tracer);
                Literal downloadLiteral = (Literal)placeHolder.Controls[0];
                writer.WriteLine(downloadLiteral.Text);
                writer.WriteLine("       </tr>");
            }

            // If there is a table of contents write it again, this time it will be complete
            // and also show a hierarchy if there is one
            if ((currentItem.Web.Static_PageCount > 1) && (currentItem.Web.Static_Division_Count > 1))
            {
                writer.WriteLine("       <tr>");
                writer.WriteLine("         <td align=\"left\"><span class=\"SobekViewerTitle\">Table of Contents</span></td>");
                writer.WriteLine("       </tr>");

                writer.WriteLine("       <tr>");
                writer.WriteLine("          <td>");
                writer.WriteLine("            <div class=\"SobekCitation\">");

                foreach (abstract_TreeNode treeNode in currentItem.Divisions.Physical_Tree.Roots)
                {
                    recursively_write_toc(writer, treeNode, "&nbsp; &nbsp; ");
                }

                writer.WriteLine("            </div>");
                writer.WriteLine("          </td>");
                writer.WriteLine("       </tr>");
            }

            // Is the text file location included, in which case any full text should be appended to the end?
            if ((text_file_location.Length > 0) && ( Directory.Exists(text_file_location)))
            {
                // Get the list of all TXT files in this division
                string[] text_files = Directory.GetFiles(text_file_location, "*.txt");
                Dictionary<string, string> text_files_existing = new Dictionary<string, string>();
                foreach (string thisTextFile in text_files)
                {
                    string text_filename = (new FileInfo(thisTextFile)).Name.ToUpper();
                    text_files_existing[text_filename] = text_filename;
                }

                // Are there ANY text files?
                if (text_files.Length > 0)
                {
                    // If this has page images, check for related text files
                    List<string> text_files_included = new List<string>();
                    bool started = false;
                    if (currentItem.Divisions.Physical_Tree.Has_Files)
                    {
                        // Go through the first 100 text pages
                        List<abstract_TreeNode> pages = currentItem.Divisions.Physical_Tree.Pages_PreOrder;
                        int page_count = 0;
                        foreach (Page_TreeNode thisPage in pages)
                        {
                            // Keep track of the page count
                            page_count++;

                            // Look for files in this page
                            if (thisPage.Files.Count > 0)
                            {
                                bool found_non_thumb_file = false;
                                foreach (SobekCM_File_Info thisFile in thisPage.Files)
                                {
                                    // Make sure this is not a thumb
                                    if (thisFile.System_Name.ToLower().IndexOf("thm.jpg") < 0)
                                    {
                                        found_non_thumb_file = true;
                                        string root = thisFile.File_Name_Sans_Extension;
                                        if (text_files_existing.ContainsKey(root.ToUpper() + ".TXT"))
                                        {
                                            string text_file = text_file_location + "\\" + thisFile.File_Name_Sans_Extension + ".txt";

                                            // SInce this is marked to be included, save this name
                                            text_files_included.Add(root.ToUpper() + ".TXT");

                                            // For size reasons, we only include the text from the first 100 pages
                                            if (page_count <= 100)
                                            {
                                                if (!started)
                                                {
                                                    writer.WriteLine("       <tr>");
                                                    writer.WriteLine("         <td align=\"left\"><span class=\"SobekViewerTitle\">Full Text</span></td>");
                                                    writer.WriteLine("       </tr>");
                                                    writer.WriteLine("       <tr>");
                                                    writer.WriteLine("          <td>");
                                                    writer.WriteLine("            <div class=\"SobekCitation\">");

                                                    started = true;
                                                }

                                                try
                                                {
                                                    StreamReader reader = new StreamReader(text_file);
                                                    string text_line = reader.ReadLine();
                                                    while (text_line != null)
                                                    {
                                                        writer.WriteLine(text_line + "<br />");
                                                        text_line = reader.ReadLine();
                                                    }
                                                    reader.Close();
                                                }
                                                catch
                                                {
                                                    writer.WriteLine("Unable to read file: " + text_file);
                                                }

                                                writer.WriteLine("<br /><br />");
                                            }
                                        }

                                    }

                                    // If a suitable file was found, break here
                                    if (found_non_thumb_file)
                                        break;
                                }
                            }
                        }

                        // End this if it was ever started
                        if (started)
                        {
                            writer.WriteLine("            </div>");
                            writer.WriteLine("          </td>");
                            writer.WriteLine("       </tr>");
                        }
                    }

                    // Now, check for any other valid text files
                    List<string> additional_text_files = text_files_existing.Keys.Where(thisTextFile => (!text_files_included.Contains(thisTextFile.ToUpper())) && (thisTextFile.ToUpper() != "AGREEMENT.TXT") && (thisTextFile.ToUpper().IndexOf("REQUEST") != 0)).ToList();

                    // Now, include any additional text files, which would not be page text files, possiblye
                    // full text for included PDFs, Powerpoint, Word Doc, etc..
                    foreach (string thisTextFile in additional_text_files)
                    {
                        if (!started)
                        {
                            writer.WriteLine("       <tr>");
                            writer.WriteLine("         <td align=\"left\"><span class=\"SobekViewerTitle\">Full Text</span></td>");
                            writer.WriteLine("       </tr>");
                            writer.WriteLine("       <tr>");
                            writer.WriteLine("          <td>");
                            writer.WriteLine("            <div class=\"SobekCitation\">");

                            started = true;
                        }

                        string text_file = text_file_location + "\\" + thisTextFile;

                        try
                        {

                            StreamReader reader = new StreamReader(text_file);
                            string text_line = reader.ReadLine();
                            while (text_line != null)
                            {
                                writer.WriteLine(text_line + "<br />");
                                text_line = reader.ReadLine();
                            }
                            reader.Close();
                        }
                        catch
                        {
                            writer.WriteLine("Unable to read file: " + text_file);
                        }

                        writer.WriteLine("<br /><br />");
                    }
                }
            }

            writer.WriteLine("      </table>");
            writer.WriteLine("    </td>");
            writer.WriteLine("  </tr>");
            writer.WriteLine("</table>");

            // Write the footer
            Display_Footer(writer, itemWriter.Skin);

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

            // Restore the text searchable flag and robot flag
            currentMode.Is_Robot = false;
            currentItem.Behaviors.Text_Searchable = false;
        }
        /// <summary> Saves the data rendered by this element to the provided bibliographic object during postback </summary>
        /// <param name="Bib"> Object into which to save the user's data, entered into the html rendered by this element </param>
        /// <remarks> This currently does not to anything, as this element is not fully implemented </remarks>
        public override void Save_To_Bib(SobekCM_Item Bib)
        {
            // Collect the list of download_files and download_labels from the form
            string[] getKeys = HttpContext.Current.Request.Form.AllKeys;
            string filename = String.Empty;
            List<string> download_files = new List<string>();
            List<string> download_labels = new List<string>();
            foreach (string thisKey in getKeys)
            {
                if (thisKey.IndexOf(html_element_name.Replace("_", "") + "_select") == 0)
                {
                    filename = HttpContext.Current.Request.Form[thisKey];
                }

                if (thisKey.IndexOf(html_element_name.Replace("_", "") + "_text") == 0)
                {
                    if (filename.Length > 0)
                    {
                        string label = HttpContext.Current.Request.Form[thisKey];
                        download_files.Add(filename.Replace(".*",""));
                        download_labels.Add(label);
                    }
                    filename = String.Empty;
                }
            }

            // Collect the list of download files and download labels from the package
            List<string> existing_files = new List<string>();
            List<string> existing_labels = new List<string>();
            List<abstract_TreeNode> downloadGroups = Bib.Divisions.Download_Tree.Pages_PreOrder;
            foreach (Page_TreeNode thisDownload in downloadGroups)
            {
                if (thisDownload.Files.Count > 0)
                {
                    string base_file = thisDownload.Files[0].File_Name_Sans_Extension;
                    if (!existing_files.Contains(base_file))
                    {
                        existing_files.Add(base_file );
                        existing_labels.Add(thisDownload.Label);
                    }
                }
            }

            // Now, compare the current list of downloads to the new list
            bool different = false;
            if (download_files.Count != existing_files.Count)
            {
                different = true;
            }
            else
            {
                // Same number of downloads, so step through and compare the files and labels
                for (int i = 0; i < download_files.Count; i++)
                {
                    // Get the index of this on the existing list
                    int index = existing_files.IndexOf(download_files[i].ToUpper());
                    if (index < 0)
                    {
                        different = true;
                        break;
                    }
                    if (existing_labels[index].Trim() != download_labels[i].Trim())
                    {
                        different = true;
                        break;
                    }
                }
            }

            // If this was different clear the existing downloads and load the new ones
            if (different)
            {
                // Get the directory for this package
                string directory = SobekCM_Library_Settings.Image_Server_Network + Bib.Web.AssocFilePath;

                // Clear existing
                Bib.Divisions.Download_Tree.Clear();

                // No nodes exist, so add a MAIN division node
                Division_TreeNode newDivNode = new Division_TreeNode("Main", String.Empty);
                Bib.Divisions.Download_Tree.Roots.Add(newDivNode);

                // Add a page for each
                for (int i = 0; i < download_files.Count; i++)
                {
                    // Get the list of matching files
                    string[] files = Directory.GetFiles(directory, download_files[i] + ".*");
                    if (files.Length > 0)
                    {
                        // Add this as a new page on the new division
                        Page_TreeNode newPage = new Page_TreeNode(download_labels[i]);
                        newDivNode.Add_Child(newPage);

                        // Add all the files next
                        foreach (SobekCM_File_Info newFile in files.Select(thisFile => (new FileInfo(thisFile)).Name).Select(add_filename => new SobekCM_File_Info(add_filename)))
                        {
                            newPage.Files.Add(newFile);
                        }
                    }
                }
            }
        }
        /// <summary> Constructor for a new instance of the Item_HtmlSubwriter class </summary>
        /// <param name="Current_Item">Current item to display </param>
        /// <param name="Current_Page"> Current page within the item</param>
        /// <param name="Current_User"> Currently logged on user for determining rights over this item </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="ShowToc"> Flag indicates whether to show the table of contents open for this item </param>
        /// <param name="Show_Zoomable"> Flag indicates if the zoomable server is available </param>
        /// <param name="Current_Mode"> Mode / navigation information for the current request</param>
        /// <param name="Current_Collection"> Current item aggregation this item is being displayed from (if there is one) </param>
        /// <param name="Item_Restricted_Message"> Message to be shown because this item is restriced from the current user by IP address </param>
        /// <param name="Items_In_Title"> List of items within a title (for item group display in particular) </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        public Item_HtmlSubwriter(SobekCM_Item Current_Item, Page_TreeNode Current_Page, User_Object Current_User,
                                  Aggregation_Code_Manager Code_Manager,
                                  Language_Support_Info Translator, bool ShowToc, bool Show_Zoomable,
                                  SobekCM_Navigation_Object Current_Mode,
                                  Item_Aggregation Current_Collection,
                                  string Item_Restricted_Message,
                                  SobekCM_Items_In_Title Items_In_Title,
                                  Custom_Tracer Tracer )
        {
            Mode = Current_Mode;
            currentUser = Current_User;
            currentItem = Current_Item;
            currentPage = Current_Page;
            itemsInTitle = Items_In_Title;
            translations = Translator;
            showToc = ShowToc;
            showZoomable = Show_Zoomable;
            Current_Aggregation = Current_Collection;
            itemCheckedOutByOtherUser = false;
            userCanEditItem = false;
            searchResultsCount = 0;

            // Determine if this item is an EAD
            isEadTypeItem = (currentItem.Get_Metadata_Module(GlobalVar.EAD_METADATA_MODULE_KEY) != null);

            // Determine if this item is actually restricted
            itemRestrictedFromUserByIp = Item_Restricted_Message.Length > 0;

            // Determine if this user can edit this item
            if (currentUser != null)
            {
                userCanEditItem = currentUser.Can_Edit_This_Item(currentItem);
            }

            // If this item is restricted by IP than alot of the upcoming code is unnecessary
            if (( currentUser != null ) && ((!itemRestrictedFromUserByIp) || ( userCanEditItem ) || ( currentUser.Is_Internal_User )))
            {
                #region Region suppressed currently - was for adding feature to a map image?

                //// Searching for EAD/EAC type items is different from others
                //if (!isEadTypeItem)
                //{
                //    // If there is a coordinate search, and polygons, do that
                //    // GEt the geospatial metadata module
                //    GeoSpatial_Information geoInfo = currentItem.Get_Metadata_Module(GlobalVar.GEOSPATIAL_METADATA_MODULE_KEY) as GeoSpatial_Information;
                //    if ((geoInfo != null) && (geoInfo.hasData))
                //    {
                //        if ((currentMode.Coordinates.Length > 0) && (geoInfo.Polygon_Count > 1))
                //        {
                //            // Determine the coordinates in this search
                //            string[] splitter = currentMode.Coordinates.Split(",".ToCharArray());

                //            if (((splitter.Length > 1) && (splitter.Length < 4)) || ((splitter.Length == 4) && (splitter[2].Length == 0) && (splitter[3].Length == 0)))
                //            {
                //                Double.TryParse(splitter[0], out providedMaxLat);
                //                Double.TryParse(splitter[1], out providedMaxLong);
                //                providedMinLat = providedMaxLat;
                //                providedMinLong = providedMaxLong;
                //            }
                //            else if (splitter.Length >= 4)
                //            {
                //                Double.TryParse(splitter[0], out providedMaxLat);
                //                Double.TryParse(splitter[1], out providedMaxLong);
                //                Double.TryParse(splitter[2], out providedMinLat);
                //                Double.TryParse(splitter[3], out providedMinLong);
                //            }

                //            // Now, if there is length, determine the count of results
                //            searchResultsString = new List<string>();
                //            if (searchResultsString.Count > 0)
                //            {
                //                searchResultsCount = searchResultsString.Count;

                //                // Also, look to see where the current point lies in the matching, current polygon
                //                if ((providedMaxLong == providedMinLong) && (providedMaxLat == providedMinLat))
                //                {
                //                    foreach (Coordinate_Polygon itemPolygon in geoInfo.Polygons)
                //                    {
                //                        // Is this the current page?
                //                        if (itemPolygon.Page_Sequence == currentMode.Page)
                //                        {
                //                            if (itemPolygon.is_In_Bounding_Box(providedMaxLat, providedMaxLong))
                //                            {
                //                                searchMatchOnThisPage = true;
                //                                ReadOnlyCollection<Coordinate_Point> boundingBox = itemPolygon.Bounding_Box;
                //                                featureYRatioLocation = Math.Abs(((providedMaxLat - boundingBox[0].Latitude)/(boundingBox[0].Latitude - boundingBox[1].Latitude)));
                //                                featureXRatioLocation = Math.Abs(((providedMaxLong - boundingBox[0].Longitude)/(boundingBox[0].Longitude - boundingBox[1].Longitude)));
                //                            }
                //                        }
                //                    }
                //                }
                //            }
                //        }
                //    }
                //}

                #endregion

                // Is this a postback?
                if (currentMode.isPostBack)
                {
                    // Handle any actions from standard user action (i.e., email, add to bookshelf, etc.. )
                    if (HttpContext.Current.Request.Form["item_action"] != null)
                    {
                        string action = HttpContext.Current.Request.Form["item_action"].ToLower().Trim();

                        if (action == "email")
                        {
                            string address = HttpContext.Current.Request.Form["email_address"].Replace(";", ",").Trim();
                            string comments = HttpContext.Current.Request.Form["email_comments"].Trim();
                            string format = HttpContext.Current.Request.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
                                HttpContext.Current.Session.Add("ON_LOAD_MESSAGE", !Item_Email_Helper.Send_Email(address, cc_list, comments, currentUser.Full_Name,currentMode.SobekCM_Instance_Abbreviation,currentItem,is_html_format,HttpContext.Current.Items["Original_URL"].ToString(), currentUser.UserID)
                                    ? "Error encountered while sending email" : "Your email has been sent");

                                HttpContext.Current.Response.Redirect( HttpContext.Current.Items["Original_URL"].ToString(), false);
                                HttpContext.Current.ApplicationInstance.CompleteRequest();
                                Current_Mode.Request_Completed = true;
                                return;
                            }
                        }

                        if (action == "add_item")
                        {
                            string usernotes = HttpContext.Current.Request.Form["add_notes"].Trim();
                            string foldername = HttpContext.Current.Request.Form["add_bookshelf"].Trim();
                            bool open_bookshelf = HttpContext.Current.Request.Form["open_bookshelf"] != null;

                            if (SobekCM_Database.Add_Item_To_User_Folder(currentUser.UserID, foldername, currentItem.BibID, currentItem.VID, 0, usernotes, Tracer))
                            {
                                currentUser.Add_Bookshelf_Item(currentItem.BibID, currentItem.VID);

                                // Ensure this user folder is not sitting in the cache
                                Cached_Data_Manager.Remove_User_Folder_Browse(currentUser.UserID, foldername, Tracer);

                                HttpContext.Current.Session.Add("ON_LOAD_MESSAGE", "Item was saved to your bookshelf.");

                                if (open_bookshelf)
                                {
                                    HttpContext.Current.Session.Add("ON_LOAD_WINDOW", "?m=lmfl" + foldername.Replace("\"", "%22").Replace("'", "%27").Replace("=", "%3D").Replace("&", "%26") + "&vp=1");
                                }
                            }
                            else
                            {
                                HttpContext.Current.Session.Add("ON_LOAD_MESSAGE", "ERROR encountered while trying to save to your bookshelf.");
                            }

                            HttpContext.Current.Response.Redirect(HttpContext.Current.Items["Original_URL"].ToString(), false);
                            HttpContext.Current.ApplicationInstance.CompleteRequest();
                            Current_Mode.Request_Completed = true;
                            return;
                        }

                        if (action == "remove")
                        {
                            if (SobekCM_Database.Delete_Item_From_User_Folders(currentUser.UserID, currentItem.BibID, currentItem.VID, Tracer))
                            {
                                currentUser.Remove_From_Bookshelves(currentItem.BibID, currentItem.VID);
                                Cached_Data_Manager.Remove_All_User_Folder_Browses(currentUser.UserID, Tracer);
                                HttpContext.Current.Session.Add("ON_LOAD_MESSAGE", "Item was removed from your bookshelves.");
                            }
                            else
                            {
                                HttpContext.Current.Session.Add("ON_LOAD_MESSAGE", "ERROR encountered while trying to remove item from your bookshelves.");
                            }

                            HttpContext.Current.Response.Redirect(HttpContext.Current.Items["Original_URL"].ToString(), false);
                            HttpContext.Current.ApplicationInstance.CompleteRequest();
                            Current_Mode.Request_Completed = true;
                            return;
                        }

                        if (action.IndexOf("add_tag") == 0)
                        {
                            int tagid = -1;
                            if (action.Replace("add_tag", "").Length > 0)
                            {
                                tagid = Convert.ToInt32(action.Replace("add_tag_", ""));
                            }
                            string description = HttpContext.Current.Request.Form["add_tag"].Trim();
                            int new_tagid = SobekCM_Database.Add_Description_Tag(currentUser.UserID, tagid, currentItem.Web.ItemID, description, Tracer);
                            if (new_tagid > 0)
                            {
                                currentItem.Behaviors.Add_User_Tag(currentUser.UserID, currentUser.Full_Name, description, DateTime.Now, new_tagid);
                                currentUser.Has_Descriptive_Tags = true;
                            }

                            HttpContext.Current.Response.Redirect(HttpContext.Current.Items["Original_URL"].ToString(), false);
                            HttpContext.Current.ApplicationInstance.CompleteRequest();
                            Current_Mode.Request_Completed = true;
                            return;
                        }

                        if (action.IndexOf("delete_tag") == 0)
                        {
                            if (action.Replace("delete_tag", "").Length > 0)
                            {
                                int tagid = Convert.ToInt32(action.Replace("delete_tag_", ""));
                                if (currentItem.Behaviors.Delete_User_Tag(tagid, currentUser.UserID))
                                {
                                    SobekCM_Database.Delete_Description_Tag(tagid, Tracer);
                                }
                            }
                            HttpContext.Current.Response.Redirect(HttpContext.Current.Items["Original_URL"].ToString(), false);
                            HttpContext.Current.ApplicationInstance.CompleteRequest();
                            Current_Mode.Request_Completed = true;
                            return;
                        }
                    }
                }

                // Handle any request from the internal header for the item
                if ((HttpContext.Current != null) && (HttpContext.Current.Request.Form["internal_header_action"] != null) && ( currentUser != null ))
                {
                    // Pull the action value
                    string internalHeaderAction = HttpContext.Current.Request.Form["internal_header_action"].Trim();

                    // Was this to save the item comments?
                    if (internalHeaderAction == "save_comments")
                    {
                        string new_comments = HttpContext.Current.Request.Form["intheader_internal_notes"].Trim();
                        if ( Resource_Object.Database.SobekCM_Database.Save_Item_Internal_Comments( currentItem.Web.ItemID, new_comments))
                            currentItem.Tracking.Internal_Comments = new_comments;
                    }

                    // Is this to change accessibility?
                    if ((internalHeaderAction == "public") || (internalHeaderAction == "private") || (internalHeaderAction == "restricted"))
                    {
                        int current_mask = currentItem.Behaviors.IP_Restriction_Membership;
                        switch (internalHeaderAction)
                        {
                            case "public":
                                currentItem.Behaviors.IP_Restriction_Membership = 0;
                                break;

                            case "private":
                                currentItem.Behaviors.IP_Restriction_Membership = -1;
                                break;

                            case "restricted":
                                currentItem.Behaviors.IP_Restriction_Membership = 1;
                                break;
                        }

                        // Is this new visibility different than the old one?
                        if (currentItem.Behaviors.IP_Restriction_Membership != current_mask)
                        {
                            // Save this to the database
                            if (Resource_Object.Database.SobekCM_Database.Set_IP_Restriction_Mask(currentItem.Web.ItemID, currentItem.Behaviors.IP_Restriction_Membership, currentUser.UserName, String.Empty))
                            {
                                // Update the cached item
                                Cached_Data_Manager.Remove_Digital_Resource_Object(currentItem.BibID, currentItem.VID, Tracer);
                                Cached_Data_Manager.Store_Digital_Resource_Object(currentItem.BibID, currentItem.VID, currentItem, Tracer);

                                // Update the web.config
                                Resource_Web_Config_Writer.Update_Web_Config(currentItem.Source_Directory, currentItem.Behaviors.Dark_Flag, (short) current_mask, currentItem.Behaviors.Main_Thumbnail);
                            }
                        }
                    }
                }
            }

            // Set the code for bib level mets to show the volume tree by default
            if ((currentItem.METS_Header.RecordStatus_Enum == METS_Record_Status.BIB_LEVEL) && (currentMode.ViewerCode.Length == 0))
            {
                currentMode.ViewerCode = "allvolumes1";
            }

            // If there is a file name included, look for the sequence of that file
            if (currentMode.Page_By_FileName.Length > 0)
            {
                int page_sequence = currentItem.Divisions.Physical_Tree.Page_Sequence_By_FileName(currentMode.Page_By_FileName);
                if (page_sequence > 0)
                {
                    currentMode.ViewerCode = page_sequence.ToString();
                    currentMode.Page = (ushort) page_sequence;
                }
            }

            // Get the valid viewer code
            Tracer.Add_Trace("Html_MainWriter.Add_Controls", "Getting the appropriate item viewer");

            if ((currentMode.ViewerCode.Length == 0) && (currentMode.Coordinates.Length > 0))
            {
                currentMode.ViewerCode = "map";
            }
            currentMode.ViewerCode = currentItem.Web.Get_Valid_Viewer_Code(currentMode.ViewerCode, currentMode.Page);
            View_Object viewObject = currentItem.Web.Get_Viewer(currentMode.ViewerCode);
            PageViewer = ItemViewer_Factory.Get_Viewer(viewObject, currentItem.Bib_Info.SobekCM_Type_String.ToUpper(), currentItem, currentUser, currentMode);

            // If this was in fact restricted by IP address, restrict now
            if (itemRestrictedFromUserByIp)
            {
                if ((PageViewer.ItemViewer_Type != ItemViewer_Type_Enum.Citation) &&
                    (PageViewer.ItemViewer_Type != ItemViewer_Type_Enum.MultiVolume) &&
                    (PageViewer.ItemViewer_Type != ItemViewer_Type_Enum.Related_Images))
                {
                    PageViewer = new Restricted_ItemViewer(Item_Restricted_Message);
                    currentMode.ViewerCode = "res";
                }
            }

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

            Tracer.Add_Trace("Html_MainWriter.Add_Controls", "Created " + PageViewer.GetType().ToString().Replace("SobekCM.Library.ItemViewer.Viewers.", ""));

            // Assign the rest of the information, if a page viewer was created
            if (PageViewer != null)
            {
                PageViewer.CurrentItem = currentItem;
                PageViewer.CurrentMode = currentMode;
                PageViewer.Translator = Translator;
                PageViewer.CurrentUser = currentUser;

                // Special code if this is the citation viewer
                Citation_ItemViewer viewer = PageViewer as Citation_ItemViewer;
                if (viewer != null)
                {
                    viewer.Code_Manager = Code_Manager;
                    viewer.Item_Restricted = itemRestrictedFromUserByIp;
                }

                // Special code if this is the multi-volumes viewer
                var itemViewer = PageViewer as MultiVolumes_ItemViewer;
                if (itemViewer != null)
                {
                    if (itemsInTitle == null)
                    {
                        // Look in the cache first
                        itemsInTitle = Cached_Data_Manager.Retrieve_Items_In_Title(currentItem.BibID, Tracer);

                        // If still null, try to pull from the database
                        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]);

                            //// Add the related titles, if there are some
                            //if ((currentGroup.Tables.Count > 3) && (currentGroup.Tables[3].Rows.Count > 0))
                            //{
                            //    foreach (DataRow thisRow in currentGroup.Tables[3].Rows)
                            //    {
                            //        string relationship = thisRow["Relationship"].ToString();
                            //        string title = thisRow["GroupTitle"].ToString();
                            //        string bibid = thisRow["BibID"].ToString();
                            //        string link_and_title = "<a href=\"" + currentMode.Base_URL + bibid + "<%URL_OPTS%>\">" + title + "</a>";
                            //        currentItem.Behaviors.All_Related_Titles.Add(new SobekCM.Resource_Object.Behaviors.Related_Titles(relationship, link_and_title));
                            //    }
                            //}

                            // Store in cache if retrieved
                            if (itemsInTitle != null)
                            {
                                Cached_Data_Manager.Store_Items_In_Title(currentItem.BibID, itemsInTitle, Tracer);
                            }
                        }
                    }

                    itemViewer.Item_List = itemsInTitle;
                }

                // Finally, perform any necessary work before display
                PageViewer.Perform_PreDisplay_Work(Tracer);

                // Get the list of any special behaviors
                behaviors = PageViewer.ItemViewer_Behaviors;
            }
            else
            {
                behaviors = new List<HtmlSubwriter_Behaviors_Enum>();
            }

            // ALways suppress the banner
            behaviors.Add(HtmlSubwriter_Behaviors_Enum.Suppress_Banner);

            //if ((searchMatchOnThisPage) && ((PageViewer.ItemViewer_Type == ItemViewer_Type_Enum.JPEG) || (PageViewer.ItemViewer_Type == ItemViewer_Type_Enum.JPEG2000)))
            //{
            //    if (PageViewer.ItemViewer_Type == ItemViewer_Type_Enum.JPEG2000)
            //    {
            //        Aware_JP2_ItemViewer jp2_viewer = (Aware_JP2_ItemViewer) PageViewer;
            //        jp2_viewer.Add_Feature("Red", "DrawEllipse", ((int) (featureXRatioLocation*jp2_viewer.Width)), ((int) (featureYRatioLocation*jp2_viewer.Height)), 800, 800);

            //    }
            //}
        }
        /// <summary> Create a test digital resource item  </summary>       
        /// <param name="directory">Directory for the package source directory</param>
        /// <returns>Fully built test bib package</returns>
        public static SobekCM_Item Create(string directory)
        {
            SobekCM_Item testPackage = new SobekCM_Item();

            // Add all the METS header information
            testPackage.METS_Header.Create_Date = new DateTime(2007, 1, 1);
            testPackage.METS_Header.Modify_Date = DateTime.Now;
            testPackage.METS_Header.Creator_Individual = "Mark Sullivan";
            testPackage.METS_Header.Add_Creator_Individual_Notes("Programmer of new SobekCM.Resource_Object");
            testPackage.METS_Header.Add_Creator_Individual_Notes("Adding coordinates");
            testPackage.METS_Header.Creator_Organization = "University of Florida";
            testPackage.METS_Header.Creator_Software = "SobekCM Bib Package Test";
            testPackage.METS_Header.RecordStatus_Enum = METS_Record_Status.COMPLETE;
            testPackage.METS_Header.Add_Creator_Org_Notes("This test package was done to test DLCs new METS package");

            // Add all the MODS elements
            Abstract_Info testAbstract = testPackage.Bib_Info.Add_Abstract("This is a sample abstract", "en");
            testPackage.Bib_Info.Add_Abstract("Tämä on esimerkki abstrakteja", "fin");
            testAbstract.Display_Label = "Summary Abstract";
            testAbstract.Type = "summary";

            testPackage.Bib_Info.Access_Condition.Text = "All rights are reserved by source institution.";
            testPackage.Bib_Info.Access_Condition.Language = "en";
            testPackage.Bib_Info.Access_Condition.Type = "restrictions on use";
            testPackage.Bib_Info.Access_Condition.Display_Label = "Rights";

            testPackage.Bib_Info.Add_Identifier("000123234", "OCLC", "Electronic OCLC");
            testPackage.Bib_Info.Add_Identifier("182-asdsd-28k", "DOI");

            testPackage.Bib_Info.Add_Language("English", String.Empty, "en");
            testPackage.Bib_Info.Add_Language("Finnish");
            testPackage.Bib_Info.Add_Language(String.Empty, "ita", String.Empty);

            testPackage.Bib_Info.Location.Holding_Code = "MVS";
            testPackage.Bib_Info.Location.Holding_Name = "From the Private Library of Mark Sullivan";
            testPackage.Bib_Info.Location.PURL = "http://www.uflib.ufl.edu/ufdc/?b=CA00000000";
            testPackage.Bib_Info.Location.Other_URL = "http://www.fnhm.edu";
            testPackage.Bib_Info.Location.Other_URL_Display_Label = "Specimen Information";
            testPackage.Bib_Info.Location.Other_URL_Note = "Specimen FLAS 125342 Database";
            testPackage.Bib_Info.Location.EAD_URL = "http://digital.uflib.ufl.edu/";
            testPackage.Bib_Info.Location.EAD_Name = "Digital Library Center Finding Guide";

            testPackage.Bib_Info.Main_Entity_Name.Name_Type = Name_Info_Type_Enum.Personal;
            testPackage.Bib_Info.Main_Entity_Name.Full_Name = "Brown, B.F.";
            testPackage.Bib_Info.Main_Entity_Name.Terms_Of_Address = "Dr.";
            testPackage.Bib_Info.Main_Entity_Name.Display_Form = "B.F. Brown";
            testPackage.Bib_Info.Main_Entity_Name.Affiliation = "Chemistry Dept., American University";
            testPackage.Bib_Info.Main_Entity_Name.Description = "Chemistry Professor Emeritus";
            testPackage.Bib_Info.Main_Entity_Name.Add_Role("Author");

            Zoological_Taxonomy_Info taxonInfo = new Zoological_Taxonomy_Info();
            testPackage.Add_Metadata_Module(GlobalVar.ZOOLOGICAL_TAXONOMY_METADATA_MODULE_KEY, taxonInfo);
            taxonInfo.Scientific_Name = "Ctenomys sociabilis";
            taxonInfo.Higher_Classification = "Animalia; Chordata; Vertebrata; Mammalia; Theria; Eutheria; Rodentia; Hystricognatha; Hystricognathi; Ctenomyidae; Ctenomyini; Ctenomys";
            taxonInfo.Kingdom = "Animalia";
            taxonInfo.Phylum = "Chordata";
            taxonInfo.Class = "Mammalia";
            taxonInfo.Order = "Rodentia";
            taxonInfo.Family = "Ctenomyidae";
            taxonInfo.Genus = "Ctenomys";
            taxonInfo.Specific_Epithet = "sociabilis";
            taxonInfo.Taxonomic_Rank = "species";
            taxonInfo.Common_Name = "Social Tuco-Tuco";

            Name_Info name1 = new Name_Info();
            name1.Name_Type = Name_Info_Type_Enum.Personal;
            name1.Given_Name = "John Paul";
            name1.Terms_Of_Address = "Pope; II";
            name1.Dates = "1920-2002";
            name1.User_Submitted = true;
            testPackage.Bib_Info.Add_Named_Entity(name1);

            Name_Info name2 = new Name_Info();
            name2.Name_Type = Name_Info_Type_Enum.Conference;
            name2.Full_Name = "Paris Peace Conference (1919-1920)";
            name2.Dates = "1919-1920";
            testPackage.Bib_Info.Add_Named_Entity(name2);

            Name_Info name3 = new Name_Info();
            name3.Name_Type = Name_Info_Type_Enum.Corporate;
            name3.Full_Name = "United States -- Court of Appeals (2nd Court)";
            testPackage.Bib_Info.Add_Named_Entity(name3);

            Name_Info name4 = new Name_Info();
            name4.Name_Type = Name_Info_Type_Enum.Personal;
            name4.Full_Name = "Wilson, Mary";
            name4.Display_Form = "Mary 'Weels' Wilson";
            name4.Given_Name = "Mary";
            name4.Family_Name = "Wilson";
            name4.ID = "NAM4";
            name4.Terms_Of_Address = "2nd";
            name4.Add_Role("illustrator");
            name4.Add_Role("cartographer");
            testPackage.Bib_Info.Add_Named_Entity(name4);

            Name_Info donor = new Name_Info();
            donor.Name_Type = Name_Info_Type_Enum.Personal;
            donor.Full_Name = "Livingston, Arthur";
            donor.Description = "Gift in honor of Arthur Livingston";
            donor.Terms_Of_Address = "3rd";
            donor.Add_Role("honoree", String.Empty);
            testPackage.Bib_Info.Donor = donor;

            testPackage.Bib_Info.Main_Title.NonSort = "The ";
            testPackage.Bib_Info.Main_Title.Title = "Man Who Would Be King";
            testPackage.Bib_Info.Main_Title.Subtitle = "The story of succession in England";

            Title_Info title1 = new Title_Info("homme qui voulut être roi", Title_Type_Enum.Translated);
            title1.NonSort = "L'";
            title1.Language = "fr";
            testPackage.Bib_Info.Add_Other_Title(title1);

            Title_Info title2 = new Title_Info();
            title2.Title = "Man Who Be King";
            title2.Display_Label = "also known as";
            title2.NonSort = "The";
            title2.Title_Type = Title_Type_Enum.Alternative;
            testPackage.Bib_Info.Add_Other_Title(title2);

            Title_Info title3 = new Title_Info();
            title3.Title = "Great works of England";
            title3.Authority = "naf";
            title3.Add_Part_Name("Second Portion");
            title3.Add_Part_Number("2nd");
            title3.Title_Type = Title_Type_Enum.Uniform;
            title3.User_Submitted = true;
            testPackage.Bib_Info.Add_Other_Title(title3);

            testPackage.Bib_Info.Add_Note("Funded by the NEH", Note_Type_Enum.Funding);
            testPackage.Bib_Info.Add_Note("Based on a play which originally appeared in France as \"Un peu plus tard, un peu plus tôt\"").User_Submitted = true;
            testPackage.Bib_Info.Add_Note("Anne Baxter (Louise), Maria Perschy (Angela), Gustavo Rojo (Bill), Reginald Gilliam (Mr. Johnson), [Catherine Elliot?] (Aunt Sallie), Ben Tatar (waiter)", Note_Type_Enum.Performers, "Performed By");

            testPackage.Bib_Info.Origin_Info.Add_Place("New York", "nyu", "usa");
            testPackage.Bib_Info.Origin_Info.Date_Issued = "1992";
            testPackage.Bib_Info.Origin_Info.MARC_DateIssued_Start = "1992";
            testPackage.Bib_Info.Origin_Info.MARC_DateIssued_End = "1993";
            testPackage.Bib_Info.Origin_Info.Date_Copyrighted = "1999";
            testPackage.Bib_Info.Origin_Info.Edition = "2nd";

            Publisher_Info newPub = testPackage.Bib_Info.Add_Publisher("Published for the American Vacuum Society by the American Institute of Physics");
            newPub.Add_Place("New York, New York");
            newPub.User_Submitted = true;
            testPackage.Bib_Info.Add_Publisher("University of Florida Press House").Add_Place("Gainesville, FL");
            testPackage.Bib_Info.Add_Manufacturer("Addison Randly Publishing House");

            testPackage.Bib_Info.Original_Description.Extent = "1 sound disc (56 min.) : digital ; 3/4 in.";
            testPackage.Bib_Info.Original_Description.Add_Note("The sleeve of this sound disc was damaged in a fire");
            testPackage.Bib_Info.Original_Description.Add_Note("The disc has a moderate amount of scratches, but still plays");

            testPackage.Bib_Info.Series_Part_Info.Day = "18";
            testPackage.Bib_Info.Series_Part_Info.Day_Index = 18;
            testPackage.Bib_Info.Series_Part_Info.Month = "Syyskuu";
            testPackage.Bib_Info.Series_Part_Info.Month_Index = 9;
            testPackage.Bib_Info.Series_Part_Info.Year = "1992";
            testPackage.Bib_Info.Series_Part_Info.Year_Index = 1992;

            testPackage.Bib_Info.Series_Part_Info.Enum1 = "Volume 12";
            testPackage.Bib_Info.Series_Part_Info.Enum1_Index = 12;
            testPackage.Bib_Info.Series_Part_Info.Enum2 = "Issue 3";
            testPackage.Bib_Info.Series_Part_Info.Enum2_Index = 3;
            testPackage.Bib_Info.Series_Part_Info.Enum3 = "Part 1";
            testPackage.Bib_Info.Series_Part_Info.Enum3_Index = 1;

            testPackage.Behaviors.Serial_Info.Add_Hierarchy(1, 1992, "1992");
            testPackage.Behaviors.Serial_Info.Add_Hierarchy(2, 9, "Syyskuu");
            testPackage.Behaviors.Serial_Info.Add_Hierarchy(3, 18, "18");

            testPackage.Bib_Info.SeriesTitle.Title = "Shakespeare's most famous musicals";

            testPackage.Bib_Info.Add_Target_Audience("young adults");
            testPackage.Bib_Info.Add_Target_Audience("adolescent", "marctarget");

            testPackage.Bib_Info.SobekCM_Type = TypeOfResource_SobekCM_Enum.Newspaper;

            // Add cartographic subject
            Subject_Info_Cartographics newCartographics = testPackage.Bib_Info.Add_Cartographics_Subject();
            newCartographics.Scale = "1:2000";
            newCartographics.Projection = "Conical Projection";
            newCartographics.Coordinates = "E 72°--E 148°/N 13°--N 18°";

            // Add hierarchical geographic subject
            Subject_Info_HierarchicalGeographic hierarchical = testPackage.Bib_Info.Add_Hierarchical_Geographic_Subject();
            hierarchical.Continent = "North America";
            hierarchical.Country = "United States of America";
            hierarchical.State = "Kansas";
            hierarchical.County = "Butler";
            hierarchical.City = "Augusta";

            // Add hierarchical geographic subject
            Subject_Info_HierarchicalGeographic hierarchical2 = testPackage.Bib_Info.Add_Hierarchical_Geographic_Subject();
            hierarchical2.Region = "Arctic Ocean";

            // Add hierarchical geographic subject
            Subject_Info_HierarchicalGeographic hierarchical3 = testPackage.Bib_Info.Add_Hierarchical_Geographic_Subject();
            hierarchical3.Island = "Puerto Rico";
            hierarchical3.Language = "English";
            hierarchical3.Province = "Provincial";
            hierarchical3.Territory = "Puerto Rico";
            hierarchical3.Area = "Intercontinental areas (Western Hemisphere)";

            // Add a name subject
            Subject_Info_Name subjname1 = testPackage.Bib_Info.Add_Name_Subject();
            subjname1.Authority = "lcsh";
            subjname1.Full_Name = "Garcia Lorca, Federico";
            subjname1.Dates = "1898-1936";
            subjname1.Add_Geographic("Russia");
            subjname1.Add_Geographic("Moscow");
            subjname1.Add_Genre("maps");
            subjname1.User_Submitted = true;

            // Add a title information subject
            Subject_Info_TitleInfo subjtitle1 = testPackage.Bib_Info.Add_Title_Subject();
            subjtitle1.Title_Type = Title_Type_Enum.Uniform;
            subjtitle1.Authority = "naf";
            subjtitle1.Title = "Missale Carnotense";

            // Add a standard subject
            Subject_Info_Standard subject1 = testPackage.Bib_Info.Add_Subject();
            subject1.Authority = "lcsh";
            subject1.Add_Topic("Real property");
            subject1.Add_Geographic("Mississippi");
            subject1.Add_Geographic("Tippah County");
            subject1.Add_Genre("Maps");

            // Add a standard subject
            Subject_Info_Standard subject2 = testPackage.Bib_Info.Add_Subject();
            subject2.Add_Occupation("Migrant laborers");
            subject2.Add_Genre("School district case files");

            // Add a standard subject
            Subject_Info_Standard subject3 = testPackage.Bib_Info.Add_Subject();
            subject3.Authority = "lctgm";
            subject3.Add_Topic("Educational buildings");
            subject3.Add_Geographic("Washington (D.C.)");
            subject3.Add_Temporal("1890-1910");

            // Add a standard subject
            Subject_Info_Standard subject4 = testPackage.Bib_Info.Add_Subject();
            subject4.Authority = "rvm";
            subject4.Language = "french";
            subject4.Add_Topic("Église catholique");
            subject4.Add_Topic("Histoire");
            subject4.Add_Temporal("20e siècle");

            // Add record information
            testPackage.Bib_Info.Record.Add_Catalog_Language(new Language_Info("English", "eng", "en"));
            testPackage.Bib_Info.Record.Add_Catalog_Language(new Language_Info("French", "fre", "fr"));
            testPackage.Bib_Info.Record.MARC_Creation_Date = "080303";
            testPackage.Bib_Info.Record.Add_MARC_Record_Content_Sources("FUG");
            testPackage.Bib_Info.Record.Record_Origin = "Imported from (OCLC)001213124";

            // Test the items which are in the non-MODS portion of the Bib_Info object
            testPackage.BibID = "MVS0000001";
            testPackage.VID = "00001";
            testPackage.Bib_Info.SortDate = 1234;
            testPackage.Bib_Info.SortTitle = "MAN WHO WOULD BE KING";
            testPackage.Bib_Info.Add_Temporal_Subject(1990, 2002, "Recent history");
            testPackage.Bib_Info.Add_Temporal_Subject(1990, 2002, "Lähihistoria");
            testPackage.Bib_Info.Source.Code = "UF";
            testPackage.Bib_Info.Source.Statement = "University of Florida";

            // Add an affiliation
            Affiliation_Info affiliation1 = new Affiliation_Info();
            affiliation1.University = "University of Florida";
            affiliation1.Campus = "Gainesville Campus";
            affiliation1.College = "College of Engineering";
            affiliation1.Department = "Computer Engineering Department";
            affiliation1.Unit = "Robotics";
            affiliation1.Name_Reference = "NAM4";
            testPackage.Bib_Info.Add_Affiliation(affiliation1);

            // Add a related item
            Related_Item_Info relatedItem1 = new Related_Item_Info();
            relatedItem1.SobekCM_ID = "UF00001234";
            relatedItem1.Relationship = Related_Item_Type_Enum.Preceding;
            relatedItem1.Publisher = "Gainesville Sun Publishing House";
            relatedItem1.Add_Note(new Note_Info("Digitized with funding from NEH", Note_Type_Enum.Funding));
            relatedItem1.Add_Note(new Note_Info("Gainesville Bee was the precursor to this item"));
            relatedItem1.Main_Title.NonSort = "The";
            relatedItem1.Main_Title.Title = "Gainesville Bee";
            relatedItem1.Add_Identifier("01234353", "oclc");
            relatedItem1.Add_Identifier("002232311", "aleph");
            Name_Info ri_name = new Name_Info();
            ri_name.Full_Name = "Hills, Bryan";
            ri_name.Terms_Of_Address = "Mr.";
            ri_name.Name_Type = Name_Info_Type_Enum.Personal;
            ri_name.Add_Role("author");
            relatedItem1.Add_Name(ri_name);
            relatedItem1.URL = @"http://www.uflib.ufl.edu/ufdc/?b=UF00001234";
            relatedItem1.URL_Display_Label = "Full Text";
            testPackage.Bib_Info.Add_Related_Item(relatedItem1);

            // Add another related item
            Related_Item_Info relatedItem2 = new Related_Item_Info();
            relatedItem2.Relationship = Related_Item_Type_Enum.Succeeding;
            relatedItem2.SobekCM_ID = "UF00009999";
            relatedItem2.Main_Title.NonSort = "The";
            relatedItem2.Main_Title.Title = "Daily Sun";
            relatedItem2.Add_Identifier("0125437", "oclc");
            relatedItem2.Add_Note("Name change occured in Fall 1933");
            relatedItem2.Start_Date = "Fall 1933";
            relatedItem2.End_Date = "December 31, 1945";
            testPackage.Bib_Info.Add_Related_Item(relatedItem2);

            // Add some processing parameters
            testPackage.Behaviors.Add_Aggregation("JUV");
            testPackage.Behaviors.Add_Aggregation("DLOC");
            testPackage.Behaviors.Add_Aggregation("DLOSA1");
            testPackage.Behaviors.Add_Aggregation("ALICE");
            testPackage.Behaviors.Add_Aggregation("ARTE");

            testPackage.Web.GUID = "GUID!";
            testPackage.Behaviors.Add_Wordmark("DLOC");
            testPackage.Behaviors.Add_Wordmark("UFSPEC");
            testPackage.Behaviors.Main_Thumbnail = "00001thm.jpg";

            // Add some downloads
            testPackage.Divisions.Download_Tree.Add_File("MVS_Complete.PDF");
            testPackage.Divisions.Download_Tree.Add_File("MVS_Complete.MP2");
            testPackage.Divisions.Download_Tree.Add_File("MVS_Part1.MP2");
            testPackage.Divisions.Download_Tree.Add_File("MVS_Part1.PDF");

            // Add some coordinate information
            GeoSpatial_Information geoSpatial = new GeoSpatial_Information();
            testPackage.Add_Metadata_Module(GlobalVar.GEOSPATIAL_METADATA_MODULE_KEY, geoSpatial);
            geoSpatial.Add_Point(29.530151, -82.301459, "Lake Wauberg");
            geoSpatial.Add_Point(29.634352, -82.350640, "Veterinary School");
            Coordinate_Polygon polygon = new Coordinate_Polygon();
            polygon.Label = "University of Florida Campus";
            polygon.Add_Edge_Point(new Coordinate_Point(29.651435, -82.339869, String.Empty));
            polygon.Add_Edge_Point(new Coordinate_Point(29.641216, -82.340298, String.Empty));
            polygon.Add_Edge_Point(new Coordinate_Point(29.629503, -82.371969, String.Empty));
            polygon.Add_Edge_Point(new Coordinate_Point(29.649645, -82.371712, String.Empty));
            polygon.Add_Inner_Point(29.649794, -82.351971, "Stadium");
            polygon.Add_Inner_Point(29.650988, -82.341156, "Library");
            geoSpatial.Add_Polygon(polygon);
            Coordinate_Line line = new Coordinate_Line();
            line.Label = "Waldo Road";
            line.Add_Point(29.652852, -82.310944, "Gainesville");
            line.Add_Point(29.716681, -82.268372, String.Empty);
            line.Add_Point(29.791494, -82.167778, "Waldo");
            geoSpatial.Add_Line(line);

            // Add some performing arts information
            Performing_Arts_Info partInfo = new Performing_Arts_Info();
            testPackage.Add_Metadata_Module("PerformingArts", partInfo);
            partInfo.Performance = "Hamlet";
            partInfo.Performance_Date = "August 12, 1923";
            Performer performer1 = partInfo.Add_Performer("Sullivan, Mark");
            performer1.Sex = "M";
            performer1.LifeSpan = "1873-";
            performer1.Occupation = "actor";
            performer1.Title = "Mr.";

            Performer performer2 = partInfo.Add_Performer("Waldbart, Julia");
            performer2.Sex = "F";
            performer2.LifeSpan = "1876-";
            performer2.Occupation = "actress";
            performer2.Title = "Mrs.";

            // Add some oral history information
            Oral_Interview_Info oralInfo = new Oral_Interview_Info();
            testPackage.Add_Metadata_Module(  "OralInterview", oralInfo);
            oralInfo.Interviewee = "Edwards, Herm";
            oralInfo.Interviewer = "Proctor, Samual";

            // Add some learning object resource information
            LearningObjectMetadata lomInfo = new LearningObjectMetadata();
            testPackage.Add_Metadata_Module( GlobalVar.IEEE_LOM_METADATA_MODULE_KEY, lomInfo );
            lomInfo.AggregationLevel = AggregationLevelEnum.level3;
            lomInfo.Status = StatusEnum.draft;
            LOM_System_Requirements lomReq1 = new LOM_System_Requirements();
            lomReq1.RequirementType = RequirementTypeEnum.operating_system;
            lomReq1.Name.Value = "Windows";
            lomReq1.MinimumVersion = "Windows XP";
            lomReq1.MaximumVersion = "Windows 7";
            lomInfo.Add_SystemRequirements(lomReq1);
            LOM_System_Requirements lomReq2 = new LOM_System_Requirements();
            lomReq2.RequirementType = RequirementTypeEnum.software;
            lomReq2.Name.Value = "Java SDK";
            lomReq2.MinimumVersion = "1.7.1";
            lomReq2.MaximumVersion = "2.09";
            lomInfo.Add_SystemRequirements(lomReq2);
            lomInfo.InteractivityType = InteractivityTypeEnum.mixed;
            lomInfo.Add_LearningResourceType("exercise");
            lomInfo.Add_LearningResourceType("Tutorials", "encdlwebpedagogicaltype");
            lomInfo.InteractivityLevel = InteractivityLevelEnum.high;
            lomInfo.Add_IntendedEndUserRole(IntendedEndUserRoleEnum.learner);
            lomInfo.Add_Context("Undergraduate lower division", "enclearningcontext");
            lomInfo.Add_Context("15", "grade");
            lomInfo.Add_Context("16", "grade");
            lomInfo.Add_Context("5", "group");
            lomInfo.Add_TypicalAgeRange("suitable for children over 7", "en");
            lomInfo.Add_TypicalAgeRange("2-8");
            lomInfo.DifficultyLevel = DifficultyLevelEnum.medium;
            lomInfo.TypicalLearningTime = "PT45M";

            LOM_Classification lomClassification1 = new LOM_Classification();
            lomInfo.Add_Classification(lomClassification1);
            lomClassification1.Purpose.Value = "Discipline";
            LOM_TaxonPath lomTaxonPath1 = new LOM_TaxonPath();
            lomClassification1.Add_TaxonPath(lomTaxonPath1);
            lomTaxonPath1.Add_SourceName("ARIADNE");
            LOM_Taxon lomTaxon1 = new LOM_Taxon();
            lomTaxonPath1.Add_Taxon(lomTaxon1);
            lomTaxon1.ID = "BF120";
            lomTaxon1.Add_Entry("Work_History", "en");
            lomTaxon1.Add_Entry("Historie", "nl");
            LOM_Taxon lomTaxon2 = new LOM_Taxon();
            lomTaxonPath1.Add_Taxon(lomTaxon2);
            lomTaxon2.ID = "BF120.1";
            lomTaxon2.Add_Entry("American Work_History", "en");
            LOM_Taxon lomTaxon3 = new LOM_Taxon();
            lomTaxonPath1.Add_Taxon(lomTaxon3);
            lomTaxon3.ID = "BF120.1.4";
            lomTaxon3.Add_Entry("American Civil War", "en");

            LOM_Classification lomClassification2 = new LOM_Classification();
            lomInfo.Add_Classification(lomClassification2);
            lomClassification2.Purpose.Value = "Educational Objective";

            LOM_TaxonPath lomTaxonPath2 = new LOM_TaxonPath();
            lomClassification2.Add_TaxonPath(lomTaxonPath2);
            lomTaxonPath2.Add_SourceName("Common Core Standards", "en");
            LOM_Taxon lomTaxon4 = new LOM_Taxon();
            lomTaxonPath2.Add_Taxon(lomTaxon4);
            lomTaxon4.ID = "CCS.Math.Content";
            LOM_Taxon lomTaxon5 = new LOM_Taxon();
            lomTaxonPath2.Add_Taxon(lomTaxon5);
            lomTaxon5.ID = "3";
            lomTaxon5.Add_Entry("Grade 3", "en");
            LOM_Taxon lomTaxon6 = new LOM_Taxon();
            lomTaxonPath2.Add_Taxon(lomTaxon6);
            lomTaxon6.ID = "OA";
            lomTaxon6.Add_Entry("Operations and Algebraic Thinking", "en");
            LOM_Taxon lomTaxon7 = new LOM_Taxon();
            lomTaxonPath2.Add_Taxon(lomTaxon7);
            lomTaxon7.ID = "A";
            lomTaxon7.Add_Entry("Represent and solve problems involving multiplication and division.", "en");
            LOM_Taxon lomTaxon8 = new LOM_Taxon();
            lomTaxonPath2.Add_Taxon(lomTaxon8);
            lomTaxon8.ID = "3";
            lomTaxon8.Add_Entry("Use multiplication and division within 100 to solve word problems in situations involving equal groups, arrays, and measurement quantities, e.g., by using drawings and equations with a symbol for the unknown number to represent the problem.", "en");

            LOM_TaxonPath lomTaxonPath3 = new LOM_TaxonPath();
            lomClassification2.Add_TaxonPath(lomTaxonPath3);
            lomTaxonPath3.Add_SourceName("Common Core Standards", "en");
            LOM_Taxon lomTaxon14 = new LOM_Taxon();
            lomTaxonPath3.Add_Taxon(lomTaxon14);
            lomTaxon14.ID = "CCS.Math.Content";
            LOM_Taxon lomTaxon15 = new LOM_Taxon();
            lomTaxonPath3.Add_Taxon(lomTaxon15);
            lomTaxon15.ID = "3";
            lomTaxon15.Add_Entry("Grade 3", "en");
            LOM_Taxon lomTaxon16 = new LOM_Taxon();
            lomTaxonPath3.Add_Taxon(lomTaxon16);
            lomTaxon16.ID = "OA";
            lomTaxon16.Add_Entry("Operations and Algebraic Thinking", "en");
            LOM_Taxon lomTaxon17 = new LOM_Taxon();
            lomTaxonPath3.Add_Taxon(lomTaxon17);
            lomTaxon17.ID = "A";
            lomTaxon17.Add_Entry("Represent and solve problems involving multiplication and division.", "en");
            LOM_Taxon lomTaxon18 = new LOM_Taxon();
            lomTaxonPath3.Add_Taxon(lomTaxon18);
            lomTaxon18.ID = "4";
            lomTaxon18.Add_Entry("Determine the unknown whole number in a multiplication or division equation relating three whole numbers. For example, determine the unknown number that makes the equation true in each of the equations 8 × ? = 48, 5 = _ ÷ 3, 6 × 6 = ?", "en");

            // Add some views and interfaces
            testPackage.Behaviors.Clear_Web_Skins();
            testPackage.Behaviors.Add_Web_Skin("dLOC");
            testPackage.Behaviors.Add_Web_Skin("UFDC");
            testPackage.Behaviors.Add_View(View_Enum.JPEG2000);
            testPackage.Behaviors.Add_View(View_Enum.JPEG);
            testPackage.Behaviors.Add_View(View_Enum.RELATED_IMAGES);
            testPackage.Behaviors.Add_View(View_Enum.HTML, "Full Document", "MVS001214.html");

            // Create the chapters and pages and link them
            Division_TreeNode chapter1 = new Division_TreeNode("Chapter", "First Chapter");
            Page_TreeNode page1 = new Page_TreeNode("First Page");
            Page_TreeNode page2 = new Page_TreeNode("Page 2");
            chapter1.Nodes.Add(page1);
            chapter1.Nodes.Add(page2);
            Division_TreeNode chapter2 = new Division_TreeNode("Chapter", "Last Chapter");
            Page_TreeNode page3 = new Page_TreeNode("Page 3");
            Page_TreeNode page4 = new Page_TreeNode("Last Page");
            chapter2.Nodes.Add(page3);
            chapter2.Nodes.Add(page4);
            testPackage.Divisions.Physical_Tree.Roots.Add(chapter1);
            testPackage.Divisions.Physical_Tree.Roots.Add(chapter2);

            // Create the files
            SobekCM_File_Info file1_1 = new SobekCM_File_Info("2000626_0001.jp2", 2120, 1100);
            SobekCM_File_Info file1_2 = new SobekCM_File_Info("2000626_0001.jpg", 630, 330);
            SobekCM_File_Info file1_3 = new SobekCM_File_Info("2000626_0001.tif");
            SobekCM_File_Info file2_1 = new SobekCM_File_Info("2000626_0002.jp2", 1754, 2453);
            SobekCM_File_Info file2_2 = new SobekCM_File_Info("2000626_0002.jpg", 630, 832);
            SobekCM_File_Info file2_3 = new SobekCM_File_Info("2000626_0002.tif");
            SobekCM_File_Info file3_1 = new SobekCM_File_Info("2000626_0003.jp2", 2321, 1232);
            SobekCM_File_Info file3_2 = new SobekCM_File_Info("2000626_0003.jpg", 630, 342);
            SobekCM_File_Info file3_3 = new SobekCM_File_Info("2000626_0003.tif");
            SobekCM_File_Info file4_1 = new SobekCM_File_Info("2000626_0004.jp2", 2145, 1024);
            SobekCM_File_Info file4_2 = new SobekCM_File_Info("2000626_0004.jpg", 630, 326);
            SobekCM_File_Info file4_3 = new SobekCM_File_Info("2000626_0004.tif");

            // Link the files to the pages
            page1.Files.Add(file1_1);
            page1.Files.Add(file1_2);
            page1.Files.Add(file1_3);
            page2.Files.Add(file2_1);
            page2.Files.Add(file2_2);
            page2.Files.Add(file2_3);
            page3.Files.Add(file3_1);
            page3.Files.Add(file3_2);
            page3.Files.Add(file3_3);
            page4.Files.Add(file4_1);
            page4.Files.Add(file4_2);
            page4.Files.Add(file4_3);

            // Add the DAITSS information
            DAITSS_Info daitssInfo = new DAITSS_Info();
            daitssInfo.Account = "FTU";
            daitssInfo.SubAccount = "CLAS";
            daitssInfo.Project = "UFDC";
            daitssInfo.toArchive = true;
            testPackage.Add_Metadata_Module(GlobalVar.DAITSS_METADATA_MODULE_KEY, daitssInfo);

            // Save this package
            testPackage.Source_Directory = directory;
            return testPackage;
        }
        /// <summary> Adds any viewer_specific information to the Navigation Bar Menu Section </summary>
        /// <param name="Navigation_Place_Holder"> Additional place holder ( &quot;navigationPlaceHolder&quot; ) in the itemNavForm form allows item-viewer-specific controls to be added to the left navigation bar</param>
        /// <param name="Internet_Explorer"> Flag indicates if the current browser is internet explorer </param>
        /// <param name="Tracer"> Trace object keeps a list of each method executed and important milestones in rendering </param>
        /// <remarks> For this item viewer, a small thumbnail of the entire image showing the current viewport location is placed in the left navigation bar </remarks>
        public void Add_Nav_Bar_Menu_Section(PlaceHolder Navigation_Place_Holder, bool Internet_Explorer, Custom_Tracer Tracer)
        {
            // If this is for a fragment, do nothing
            if ( !String.IsNullOrEmpty(currentMode.Fragment))
                return;

            StringBuilder buildResponse = new StringBuilder(2000);
            buildResponse.AppendLine();

            // Add the divs for loading the pop-up forms
            buildResponse.AppendLine("<!-- Place holders for pop-up forms which load dynamically if required -->");
            buildResponse.AppendLine("<div class=\"print_popup_div\" id=\"form_print\" style=\"display:none;\"></div>");
            buildResponse.AppendLine("<div class=\"email_popup_div\" id=\"form_email\" style=\"display:none;\"></div>");
            buildResponse.AppendLine("<div class=\"add_popup_div\" id=\"add_item_form\" style=\"display:none;\"></div>");
            buildResponse.AppendLine("<div class=\"share_popup_div\" id=\"share_form\" style=\"display:none;\"></div>");
            buildResponse.AppendLine();

            if (PageViewer.ItemViewer_Type != ItemViewer_Type_Enum.GnuBooks_PageTurner)
            {
                buildResponse.AppendLine("<!-- Show the title and any other important item information -->");
                buildResponse.AppendLine("<div id=\"itemtitlebar\">");
                if (currentItem.METS_Header.RecordStatus_Enum == METS_Record_Status.BIB_LEVEL)
                {
                    string grouptitle = currentItem.Behaviors.GroupTitle;
                    if (grouptitle.Length > 125)
                    {
                        buildResponse.AppendLine("\t<h1><abbr title=\"" + grouptitle + "\">" + grouptitle.Substring(0, 120) + "...</abbr></h1>");
                    }
                    else
                    {
                        buildResponse.AppendLine("\t<h1>" + grouptitle + "</h1>");
                    }
                }
                else
                {
                    string final_title = currentItem.Bib_Info.Main_Title.Title;
                    if (currentItem.Bib_Info.Main_Title.NonSort.Length > 0)
                    {
                        if (currentItem.Bib_Info.Main_Title.NonSort[currentItem.Bib_Info.Main_Title.NonSort.Length - 1] == ' ')
                            final_title = currentItem.Bib_Info.Main_Title.NonSort + currentItem.Bib_Info.Main_Title.Title;
                        else
                        {
                            if (currentItem.Bib_Info.Main_Title.NonSort[currentItem.Bib_Info.Main_Title.NonSort.Length - 1] == '\'')
                            {
                                final_title = currentItem.Bib_Info.Main_Title.NonSort + currentItem.Bib_Info.Main_Title.Title;
                            }
                            else
                            {
                                final_title = currentItem.Bib_Info.Main_Title.NonSort + " " + currentItem.Bib_Info.Main_Title.Title;
                            }
                        }
                    }

                    // Add the Title if there is one
                    if (final_title.Length > 0)
                    {
                        if (final_title.Length > 125)
                        {
                            buildResponse.AppendLine("\t<h1><abbr title=\"" + final_title + "\">" + final_title.Substring(0, 120) + "...</abbr></h1>");
                        }
                        else
                        {
                            buildResponse.AppendLine("\t<h1>" + final_title + "</h1>");
                        }
                    }

                    // Add the link if there is one
                    if ((currentItem.Bib_Info.hasLocationInformation) && (currentItem.Bib_Info.Location.Other_URL.Length > 0))
                    {
                        if (currentItem.Bib_Info.Location.Other_URL.ToLower().IndexOf("www.youtube.com") < 0)
                        {

                            // Determine the type of link
                            string type = translations.Get_Translation("Related Link", currentMode.Language);
                            if (currentItem.Bib_Info.Location.Other_URL_Display_Label.Length > 0)
                            {
                                type = translations.Get_Translation(currentItem.Bib_Info.Location.Other_URL_Display_Label, currentMode.Language);
                            }

                            // Determine the display value
                            string note = currentItem.Bib_Info.Location.Other_URL;
                            if (currentItem.Bib_Info.Location.Other_URL_Note.Length > 0)
                            {
                                note = currentItem.Bib_Info.Location.Other_URL_Note;
                            }

                            // Add the link
                            buildResponse.AppendLine("\t<a href=\"" + currentItem.Bib_Info.Location.Other_URL + "\">" + note + " ( " + type + " )</a><br />");
                        }
                    }

                    // If there is an ACCESSION number and this is an ARTIFACT, include that at the top
                    if ((currentItem.Bib_Info.SobekCM_Type == TypeOfResource_SobekCM_Enum.Artifact) && (currentItem.Bib_Info.Identifiers_Count > 0))
                    {
                        foreach (Identifier_Info thisIdentifier in currentItem.Bib_Info.Identifiers)
                        {
                            if (thisIdentifier.Type.ToUpper().IndexOf("ACCESSION") >= 0)
                            {
                                buildResponse.AppendLine("\t" + translations.Get_Translation("Accession number", currentMode.Language) + " " + thisIdentifier.Identifier + "<br />");
                                break;
                            }
                        }
                    }
                }

                buildResponse.AppendLine("</div>");
                buildResponse.AppendLine();

                // Add the item views
                buildResponse.AppendLine("<!-- Add the different view and social options -->");
                buildResponse.AppendLine("<div id=\"itemviewersbar\" style=\"text-align: center\">");
                buildResponse.AppendLine("\t<ul class=\"sf-menu\">");

                // Save the current view type
                ushort page = currentMode.Page;

                // Add the item level views
                foreach (View_Object thisView in currentItem.Behaviors.Views)
                {
                    if ((!itemRestrictedFromUserByIp) || (thisView.View_Type == View_Enum.CITATION) || (thisView.View_Type == View_Enum.ALL_VOLUMES) || (thisView.View_Type == View_Enum.RELATED_IMAGES))
                    {
                        // Special code for the CITATION view (TEMPORARY - v.3.2)
                        if (thisView.View_Type == View_Enum.CITATION)
                        {
                            string viewerCode = currentMode.ViewerCode;
                            currentMode.ViewerCode = "citation";
                            if ((viewerCode == "citation") || (viewerCode == "marc") || (viewerCode == "metadata") || (viewerCode == "usage"))
                            {
                                buildResponse.Append("\t\t<li id=\"selected-sf-menu-item\">Citation");
                            }
                            else
                            {
                                buildResponse.Append("\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">Citation</a>");
                            }
                            buildResponse.AppendLine("<ul>");

                            buildResponse.AppendLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">Standard View</a></li>");

                            currentMode.ViewerCode = "marc";
                            buildResponse.AppendLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">MARC View</a></li>");

                            currentMode.ViewerCode = "metadata";
                            buildResponse.AppendLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">Metadata</a></li>");

                            currentMode.ViewerCode = "usage";
                            buildResponse.AppendLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">Usage Statistics</a></li>");

                            buildResponse.AppendLine("\t\t</ul></li>");
                            currentMode.ViewerCode = viewerCode;
                        }
                        else if (thisView.View_Type == View_Enum.ALL_VOLUMES)
                        {
                            string viewerCode = currentMode.ViewerCode;
                            string resource_type_upper = currentItem.Bib_Info.SobekCM_Type_String.ToUpper();
                            string all_volumes = "All Volumes";
                            if (resource_type_upper.IndexOf("NEWSPAPER") >= 0)
                            {
                                all_volumes = "All Issues";
                            }
                            else if (resource_type_upper.IndexOf("MAP") >= 0)
                            {
                                all_volumes = "Related Maps";
                            }
                            else if ( resource_type_upper.IndexOf("AERIAL") >= 0 )
                            {
                                all_volumes = "Related Flights";
                            }

                            currentMode.ViewerCode = "allvolumes";
                            if ((viewerCode == "allvolumes") || (viewerCode == "allvolumes2") || (viewerCode == "allvolumes3"))
                            {
                                buildResponse.Append("\t\t<li id=\"selected-sf-menu-item\">" + all_volumes);
                            }
                            else
                            {
                                buildResponse.Append("\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">" + all_volumes + "</a>");
                            }
                            buildResponse.AppendLine("<ul>");

                            currentMode.ViewerCode = "allvolumes";
                            buildResponse.AppendLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">Tree View</a></li>");

                            currentMode.ViewerCode = "allvolumes2";
                            buildResponse.AppendLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">Thumbnails</a></li>");

                            if (currentMode.Internal_User)
                            {
                                currentMode.ViewerCode = "allvolumes3";
                                buildResponse.AppendLine("\t\t\t<li><a href=\"" + currentMode.Redirect_URL() + "\">List View</a></li>");
                            }

                            buildResponse.AppendLine("\t\t</ul></li>");
                            currentMode.ViewerCode = viewerCode;
                        }
                        else
                        {
                            List<string> item_nav_bar_link = Item_Nav_Bar_HTML_Factory.Get_Nav_Bar_HTML(thisView, currentItem.Bib_Info.SobekCM_Type_String, htmlSkin.Base_Skin_Code, currentMode, -1, translations, showZoomable, currentItem);
                            // Add each nav bar link
                            foreach (string this_link in item_nav_bar_link)
                            {
                                buildResponse.AppendLine("\t\t" + this_link + "");
                            }
                        }
                    }
                }

                // If this is citation or index mode, the number may be an invalid page sequence
                if ((page <= 0) || (currentMode.ViewerCode == View_Object.Viewer_Code_By_Type(View_Enum.RELATED_IMAGES)[0]))
                {
                    currentMode.Page = 1;

                }

                if ((currentItem.Web.Static_PageCount > 0) && (currentPage == null))
                {
                    currentPage = currentItem.Web.Pages_By_Sequence[0];
                }

                // Add each page display type
                if ((currentPage != null) && (!itemRestrictedFromUserByIp))
                {
                    int page_seq = currentMode.Page;
                    if (currentItem.Behaviors.Item_Level_Page_Views_Count > 0)
                    {
                        foreach (View_Object thisPageView in currentItem.Behaviors.Item_Level_Page_Views)
                        {
                            View_Enum thisViewType = thisPageView.View_Type;
                            foreach (List<string> page_nav_bar_link in from thisFile in currentPage.Files let fileObject = thisFile.Get_Viewer() where fileObject != null where fileObject.View_Type == thisViewType select Item_Nav_Bar_HTML_Factory.Get_Nav_Bar_HTML(thisFile.Get_Viewer(), currentItem.Bib_Info.SobekCM_Type_String.ToUpper(), htmlSkin.Base_Skin_Code, currentMode, page_seq, translations, showZoomable, currentItem))
                            {
                                foreach (string nav_link in page_nav_bar_link)
                                {
                                    buildResponse.AppendLine("\t\t" + nav_link + "");
                                }
                                break;
                            }
                        }
                    }
                }

                if (itemRestrictedFromUserByIp)
                {
                    List<string> restricted_nav_bar_link = Item_Nav_Bar_HTML_Factory.Get_Nav_Bar_HTML(new View_Object(View_Enum.RESTRICTED), currentItem.Bib_Info.SobekCM_Type_String.ToUpper(), htmlSkin.Base_Skin_Code, currentMode, 0, translations, showZoomable, currentItem);
                    buildResponse.AppendLine("\t\t" + restricted_nav_bar_link[0] + "");
                }

                // Set current submode back
                currentMode.Page = page;

                // Add the sharing buttons if this is not restricted by IP address or checked out
                if ((!itemRestrictedFromUserByIp) && (!itemCheckedOutByOtherUser) && (!currentMode.Is_Robot))
                {
                    buildResponse.AppendLine("\t\t<li id=\"sharebuttonitem\" class=\"action-sf-menu-item\" style=\"float:right;\" onclick=\"toggle_share_form('share_button');\"><span id=\"sharebuttonspan\">Share</span></li>");

                    //if (currentItem.Behaviors.Can_Be_Described)
                    //{
                    //    if (currentUser != null)
                    //    {
                    //        Output.Write("<a href=\"?m=hmh\" onmouseover=\"document.getElementById('describe_button').src='" + currentMode.Base_URL + "design/skins/" + htmlSkin.Base_Skin_Code + "/buttons/describe_rect_button_h.gif'\" onmouseout=\"document.getElementById('describe_button').src='" + currentMode.Base_URL + "design/skins/" + htmlSkin.Base_Skin_Code + "/buttons/describe_rect_button.gif'\"  onclick=\"return describe_item_form_open( 'describe_button' );\"><img class=\"ResultSavePrintButtons\" border=\"0px\" name=\"describe_button\" id=\"describe_button\" src=\"" + currentMode.Base_URL + "design/skins/" + htmlSkin.Base_Skin_Code + "/buttons/describe_rect_button.gif\" title=\"Add a description to this item\" alt=\"DESCRIBE\" /></a>");
                    //    }
                    //    else
                    //    {
                    //        Output.Write("<a href=\"?m=hmh\" onmouseover=\"document.getElementById('describe_button').src='" + currentMode.Base_URL + "design/skins/" + htmlSkin.Base_Skin_Code + "/buttons/describe_rect_button_h.gif'\" onmouseout=\"document.getElementById('describe_button').src='" + currentMode.Base_URL + "design/skins/" + htmlSkin.Base_Skin_Code + "/buttons/describe_rect_button.gif'\"><img class=\"ResultSavePrintButtons\" border=\"0px\" name=\"describe_button\" id=\"describe_button\" src=\"" + currentMode.Base_URL + "design/skins/" + htmlSkin.Base_Skin_Code + "/buttons/describe_rect_button.gif\" title=\"Add a description to this item\" alt=\"DESCRIBE\" /></a>");
                    //    }
                    //}

                    if ((currentUser != null))
                    {
                        if (currentItem.Web.ItemID > 0)
                        {
                            if (currentUser.Is_In_Bookshelf(currentItem.BibID, currentItem.VID))
                            {
                                buildResponse.AppendLine("\t\t<li id=\"addbuttonitem\" class=\"action-sf-menu-item\" style=\"float:right;\" onclick=\"return remove_item_itemviewer();\"><img src=\"" + currentMode.Base_URL + "default/images/minussign.png\" alt=\"\" style=\"vertical-align:middle\" /><span id=\"addbuttonspan\">Remove</span></li>");
                            }
                            else
                            {
                                buildResponse.AppendLine("\t\t<li id=\"addbuttonitem\" class=\"action-sf-menu-item\" style=\"float:right;\" onclick=\"add_item_form_open();\"><img src=\"" + currentMode.Base_URL + "default/images/plussign.png\" alt=\"\" style=\"vertical-align:middle\" /><span id=\"addbuttonspan\">Add</span></li>");
                            }
                        }

                        buildResponse.AppendLine("\t\t<li id=\"sendbuttonitem\" class=\"action-sf-menu-item\" style=\"float:right;\" onclick=\"email_form_open();\"><img src=\"" + currentMode.Base_URL + "default/images/email.png\" alt=\"\" style=\"vertical-align:middle\" /><span id=\"sendbuttonspan\">Send</span></li>");
                    }
                    else
                    {
                        if (currentItem.Web.ItemID > 0)
                            buildResponse.AppendLine("\t\t<li id=\"addbuttonitem\" class=\"action-sf-menu-item\" style=\"float:right;\" onclick=\"window.location='?m=hmh';\"><img src=\"" + currentMode.Base_URL + "default/images/plussign.png\" alt=\"\" style=\"vertical-align:middle\" /><span id=\"addbuttonspan\">Add</span></li>");

                        buildResponse.AppendLine("\t\t<li id=\"sendbuttonitem\" class=\"action-sf-menu-item\" style=\"float:right;\" onclick=\"window.location='?m=hmh';\"><img src=\"" + currentMode.Base_URL + "default/images/email.png\" alt=\"\" style=\"vertical-align:middle\" /><span id=\"sendbuttonspan\">Send</span></li>");
                    }

                    if (currentItem.Web.ItemID > 0)
                    {
                        buildResponse.AppendLine("\t\t<li id=\"printbuttonitem\" class=\"action-sf-menu-item\" style=\"float:right;\" onclick=\"print_form_open();\"><img src=\"" + currentMode.Base_URL + "default/images/printer.png\" alt=\"\" style=\"vertical-align:middle\" /><span id=\"printbuttonspan\">Print</span></li>");
                    }
                    else
                    {
                        buildResponse.AppendLine("\t\t<li id=\"printbuttonitem\" class=\"action-sf-menu-item\" style=\"float:right;\" onclick=\"window.print();return false;\"><img src=\"" + currentMode.Base_URL + "default/images/printer.png\" alt=\"\" style=\"vertical-align:middle\" /><span id=\"printbuttonspan\">Print</span></li>");
                    }

                }

                buildResponse.AppendLine("\t</ul>");
                buildResponse.AppendLine();

                buildResponse.AppendLine("</div>");
                buildResponse.AppendLine();

            }

            if (should_left_navigation_bar_be_shown)
            {
                // Start the item viewer
                buildResponse.AppendLine("<!-- Begin the left navigational bar -->");
                if ( PageViewer.ItemViewer_Type == ItemViewer_Type_Enum.JPEG2000 )
                    buildResponse.AppendLine("<div id=\"itemviewleftnavbar_hack\">");
                else
                    buildResponse.AppendLine("<div id=\"itemviewleftnavbar\">");

                // Compute the URL options which may be needed
                string url_options = currentMode.URL_Options();
                string urlOptions1 = String.Empty;
                string urlOptions2 = String.Empty;
                if (url_options.Length > 0)
                {
                    urlOptions1 = "?" + url_options;
                    urlOptions2 = "&" + url_options;
                }

                // Show search results if there is a saved result
                if (searchResultsCount > 0)
                {
                    buildResponse.AppendLine("\t<ul class=\"SobekNavBarMenu\">");
                    buildResponse.AppendLine(currentMode.Text_Search.Length > 0
                                                 ? "\t\t<li class=\"SobekNavBarHeader\">MATCHING PAGES</li>"
                                                 : "\t\t<li class=\"SobekNavBarHeader\">MATCHING TILES</li>");

                    foreach (string thisMatch in searchResultsString)
                    {
                        buildResponse.AppendLine("\t\t<li>" + thisMatch.Replace("<%URLOPTS%>", url_options).Replace("<%?URLOPTS%>", urlOptions1).Replace("<%&URLOPTS%>", urlOptions2) + "</li>");
                    }
                    buildResponse.AppendLine("\t</ul>");
                    buildResponse.AppendLine();
                }

                // Provide way to expand TOC
                if ((!showToc) && (currentItem.Web.Static_PageCount > 1) && (currentItem.Web.Static_Division_Count > 1))
                {
                    string show_toc_text = "SHOW TABLE OF CONTENTS";
                    int width = 180;

                    if (currentMode.Language == Web_Language_Enum.French)
                    {
                        show_toc_text = "VOIR L'INDEX";
                        width = 120;
                    }
                    if (currentMode.Language == Web_Language_Enum.Spanish)
                    {
                        show_toc_text = "MOSTRAR INDICE";
                        width = 140;
                    }

                    buildResponse.AppendLine("\t<div class=\"ShowTocRow\" style=\"width: " + width + "px;\" >");
                    string redirect_url = currentMode.Redirect_URL().Replace("&", "&amp;");
                    if (redirect_url.IndexOf("?") < 0)
                        redirect_url = redirect_url + "?toc=y";
                    else
                        redirect_url = redirect_url + "&toc=y";
                    buildResponse.AppendLine("\t\t<a href=\"" + redirect_url + "\">");
                    buildResponse.AppendLine("\t\t\t<img src=\"" + currentMode.Base_URL + "design/skins/" + htmlSkin.Base_Skin_Code + "/tabs/cLDG.gif\" alt=\"\" /><img src=\"" + currentMode.Base_URL + "design/skins/" + htmlSkin.Base_Skin_Code + "/tabs/AD.gif\" border=\"0\" alt=\"\" /><span class=\"tab\">" + show_toc_text + "</span><img src=\"" + currentMode.Base_URL + "design/skins/" + htmlSkin.Base_Skin_Code + "/tabs/cRDG.gif\" alt=\"\" />");
                    buildResponse.AppendLine("\t\t</a>");
                    buildResponse.AppendLine("\t</div>");
                }

                // Anything to add?
                if (buildResponse.Length > 0)
                {
                    Literal newLiteral = new Literal {Text = buildResponse.ToString()};
                    Navigation_Place_Holder.Controls.Add(newLiteral);
                }

                // Add the navigation part to this form
                if (PageViewer != null)
                {
                    Tracer.Add_Trace("Html_MainWriter.Add_Controls", "Allowing page viewer to add left navigation bar section to <i>navigationPlaceHolder</i>");
                    Nav_Bar_Menu_Section_Added = PageViewer.Add_Nav_Bar_Menu_Section(Navigation_Place_Holder, Internet_Explorer, Tracer);
                }
            }
            else
            {
                // Anything to add?
                if (buildResponse.Length > 0)
                {
                    Literal newLiteral = new Literal { Text = buildResponse.ToString() };
                    Navigation_Place_Holder.Controls.Add(newLiteral);
                }
            }
        }
        private void Finish_writing_html(SobekCM_Item CurrentItem, Page_TreeNode CurrentPage, string Filename, string TextFileLocation )
        {
            //bool textSearchable = CurrentItem.Behaviors.Text_Searchable;
            //CurrentItem.Behaviors.Text_Searchable = false;
            //if (staticSobekcmLocation.Length > 0)
            //    UI_ApplicationCache_Gateway.Settings.Servers.Base_Directory = staticSobekcmLocation;

            //// Get the skin
            //if ((CurrentItem.Behaviors.Web_Skin_Count > 0) && ( !CurrentItem.Behaviors.Web_Skins.Contains( defaultSkin.ToUpper())))
            //    currentMode.Skin = CurrentItem.Behaviors.Web_Skins[0];

            //// Get the skin object
            //Web_Skin_Object skinObject = skinsCollection[currentMode.Skin];
            //if (skinObject == null)
            //{
            //    skinObject = assistant.Get_HTML_Skin(currentMode, skinsCollection, false, null);
            //    skinsCollection.Add(skinObject);
            //}

            //// Create the HTML writer
            //Item_HtmlSubwriter itemWriter = new Item_HtmlSubwriter(CurrentItem, CurrentPage, null, codeManager, translations, true, true, currentMode, null, String.Empty, null, tracer) { Mode = currentMode, Skin = skinObject };
            //UI_ApplicationCache_Gateway.Settings.Base_SobekCM_Location_Relative = currentMode.Base_URL;
            //if ((UI_ApplicationCache_Gateway.Settings.Base_SobekCM_Location_Relative.Length == 0) || (UI_ApplicationCache_Gateway.Settings.Base_SobekCM_Location_Relative.Contains("localhost")))
            //{
            //    UI_ApplicationCache_Gateway.Settings.Base_SobekCM_Location_Relative = primaryWebServerUrl;
            //    currentMode.Base_URL = UI_ApplicationCache_Gateway.Settings.Base_SobekCM_Location_Relative;
            //}

            //// Now that the item viewer is built, set the robot flag to suppress some checks
            //currentMode.Is_Robot = true;

            //// Create the TextWriter
            //StreamWriter writer = new StreamWriter(Filename, false, Encoding.UTF8);

            //writer.WriteLine("<!DOCTYPE html>");
            //writer.WriteLine("<html>");
            //writer.WriteLine("<head>");
            //writer.WriteLine("  <title>" + CurrentItem.Bib_Info.Main_Title + "</title>");
            //writer.WriteLine();
            //writer.WriteLine("  <!-- " + UI_ApplicationCache_Gateway.Settings.System.System_Name + " : SobekCM Digital Repository -->");
            //writer.WriteLine();
            //writer.WriteLine("  <link href=\"" + UI_ApplicationCache_Gateway.Settings.Servers.System_Base_URL + "default/SobekCM.min.css\" rel=\"stylesheet\" type=\"text/css\" />");
            //writer.WriteLine("  <script type=\"text/javascript\" src=\"" + UI_ApplicationCache_Gateway.Settings.Servers.System_Base_URL + "default/scripts/jquery/jquery-1.10.2.min.js\"></script>");
            //writer.WriteLine("  <script type=\"text/javascript\" src=\"" + UI_ApplicationCache_Gateway.Settings.Servers.System_Base_URL + "default/scripts/sobekcm_full.min.js\"></script>");
            //writer.WriteLine("  <link href=\"" + UI_ApplicationCache_Gateway.Settings.Servers.System_Base_URL + "default/SobekCM_Item.min.css\" rel=\"stylesheet\" type=\"text/css\" />");

            //writer.WriteLine("  <meta name=\"robots\" content=\"index, follow\" />");
            //if (skinObject.CSS_Style.Length > 0)
            //{
            //    writer.WriteLine("  <link href=\"" + UI_ApplicationCache_Gateway.Settings.Servers.System_Base_URL + skinObject.CSS_Style + "\" rel=\"stylesheet\" type=\"text/css\" />");
            //}

            //string image_src = currentMode.Base_URL + "/" + CurrentItem.Web.AssocFilePath + "/" + CurrentItem.Behaviors.Main_Thumbnail;
            //writer.WriteLine("  <link rel=\"image_src\" href=\"" + image_src.Replace("\\", "/").Replace("//", "/").Replace("http:/", "http://") + "\" />");

            //writer.WriteLine("</head>");
            //writer.WriteLine("<body>");

            //// Is this item DARK or PRIVATE
            //if ((CurrentItem.Behaviors.Dark_Flag) || ( CurrentItem.Behaviors.IP_Restriction_Membership < 0 ))
            //{
            //    writer.WriteLine("THIS ITEM IS CURRENTLY DARK OR PRIVATE");
            //    writer.WriteLine("</body>");
            //    writer.WriteLine("</html>");
            //    writer.Flush();
            //    writer.Close();
            //    return;
            //}

            //// Add the header
            //Display_Header(writer, itemWriter.Skin, CurrentItem);

            //// Begin to write the item view
            //itemWriter.Write_HTML(writer, tracer);

            //if ((CurrentItem.Behaviors.Wordmark_Count > 0) || ((CurrentItem.Web.Static_PageCount > 1) && (CurrentItem.Web.Static_Division_Count > 1)))
            //{
            //    writer.WriteLine("<nav id=\"sbkIsw_Leftnavbar\" style=\"padding-top:3px\">");

            //    // Write the table of contents as static HTML, rather than the TreeView web control
            //    if ((CurrentItem.Web.Static_PageCount > 1) && (CurrentItem.Web.Static_Division_Count > 1))
            //    {
            //        writer.WriteLine("  <div class=\"sbkIsw_ShowTocRow\">");
            //        writer.WriteLine("    <div class=\"sbkIsw_UpToc\">HIDE TABLE OF CONTENTS</div>");
            //        writer.WriteLine("  </div>");

            //        writer.WriteLine("<div class=\"sbkIsw_TocTreeView\">");

            //        // load the table of contents in the tree
            //        TreeView treeView1 = new TreeView();
            //        itemWriter.Create_TreeView_From_Divisions(treeView1);

            //        // Step through all the parent nodes
            //        writer.WriteLine("  <table cellspacing=\"4px\">");
            //        foreach (TreeNode thisNode in treeView1.Nodes)
            //        {
            //            writer.WriteLine("    <tr><td width=\"9px\">&nbsp;</td><td>" + thisNode.Text.Replace("sbkIsw_SelectedTocTreeViewItem", "sbkIsw_TocTreeViewItem") + "</td></tr>");
            //        }
            //        writer.WriteLine("  </table>");
            //        writer.WriteLine("</div>");
            //    }

            //}

            //itemWriter.Write_Additional_HTML(writer, tracer);

            ////Literal citationLiteral = (Literal)placeHolder.Controls[0];
            ////writer.WriteLine(citationLiteral.Text);
            ////placeHolder.Controls.Clear();

            //writer.WriteLine("<!-- COMMENT HERE -->");

            //// Close out this tables and form
            //writer.WriteLine("       </tr>");

            //// If this is IP restricted, show nothing else
            //if (CurrentItem.Behaviors.IP_Restriction_Membership == 0)
            //{
            //    // Add the download list if there are some
            //    if (CurrentItem.Divisions.Download_Tree.Has_Files)
            //    {
            //        writer.WriteLine("       <tr>");
            //        // Create the downloads viewer to ouput the html
            //        Download_ItemViewer downloadViewer = new Download_ItemViewer {CurrentItem = CurrentItem, CurrentMode = currentMode};

            //        // Add the HTML for this now
            //        downloadViewer.Write_Main_Viewer_Section(writer, tracer);
            //        writer.WriteLine("       </tr>");
            //    }

            //    // If there is a table of contents write it again, this time it will be complete
            //    // and also show a hierarchy if there is one
            //    if ((CurrentItem.Web.Static_PageCount > 1) && (CurrentItem.Web.Static_Division_Count > 1))
            //    {
            //        writer.WriteLine("       <tr>");
            //        writer.WriteLine("         <td align=\"left\"><span class=\"SobekViewerTitle\">Table of Contents</span></td>");
            //        writer.WriteLine("       </tr>");

            //        writer.WriteLine("       <tr>");
            //        writer.WriteLine("          <td>");
            //        writer.WriteLine("            <div class=\"sbkCiv_Citation\">");

            //        foreach (abstract_TreeNode treeNode in CurrentItem.Divisions.Physical_Tree.Roots)
            //        {
            //            recursively_write_toc(writer, treeNode, "&nbsp; &nbsp; ");
            //        }

            //        writer.WriteLine("            </div>");
            //        writer.WriteLine("          </td>");
            //        writer.WriteLine("       </tr>");
            //    }

            //    // Is the text file location included, in which case any full text should be appended to the end?
            //    if ((TextFileLocation.Length > 0) && (Directory.Exists(TextFileLocation)))
            //    {
            //        // Get the list of all TXT files in this division
            //        string[] text_files = Directory.GetFiles(TextFileLocation, "*.txt");
            //        Dictionary<string, string> text_files_existing = new Dictionary<string, string>();
            //        foreach (string thisTextFile in text_files)
            //        {
            //            string text_filename = (new FileInfo(thisTextFile)).Name.ToUpper();
            //            text_files_existing[text_filename] = text_filename;
            //        }

            //        // Are there ANY text files?
            //        if (text_files.Length > 0)
            //        {
            //            // If this has page images, check for related text files
            //            List<string> text_files_included = new List<string>();
            //            bool started = false;
            //            if (CurrentItem.Divisions.Physical_Tree.Has_Files)
            //            {
            //                // Go through the first 100 text pages
            //                List<abstract_TreeNode> pages = CurrentItem.Divisions.Physical_Tree.Pages_PreOrder;
            //                int page_count = 0;
            //                foreach (Page_TreeNode thisPage in pages)
            //                {
            //                    // Keep track of the page count
            //                    page_count++;

            //                    // Look for files in this page
            //                    if (thisPage.Files.Count > 0)
            //                    {
            //                        bool found_non_thumb_file = false;
            //                        foreach (SobekCM_File_Info thisFile in thisPage.Files)
            //                        {
            //                            // Make sure this is not a thumb
            //                            if (thisFile.System_Name.ToLower().IndexOf("thm.jpg") < 0)
            //                            {
            //                                found_non_thumb_file = true;
            //                                string root = thisFile.File_Name_Sans_Extension;
            //                                if (text_files_existing.ContainsKey(root.ToUpper() + ".TXT"))
            //                                {
            //                                    string text_file = TextFileLocation + "\\" + thisFile.File_Name_Sans_Extension + ".txt";

            //                                    // SInce this is marked to be included, save this name
            //                                    text_files_included.Add(root.ToUpper() + ".TXT");

            //                                    // For size reasons, we only include the text from the first 100 pages
            //                                    if (page_count <= 100)
            //                                    {
            //                                        if (!started)
            //                                        {
            //                                            writer.WriteLine("       <tr>");
            //                                            writer.WriteLine("         <td align=\"left\"><span class=\"SobekViewerTitle\">Full Text</span></td>");
            //                                            writer.WriteLine("       </tr>");
            //                                            writer.WriteLine("       <tr>");
            //                                            writer.WriteLine("          <td>");
            //                                            writer.WriteLine("            <div class=\"sbkCiv_Citation\">");

            //                                            started = true;
            //                                        }

            //                                        try
            //                                        {
            //                                            StreamReader reader = new StreamReader(text_file);
            //                                            string text_line = reader.ReadLine();
            //                                            while (text_line != null)
            //                                            {
            //                                                writer.WriteLine(text_line + "<br />");
            //                                                text_line = reader.ReadLine();
            //                                            }
            //                                            reader.Close();
            //                                        }
            //                                        catch
            //                                        {
            //                                            writer.WriteLine("Unable to read file: " + text_file);
            //                                        }

            //                                        writer.WriteLine("<br /><br />");
            //                                    }
            //                                }

            //                            }

            //                            // If a suitable file was found, break here
            //                            if (found_non_thumb_file)
            //                                break;
            //                        }
            //                    }
            //                }

            //                // End this if it was ever started
            //                if (started)
            //                {
            //                    writer.WriteLine("            </div>");
            //                    writer.WriteLine("          </td>");
            //                    writer.WriteLine("       </tr>");
            //                }
            //            }

            //            // Now, check for any other valid text files
            //            List<string> additional_text_files = text_files_existing.Keys.Where(ThisTextFile => (!text_files_included.Contains(ThisTextFile.ToUpper())) && (ThisTextFile.ToUpper() != "AGREEMENT.TXT") && (ThisTextFile.ToUpper().IndexOf("REQUEST") != 0)).ToList();

            //            // Now, include any additional text files, which would not be page text files, possiblye
            //            // full text for included PDFs, Powerpoint, Word Doc, etc..
            //            started = false;
            //            foreach (string thisTextFile in additional_text_files)
            //            {
            //                if (!started)
            //                {
            //                    writer.WriteLine("       <tr>");
            //                    writer.WriteLine("         <td align=\"left\"><span class=\"SobekViewerTitle\">Full Text</span></td>");
            //                    writer.WriteLine("       </tr>");
            //                    writer.WriteLine("       <tr>");
            //                    writer.WriteLine("          <td>");
            //                    writer.WriteLine("            <div class=\"sbkCiv_Citation\">");

            //                    started = true;
            //                }

            //                string text_file = TextFileLocation + "\\" + thisTextFile;

            //                try
            //                {

            //                    StreamReader reader = new StreamReader(text_file);
            //                    string text_line = reader.ReadLine();
            //                    while (text_line != null)
            //                    {
            //                        writer.WriteLine(text_line + "<br />");
            //                        text_line = reader.ReadLine();
            //                    }
            //                    reader.Close();
            //                }
            //                catch
            //                {
            //                    writer.WriteLine("Unable to read file: " + text_file);
            //                }

            //                writer.WriteLine("<br /><br />");
            //            }

            //            // End this if it was ever started
            //            if (started)
            //            {
            //                writer.WriteLine("            </div>");
            //                writer.WriteLine("          </td>");
            //                writer.WriteLine("       </tr>");
            //            }
            //        }
            //    }
            //}

            //writer.WriteLine("      </table>");
            //writer.WriteLine("      </div>");

            //// Write the footer
            //Display_Footer(writer, itemWriter.Skin);

            //writer.WriteLine("</body>");
            //writer.WriteLine("</html>");

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

            //// Restore the text searchable flag and robot flag
            //currentMode.Is_Robot = false;
            //CurrentItem.Behaviors.Text_Searchable = textSearchable;
        }
        /// <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);
                    }
                }
            }
        }
        /// <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> Adds all of the file information to a digital resource package by analyzing the directory </summary>
        /// <param name="BIBPackage">Digital resource package to enrich</param>
        /// <param name="FilesFilter"> Files to be added as page image files ( such as "*.tif|*.jpg|*.jp2" )</param>
        /// <param name="RecursivelyIncludeSubfolders"> Flag indicates if all files in subfolders should also be added </param>
        /// <param name="PageImagesInSeperateFoldersCanBeSamePage"> If two images with the same root are found in subfolders, should </param>
        public static void Add_All_Files(SobekCM_Item BIBPackage, string FilesFilter, bool RecursivelyIncludeSubfolders, bool PageImagesInSeperateFoldersCanBeSamePage)
        {
            // Get the set of file filters within a list
            List<string> file_filters = new List<string>();
            if (FilesFilter.IndexOf("|") < 0)
            {
                file_filters.Add(FilesFilter.ToUpper());
            }
            else
            {
                string[] splitter = FilesFilter.Split("|".ToCharArray());
                foreach (string thisFilter in splitter)
                {
                    file_filters.Add(thisFilter.ToUpper());
                }
            }

            // Get the files from the current directory (or recursive directories)
            Builder_Page_File_Collection fileCollection = new Builder_Page_File_Collection();
            get_files_from_current_directory(fileCollection, file_filters, BIBPackage.Source_Directory, String.Empty, RecursivelyIncludeSubfolders);

            // Now, determine which files are already in the METS file.
            // Build a collection of file objects from the METS
            List<SobekCM_File_Info> metsFiles = new List<SobekCM_File_Info>();
            Builder_Page_File_Collection metsFileCollection = new Builder_Page_File_Collection();
            Dictionary<SobekCM_File_Info, Page_TreeNode> fileToPage = new Dictionary<SobekCM_File_Info, Page_TreeNode>();
            Dictionary<Page_TreeNode, Division_TreeNode> pageToDiv = new Dictionary<Page_TreeNode, Division_TreeNode>();

            foreach (abstract_TreeNode rootNode in BIBPackage.Divisions.Physical_Tree.Roots)
            {
                recursively_add_all_METS_files(rootNode, metsFiles, metsFileCollection, fileToPage, pageToDiv, file_filters);
            }

            // Determine which files to delete from the METS package
            List<SobekCM_File_Info> deletes = new List<SobekCM_File_Info>();
            foreach (SobekCM_File_Info thisFile in metsFiles)
            {
                if ((thisFile.METS_LocType == SobekCM_File_Info_Type_Enum.SYSTEM) && (!File.Exists(BIBPackage.Source_Directory + "//" + thisFile.System_Name)))
                {
                    deletes.Add(thisFile);
                }
            }

            // Delete the files, and related pages
            foreach (SobekCM_File_Info thisFile in deletes)
            {
                metsFiles.Remove(thisFile);

                Page_TreeNode thisPage = fileToPage[thisFile];
                if (thisPage != null)
                {
                    thisPage.Files.Remove(thisFile);
                    Division_TreeNode thisDiv = pageToDiv[thisPage];
                    if (thisDiv != null)
                    {
                        thisDiv.Nodes.Remove(thisPage);
                    }
                }

                // Remove this from the other mets list
                int index = 0;
                int deleteIndex = -1;
                foreach (Builder_Page_File thisPageFile in metsFileCollection)
                {
                    if (thisPageFile.FullName.ToUpper() == thisFile.System_Name.ToUpper())
                    {
                        deleteIndex = index;
                        break;
                    }

                    index++;
                }
                if (deleteIndex >= 0)
                {
                    metsFileCollection.RemoveAt(deleteIndex);
                }
            }

            // Now, recursively check each division and remove empty divisions
            int rootNodeCounter = 0;
            while (rootNodeCounter < BIBPackage.Divisions.Physical_Tree.Roots.Count)
            {
                abstract_TreeNode rootNode = BIBPackage.Divisions.Physical_Tree.Roots[rootNodeCounter];
                if (recursively_remove_empty_divisions(rootNode))
                    BIBPackage.Divisions.Physical_Tree.Roots.Remove(rootNode);
                else
                    rootNodeCounter++;
            }

            // Build the list of all the remaining files
            Hashtable filesPresent = new Hashtable();
            foreach (SobekCM_File_Info thisFile in metsFiles)
            {
                filesPresent[thisFile.System_Name] = thisFile;
            }

            // Determine which files need to be added
            Builder_Page_File_Collection addFiles = new Builder_Page_File_Collection();
            foreach (Builder_Page_File thisFile in fileCollection)
            {
                if (!filesPresent.Contains(thisFile.FullName_With_Relative_Directory))
                {
                    addFiles.Add(thisFile);
                }
            }

            // Add files that need to be added
            if (addFiles.Count > 0)
            {
                // Make sure there is at least one division
                if (BIBPackage.Divisions.Physical_Tree.Roots.Count == 0)
                {
                    Division_TreeNode newRootNode = new Division_TreeNode("Main", String.Empty);
                    BIBPackage.Divisions.Physical_Tree.Roots.Add(newRootNode);
                }

                // Create the map of file names to pages
                Dictionary<string, Page_TreeNode> file_to_page_hash = new Dictionary<string, Page_TreeNode>();
                List<abstract_TreeNode> pageNodes = BIBPackage.Divisions.Physical_Tree.Pages_PreOrder;
                foreach (Page_TreeNode pageNode in pageNodes)
                {
                    if (pageNode.Files.Count > 0)
                    {
                        string first_page_name = pageNode.Files[0].File_Name_Sans_Extension;

                        if (first_page_name.IndexOf(".") > 0)
                            first_page_name = first_page_name.Substring(0, first_page_name.IndexOf("."));

                        if ((PageImagesInSeperateFoldersCanBeSamePage) || (pageNode.Files[0].METS_LocType == SobekCM_File_Info_Type_Enum.URL))
                        {
                            if (first_page_name.IndexOf("\\") > 0)
                            {
                                string[] slash_splitter = first_page_name.Split("\\".ToCharArray());
                                first_page_name = slash_splitter[slash_splitter.Length - 1];
                            }
                        }

                        if (!file_to_page_hash.ContainsKey(first_page_name.ToUpper()))
                        {
                            file_to_page_hash[first_page_name.ToUpper()] = pageNode;
                        }
                    }
                }

                // If there are no existing pages, this can be easily assembled
                if (metsFiles.Count == 0)
                {
                    try
                    {
                        // Get the first division
                        Division_TreeNode firstDiv = (Division_TreeNode) BIBPackage.Divisions.Physical_Tree.Roots[0];

                        // Add each file
                        foreach (Builder_Page_File thisFile in addFiles)
                        {
                            // Create the new METS file object
                            SobekCM_File_Info newFileForMETS = new SobekCM_File_Info(thisFile.FullName_With_Relative_Directory);

                            // Get the root of this file, to put all files of the same root on the same page
                            string thisFileShort = newFileForMETS.File_Name_Sans_Extension;
                            if (PageImagesInSeperateFoldersCanBeSamePage)
                            {
                                if (thisFileShort.IndexOf("\\") > 0)
                                {
                                    string[] slash_splitter = thisFileShort.Split("\\".ToCharArray());
                                    thisFileShort = slash_splitter[slash_splitter.Length - 1];
                                }
                            }

                            // Is this a pre-existing root ( therefore pre-existing page )?
                            if (file_to_page_hash.ContainsKey(thisFileShort))
                            {
                                // Just add this file to the pre-existing page
                                file_to_page_hash[thisFileShort].Files.Add(newFileForMETS);
                            }
                            else
                            {
                                // This needs a new page then
                                Page_TreeNode newPage = new Page_TreeNode();
                                newPage.Files.Add(newFileForMETS);
                                firstDiv.Nodes.Add(newPage);

                                // Add this page to the hash, so it is not added again later
                                file_to_page_hash[thisFileShort] = newPage;
                            }
                        }
                    }
                    catch
                    {
                    }
                }
                else
                {
                    // Configure the initial pointers
                    Builder_Page_File previous_file = null;
                    Builder_Page_File next_file = metsFileCollection[0];
                    Builder_Page_File new_file = addFiles[0];
                    int new_file_counter = 1;
                    int next_file_counter = 1;

                    // Loop through each file to be added
                    while (new_file != null)
                    {
                        // Create the new METS file object
                        SobekCM_File_Info newFileForMETS = new SobekCM_File_Info(new_file.FullName_With_Relative_Directory);

                        // Get the root of this file, to put all files of the same root on the same page
                        string thisFileShort = newFileForMETS.File_Name_Sans_Extension;
                        if (PageImagesInSeperateFoldersCanBeSamePage)
                        {
                            if (thisFileShort.IndexOf("\\") > 0)
                            {
                                string[] slash_splitter = thisFileShort.Split("\\".ToCharArray());
                                thisFileShort = slash_splitter[slash_splitter.Length - 1];
                            }
                        }

                        // First, ensure that we have not already added a page for this
                        if (file_to_page_hash.ContainsKey(thisFileShort))
                        {
                            // Just add this file to the pre-existing page
                            file_to_page_hash[thisFileShort].Files.Add(newFileForMETS);
                        }
                        else
                        {
                            // Move to the right part of the existing files list
                            while ((new_file.CompareTo(next_file) > 0) && (next_file != null))
                            {
                                previous_file = next_file;
                                if (next_file_counter < metsFileCollection.Count)
                                {
                                    next_file = metsFileCollection[next_file_counter++];
                                }
                                else
                                {
                                    next_file = null;
                                }
                            }

                            // Add the page for this and link the new file
                            Page_TreeNode newPage = new Page_TreeNode();
                            newPage.Files.Add(newFileForMETS);
                            file_to_page_hash[thisFileShort] = newPage;

                            // Get the parent division and add this page in the right place
                            // Check there was a previous page, otherwise this inserts at the very beginning
                            if (previous_file == null)
                            {
                                abstract_TreeNode abstractNode = BIBPackage.Divisions.Physical_Tree.Roots[0];
                                Division_TreeNode lastDivNode = (Division_TreeNode) abstractNode;
                                while (!abstractNode.Page)
                                {
                                    lastDivNode = (Division_TreeNode) abstractNode;
                                    if (lastDivNode.Nodes.Count > 0)
                                    {
                                        abstractNode = lastDivNode.Nodes[0];
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                                lastDivNode.Nodes.Insert(0, newPage);
                                metsFileCollection.Insert(new_file);
                                new_file.METS_Division = lastDivNode;
                                new_file.METS_Page = newPage;
                                next_file = metsFileCollection[0];
                            }
                            else
                            {
                                Division_TreeNode parentDivNode = previous_file.METS_Division;
                                Page_TreeNode previousPageNode = previous_file.METS_Page;
                                int previousFileIndex = parentDivNode.Nodes.IndexOf(previousPageNode);
                                if (previousFileIndex + 1 >= parentDivNode.Nodes.Count)
                                    parentDivNode.Nodes.Add(newPage);
                                else
                                    parentDivNode.Nodes.Insert(previousFileIndex + 1, newPage);
                                next_file = previous_file;
                                next_file_counter--;
                                new_file.METS_Division = parentDivNode;
                                new_file.METS_Page = newPage;
                                metsFileCollection.Insert(new_file);
                            }
                        }

                        // Move to the next new file
                        if (new_file_counter < addFiles.Count)
                        {
                            new_file = addFiles[new_file_counter++];
                        }
                        else
                        {
                            new_file = null;
                        }
                    }
                }
            }
        }