/// <summary>
        /// Returns a percentage based score on how similar the passed record is to the current instance.
        /// </summary>
        /// <param name="ev">The event to compare against this instance.</param>
        /// <returns>A score from 0 to 100 representing the percentage match.</returns>
        public decimal CalculateSimilarityScore(GedcomEvent ev)
        {
            var match = decimal.Zero;

            if (ev.EventType == EventType)
            {
                // match date
                var dateMatch = decimal.Zero;
                if (Date == null && ev.Date == null)
                {
                    dateMatch = 100m;
                }
                else if (Date != null && ev.Date != null)
                {
                    dateMatch = Date.CalculateSimilarityScore(ev.Date);
                }

                // match location
                var locMatch = decimal.Zero;
                if (Place == null && ev.Place == null)
                {
                    locMatch = 100m;
                }
                else if (Place != null && ev.Place != null)
                {
                    if (Place.Name == ev.Place.Name)
                    {
                        locMatch = 100m;
                    }
                }

                match = (dateMatch + locMatch) / 2m;
            }

            return(match);
        }
        /// <summary>
        /// Generates the XML.
        /// </summary>
        /// <param name="root">The root.</param>
        public override void GenerateXML(XmlNode root)
        {
            XmlDocument doc = root.OwnerDocument;

            XmlNode      node;
            XmlAttribute attr;

            XmlNode eventNode = doc.CreateElement("EventRec");

            attr       = doc.CreateAttribute("Id");
            attr.Value = EventXRefID;
            eventNode.Attributes.Append(attr);

            attr       = doc.CreateAttribute("Type");
            attr.Value = GedcomEvent.TypeToReadable(EventType);
            eventNode.Attributes.Append(attr);

            // TODO: VitalType attribute
            // (marriage | befmarriage | aftmarriage |
            // birth | befbirth | aftbirth |
            // death | befdeath | aftdeath)
            if (RecordType == GedcomRecordType.FamilyEvent)
            {
                GedcomFamilyEvent  famEvent = this as GedcomFamilyEvent;
                GedcomFamilyRecord family   = famEvent.FamRecord;

                // TODO: <Participant>s
                // probably not right, but always stick husband/wife in as
                // participants
                bool added = false;

                if (!string.IsNullOrEmpty(family.Husband))
                {
                    GedcomIndividualRecord husb = Database[family.Husband] as GedcomIndividualRecord;
                    if (husb != null)
                    {
                        node = doc.CreateElement("Participant");

                        XmlNode linkNode = doc.CreateElement("Link");

                        attr       = doc.CreateAttribute("Target");
                        attr.Value = "IndividualRec";
                        linkNode.Attributes.Append(attr);

                        attr       = doc.CreateAttribute("Ref");
                        attr.Value = family.Husband;
                        linkNode.Attributes.Append(attr);

                        node.AppendChild(linkNode);

                        eventNode.AppendChild(node);
                        added = true;
                    }
                    else
                    {
                        System.Diagnostics.Debug.WriteLine("Pointer to non existant husband");
                    }
                }

                if (!string.IsNullOrEmpty(family.Wife))
                {
                    GedcomIndividualRecord wife = Database[family.Wife] as GedcomIndividualRecord;
                    if (wife != null)
                    {
                        node = doc.CreateElement("Participant");

                        XmlNode linkNode = doc.CreateElement("Link");

                        attr       = doc.CreateAttribute("Target");
                        attr.Value = "IndividualRec";
                        linkNode.Attributes.Append(attr);

                        attr       = doc.CreateAttribute("Ref");
                        attr.Value = family.Wife;
                        linkNode.Attributes.Append(attr);

                        node.AppendChild(linkNode);

                        eventNode.AppendChild(node);
                        added = true;
                    }
                    else
                    {
                        System.Diagnostics.Debug.WriteLine("Pointer to non existant wife");
                    }
                }

                if (!added)
                {
                    // TODO: no husband or wife now what?  XML will be invalid
                    // without a participant
                }
            }
            else
            {
                GedcomIndividualRecord indi = (this as GedcomIndividualEvent).IndiRecord;

                node = doc.CreateElement("Participant");

                XmlNode linkNode = doc.CreateElement("Link");

                attr       = doc.CreateAttribute("Target");
                attr.Value = "IndividualRec";
                linkNode.Attributes.Append(attr);

                attr       = doc.CreateAttribute("Ref");
                attr.Value = indi.XRefID;
                linkNode.Attributes.Append(attr);

                XmlNode roleNode = doc.CreateElement("Role");
                if (this == indi.Birth)
                {
                    roleNode.AppendChild(doc.CreateTextNode("child"));
                }
                else
                {
                    roleNode.AppendChild(doc.CreateTextNode("principle"));
                }

                linkNode.AppendChild(roleNode);

                node.AppendChild(linkNode);

                eventNode.AppendChild(node);
            }

            if (Date != null)
            {
                node = doc.CreateElement("Date");
                node.AppendChild(doc.CreateTextNode(Date.DateString));
                eventNode.AppendChild(node);
            }

            if (Place != null)
            {
                node = doc.CreateElement("Place");
                node.AppendChild(doc.CreateTextNode(Place.Name));
                eventNode.AppendChild(node);
            }

            GenerateNoteXML(eventNode);
            GenerateCitationsXML(eventNode);
            GenerateMultimediaXML(eventNode);

            GenerateChangeDateXML(eventNode);

            root.AppendChild(eventNode);
        }
        /// <summary>
        /// Outputs this source record as a GEDCOM record.
        /// </summary>
        /// <param name="tw">The writer to output to.</param>
        public override void Output(TextWriter tw)
        {
            base.Output(tw);

            string levelPlusOne = null;
            string levelPlusTwo = null;

            if (!string.IsNullOrEmpty(Agency) ||
                (DataNotes != null && DataNotes.Count > 0) ||
                EventsRecorded.Count > 0)
            {
                if (levelPlusOne == null)
                {
                    levelPlusOne = (Level + 1).ToString();
                }

                tw.Write(Environment.NewLine);
                tw.Write(levelPlusOne);
                tw.Write(" DATA ");

                if (!string.IsNullOrEmpty(Agency))
                {
                    if (levelPlusTwo == null)
                    {
                        levelPlusTwo = (Level + 2).ToString();
                    }

                    tw.Write(Environment.NewLine);
                    tw.Write(levelPlusTwo);
                    tw.Write(" AGNC ");
                    string line = Agency.Replace("@", "@@");
                    tw.Write(line);
                }

                if (DataNotes != null)
                {
                    if (levelPlusTwo == null)
                    {
                        levelPlusTwo = (Level + 2).ToString();
                    }

                    foreach (string noteID in DataNotes)
                    {
                        tw.Write(Environment.NewLine);
                        tw.Write(levelPlusTwo);
                        tw.Write(" NOTE ");
                        tw.Write("@");
                        tw.Write(noteID);
                        tw.Write("@");
                    }
                }

                if (EventsRecorded != null && EventsRecorded.Count > 0)
                {
                    if (levelPlusTwo == null)
                    {
                        levelPlusTwo = (Level + 2).ToString();
                    }

                    foreach (GedcomRecordedEvent recordedEvent in EventsRecorded)
                    {
                        tw.Write(Environment.NewLine);
                        tw.Write(levelPlusTwo);
                        tw.Write(" EVEN ");
                        bool first = true;

                        foreach (GedcomEventType eventType in recordedEvent.Types)
                        {
                            if (!first)
                            {
                                tw.Write(",");
                            }

                            tw.Write(GedcomEvent.TypeToTag(eventType));
                            first = false;
                        }

                        if (recordedEvent.Date != null)
                        {
                            recordedEvent.Date.Output(tw);
                        }

                        if (recordedEvent.Place != null)
                        {
                            recordedEvent.Place.Output(tw);
                        }
                    }
                }
            }

            if (!string.IsNullOrEmpty(Originator))
            {
                if (levelPlusOne == null)
                {
                    levelPlusOne = (Level + 1).ToString();
                }

                tw.Write(Environment.NewLine);
                tw.Write(levelPlusOne);
                tw.Write(" AUTH ");
                Util.SplitLineText(tw, Originator, Level + 1, 248);
            }

            if (!string.IsNullOrEmpty(Title))
            {
                if (levelPlusOne == null)
                {
                    levelPlusOne = (Level + 1).ToString();
                }

                tw.Write(Environment.NewLine);
                tw.Write(levelPlusOne);
                tw.Write(" TITL ");
                Util.SplitLineText(tw, Title, Level + 1, 248);
            }

            if (!string.IsNullOrEmpty(FiledBy))
            {
                if (levelPlusOne == null)
                {
                    levelPlusOne = (Level + 1).ToString();
                }

                tw.Write(Environment.NewLine);
                tw.Write(levelPlusOne);
                tw.Write(" ABBR ");
                Util.SplitLineText(tw, FiledBy, Level + 1, 60, 1, true);
            }

            if (!string.IsNullOrEmpty(PublicationFacts))
            {
                if (levelPlusOne == null)
                {
                    levelPlusOne = (Level + 1).ToString();
                }

                tw.Write(Environment.NewLine);
                tw.Write(levelPlusOne);
                tw.Write(" PUBL ");
                Util.SplitLineText(tw, PublicationFacts, Level + 1, 248);
            }

            if (!string.IsNullOrEmpty(Text))
            {
                if (levelPlusOne == null)
                {
                    levelPlusOne = (Level + 1).ToString();
                }

                tw.Write(Environment.NewLine);
                tw.Write(levelPlusOne);
                tw.Write(" TEXT ");
                Util.SplitLineText(tw, Text, Level + 1, 248);
            }

            if (RepositoryCitations != null)
            {
                foreach (GedcomRepositoryCitation citation in RepositoryCitations)
                {
                    citation.Output(tw);
                }
            }
        }