/// <summary> Returns the OAI-PMH metadata in dublin core (OAI-flavored) for this item </summary>
        /// <param name="Item_To_Save"> Package with all the metadata to save </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 write </param>
        /// <returns> Metadata for a OAI-PMH record of a particular metadata format/type </returns>
        public override string Create_OAI_PMH_Metadata( SobekCM_Item Item_To_Save, Dictionary<string, object> Options, out string Error_Message)
        {
            // Set default error outpt message
            Error_Message = String.Empty;

            StringBuilder results = new StringBuilder();
            StringWriter writer = new StringWriter(results);

            writer.WriteLine("<oai_dc:dc xmlns:oai_dc=\"http://www.openarchives.org/OAI/2.0/oai_dc/\" ");
            writer.WriteLine("xmlns:dc=\"http://purl.org/dc/elements/1.1/\" ");
            writer.WriteLine("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ");
            writer.WriteLine("xsi:schemaLocation=\"http://www.openarchives.org/OAI/2.0/oai_dc/ ");
            writer.WriteLine("http://www.openarchives.org/OAI/2.0/oai_dc.xsd\">");

            // Add the dublin core
            DC_METS_dmdSec_ReaderWriter.Write_Simple_Dublin_Core(writer, Item_To_Save.Bib_Info);

            // Add the URL as the identifier
            if (Item_To_Save.Bib_Info.Location.PURL.Length > 0)
            {
                writer.WriteLine("<dc:identifier>" + Item_To_Save.Bib_Info.Location.PURL + "</dc:identifier>");
            }
            else if (Item_To_Save.Web.Service_URL.Length > 0)
            {
                writer.WriteLine("<dc:identifier>" + Item_To_Save.Web.Service_URL + "</dc:identifier>");
            }

            // Finish this OAI
            writer.WriteLine("</oai_dc:dc>");

            string resultsString = results.ToString();
            writer.Close();

            return resultsString;
        }
        /// <summary> Chance for this metadata module to load any additional data from the 
        /// database when building this digital resource  in memory </summary>
        /// <param name="ItemID"> Primary key for this item within the SobekCM database </param>
        /// <param name="DB_ConnectionString">Connection string for the current database</param>
        /// <param name="BibObject"> Entire resource, in case there are dependencies between this module and somethingt in the full resource </param>
        /// <param name="Error_Message"> In the case of an error, this contains text of the error </param>
        /// <returns> TRUE if no error occurred, otherwise FALSE </returns>
        /// <remarks> This module currently  does no additional processing in this method </remarks>
        public bool Retrieve_Additional_Info_From_Database(int ItemID, string DB_ConnectionString, SobekCM_Item BibObject, out string Error_Message)
        {
            // Set the default error mesasge
            Error_Message = String.Empty;

            return true;
        }
        /// <summary> Writes the formatted metadata from the provided item to a file </summary>
        /// <param name="MetadataFilePathName"> Path and name of the metadata file to write</param>
        /// <param name="Item_To_Save"> Package with all the metadata to save </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 write </param>
        /// <returns>TRUE if successful, otherwise FALSE </returns>
        public bool Write_Metadata(string MetadataFilePathName, SobekCM_Item Item_To_Save, Dictionary<string, object> Options, out string Error_Message)
        {
            StreamWriter results = null;
            bool returnValue;
            try
            {
                results = new StreamWriter(MetadataFilePathName, false, Encoding.UTF8);
                returnValue = Write_Metadata(results, Item_To_Save, Options, out Error_Message);
                
            }
            catch (Exception ee)
            {
                Error_Message = "Error writing METS metadata to file '" + MetadataFilePathName + ": " + ee.Message;
                returnValue = false;
            }
            finally
            {
                if (results != null)
                {
                    results.Flush();
                    results.Close();
                }
            }

            return returnValue;
        }
        /// <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>
        public bool Read_Metadata(Stream Input_Stream, SobekCM_Item Return_Package, Dictionary<string, object> Options, out string Error_Message)
        {
            // Set default error outpt message
            Error_Message = String.Empty;

            // Create a XML reader and read the metadata
            XmlTextReader nodeReader = null;
            bool returnValue = true;
            try
            {
                // create the node reader
                nodeReader = new XmlTextReader(Input_Stream);
                MODS_METS_dmdSec_ReaderWriter.Read_MODS_Info(nodeReader, Return_Package.Bib_Info, Return_Package);
            }
            catch (Exception ee)
            {
                Error_Message = "Error reading MODS from stream: " + ee.Message;
                returnValue = false;
            }
            finally
            {
                if (nodeReader != null)
                    nodeReader.Close();
            }

            return returnValue;
        }
        /// <summary> Reads metadata from an existing metadata file and saves to the provided item/package </summary>
        /// <param name="MetadataFilePathName"> Path and name of the metadata file to read </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>
        public bool Read_Metadata(string MetadataFilePathName, SobekCM_Item Return_Package, Dictionary<string, object> Options, out string Error_Message)
        {
            // Set default error outpt message
            Error_Message = String.Empty;

            // Create a stream and XML reader and read the metadata
            Stream reader = null;
            XmlTextReader nodeReader = null;
            bool returnValue = true;

            try
            {
                reader = new FileStream(MetadataFilePathName, FileMode.Open, FileAccess.Read);

                // create the node reader
                nodeReader = new XmlTextReader(reader);

                MarcXML_METS_dmdSec_ReaderWriter.Read_MarcXML_Info(nodeReader, Return_Package.Bib_Info, Return_Package, true, Options );
            }
            catch (Exception ee)
            {
                Error_Message = "Error reading MarcXML from stream: " + ee.Message;
                returnValue = false;
            }
            finally
            {
                if (nodeReader != null)
                    nodeReader.Close();
                if (reader != null)
                    reader.Close();
            }

            return returnValue;
        }
 /// <summary> Flag indicates if this active reader/writer will write a dmdSec </summary>
 /// <param name="METS_Item"> Package with all the metadata to save</param>
 /// <param name="Options"> Dictionary of any options which this METS section writer may utilize</param>
 /// <returns> TRUE if the package has data to be written, otherwise fALSE </returns>
 public bool Include_dmdSec(SobekCM_Item METS_Item, Dictionary<string, object> Options)
 {
     // GEt the geo-spatial information if it exists
     GeoSpatial_Information geoInfo = METS_Item.Get_Metadata_Module(GlobalVar.GEOSPATIAL_METADATA_MODULE_KEY) as GeoSpatial_Information;
     if ((geoInfo == null) || (!geoInfo.hasData))
         return false;
     return true;
 }
 /// <summary> Flag indicates if this active reader/writer will write a dmdSec </summary>
 /// <param name="METS_Item"> Package with all the metadata to save</param>
 /// <param name="Options"> Dictionary of any options which this METS section writer may utilize</param>
 /// <returns> TRUE if the package has data to be written, otherwise fALSE </returns>
 public bool Include_dmdSec(SobekCM_Item METS_Item, Dictionary<string, object> Options)
 {
     // Ensure this metadata module extension exists and has data
     Thesis_Dissertation_Info thesisInfo = METS_Item.Get_Metadata_Module(GlobalVar.THESIS_METADATA_MODULE_KEY) as Thesis_Dissertation_Info;
     if ((thesisInfo == null) || (!thesisInfo.hasData))
         return false;
     return true;
 }
 /// <summary> Flag indicates if this active reader/writer will write a dmdSec </summary>
 /// <param name="METS_Item"> Package with all the metadata to save</param>
 /// <returns> TRUE if the package has data to be written, otherwise fALSE </returns>
 public bool Include_dmdSec(SobekCM_Item METS_Item, Dictionary<string, object> Options)
 {
     // Ensure this metadata module extension exists and has data
     VRACore_Info vraInfo = METS_Item.Get_Metadata_Module(GlobalVar.VRACORE_METADATA_MODULE_KEY) as VRACore_Info;
     if ((vraInfo == null) || (!vraInfo.hasData))
         return false;
     return true;
 }
 /// <summary> Flag indicates if this active reader/writer will write a dmdSec </summary>
 /// <param name="METS_Item"> Package with all the metadata to save</param>
 /// <param name="Options"> Dictionary of any options which this METS section writer may utilize</param>
 /// <returns> TRUE if the package has data to be written, otherwise fALSE </returns>
 public bool Include_dmdSec(SobekCM_Item METS_Item, Dictionary<string, object> Options)
 {
     // Ensure this metadata module extension exists and has data
     LearningObjectMetadata lomInfo = METS_Item.Get_Metadata_Module(GlobalVar.IEEE_LOM_METADATA_MODULE_KEY) as LearningObjectMetadata;
     if ((lomInfo == null) || (!lomInfo.hasData))
         return false;
     return true;
 }
 /// <summary> Flag indicates if this active reader/writer will write a dmdSec </summary>
 /// <param name="METS_Item"> Package with all the metadata to save</param>
 /// <param name="Options"> Dictionary of any options which this METS section writer may utilize</param>
 /// <returns> TRUE if the package has data to be written, otherwise fALSE </returns>
 public bool Include_dmdSec(SobekCM_Item METS_Item, Dictionary<string, object> Options)
 {
     // Ensure this metadata module extension exists and has data
     Zoological_Taxonomy_Info taxonInfo = METS_Item.Get_Metadata_Module(GlobalVar.ZOOLOGICAL_TAXONOMY_METADATA_MODULE_KEY) as Zoological_Taxonomy_Info;
     if ((taxonInfo == null) || (!taxonInfo.hasData))
         return false;
     return true;
 }
        /// <summary> Reads metadata from an existing metadata file and saves to the provided item/package </summary>
        /// <param name="MetadataFilePathName"> Path and name of the metadata file to read </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>
        public bool Read_Metadata(string MetadataFilePathName, SobekCM_Item Return_Package, Dictionary<string, object> Options, out string Error_Message)
        {
            Stream reader = new FileStream(MetadataFilePathName, FileMode.Open, FileAccess.Read);
            bool returnValue = Read_Metadata(reader, Return_Package, Options, out Error_Message);
            reader.Close();

            return returnValue;
        }
 /// <summary> Flag indicates if this active reader/writer will write an amdSec </summary>
 /// <param name="METS_Item"> Package with all the metadata to save</param>
 /// <param name="Options"> Dictionary of any options which this METS section writer may utilize</param>
 /// <returns> TRUE if the package has data to be written, otherwise fALSE </returns>
 public bool Include_amdSec(SobekCM_Item METS_Item, Dictionary<string, object> Options)
 {
     // Ensure this metadata module extension exists and has data
     DAITSS_Info daitssInfo = METS_Item.Get_Metadata_Module(GlobalVar.DAITSS_METADATA_MODULE_KEY) as DAITSS_Info;
     if ((daitssInfo == null) || (!daitssInfo.hasData))
         return false;
     return true;
 }
        /// <summary> Reads metadata from an existing metadata file and saves to the provided item/package </summary>
        /// <param name="MetadataFilePathName"> Path and name of the metadata file to read </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>
        public bool Read_Metadata(string MetadataFilePathName, SobekCM_Item Return_Package, Dictionary<string, object> Options, out string Error_Message)
        {
            Stream reader = new FileStream(MetadataFilePathName, FileMode.Open, FileAccess.Read);
            Read_Metadata(reader, Return_Package, Options, out Error_Message);
            reader.Close();

            throw new NotImplementedException();
        }
 /// <summary> Flag indicates if this active reader/writer will write a dmdSec </summary>
 /// <param name="METS_Item"> Package with all the metadata to save</param>
 /// <param name="Options"> Dictionary of any options which this METS section writer may utilize</param>
 /// <returns> TRUE if the package has data to be written, otherwise fALSE </returns>
 public bool Include_dmdSec(SobekCM_Item METS_Item, Dictionary<string, object> Options)
 {
     // Ensure this metadata module extension exists and has data
     Map_Info mapInfo = METS_Item.Get_Metadata_Module(GlobalVar.SOBEKCM_MAPS_METADATA_MODULE_KEY) as Map_Info;
     if ((mapInfo == null) || (!mapInfo.hasData))
         return false;
     return true;
 }
 /// <summary> Flag indicates if this active reader/writer will write an amdSec </summary>
 /// <param name="METS_Item"> Package with all the metadata to save</param>
 /// <param name="Options"> Dictionary of any options which this METS section writer may utilize</param>
 /// <returns> TRUE if the package has data to be written, otherwise fALSE </returns>
 public bool Include_amdSec(SobekCM_Item METS_Item, Dictionary<string, object> Options)
 {
     // Ensure this metadata module extension exists and has data
     RightsMD_Info rightsInfo = METS_Item.Get_Metadata_Module( GlobalVar.PALMM_RIGHTSMD_METADATA_MODULE_KEY)  as RightsMD_Info;
     if ((rightsInfo == null) || (!rightsInfo.hasData))
         return false;
     return true;
 }
        /// <summary> Writes the dmdSec for the entire package to the text writer </summary>
        /// <param name="Output_Stream">Stream to which the formatted text is written </param>
        /// <param name="METS_Item">Package with all the metadata to save</param>
        /// <param name="Options"> Dictionary of any options which this METS section writer may utilize</param>
        /// <returns>TRUE if successful, otherwise FALSE </returns>
        public override bool Write_dmdSec(TextWriter Output_Stream, SobekCM_Item METS_Item, Dictionary<string, object> Options)
        {
            // Ensure this metadata module extension exists and has data
            Thesis_Dissertation_Info thesisInfo = METS_Item.Get_Metadata_Module(GlobalVar.THESIS_METADATA_MODULE_KEY) as Thesis_Dissertation_Info;
            if ((thesisInfo == null) || (!thesisInfo.hasData))
                return true;

            Output_Stream.WriteLine("<palmm:thesis>");
            if (!String.IsNullOrEmpty(thesisInfo.Committee_Chair))
                Output_Stream.WriteLine("<palmm:committeeChair>" + Convert_String_To_XML_Safe(thesisInfo.Committee_Chair) + "</palmm:committeeChair>");
            if (!String.IsNullOrEmpty(thesisInfo.Committee_Co_Chair))
                Output_Stream.WriteLine("<palmm:committeeCoChair>" + Convert_String_To_XML_Safe(thesisInfo.Committee_Co_Chair) + "</palmm:committeeCoChair>");
            if (thesisInfo.Committee_Members_Count > 0)
            {
                foreach (string thisCommitteeMember in thesisInfo.Committee_Members)
                {
                    Output_Stream.WriteLine("<palmm:committeeMember>" + Convert_String_To_XML_Safe(thisCommitteeMember) + "</palmm:committeeMember>");
                }
            }
            if (thesisInfo.Graduation_Date.HasValue)
            {
                string encoded_date = thesisInfo.Graduation_Date.Value.Year + "-" + thesisInfo.Graduation_Date.Value.Month.ToString().PadLeft(2, '0') + "-" + thesisInfo.Graduation_Date.Value.Day.ToString().PadLeft(2, '0');
                Output_Stream.WriteLine("<palmm:graduationDate>" + encoded_date + "</palmm:graduationDate>");
            }
            if (!String.IsNullOrEmpty(thesisInfo.Degree))
                Output_Stream.WriteLine("<palmm:degree>" + Convert_String_To_XML_Safe(thesisInfo.Degree) + "</palmm:degree>");
            if (thesisInfo.Degree_Disciplines_Count > 0)
            {
                if ( thesisInfo.Degree_Disciplines_Count == 1 )
                    Output_Stream.WriteLine("<palmm:degreeDiscipline>" + Convert_String_To_XML_Safe(thesisInfo.Degree_Disciplines[0]) + "</palmm:degreeDiscipline>");
                else
                {
                    Output_Stream.Write("<palmm:degreeDiscipline>");
                    bool first = true;
                    foreach (string thisDiscipline in thesisInfo.Degree_Disciplines)
                    {
                        if ( !first )
                            Output_Stream.Write(";");
                        else
                            first = false;

                        Output_Stream.Write( Convert_String_To_XML_Safe(thisDiscipline));
                    }
                    Output_Stream.WriteLine("</palmm:degreeDiscipline>");
                }
            }
            if (!String.IsNullOrEmpty(thesisInfo.Degree_Grantor))
                Output_Stream.WriteLine("<palmm:degreeGrantor>" + Convert_String_To_XML_Safe(thesisInfo.Degree_Grantor) + "</palmm:degreeGrantor>");
            if (thesisInfo.Degree_Level == Thesis_Dissertation_Info.Thesis_Degree_Level_Enum.Bachelors)
                Output_Stream.WriteLine("<palmm:degreeLevel>Bachelors</palmm:degreeLevel>");
            if (thesisInfo.Degree_Level == Thesis_Dissertation_Info.Thesis_Degree_Level_Enum.Masters)
                Output_Stream.WriteLine("<palmm:degreeLevel>Masters</palmm:degreeLevel>");
            if (thesisInfo.Degree_Level == Thesis_Dissertation_Info.Thesis_Degree_Level_Enum.Doctorate)
                Output_Stream.WriteLine("<palmm:degreeLevel>Doctorate</palmm:degreeLevel>");
            Output_Stream.WriteLine("</palmm:thesis>");
            return true;
        }
        /// <summary> Reads metadata from an existing metadata file and saves to the provided item/package </summary>
        /// <param name="MetadataFilePathName"> Path and name of the metadata file to read </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>
        public bool Read_Metadata(string MetadataFilePathName, SobekCM_Item Return_Package, Dictionary<string, object> Options, out string Error_Message)
        {
            // Set default error outpt message
            Error_Message = String.Empty;

            // Old MXF files will not have a VID, so assign 00001
            if (Return_Package.VID.Length == 0)
            {
                Return_Package.VID = "00001";
            }

            // Load this MXF File
            XmlDocument mxfXML = new XmlDocument();
            mxfXML.Load(MetadataFilePathName);

            // Set the source directory correctly
            Return_Package.Source_Directory = (new FileInfo(MetadataFilePathName)).DirectoryName;

            // create the node reader
            XmlNodeReader nodeReader = new XmlNodeReader(mxfXML);

            // Read through all the nodes until the package tag is found
            move_to_node(nodeReader, "package");

            // Get the package attribute
            process_package_tag(nodeReader, Return_Package);

            // Read through all the nodes until the packageDesc section is found
            move_to_node(nodeReader, "packageDesc");

            // Process all of the packageDesc sections
            process_packageDesc(nodeReader, Return_Package);

            // Read through to the beginning of the entity description
            move_to_node(nodeReader, "entityDesc");

            // Process the entire entity tag and the projects tag
            process_entity_tag_and_project(nodeReader, Return_Package);

            // Set the object id and some other METS values not in the MXF
            Return_Package.METS_Header.ObjectID = Return_Package.BibID + "_" + Return_Package.VID;

            // Move to the bibDesc
            move_to_node(nodeReader, "bibDesc");

            // Process the bib desc section
            process_bib_desc(nodeReader, Return_Package);

            // Will just use a text reader to step through all of the division information
            process_divisions(MetadataFilePathName, Return_Package);

            nodeReader.Close();

            return true;
        }
        /// <summary> Reads the dmdSec at the current position in the XmlTextReader and associates it with the 
        /// entire package  </summary>
        /// <param name="Input_XmlReader"> Open XmlReader from which to read the metadata </param>
        /// <param name="Return_Package"> Package into which to read the metadata</param>
        /// <param name="Options"> Dictionary of any options which this METS section reader may utilize</param>
        /// <returns> TRUE if successful, otherwise FALSE</returns>  
        public bool Read_dmdSec(XmlReader Input_XmlReader, SobekCM_Item Return_Package, Dictionary<string, object> Options)
        {
            // Get the geo-spatial information if it exists or create a new one
            GeoSpatial_Information geoInfo = Return_Package.Get_Metadata_Module(GlobalVar.GEOSPATIAL_METADATA_MODULE_KEY) as GeoSpatial_Information;
            if (geoInfo == null)
            {
                geoInfo = new GeoSpatial_Information();
                Return_Package.Add_Metadata_Module(GlobalVar.GEOSPATIAL_METADATA_MODULE_KEY, geoInfo);
            }

            return Read_Metadata_Section(Input_XmlReader, geoInfo, Options);
        }
        /// <summary> Reads the dmdSec at the current position in the XmlTextReader and associates it with the 
        /// entire package  </summary>
        /// <param name="Input_XmlReader"> Open XmlReader from which to read the metadata </param>
        /// <param name="Return_Package"> Package into which to read the metadata</param>
        /// <param name="Options"> Dictionary of any options which this METS section reader may utilize</param>
        /// <returns> TRUE if successful, otherwise FALSE</returns>
        public bool Read_dmdSec(XmlReader Input_XmlReader, SobekCM_Item Return_Package, Dictionary<string, object> Options)
        {
            // Ensure this metadata module extension exists
            LearningObjectMetadata lomInfo = Return_Package.Get_Metadata_Module(GlobalVar.IEEE_LOM_METADATA_MODULE_KEY) as LearningObjectMetadata;
            if (lomInfo == null)
            {
                lomInfo = new LearningObjectMetadata();
                Return_Package.Add_Metadata_Module(GlobalVar.IEEE_LOM_METADATA_MODULE_KEY, lomInfo);
            }

            // Loop through reading each XML node
            do
            {
                // If this is the end of this section, return
                if ((Input_XmlReader.NodeType == XmlNodeType.EndElement) && ((Input_XmlReader.Name == "METS:mdWrap") || (Input_XmlReader.Name == "mdWrap")))
                    return true;

                // get the right division information based on node type
                if (Input_XmlReader.NodeType == XmlNodeType.Element)
                {
                    string name = Input_XmlReader.Name.ToLower();
                    if (( lom_namespace.Length > 0 ) && ( name.IndexOf( lom_namespace ) == 0))
                        name = name.Substring(lom_namespace.Length);

                    switch (name)
                    {
                        case "general":
                            read_general(Input_XmlReader.ReadSubtree(), lomInfo);
                            break;

                        case "lifecycle":
                            read_lifecycle(Input_XmlReader.ReadSubtree(), lomInfo);
                            break;

                        case "technical":
                            read_technical(Input_XmlReader.ReadSubtree(), lomInfo);
                            break;

                        case "educational":
                            read_educational(Input_XmlReader.ReadSubtree(), lomInfo);
                            break;

                        case "classification":
                            read_classification(Input_XmlReader.ReadSubtree(), lomInfo);
                            break;

                    }
                }

            } while (Input_XmlReader.Read());

            return true;
        }
        /// <summary> Writes the formatted metadata from the provided item to a file </summary>
        /// <param name="MetadataFilePathName"> Path and name of the metadata file to write</param>
        /// <param name="Item_To_Save"> Package with all the metadata to save </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 write </param>
        /// <returns>TRUE if successful, otherwise FALSE </returns>
        public bool Write_Metadata(string MetadataFilePathName, SobekCM_Item Item_To_Save, Dictionary<string, object> Options, out string Error_Message)
        {
            // Determine if this is CSV or XML
            string extension = Path.GetExtension(MetadataFilePathName);
            if (( extension != null ) && (( extension.ToLower() == ".csv" ) || ( extension.ToLower() == ".txt" )))
            {
                // In this case, need to pass a new option to the stream writer, without altering the
                // original options
                Dictionary<string, object> newOptions = new Dictionary<string, object>();
                foreach (string thisKey in Options.Keys)
                {
                    if (thisKey != "Coordinates_File_ReaderWriter:CSV_Style")
                        newOptions[thisKey] = Options[thisKey];
                }
                newOptions["Coordinates_File_ReaderWriter:CSV_Style"] = true;

                try
                {
                    StreamWriter results = new StreamWriter(MetadataFilePathName, false, Encoding.UTF8);
                    bool returnValue = Write_Metadata(results, Item_To_Save, newOptions, out Error_Message);
                    results.Flush();
                    results.Close();

                    return returnValue;
                }
                catch (Exception ee)
                {
                    Error_Message = "Error writing GML Coordinates metadata to file '" + MetadataFilePathName + ": " + ee.Message;
                    return false;
                }
            }
            else
            {
                try
                {
                    StreamWriter results = new StreamWriter(MetadataFilePathName, false, Encoding.UTF8);
                    bool returnValue = Write_Metadata(results, Item_To_Save, Options, out Error_Message);
                    results.Flush();
                    results.Close();

                    return returnValue;
                }
                catch (Exception ee)
                {
                    Error_Message = "Error writing GML Coordinates metadata to file '" + MetadataFilePathName + ": " + ee.Message;
                    return false;
                }
            }
        }
        /// <summary> Adds a bit of data to a bibliographic package using the mapping </summary>
        /// <param name="Package">Bibliographic package to receive the data</param>
        /// <param name="Data">Text of the data</param>
        /// <param name="Field">Mapped field</param>
        /// <returns> TRUE if the field was mapped, FALSE if there was data and no mapping was found </returns>
        public static bool Add_Data(SobekCM_Item Package, string Data, string Field )
        {
            // Try to map using the mappers in order
            foreach (iBibliographicMapper mapper in mappers)
            {
                // Did this map this piece of data?
                if (mapper.Add_Data(Package, Data, Field))
                {
                    return true;
                }
            }

            // Apparently it was never mapped
            return false;
        }
        /// <summary> Reads metadata from an existing metadata file and saves to the provided item/package </summary>
        /// <param name="MetadataFilePathName"> Path and name of the metadata file to read </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(string MetadataFilePathName, SobekCM_Item Return_Package, Dictionary<string, object> Options, out string Error_Message)
        {
            Stream reader = new FileStream(MetadataFilePathName, FileMode.Open, FileAccess.Read);
            bool returnValue = Read_Metadata(reader, Return_Package, Options, out Error_Message);
            reader.Close();

            FileInfo eadFileInfo = new FileInfo(MetadataFilePathName);
            Return_Package.Source_Directory = eadFileInfo.DirectoryName;
            if (Return_Package.BibID.Length == 0)
                Return_Package.BibID = eadFileInfo.Name.Replace(".xml", "");
            Return_Package.VID = "00001";
            Return_Package.Bib_Info.SobekCM_Type = TypeOfResource_SobekCM_Enum.Archival;
            Return_Package.Bib_Info.Type.Collection = true;

            return returnValue;
        }
        /// <summary> Adds a bit of data to a bibliographic package using the mapping </summary>
        /// <param name="Package">Bibliographic package to receive the data</param>
        /// <param name="Data">Text of the data</param>
        /// <param name="Field">Mapped field</param>
        /// <param name="Message"> [OUT] Message also indicates if the field was mapped, and which mapper found the match </param>
        /// <returns> TRUE if the field was mapped, FALSE if there was data and no mapping was found </returns>
        public static bool Add_Data(SobekCM_Item Package, string Data, string Field, out string Message )
        {
            // Try to map using the mappers in order
            foreach (iBibliographicMapper mapper in mappers)
            {
                // Did this map this piece of data?
                if (mapper.Add_Data(Package, Data, Field))
                {
                    Message = "Mapped '" + Field + "' using " + mapper.Name;
                    return true;
                }
            }

            // Apparently it was never mapped
            Message = "Unable to find a mapping for '" + Field + "'";
            return false;
        }
        /// <summary> Get the list of metadata records associated with a single ite </summary>
        /// <param name="ThisItem"> Item to create the metadata records for </param>
        /// <param name="Options"> Options used possibly during the saving process </param>
        /// <returns> List of the OAI metadata prefixes and the associated metadata records </returns>
        public static List<Tuple<string, string>> Get_OAI_PMH_Metadata_Records(SobekCM_Item ThisItem, Dictionary<string, object> Options)
        {
            List<Tuple<string, string>> returnValue = new List<Tuple<string, string>>();

            foreach (Tuple<string, iOAI_PMH_Metadata_Type_Writer> thisWriter in writers)
            {
                try
                {
                    string error_message;
                    string record = thisWriter.Item2.Create_OAI_PMH_Metadata(ThisItem, Options, out error_message);
                    returnValue.Add(new Tuple<string, string>(thisWriter.Item1, record));
                }
                catch {  }
            }

            return returnValue;
        }
        /// <summary> Reads the dmdSec at the current position in the XmlTextReader and associates it with the 
        /// entire package  </summary>
        /// <param name="Input_XmlReader"> Open XmlReader from which to read the metadata </param>
        /// <param name="Return_Package"> Package into which to read the metadata</param>
        /// <param name="Options"> Dictionary of any options which this METS section reader may utilize</param>
        /// <returns> TRUE if successful, otherwise FALSE</returns>
        public bool Read_dmdSec(XmlReader Input_XmlReader, SobekCM_Item Return_Package, Dictionary<string, object> Options)
        {
            // Ensure this metadata module extension exists
            Map_Info mapInfo = Return_Package.Get_Metadata_Module(GlobalVar.SOBEKCM_MAPS_METADATA_MODULE_KEY) as Map_Info;
            if (mapInfo == null)
            {
                mapInfo = new Map_Info();
                Return_Package.Add_Metadata_Module(GlobalVar.SOBEKCM_MAPS_METADATA_MODULE_KEY, mapInfo);
            }

            // Try to get the attributes from here first
            if (Input_XmlReader.MoveToAttribute("id"))
                mapInfo.MapID = Input_XmlReader.Value;

            // Step through each field
            while (Input_XmlReader.Read())
            {
                if ((Input_XmlReader.NodeType == XmlNodeType.EndElement) && (Input_XmlReader.Name == "map:ufdc_map"))
                    return true;

                if (Input_XmlReader.NodeType == XmlNodeType.Element)
                {
                    switch (Input_XmlReader.Name)
                    {
                        case "map:indexes":
                            read_map_indexes(Input_XmlReader, mapInfo);
                            break;

                        case "map:entities":
                            read_map_entities(Input_XmlReader, mapInfo);
                            break;

                        case "map:sheets":
                            read_map_sheets(Input_XmlReader, mapInfo);
                            break;
                    }
                }
            }

            // Return false since this read all the way to the end of the steam
            return false;
        }
        /// <summary> Reads the amdSec at the current position in the XmlTextReader and associates it with the 
        /// entire package  </summary>
        /// <param name="Input_XmlReader"> Open XmlReader from which to read the metadata </param>
        /// <param name="Return_Package"> Package into which to read the metadata</param>
        /// <param name="Options"> Dictionary of any options which this METS section reader may utilize</param>
        /// <returns> TRUE if successful, otherwise FALSE</returns>
        public bool Read_amdSec(XmlReader Input_XmlReader, SobekCM_Item Return_Package, Dictionary<string, object> Options)
        {
            // Ensure this metadata module extension exists
            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);
            }

            // Loop through reading each XML node
            do
            {
                // If this is the end of this section, return
                if ((Input_XmlReader.NodeType == XmlNodeType.EndElement) && ((Input_XmlReader.Name == "METS:mdWrap") || (Input_XmlReader.Name == "mdWrap")))
                    return true;

                // get the right division information based on node type
                switch (Input_XmlReader.NodeType)
                {
                    case XmlNodeType.Element:
                        if ((Input_XmlReader.Name.ToLower() == "daitss:agreement_info") && (Input_XmlReader.HasAttributes))
                        {
                            if (Input_XmlReader.MoveToAttribute("ACCOUNT"))
                                daitssInfo.Account = Input_XmlReader.Value;

                            if (Input_XmlReader.MoveToAttribute("SUB_ACCOUNT"))
                                daitssInfo.SubAccount = Input_XmlReader.Value;

                            if (Input_XmlReader.MoveToAttribute("PROJECT"))
                                daitssInfo.Project = Input_XmlReader.Value;
                        }
                        break;
                }
            } while (Input_XmlReader.Read());

            // Return false since this read all the way to the end of the steam
            return false;
        }
        /// <summary> Writes the dmdSec for the entire package to the text writer </summary>
        /// <param name="Output_Stream">Stream to which the formatted text is written </param>
        /// <param name="METS_Item">Package with all the metadata to save</param>
        /// <param name="Options"> Dictionary of any options which this METS section writer may utilize</param>
        /// <returns>TRUE if successful, otherwise FALSE </returns>
        /// <remarks>This utilized the DC writer in the base class and just adds the ETD information </remarks>
        public override bool Write_dmdSec(System.IO.TextWriter Output_Stream, SobekCM_Item METS_Item, Dictionary<string, object> Options)
        {
            // Write the base stuff
            base.Write_dmdSec(Output_Stream, METS_Item, Options);

            // Ensure this metadata module extension exists and has data
            Thesis_Dissertation_Info thesisInfo = METS_Item.Get_Metadata_Module(GlobalVar.THESIS_METADATA_MODULE_KEY) as Thesis_Dissertation_Info;
            if ((thesisInfo == null) || (!thesisInfo.hasData))
                return true;

            // Add the ETD stuff if the ETD metadata module exists
            if (!String.IsNullOrEmpty(thesisInfo.Degree))
                Output_Stream.WriteLine("<thesis.degree.name>" + Convert_String_To_XML_Safe(thesisInfo.Degree) + "</thesis.degree.name>");

            if (thesisInfo.Degree_Level == Thesis_Dissertation_Info.Thesis_Degree_Level_Enum.Bachelors)
                Output_Stream.WriteLine("<thesis.degree.level>Bachelors</thesis.degree.level>");
            if (thesisInfo.Degree_Level == Thesis_Dissertation_Info.Thesis_Degree_Level_Enum.Masters)
                Output_Stream.WriteLine("<thesis.degree.level>Masters</thesis.degree.level>");
            if (thesisInfo.Degree_Level == Thesis_Dissertation_Info.Thesis_Degree_Level_Enum.Doctorate)
                Output_Stream.WriteLine("<thesis.degree.level>Doctorate</thesis.degree.level>");
            if (thesisInfo.Degree_Level == Thesis_Dissertation_Info.Thesis_Degree_Level_Enum.PostDoctorate)
                Output_Stream.WriteLine("<thesis.degree.level>Post-Doctorate</thesis.degree.level>");

            if (thesisInfo.Degree_Disciplines_Count > 0)
            {
                foreach (string thisDiscipline in thesisInfo.Degree_Disciplines)
                {
                    Output_Stream.WriteLine("<thesis.degree.discipline>" + Convert_String_To_XML_Safe(thisDiscipline) + "</thesis.degree.discipline>");
                }
            }

            if (!String.IsNullOrEmpty(thesisInfo.Degree_Grantor))
                Output_Stream.WriteLine("<thesis.degree.grantor>" + Convert_String_To_XML_Safe(thesisInfo.Degree_Grantor) + "</thesis.degree.grantor>");

            return true;
        }
        /// <summary> Writes the amdSec for the entire package to the text writer </summary>
        /// <param name="Output_Stream">Stream to which the formatted text is written </param>
        /// <param name="METS_Item">Package with all the metadata to save</param>
        /// <param name="Options"> Dictionary of any options which this METS section writer may utilize</param>
        /// <returns>TRUE if successful, otherwise FALSE </returns>
        /// <remarks> This writer REQUIRES the list of all SobekCM files </remarks>
        public bool Write_amdSec(TextWriter Output_Stream, SobekCM_Item METS_Item, Dictionary<string, object> Options)
        {
            List<SobekCM_File_Info> fileList = Options["SobekCM_FileInfo_METS_amdSec_ReaderWriter:All_Files"] as List<SobekCM_File_Info>;
            if (fileList == null) return false;

            // If there ARE no files, just return
            if (fileList.Count == 0)
                return true;

            Output_Stream.WriteLine("<" + sobekcm_namespace + ":FileInfo>");

            // Step through each file
            foreach (SobekCM_File_Info thisFileInfo in fileList)
            {
                if ((thisFileInfo.Height > 0) && (thisFileInfo.Width > 0))
                {
                    Output_Stream.WriteLine("<" + sobekcm_namespace + ":File fileid=\"" + thisFileInfo.ID + "\" width=\"" + thisFileInfo.Width + "\" height=\"" + thisFileInfo.Height + "\" />");
                }
            }

            Output_Stream.WriteLine("</" + sobekcm_namespace + ":FileInfo>");
            return true;
        }
 /// <summary> Flag indicates if this active reader/writer will write an amdSec </summary>
 /// <param name="METS_Item"> Package with all the metadata to save</param>
 /// <param name="Options"> Dictionary of any options which this METS section writer may utilize</param>
 /// <returns> TRUE if the package has data to be written, otherwise fALSE </returns>
 public bool Include_amdSec(SobekCM_Item METS_Item, Dictionary<string, object> Options)
 {
     List<SobekCM_File_Info> fileList = Options["SobekCM_FileInfo_METS_amdSec_ReaderWriter:All_Files"] as List<SobekCM_File_Info>;
     if (fileList == null) return false;
     return (fileList.Count > 0);
 }
        /// <summary> Reads the amdSec at the current position in the XmlTextReader and associates it with the 
        /// entire package  </summary>
        /// <param name="Input_XmlReader"> Open XmlReader from which to read the metadata </param>
        /// <param name="Return_Package"> Package into which to read the metadata</param>
        /// <param name="Options"> Dictionary of any options which this METS section reader may utilize</param>
        /// <returns> TRUE if successful, otherwise FALSE</returns>
        /// <remarks> One option is REQUIRED for this to work, you must pass in  a Dictionary&lt;string,SobekCM_File_Info&gt;
        /// generic dictionary with all the pre-collection file information stored by fileid.  It should be include in the 
        /// Options dictionary under the key 'SobekCM_FileInfo_METS_amdSec_ReaderWriter:Files_By_FileID'.</remarks>
        public bool Read_amdSec(XmlReader Input_XmlReader, SobekCM_Item Return_Package, Dictionary<string, object> Options)
        {
            Dictionary<string, SobekCM_File_Info> files_by_fileid = null;
            if ((Options == null) || (!Options.ContainsKey("SobekCM_FileInfo_METS_amdSec_ReaderWriter:Files_By_FileID")))
                return false;

            files_by_fileid = (Dictionary<string, SobekCM_File_Info>) Options["SobekCM_FileInfo_METS_amdSec_ReaderWriter:Files_By_FileID"];

            string fileid = String.Empty;

            // Loop through reading each XML node
            do
            {
                // If this is the end of this section, return
                if ((Input_XmlReader.NodeType == XmlNodeType.EndElement) && (Input_XmlReader.Name == sobekcm_namespace + ":FileInfo"))
                    return true;

                // get the right division information based on node type
                switch (Input_XmlReader.NodeType)
                {
                    case XmlNodeType.EndElement:
                        if (Input_XmlReader.Name == sobekcm_namespace + ":FileInfo")
                            return true;
                        break;

                    case XmlNodeType.Element:
                        if ((Input_XmlReader.Name == sobekcm_namespace + ":File") && (Input_XmlReader.HasAttributes) && (Input_XmlReader.MoveToAttribute("fileid")))
                        {
                            fileid = Input_XmlReader.Value;

                            // Save this information
                            SobekCM_File_Info existingFile = null;
                            if (!files_by_fileid.ContainsKey(fileid))
                            {
                                existingFile = new SobekCM_File_Info(String.Empty);
                                files_by_fileid[fileid] = existingFile;
                            }
                            else
                            {
                                existingFile = files_by_fileid[fileid];
                            }

                            try
                            {
                                if (Input_XmlReader.MoveToAttribute("width"))
                                    existingFile.Width = Convert.ToUInt16(Input_XmlReader.Value);

                                if (Input_XmlReader.MoveToAttribute("height"))
                                    existingFile.Height = Convert.ToUInt16(Input_XmlReader.Value);
                            }
                            catch
                            {
                            }
                        }
                        break;
                }
            } while (Input_XmlReader.Read());

            // Return false since this read all the way to the end of the steam
            return false;
        }
 /// <summary> Prepares the bib object for the save, by clearing any existing data in this element's related field(s) </summary>
 /// <param name="Bib"> Existing digital resource object which may already have values for this element's data field(s) </param>
 /// <param name="Current_User"> Current user, who's rights may impact the way an element is rendered </param>
 /// <remarks> This does nothing since there is only one ead reference </remarks>
 public override void Prepare_For_Save(SobekCM_Item Bib, User_Object Current_User)
 {
     // Do nothing
 }