/// <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>This reader accepts two option values.  'EAD_File_ReaderWriter:XSL_Location' gives the location of a XSL
        /// file, which can be used to transform the description XML read from this EAD into HTML (or another format of XML).  
        /// 'EAD_File_ReaderWriter:Analyze_Description' indicates whether to analyze the description section of the EAD and
        /// read it into the item. (Default is TRUE).</remarks>
        public bool Read_Metadata(Stream Input_Stream, SobekCM_Item Return_Package, Dictionary<string, object> Options, out string Error_Message)
        {
            // Ensure this metadata module extension exists
            EAD_Info eadInfo = Return_Package.Get_Metadata_Module(GlobalVar.EAD_METADATA_MODULE_KEY) as EAD_Info;
            if (eadInfo == null)
            {
                eadInfo = new EAD_Info();
                Return_Package.Add_Metadata_Module(GlobalVar.EAD_METADATA_MODULE_KEY, eadInfo);
            }

            // Set a couple defaults first
            Return_Package.Bib_Info.SobekCM_Type = TypeOfResource_SobekCM_Enum.Archival;
            Return_Package.Bib_Info.Type.Collection = true;
            Error_Message = String.Empty;

            // Check for some options
            string XSL_Location = String.Empty;
            bool Analyze_Description = true;
            if (Options != null)
            {
                if (Options.ContainsKey("EAD_File_ReaderWriter:XSL_Location"))
                {
                    XSL_Location = Options["EAD_File_ReaderWriter:XSL_Location"].ToString();
                }
                if (Options.ContainsKey("EAD_File_ReaderWriter:Analyze_Description"))
                {
                    bool.TryParse(Options["EAD_File_ReaderWriter:Analyze_Description"].ToString(), out Analyze_Description);
                }
            }

            // Use a string builder to seperate the description and container sections
            StringBuilder description_builder = new StringBuilder(20000);
            StringBuilder container_builder = new StringBuilder(20000);

            // Read through with a simple stream reader first
            StreamReader reader = new StreamReader(Input_Stream);
            string line = reader.ReadLine();
            bool in_container_list = false;

            // Step through each line
            while (line != null)
            {
                if (!in_container_list)
                {
                    // Do not import the XML stylesheet portion
                    if ((line.IndexOf("xml-stylesheet") < 0) && (line.IndexOf("<!DOCTYPE ") < 0))
                    {
                        // Does the start a DSC section?
                        if ((line.IndexOf("<dsc ") >= 0) || (line.IndexOf("<dsc>") > 0))
                        {
                            in_container_list = true;
                            container_builder.AppendLine(line);
                        }
                        else
                        {
                            description_builder.AppendLine(line);
                        }
                    }
                }
                else
                {
                    // Add this to the container builder
                    container_builder.AppendLine(line);

                    // Does this end the container list section?
                    if (line.IndexOf("</dsc>") >= 0)
                        in_container_list = false;
                }

                // Get the next line
                line = reader.ReadLine();
            }

            // Close the reader
            reader.Close();

            // Just assign all the description section first
            eadInfo.Full_Description = description_builder.ToString();

            // Should the decrpition additionally be analyzed?
            if (Analyze_Description)
            {
                // Try to read the XML
                try
                {
                    XmlTextReader reader2 = new XmlTextReader(description_builder.ToString());

                    // Initial doctype declaration sometimes throws an error for a missing EAD.dtd.
                    bool ead_start_found = false;
                    int error = 0;
                    while ((!ead_start_found) && (error < 5))
                    {
                        try
                        {
                            reader2.Read();
                            if ((reader2.NodeType == XmlNodeType.Element) && (reader2.Name.ToLower() == GlobalVar.EAD_METADATA_MODULE_KEY))
                            {
                                ead_start_found = true;
                            }
                        }
                        catch
                        {
                            error++;
                        }
                    }

                    // Now read the body of the EAD
                    while (reader2.Read())
                    {
                        if (reader2.NodeType == XmlNodeType.Element)
                        {
                            string nodeName = reader2.Name.ToLower();
                            switch (nodeName)
                            {
                                case "descrules":
                                    string descrules_text = reader2.ReadInnerXml().ToUpper();
                                    if (descrules_text.IndexOf("FINDING AID PREPARED USING ") == 0)
                                    {
                                        Return_Package.Bib_Info.Record.Description_Standard = descrules_text.Replace("FINDING AID PREPARED USING ", "");
                                    }
                                    else
                                    {
                                        string[] likely_description_standards = {"DACS", "APPM", "AACR2", "RDA", "ISADG", "ISAD", "MAD", "RAD"};
                                        foreach (string likely_standard in likely_description_standards)
                                        {
                                            if (descrules_text.IndexOf(likely_standard) >= 0)
                                            {
                                                Return_Package.Bib_Info.Record.Description_Standard = likely_standard;
                                                break;
                                            }
                                        }
                                    }
                                    break;

                                case "unittitle":
                                    while (reader2.Read())
                                        if (reader2.NodeType == XmlNodeType.Text)
                                        {
                                            Return_Package.Bib_Info.Main_Title.Title = reader2.Value;
                                            break;
                                        }
                                        else if (reader2.NodeType == XmlNodeType.EndElement && reader2.Name.Equals("unittitle"))
                                            break;
                                    while (!(reader2.NodeType == XmlNodeType.EndElement && reader2.Name.Equals("unittitle")))
                                        reader2.Read();
                                    break;

                                case "unitid":
                                    while (reader2.Read())
                                    {
                                        if (reader2.NodeType == XmlNodeType.Text)
                                        {
                                            Return_Package.Bib_Info.Add_Identifier(reader2.Value, "Main Identifier");
                                        }
                                        if (reader2.NodeType == XmlNodeType.EndElement && reader2.Name.ToLower().Equals(nodeName))
                                            break;
                                    }
                                    break;

                                case "origination":
                                    while (reader2.Read())
                                    {
                                        if (reader2.NodeType == XmlNodeType.Element && reader2.Name.Equals("persname"))
                                        {
                                            while (reader2.Read())
                                            {
                                                if (reader2.NodeType == XmlNodeType.Text)
                                                {
                                                    Return_Package.Bib_Info.Main_Entity_Name.Full_Name = Trim_Final_Punctuation(reader2.Value);
                                                    Return_Package.Bib_Info.Main_Entity_Name.Name_Type = Name_Info_Type_Enum.personal;
                                                }
                                                else if (reader2.NodeType == XmlNodeType.EndElement && reader2.Name.ToLower().Equals(nodeName))
                                                    break;
                                            }
                                        }
                                        if (reader2.NodeType == XmlNodeType.EndElement && reader2.Name.ToLower().Equals(nodeName))
                                            break;
                                    }
                                    break;

                                case "physdesc":
                                    while (reader2.Read())
                                    {
                                        if (reader2.NodeType == XmlNodeType.Element && reader2.Name.Equals("extent"))
                                        {
                                            while (reader2.Read())
                                            {
                                                if (reader2.NodeType == XmlNodeType.Text)
                                                    Return_Package.Bib_Info.Original_Description.Extent = reader2.Value;
                                                else if (reader2.NodeType == XmlNodeType.EndElement && reader2.Name.Equals("extent"))
                                                    break;
                                            }
                                        }
                                        if (reader2.NodeType == XmlNodeType.EndElement && reader2.Name.Equals("physdesc"))
                                            break;
                                    }
                                    break;

                                case "abstract":
                                    while (reader2.Read())
                                    {
                                        if (reader2.NodeType == XmlNodeType.Text)
                                            Return_Package.Bib_Info.Add_Abstract(reader2.Value);
                                        else if (reader2.NodeType == XmlNodeType.EndElement && reader2.Name.ToLower().Equals(nodeName))
                                            break;
                                    }
                                    break;

                                case "repository":
                                    while (reader2.Read())
                                    {
                                        if (reader2.NodeType == XmlNodeType.Element && reader2.Name.Equals("corpname"))
                                        {
                                            while (reader2.Read())
                                            {
                                                if (reader2.NodeType == XmlNodeType.Text)
                                                    Return_Package.Bib_Info.Location.Holding_Name = reader2.Value;
                                                else if (reader2.NodeType == XmlNodeType.EndElement && reader2.Name.ToLower().Equals(nodeName))
                                                    break;
                                            }
                                        }
                                        if (reader2.NodeType == XmlNodeType.EndElement && reader2.Name.ToLower().Equals(nodeName))
                                            break;
                                    }
                                    break;

                                case "accessrestrict":
                                    Return_Package.Bib_Info.Add_Note(Clean_Text_Block(reader2.ReadInnerXml()), Note_Type_Enum.restriction);
                                    break;

                                case "userestrict":
                                    Return_Package.Bib_Info.Access_Condition.Text = Clean_Text_Block(reader2.ReadInnerXml());
                                    break;

                                case "acqinfo":
                                    Return_Package.Bib_Info.Add_Note(Clean_Text_Block(reader2.ReadInnerXml()), Note_Type_Enum.acquisition);
                                    break;

                                case "bioghist":
                                    Return_Package.Bib_Info.Add_Note(Clean_Text_Block(reader2.ReadInnerXml()), Note_Type_Enum.biographical);
                                    break;

                                case "scopecontent":
                                    Return_Package.Bib_Info.Add_Abstract(Clean_Text_Block(reader2.ReadInnerXml()), "", "summary", "Summary");
                                    break;

                                case "controlaccess":
                                    while (reader2.Read())
                                    {
                                        if (reader2.NodeType == XmlNodeType.Element && (reader2.Name.Equals("corpname") || reader2.Name.Equals("persname")))
                                        {
                                            string tagnamei = reader2.Name;
                                            string source = "";
                                            if (reader2.MoveToAttribute("source"))
                                                source = reader2.Value;
                                            while (reader2.Read())
                                            {
                                                if (reader2.NodeType == XmlNodeType.Text)
                                                {
                                                    Subject_Info_Name newName = new Subject_Info_Name();
                                                    //ToSee: where to add name? and ehat types
                                                    //ToDo: Type
                                                    newName.Full_Name = Trim_Final_Punctuation(reader2.Value);
                                                    newName.Authority = source;
                                                    Return_Package.Bib_Info.Add_Subject(newName);
                                                    if (tagnamei.StartsWith("corp"))
                                                        newName.Name_Type = Name_Info_Type_Enum.corporate;
                                                    else if (tagnamei.StartsWith("pers"))
                                                        newName.Name_Type = Name_Info_Type_Enum.personal;
                                                    else
                                                        newName.Name_Type = Name_Info_Type_Enum.UNKNOWN;
                                                }
                                                else if (reader2.NodeType == XmlNodeType.EndElement && reader2.Name.Equals(tagnamei))
                                                    break;
                                            }
                                        }
                                        else if (reader2.NodeType == XmlNodeType.Element && (reader2.Name.Equals("subject")))
                                        {
                                            string tagnamei = reader2.Name;
                                            string source = "";
                                            if (reader2.MoveToAttribute("source"))
                                                source = reader2.Value;
                                            while (reader2.Read())
                                            {
                                                if (reader2.NodeType == XmlNodeType.Text)
                                                {
                                                    string subjectTerm = Trim_Final_Punctuation(reader2.Value.Trim());
                                                    if (subjectTerm.Length > 1)
                                                    {
                                                        Subject_Info_Standard subject = Return_Package.Bib_Info.Add_Subject();
                                                        subject.Authority = source;
                                                        if (subjectTerm.IndexOf("--") == 0)
                                                            subject.Add_Topic(subjectTerm);
                                                        else
                                                        {
                                                            while (subjectTerm.IndexOf("--") > 0)
                                                            {
                                                                string fragment = subjectTerm.Substring(0, subjectTerm.IndexOf("--")).Trim();
                                                                if (fragment.ToLower() == "florida")
                                                                    subject.Add_Geographic(fragment);
                                                                else
                                                                    subject.Add_Topic(fragment);

                                                                if (subjectTerm.Length > subjectTerm.IndexOf("--") + 3)
                                                                    subjectTerm = subjectTerm.Substring(subjectTerm.IndexOf("--") + 2);
                                                                else
                                                                    subjectTerm = String.Empty;
                                                            }
                                                            if (subjectTerm.Trim().Length > 0)
                                                            {
                                                                string fragment = subjectTerm.Trim();
                                                                if (fragment.ToLower() == "florida")
                                                                    subject.Add_Geographic(fragment);
                                                                else
                                                                    subject.Add_Topic(fragment);
                                                            }
                                                        }
                                                    }
                                                }
                                                else if (reader2.NodeType == XmlNodeType.EndElement && reader2.Name.Equals(tagnamei))
                                                    break;
                                            }
                                        }
                                        if (reader2.NodeType == XmlNodeType.EndElement && reader2.Name.ToLower().Equals(nodeName))
                                            break;
                                    }
                                    break;

                                case "dsc":
                                    eadInfo.Container_Hierarchy.Read(reader2);
                                    break;
                            }
                        }

                        if (reader2.NodeType == XmlNodeType.EndElement && reader2.Name.Equals(GlobalVar.EAD_METADATA_MODULE_KEY))
                            break;
                    }

                    reader2.Close();
                }
                catch (Exception ee)
                {
                    Error_Message = "Error caught in EAD_reader2_Writer: " + ee.Message;
                    return false;
                }
            }

            // If there is a XSL, apply it to the description stored in the EAD sub-section of the item id
            if (XSL_Location.Length > 0)
            {
                try
                {
                    // Create the transform and load the XSL indicated
                    XslCompiledTransform transform = new XslCompiledTransform();
                    transform.Load(XSL_Location);

                    // Apply the transform to convert the XML into HTML
                    StringWriter results = new StringWriter();
                    XmlReaderSettings settings = new XmlReaderSettings();
                    settings.ProhibitDtd = false;
                    using (XmlReader transformreader = XmlReader.Create(new StringReader(eadInfo.Full_Description), settings))
                    {
                        transform.Transform(transformreader, null, results);
                    }
                    eadInfo.Full_Description = results.ToString();

                    // Get rid of the <?xml header
                    if (eadInfo.Full_Description.IndexOf("<?xml") >= 0)
                    {
                        int xml_end_index = eadInfo.Full_Description.IndexOf("?>");
                        eadInfo.Full_Description = eadInfo.Full_Description.Substring(xml_end_index + 2);
                    }

                    // Since this was successful, try to build the TOC list of included sections
                    SortedList<int, string> toc_sorter = new SortedList<int, string>();
                    string description = eadInfo.Full_Description;
                    int did = description.IndexOf("<a name=\"did\"");
                    int bioghist = description.IndexOf("<a name=\"bioghist\"");
                    int scopecontent = description.IndexOf("<a name=\"scopecontent\"");
                    int organization = description.IndexOf("<a name=\"organization\"");
                    int arrangement = description.IndexOf("<a name=\"arrangement\"");
                    int relatedmaterial = description.IndexOf("<a name=\"relatedmaterial\"");
                    int otherfindaid = description.IndexOf("<a name=\"otherfindaid\"");
                    int index = description.IndexOf("<a name=\"index\">");
                    int bibliography = description.IndexOf("<a name=\"bibliography\"");
                    int odd = description.IndexOf("<a name=\"odd\"");
                    int controlaccess = description.IndexOf("<a name=\"controlaccess\"");
                    int accruals = description.IndexOf("<a name=\"accruals\"");
                    int appraisal = description.IndexOf("<a name=\"appraisal\"");
                    int processinfo = description.IndexOf("<a name=\"processinfo\"");
                    int acqinfo = description.IndexOf("<a name=\"acqinfo\"");
                    int prefercite = description.IndexOf("<a name=\"prefercite\"");
                    int altformavail = description.IndexOf("<a name=\"altformavail\"");
                    int custodhist = description.IndexOf("<a name=\"custodhist\"");
                    int accessrestrict = description.IndexOf("<a name=\"accessrestrict\"");
                    int admininfo = description.IndexOf("<a name=\"admininfo\"");

                    if (did >= 0) toc_sorter[did] = "did";
                    if (bioghist >= 0) toc_sorter[bioghist] = "bioghist";
                    if (scopecontent >= 0) toc_sorter[scopecontent] = "scopecontent";
                    if (organization >= 0) toc_sorter[organization] = "organization";
                    if (arrangement >= 0) toc_sorter[arrangement] = "arrangement";
                    if (relatedmaterial >= 0) toc_sorter[relatedmaterial] = "relatedmaterial";
                    if (otherfindaid >= 0) toc_sorter[otherfindaid] = "otherfindaid";
                    if (index >= 0) toc_sorter[index] = "index";
                    if (bibliography >= 0) toc_sorter[bibliography] = "bibliography";
                    if (odd >= 0) toc_sorter[odd] = "odd";
                    if (controlaccess >= 0) toc_sorter[controlaccess] = "controlaccess";
                    if (accruals >= 0) toc_sorter[accruals] = "accruals";
                    if (appraisal >= 0) toc_sorter[appraisal] = "appraisal";
                    if (processinfo >= 0) toc_sorter[processinfo] = "processinfo";
                    if (acqinfo >= 0) toc_sorter[acqinfo] = "acqinfo";
                    if (prefercite >= 0) toc_sorter[prefercite] = "prefercite";
                    if (altformavail >= 0) toc_sorter[altformavail] = "altformavail";
                    if (custodhist >= 0) toc_sorter[custodhist] = "custodhist";
                    if (accessrestrict >= 0) toc_sorter[accessrestrict] = "accessrestrict";
                    if (admininfo >= 0) toc_sorter[admininfo] = "admininfo";

                    // Now, add each section back to the TOC list
                    foreach (string thisEadSection in toc_sorter.Values)
                    {
                        // Index needs to have its head looked up, everything else adds simply
                        if (thisEadSection != "index")
                        {
                            switch (thisEadSection)
                            {
                                case "did":
                                    eadInfo.Add_TOC_Included_Section("did", "Descriptive Summary");
                                    break;

                                case "bioghist":
                                    eadInfo.Add_TOC_Included_Section("bioghist", "Biographical / Historical Note");
                                    break;

                                case "scopecontent":
                                    eadInfo.Add_TOC_Included_Section("scopecontent", "Scope and Content");
                                    break;

                                case "accessrestrict":
                                    eadInfo.Add_TOC_Included_Section("accessrestrict", "Access or Use Restrictions");
                                    break;

                                case "relatedmaterial":
                                    eadInfo.Add_TOC_Included_Section("relatedmaterial", "Related or Separated Material");
                                    break;

                                case "admininfo":
                                    eadInfo.Add_TOC_Included_Section("admininfo", "Administrative Information");
                                    break;

                                case "altformavail":
                                    eadInfo.Add_TOC_Included_Section("altformavail", " &nbsp; &nbsp; Alternate Format Available");
                                    break;

                                case "prefercite":
                                    eadInfo.Add_TOC_Included_Section("prefercite", " &nbsp; &nbsp; Preferred Citation");
                                    break;

                                case "acqinfo":
                                    eadInfo.Add_TOC_Included_Section("acqinfo", " &nbsp; &nbsp; Acquisition Information");
                                    break;

                                case "processinfo":
                                    eadInfo.Add_TOC_Included_Section("processinfo", " &nbsp; &nbsp; Processing Information");
                                    break;

                                case "custodhist":
                                    eadInfo.Add_TOC_Included_Section("custodhist", " &nbsp; &nbsp; Custodial Work_History");
                                    break;

                                case "controlaccess":
                                    eadInfo.Add_TOC_Included_Section("controlaccess", "Selected Subjects");
                                    break;

                                case "otherfindaid":
                                    eadInfo.Add_TOC_Included_Section("otherfindaid", "Alternate Form of Finding Aid");
                                    break;
                            }
                        }
                        else
                        {
                            int end_link = eadInfo.Full_Description.IndexOf("</a>", index);
                            string index_title = eadInfo.Full_Description.Substring(index + 16, end_link - index - 16);
                            if (index_title.Length > 38)
                                index_title = index_title.Substring(0, 32) + "...";
                            eadInfo.Add_TOC_Included_Section("index", index_title);
                        }
                    }
                }
                catch (Exception ee)
                {
                    bool error = false;
                }
            }

            // Now, parse the container section as XML
            if (container_builder.Length > 0)
            {
                StringReader containerReader = new StringReader(container_builder.ToString());
                XmlTextReader xml_reader = new XmlTextReader(containerReader);
                xml_reader.Read();
                eadInfo.Container_Hierarchy.Read(xml_reader);
            }

            return true;
        }
        private static void Add_Personal_Name(Bibliographic_Info thisBibInfo, MARC_Record record, int tag, int name_type)
        {
            // Step through each instance of this tag
            foreach (MARC_Field thisRecord in record[tag])
            {
                // Create the name object
                Name_Info newName = new Name_Info();
                newName.Name_Type = Name_Info_Type_Enum.Personal;

                // Only continue if there is an id in this record
                if ((thisRecord.has_Subfield('a')) && (thisRecord['a'].ToUpper().IndexOf("PALMM") < 0))
                {
                    // Save the 'a' value
                    switch (thisRecord.Indicator1)
                    {
                        case '0':
                            newName.Given_Name = Remove_Trailing_Punctuation(thisRecord['a']);
                            newName.Full_Name = newName.Given_Name;
                            break;

                        case '1':
                            string tempName = Remove_Trailing_Punctuation(thisRecord['a']);
                            int tempCommaIndex = tempName.IndexOf(",");
                            if (tempCommaIndex > 0)
                            {
                                newName.Family_Name = tempName.Substring(0, tempCommaIndex).Trim();
                                newName.Given_Name = tempName.Substring(tempCommaIndex + 1).Trim();
                                newName.Full_Name = tempName;
                            }
                            else
                            {
                                newName.Family_Name = tempName;
                            }
                            break;

                        case '3':
                            newName.Family_Name = Remove_Trailing_Punctuation(thisRecord['a']);
                            newName.Full_Name = newName.Family_Name;
                            break;

                        default:
                            newName.Full_Name = Remove_Trailing_Punctuation(thisRecord['a']);
                            break;
                    }

                    if (thisRecord.has_Subfield('b'))
                        newName.Terms_Of_Address = thisRecord['b'];
                    if (thisRecord.has_Subfield('c'))
                    {
                        if (newName.Terms_Of_Address.Length > 0)
                        {
                            newName.Terms_Of_Address = newName.Terms_Of_Address + "; " + thisRecord['c'];
                        }
                        else
                        {
                            newName.Terms_Of_Address = thisRecord['c'];
                        }
                    }
                    if (thisRecord.has_Subfield('d'))
                        newName.Dates = Remove_Trailing_Punctuation(thisRecord['d']);
                    if (thisRecord.has_Subfield('e'))
                        newName.Add_Role(Remove_Trailing_Punctuation(thisRecord['e']));
                    if (thisRecord.has_Subfield('g'))
                        newName.Description = Remove_Trailing_Punctuation(thisRecord['g']);
                    if (thisRecord.has_Subfield('j'))
                    {
                        if (newName.Description.Length > 0)
                        {
                            newName.Description = newName.Description + "; " + thisRecord['j'];
                        }
                        else
                        {
                            newName.Description = thisRecord['j'];
                        }
                    }
                    if (thisRecord.has_Subfield('u'))
                        newName.Affiliation = Remove_Trailing_Punctuation(thisRecord['u']);
                    if (thisRecord.has_Subfield('q'))
                        newName.Display_Form = Remove_Trailing_Punctuation(thisRecord['q'].Replace("(", "").Replace(")", ""));

                    // Is there a relator code?
                    if (thisRecord.has_Subfield('4'))
                    {
                        // Get the relator code
                        string completeRelatorcode = thisRecord['4'];
                        string[] relatorCodesSplitter = completeRelatorcode.Split("|".ToCharArray());
                        foreach (string relatorcode in relatorCodesSplitter)
                        {
                            newName.Add_Role(relatorcode, "marcrelator", Name_Info_Role_Type_Enum.Code);
                        }
                    }

                    switch (name_type)
                    {
                        case 1:
                            thisBibInfo.Main_Entity_Name = newName;
                            break;

                        case 2:
                            thisBibInfo.Add_Named_Entity(newName);
                            break;

                        case 3:
                            thisBibInfo.Donor = newName;
                            break;

                        case 4:
                            Subject_Info_Name newNameSubj = new Subject_Info_Name();
                            newNameSubj.Set_Internal_Name(newName);
                            if (thisRecord.has_Subfield('v'))
                                newNameSubj.Add_Genre(Remove_Trailing_Punctuation(thisRecord['v']));
                            if (thisRecord.has_Subfield('x'))
                                newNameSubj.Add_Topic(Remove_Trailing_Punctuation(thisRecord['x']));
                            if (thisRecord.has_Subfield('y'))
                                newNameSubj.Add_Temporal(Remove_Trailing_Punctuation(thisRecord['y']));
                            if (thisRecord.has_Subfield('z'))
                                newNameSubj.Add_Geographic(Remove_Trailing_Punctuation(thisRecord['z']));
                            if (thisRecord.has_Subfield('2'))
                                newNameSubj.Authority = thisRecord['2'];
                            switch (thisRecord.Indicator2)
                            {
                                case '0':
                                    newNameSubj.Authority = "lcsh";
                                    break;

                                case '1':
                                    newNameSubj.Authority = "lcshac";
                                    break;

                                case '2':
                                    newNameSubj.Authority = "mesh";
                                    break;

                                case '3':
                                    newNameSubj.Authority = "nal";
                                    break;

                                case '5':
                                    newNameSubj.Authority = "csh";
                                    break;

                                case '6':
                                    newNameSubj.Authority = "rvm";
                                    break;
                            }
                            break;
                    }
                }
            }
        }
        private static void read_subject_object(XmlReader r, Bibliographic_Info thisBibInfo)
        {
            string language = String.Empty;
            string authority = String.Empty;
            string id = String.Empty;

            if (r.MoveToAttribute("ID"))
                id = r.Value;
            if (r.MoveToAttribute("lang"))
                language = r.Value;
            if (r.MoveToAttribute("authority"))
                authority = r.Value;

            // Move to the next element
            while (r.Read())
            {
                if (r.NodeType == XmlNodeType.Element)
                    break;
            }

            // Determine the subject type
            Subject_Info_Type type = Subject_Info_Type.UNKNOWN;

            // What is the name of this node?
            switch (r.Name)
            {
                case "mods:topic":
                case "mods:geographic":
                case "mods:genre":
                case "mods:temporal":
                case "mods:occupation":
                case "topic":
                case "geographic":
                case "genre":
                case "temporal":
                case "occupation":
                    type = Subject_Info_Type.Standard;
                    break;

                case "mods:hierarchicalGeographic":
                case "hierarchicalGeographic":
                    type = Subject_Info_Type.Hierarchical_Spatial;
                    break;

                case "mods:cartographics":
                case "cartographics":
                    type = Subject_Info_Type.Cartographics;
                    break;

                case "mods:name":
                case "name":
                    type = Subject_Info_Type.Name;
                    break;

                case "mods:titleInfo":
                case "titleInfo":
                    type = Subject_Info_Type.TitleInfo;
                    break;
            }

            // If no type was determined, return null
            if (type == Subject_Info_Type.UNKNOWN)
                return;

            // Was this the standard subject object?
            if (type == Subject_Info_Type.Standard)
            {
                Subject_Info_Standard standardSubject = new Subject_Info_Standard();
                standardSubject.Language = language;
                standardSubject.Authority = authority;
                standardSubject.ID = id;

                do
                {
                    if ((r.NodeType == XmlNodeType.EndElement) && ((r.Name == "mods:subject") || (r.Name == "subject")))
                    {
                        if ((standardSubject.Topics_Count > 0) || (standardSubject.Geographics_Count > 0) || (standardSubject.Genres_Count > 0) ||
                            (standardSubject.Temporals_Count > 0) || (standardSubject.Occupations_Count > 0))
                        {
                            thisBibInfo.Add_Subject(standardSubject);
                        }
                        return;
                    }

                    if (r.NodeType == XmlNodeType.Element)
                    {
                        switch (r.Name)
                        {
                            case "mods:topic":
                            case "topic":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    standardSubject.Add_Topic(r.Value);
                                break;

                            case "mods:geographic":
                            case "geographic":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    standardSubject.Add_Geographic(r.Value);
                                break;

                            case "mods:genre":
                            case "genre":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    standardSubject.Add_Genre(r.Value);
                                break;

                            case "mods:temporal":
                            case "temporal":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    standardSubject.Add_Temporal(r.Value);
                                break;

                            case "mods:occupation":
                            case "occupation":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    standardSubject.Add_Occupation(r.Value);
                                break;
                        }
                    }
                } while (r.Read());
            }

            // Was this the hierarchical geography subject?
            if (type == Subject_Info_Type.Hierarchical_Spatial)
            {
                Subject_Info_HierarchicalGeographic geoSubject = new Subject_Info_HierarchicalGeographic();
                geoSubject.Language = language;
                geoSubject.Authority = authority;
                geoSubject.ID = id;

                while (r.Read())
                {
                    if ((r.NodeType == XmlNodeType.EndElement) && ((r.Name == "mods:subject") || (r.Name == "subject")))
                    {
                        thisBibInfo.Add_Subject(geoSubject);
                        return;
                    }

                    if (r.NodeType == XmlNodeType.Element)
                    {
                        switch (r.Name)
                        {
                            case "mods:continent":
                            case "continent":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    geoSubject.Continent = r.Value;
                                break;

                            case "mods:country":
                            case "country":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    geoSubject.Country = r.Value;
                                break;

                            case "mods:province":
                            case "province":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    geoSubject.Province = r.Value;
                                break;

                            case "mods:region":
                            case "region":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    geoSubject.Region = r.Value;
                                break;

                            case "mods:state":
                            case "state":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    geoSubject.State = r.Value;
                                break;

                            case "mods:territory":
                            case "territory":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    geoSubject.Territory = r.Value;
                                break;

                            case "mods:county":
                            case "county":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    geoSubject.County = r.Value;
                                break;

                            case "mods:city":
                            case "city":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    geoSubject.City = r.Value;
                                break;

                            case "mods:citySection":
                            case "citySection":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    geoSubject.CitySection = r.Value;
                                break;

                            case "mods:island":
                            case "island":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    geoSubject.Island = r.Value;
                                break;

                            case "mods:area":
                            case "area":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    geoSubject.Area = r.Value;
                                break;
                        }
                    }
                }
            }

            // Was this the cartographics subject?
            if (type == Subject_Info_Type.Cartographics)
            {
                Subject_Info_Cartographics mapSubject = new Subject_Info_Cartographics();
                mapSubject.Language = language;
                mapSubject.Authority = authority;
                mapSubject.ID = id;

                while (r.Read())
                {
                    if ((r.NodeType == XmlNodeType.EndElement) && ((r.Name == "mods:subject") || (r.Name == "subject")))
                    {
                        if ((mapSubject.Projection.Length > 0) || (mapSubject.Coordinates.Length > 0) || (mapSubject.Scale.Length > 0))
                        {
                            thisBibInfo.Add_Subject(mapSubject);
                        }
                        return;
                    }

                    if (r.NodeType == XmlNodeType.Element)
                    {
                        switch (r.Name)
                        {
                            case "mods:coordinates":
                            case "coordinates":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    mapSubject.Coordinates = r.Value;
                                break;

                            case "mods:scale":
                            case "scale":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    mapSubject.Scale = r.Value;
                                break;

                            case "mods:projection":
                            case "projection":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    mapSubject.Projection = r.Value;
                                break;
                        }
                    }
                }
            }

            // Was this the name subject?
            if (type == Subject_Info_Type.Name)
            {
                Subject_Info_Name nameSubject = new Subject_Info_Name();
                nameSubject.Language = language;
                nameSubject.Authority = authority;
                nameSubject.ID = id;

                do
                {
                    if ((r.NodeType == XmlNodeType.EndElement) && ((r.Name == "mods:subject") || (r.Name == "subject")))
                    {
                        thisBibInfo.Add_Subject(nameSubject);
                        return;
                    }

                    if (r.NodeType == XmlNodeType.Element)
                    {
                        switch (r.Name)
                        {
                            case "mods:name":
                            case "name":
                                Name_Info nameInfo = read_name_object(r);
                                nameSubject.Set_Internal_Name(nameInfo);
                                break;

                            case "mods:topic":
                            case "topic":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    nameSubject.Add_Topic(r.Value);
                                break;

                            case "mods:geographic":
                            case "geographic":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    nameSubject.Add_Geographic(r.Value);
                                break;

                            case "mods:genre":
                            case "genre":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    nameSubject.Add_Genre(r.Value);
                                break;

                            case "mods:temporal":
                            case "temporal":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    nameSubject.Add_Temporal(r.Value);
                                break;
                        }
                    }
                } while (r.Read());
            }

            // Was this the title subject?
            if (type == Subject_Info_Type.TitleInfo)
            {
                Subject_Info_TitleInfo titleSubject = new Subject_Info_TitleInfo();
                titleSubject.Language = language;
                titleSubject.Authority = authority;
                titleSubject.ID = id;

                do
                {
                    if ((r.NodeType == XmlNodeType.EndElement) && ((r.Name == "mods:subject") || (r.Name == "subject")))
                    {
                        thisBibInfo.Add_Subject(titleSubject);
                        return;
                    }

                    if (r.NodeType == XmlNodeType.Element)
                    {
                        switch (r.Name)
                        {
                            case "mods:titleInfo":
                            case "titleInfo":
                                Title_Info titleInfo = read_title_object(r);
                                titleSubject.Set_Internal_Title(titleInfo);
                                break;

                            case "mods:topic":
                            case "topic":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    titleSubject.Add_Topic(r.Value);
                                break;

                            case "mods:geographic":
                            case "geographic":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    titleSubject.Add_Geographic(r.Value);
                                break;

                            case "mods:genre":
                            case "genre":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    titleSubject.Add_Genre(r.Value);
                                break;

                            case "mods:temporal":
                            case "temporal":
                                r.Read();
                                if (r.NodeType == XmlNodeType.Text)
                                    titleSubject.Add_Temporal(r.Value);
                                break;
                        }
                    }
                } while (r.Read());
            }
        }
        private static void Add_Corporate_Name(Bibliographic_Info thisBibInfo, MARC_Record record, int tag, int name_type)
        {
            // Step through each instance of this tag
            foreach (MARC_Field thisRecord in record[tag])
            {
                if ((name_type != 3) || (thisRecord.Indicator2 == '3'))
                {
                    // Create the name object
                    Name_Info newName = new Name_Info();
                    newName.Name_Type = Name_Info_Type_Enum.Corporate;

                    // Only continue if there is an id in this record
                    if ((thisRecord.has_Subfield('a')) && (thisRecord['a'].ToUpper().IndexOf("PALMM") < 0))
                    {
                        newName.Full_Name = Remove_Trailing_Punctuation(thisRecord['a']);
                        if (thisRecord.has_Subfield('b'))
                        {
                            newName.Full_Name = newName.Full_Name + " -- " + Remove_Trailing_Punctuation(thisRecord['b']);
                        }
                        if (thisRecord.has_Subfield('c'))
                            newName.Description = thisRecord['c'];
                        if (thisRecord.has_Subfield('d'))
                            newName.Dates = Remove_Trailing_Punctuation(thisRecord['d']);
                        if (thisRecord.has_Subfield('e'))
                            newName.Add_Role(Remove_Trailing_Punctuation(thisRecord['e']));
                        if (thisRecord.has_Subfield('u'))
                            newName.Affiliation = Remove_Trailing_Punctuation(thisRecord['u']);

                        // Is there a relator code?
                        if (thisRecord.has_Subfield('4'))
                        {
                            // Get the relator code
                            string relatorcode = thisRecord['4'];
                            newName.Add_Role(relatorcode, "marcrelator", Name_Info_Role_Type_Enum.Code);
                        }

                        switch (name_type)
                        {
                            case 1:
                                thisBibInfo.Main_Entity_Name = newName;
                                break;

                            case 2:
                                thisBibInfo.Add_Named_Entity(newName);
                                break;

                            case 3:
                                thisBibInfo.Donor = newName;
                                break;

                            case 4:
                                Subject_Info_Name newNameSubj = new Subject_Info_Name();
                                newNameSubj.Set_Internal_Name(newName);
                                if (thisRecord.has_Subfield('v'))
                                    newNameSubj.Add_Genre(Remove_Trailing_Punctuation(thisRecord['v']));
                                if (thisRecord.has_Subfield('x'))
                                    newNameSubj.Add_Topic(Remove_Trailing_Punctuation(thisRecord['x']));
                                if (thisRecord.has_Subfield('y'))
                                    newNameSubj.Add_Temporal(Remove_Trailing_Punctuation(thisRecord['y']));
                                if (thisRecord.has_Subfield('z'))
                                    newNameSubj.Add_Geographic(Remove_Trailing_Punctuation(thisRecord['z']));
                                if (thisRecord.has_Subfield('2'))
                                    newNameSubj.Authority = thisRecord['2'];
                                switch (thisRecord.Indicator2)
                                {
                                    case '0':
                                        newNameSubj.Authority = "lcsh";
                                        break;

                                    case '1':
                                        newNameSubj.Authority = "lcshac";
                                        break;

                                    case '2':
                                        newNameSubj.Authority = "mesh";
                                        break;

                                    case '3':
                                        newNameSubj.Authority = "nal";
                                        break;

                                    case '5':
                                        newNameSubj.Authority = "csh";
                                        break;

                                    case '6':
                                        newNameSubj.Authority = "rvm";
                                        break;
                                }
                                break;
                        }
                    }
                }
            }
        }
        /// <summary> Add a new empty name subject and return it  </summary>
        /// <returns>Newly built name subject</returns>
        public Subject_Info_Name Add_Name_Subject()
        {
            if (subjects == null)
                subjects = new List<Subject_Info>();

            Subject_Info_Name returnValue = new Subject_Info_Name();
            subjects.Add(returnValue);
            return returnValue;
        }