/*
 * Copyright 2011 NEHTA
 *
 * Licensed under the NEHTA Open Source (Apache) License; you may not use this
 * file except in compliance with the License. A copy of the License is in the
 * 'license.txt' file, which should be provided with this work.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or imp201112131459lied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Linq;
using CDA.Generator.Common;
using CDA.Generator.Common.CDAModel.Entities;
using CDA.Generator.Common.SCSModel.ConsolidatedView.Entities;
using Nehta.VendorLibrary.CDA.SCSModel.Common;
using Nehta.HL7.CDA;

using Nehta.VendorLibrary.CDA.Common;
using Nehta.VendorLibrary.CDA.Common.Enums;
using Nehta.VendorLibrary.CDA.Generator.Enums;
using Nehta.VendorLibrary.CDA.SCSModel;
using Nehta.VendorLibrary.CDA.SCSModel.Common.Entities;
using Nehta.VendorLibrary.Common;


using Entitlement = Nehta.VendorLibrary.CDA.SCSModel.Common.Entitlement;
using CDA.Generator.Common.SCSModel.MedicareInformationView.Entities;

namespace Nehta.VendorLibrary.CDA.Generator
{
    /// <summary>
    /// This helper class is used to aid in converting the various SCS and CDA model objects 
    /// into an actual CDA Document.  
    /// </summary>
    public static partial class CDAGeneratorHelper
    {
        #region Constants

        private const String HEALTH_IDENTIFIER_QUALIFIER = "1.2.36.1.2001.1003.0.";

        private const String DATE_TIME_FORMAT = "yyyyMMddHHmmsszz";
        private const String DATE_TIME_SHORT_FORMAT = "yyyyMMdd";

        #endregion

        #region internal Methods

        #region Create Document Methods

        /// <summary>
        /// Creates a CDA Clinical Document object and sets the document type, version, ID etc
        /// </summary>
        /// <param name="documentCreationTimeDateTime">The date / time the document is effective from</param>
        /// <param name="cdaDocumentType">The document type, E.g. SharedHealthSummary </param>
        /// <param name="setId">The set ID for this CDA document</param>
        /// <param name="version">The document version</param>
        /// <param name="documentStatus">The document status</param>
        /// <param name="documentId">The ID of the clinical document</param>
        /// <returns>POCD_MT000040ClinicalDocument</returns>
        internal static POCD_MT000040ClinicalDocument CreateDocument(ISO8601DateTime documentCreationTimeDateTime,
                                                                     CDADocumentType cdaDocumentType, Identifier documentId, Identifier setId,
                                                                     String version, DocumentStatus? documentStatus
                                                                     )
        {
            POCD_MT000040InfrastructureRoottypeId typeID;

            typeID = new POCD_MT000040InfrastructureRoottypeId{extension = "POCD_HD000040", root = "2.16.840.1.113883.1.3"};

            var clinicalDocument = new POCD_MT000040ClinicalDocument
                                       {
                                           typeId = typeID,
                                           title = CreateStructuredText(cdaDocumentType.GetAttributeValue<NameAttribute, string>(x => x.Title), null),
                                           templateId = new []
                                                        {
                                                             CreateIdentifierElement(
                                                               cdaDocumentType.GetAttributeValue<NameAttribute, string>(x => x.Identifier),
                                                               cdaDocumentType.GetAttributeValue<NameAttribute, string>(x => x.Version),
                                                               null),
                                                             CreateIdentifierElement("1.2.36.1.2001.1001.100.149", "1.0", null)
                                                        },
                                      
                                           id = documentId != null ? CreateIdentifierElement(documentId) : CreateIdentifierElement( CreateGuid(), null),
                                           setId = setId != null ? CreateIdentifierElement(setId) : CreateIdentifierElement(CreateGuid(), null),
                                           code = CreateCodedWithExtensionElement(
                                                   cdaDocumentType.GetAttributeValue<NameAttribute, string>(x => x.Code),
                                                   (CodingSystem)Enum.Parse(typeof(CodingSystem), cdaDocumentType.GetAttributeValue<NameAttribute, string>(x => x.CodeSystem)), 
                                                    null,
                                                    cdaDocumentType.GetAttributeValue<NameAttribute, string>(x => x.Name), null, null),
                                           effectiveTime = documentCreationTimeDateTime != null ? CreateTimeStampElementIso(documentCreationTimeDateTime, null, true) : CreateTimeStampElementIso(new ISO8601DateTime(DateTime.Now), null, true),
                                           confidentialityCode = CreateCodedWithExtensionElement(null, null, null, null, null, NullFlavour.NotApplicable),
                                           languageCode = CreateCodeSystem("en-AU", null, null, null, null, null, null),
                                           completionCode = documentStatus != null ? CreateCodedWithExtensionElement(
                                                       documentStatus.GetAttributeValue<NameAttribute, string>(x => x.Code),
                                                       CodingSystem.NCTISDocumentStatusValues, 
                                                       null,
                                                       documentStatus.GetAttributeValue<NameAttribute, string>(x => x.Name), null, null): null,
                                           component = new POCD_MT000040Component2()
                                       };

            if (!string.IsNullOrEmpty(version))
            {
                clinicalDocument.versionNumber = new INT {value = version};
            }

            return clinicalDocument;
        }

        /// <summary>
        /// Creates a CDA Clinical Document object and sets the document type, version, ID etc
        /// </summary>
        /// <param name="parentDocument">ParentDocument</param>
        /// <returns>POCD_MT000040ClinicalDocument</returns>
        internal static List<POCD_MT000040RelatedDocument> CreateRelatedDocument(List<ParentDocument> parentDocument)
        {
          List<POCD_MT000040RelatedDocument> relatedDocumentList = null;

          if (parentDocument.Any())
          {
              relatedDocumentList = new List<POCD_MT000040RelatedDocument>();

              foreach (var document in parentDocument)
              {
                var relatedDocument = new POCD_MT000040RelatedDocument();

                if (document.ReleatedDocumentType.HasValue)
                  relatedDocument.typeCode = (x_ActRelationshipDocument)Enum.Parse(typeof(x_ActRelationshipDocument), document.ReleatedDocumentType.Value.GetAttributeValue<NameAttribute, string>(x => x.Code));

                relatedDocument.parentDocument = new POCD_MT000040ParentDocument();

                if (document.DocumentId != null)
                  relatedDocument.parentDocument.id = new[]
                                                      {
                                                        CreateIdentifierElement(document.DocumentId)
                                                      };

                if (document.DocumentType.HasValue)
                  relatedDocument.parentDocument.code = CreateCodedWithExtensionElement(
                          document.DocumentType.Value.GetAttributeValue<NameAttribute, string>(x => x.Code),
                          (CodingSystem)Enum.Parse(typeof(CodingSystem), document.DocumentType.Value.GetAttributeValue<NameAttribute, string>(x => x.CodeSystem)),
                           null,
                           document.DocumentType.Value.GetAttributeValue<NameAttribute, string>(x => x.Name), null, null);

                // 0..1
                relatedDocument.parentDocument.text = new ED { nullFlavor = NullFlavor.NA, nullFlavorSpecified = true };

                if (document.SetId != null)
                  relatedDocument.parentDocument.setId = CreateIdentifierElement(document.SetId);

                if (!document.VersionNumber.IsNullOrEmptyWhitespace())
                  relatedDocument.parentDocument.versionNumber = new INT { value = document.VersionNumber};

                relatedDocumentList.Add(relatedDocument);
              }
          }

          return relatedDocumentList;
        }


        /// <summary>
        /// Creates the actual CDA document.
        /// 
        /// This method requires that each of the parameters has been populated.
        /// </summary>
        /// <param name="clinicalDocument">The CDA document</param>
        /// <param name="authors">A list of Authors associated with the document</param>
        /// <param name="legalAuthenticator">The legal authenticator associated with the document</param>
        /// <param name="authenticators">A list of Authenticators</param>
        /// <param name="recipients">A list of Recipients</param>
        /// <param name="participants">A list of Participants</param>
        /// <param name="components">A list of Components</param>.
        /// <param name="nonXmlBody">A referenced file that contains the payload for this CDA document</param>
        /// <param name="includeLogo">Indicates if the logo is to be included as an ObservationMultiMedia entry within this document</param>
        /// <param name="version">The HL7 object set to use when generating this document</param>
        /// <returns>XmlDocument (CDA document)</returns>
        internal static XmlDocument CreateXml(POCD_MT000040ClinicalDocument clinicalDocument,
                                              List<POCD_MT000040Author> authors,
                                              POCD_MT000040LegalAuthenticator legalAuthenticator,
                                              List<POCD_MT000040Authenticator> authenticators,
                                              List<POCD_MT000040InformationRecipient> recipients,
                                              List<POCD_MT000040Participant1> participants,
                                              List<POCD_MT000040Component3> components,
                                              POCD_MT000040NonXMLBody nonXmlBody, Boolean includeLogo,
                                              CDADocumentExtensionVersion version)
        {
            // Add Authors
            if (authors != null)
            {
                clinicalDocument.author = authors.ToArray();
            }

            // Add Legal Authenticator
            clinicalDocument.legalAuthenticator = legalAuthenticator;

            // Add Authenticators
            if (authenticators != null)
            {
                clinicalDocument.authenticator = authenticators.ToArray();
            }

            // Add Information recipients
            if (recipients != null)
            {
                clinicalDocument.informationRecipient = recipients.ToArray();
            }

            // Add participants
            if (participants != null)
            {
                clinicalDocument.participant = participants.ToArray();
            }

            if (includeLogo)
            {
                if (clinicalDocument.component.structuredBody == null)
                {
                    clinicalDocument.component.structuredBody = new POCD_MT000040StructuredBody();
                }

                var externalData = new ExternalData
                                       {
                                           Caption = "logo",
                                           //FileStorageType = FileStorageType.Reference,
                                           ExternalDataMediaType = MediaType.PNG,
                                           Path = @".\logo.png",
                                           ID = "LOGO"
                                       };

                components.Add(new POCD_MT000040Component3
                                   {
                                       section =
                                   new POCD_MT000040Section
                                       {
                                           entry = new[]
                                                   {
                                                       new POCD_MT000040Entry {observationMedia = CreateObservationMedia(externalData)}
                                                   }
                                       }
                                   });
            }

            //Add Body parts
            if (nonXmlBody != null)
            {
                clinicalDocument.component.nonXMLBody = nonXmlBody;
            }

            if (components != null)
            {
                if (components.Exists(component => component != null))
                {
                    if (clinicalDocument.component.structuredBody == null)
                    {
                        clinicalDocument.component.structuredBody = new POCD_MT000040StructuredBody();
                    }

                    clinicalDocument.component.structuredBody.component = components.ToArray();
                }
            }

            //Generate CDA document
            var xml = SerializeXML(clinicalDocument, "ClinicalDocument", version);

            return xml;
        }

        #endregion

        /// <summary>
        /// Creates an XML element that contains a CDA reference to the  eternal data that was passed into this method
        /// </summary>
        /// <param name="externalData">externalData</param>
        /// <returns>an XmlElement containing a CDA reference to the external data</returns>
        internal static POCD_MT000040NonXMLBody CreateNonXmlComponent(ExternalData externalData)
        {
            POCD_MT000040NonXMLBody nonXmlBody = null;

            if (externalData != null)
            {
                nonXmlBody = new POCD_MT000040NonXMLBody {text = CreateEncapsulatedData(externalData)};
            }

            return nonXmlBody;
        }

        /// <summary>
        /// Creates a CDA custodian entry from the Custodian model
        /// </summary>
        /// <param name="custodian">Custodian</param>
        /// <returns>POCD_MT000040Custodian</returns>
        internal static POCD_MT000040Custodian CreateCustodian(IParticipationCustodian custodian)
        {
            if (custodian == null) return null;

            var cdaCustodian = new POCD_MT000040Custodian
                                   {
                                       assignedCustodian =
                                           new POCD_MT000040AssignedCustodian
                                               {
                                                   representedCustodianOrganization =
                                                       new POCD_MT000040CustodianOrganization
                                                           {
                                                               id = custodian.Participant != null ? CreateIdentifierArray(custodian.Participant.UniqueIdentifier.ToString(), null, null) : null,
                                                               name = custodian.Participant == null || custodian.Participant.Organisation == null ? null : CreateOrganisationName(custodian.Participant.Organisation.Name),
                                                               asEntityIdentifier =
                                                                   custodian.Participant == null ||
                                                                   custodian.Participant.Organisation == null ||
                                                                   custodian.Participant.Organisation.Identifiers ==
                                                                   null ? null : CreateEntityIdentifier(custodian.Participant.Organisation.Identifiers).ToArray(),
                                                               addr = custodian.Participant == null ? null : CreateAddress(custodian.Participant.Address),
                                                               telecom = custodian.Participant == null ? null : CreateTelecomunication(custodian.Participant. ElectronicCommunicationDetail)
                                                           }
                                               }
                                   };

            return cdaCustodian;
        }

        /// <summary>Legal Authenticator
        /// Creates a legal authenticator from the Authenticator model
        /// </summary>
        /// <param name="authenticator">Authenticator</param>
        /// <returns>POCD_MT000040LegalAuthenticator</returns>
        internal static POCD_MT000040LegalAuthenticator CreateLegalAuthenticator(IParticipationLegalAuthenticator authenticator)
        {
            if (authenticator == null) return null;

            var cdaAuthenticator = new POCD_MT000040LegalAuthenticator
                                       {
                                           time = authenticator.Participant == null || authenticator.Participant.DateTimeAuthenticated == null ? null : CreateTimeStampElementIso(authenticator.Participant.DateTimeAuthenticated, null, true),
                                           signatureCode = CreateCodeSystem("S", null, null, null, null, null, null),
                                           assignedEntity =
                                               new POCD_MT000040AssignedEntity
                                                   {
                                                       id = authenticator.Participant != null ? CreateIdentifierArray(authenticator.Participant.UniqueIdentifier.ToString(), null, null) : null,
                                                       code = CreateCodedWithExtensionElement(authenticator.Role),
                                                       addr = authenticator.Participant == null ? null : CreateAddressArray(authenticator.Participant.Addresses),
                                                       telecom = authenticator.Participant == null ? null : CreateTelecomunicationArray(
                                                       authenticator.Participant.
                                                       ElectronicCommunicationDetails),
                                                       assignedPerson = new POCD_MT000040Person
                                                                            {   // PersonName
                                                                                name = authenticator.Participant != null &&
                                                                                       authenticator.Participant.Person != null &&
                                                                                       authenticator.Participant.Person.PersonNames != null ? CreatePersonNameArray(authenticator.Participant.Person.PersonNames): null,
                                                                                // EntityIdentifier
                                                                                asEntityIdentifier = authenticator.Participant != null && authenticator.Participant.Person != null && authenticator.Participant.Person.Identifiers != null ? CreateEntityIdentifier( authenticator.Participant.Person.Identifiers).ToArray() : null
                                                                            },
                                                   }
                                       };


            if (authenticator.Participant != null && authenticator.Participant.Organisation != null &&
                (authenticator.Participant.Organisation.Identifiers != null ||
                 !String.IsNullOrEmpty(authenticator.Participant.Organisation.Name)))
            {
                cdaAuthenticator.assignedEntity.representedOrganization =
                    CreateOrganisation(authenticator.Participant.Organisation);
            }

            return cdaAuthenticator;
        }

        /// <summary>
        /// Creates an information recipient from the Recipient model
        /// </summary>
        /// <param name="participationRecipient">Recipient</param>
        /// <returns>POCD_MT000040InformationRecipient</returns>
        internal static POCD_MT000040InformationRecipient CreateInformationRecipient(IParticipationInformationRecipient participationRecipient)
        {
            POCD_MT000040InformationRecipient cdaRecipient = null;
            var recipient = participationRecipient.Participant;

            if (recipient != null)
            {

                cdaRecipient = new POCD_MT000040InformationRecipient
                                   {
                                       typeCode =
                                           recipient.RecipientType == RecipientType.Primary
                                               ? x_InformationRecipient.PRCP
                                               : x_InformationRecipient.TRC,
                                       intendedRecipient =
                                           new POCD_MT000040IntendedRecipient
                                               {
                                                   classCode = x_InformationRecipientRole.ASSIGNED,
                                                   id = participationRecipient.Participant != null ? CreateIdentifierArray(participationRecipient.Participant.UniqueIdentifier.ToString(), null) : null,
                                                   addr = CreateAddressArray(recipient.Addresses),
                                               }
                                   };

                if (recipient.ElectronicCommunicationDetails != null &&
                    recipient.ElectronicCommunicationDetails.Any())
                    cdaRecipient.intendedRecipient.telecom =
                        CreateTelecomunicationArray(recipient.ElectronicCommunicationDetails);

                if (recipient.Person != null && recipient.Person.PersonNames != null)
                {
                    if (cdaRecipient.intendedRecipient.informationRecipient == null)
                        cdaRecipient.intendedRecipient.informationRecipient = new POCD_MT000040Person();

                    cdaRecipient.intendedRecipient.informationRecipient.name =
                        CreatePersonNameArray(recipient.Person.PersonNames);
                }

                if (recipient.Person != null && recipient.Person.Identifiers != null &&
                    recipient.Person.Identifiers.Any())
                {
                    if (cdaRecipient.intendedRecipient.informationRecipient == null)
                        cdaRecipient.intendedRecipient.informationRecipient = new POCD_MT000040Person();

                    cdaRecipient.intendedRecipient.informationRecipient.asEntityIdentifier =
                        CreateEntityIdentifier(recipient.Person.Identifiers).ToArray();
                }

                if (recipient.Organisation != null &&
                    (recipient.Organisation.Identifiers != null || !String.IsNullOrEmpty(recipient.Organisation.Name)))
                {
                    cdaRecipient.intendedRecipient.receivedOrganization = CreateOrganisation(recipient.Organisation);
                }
            }

            return cdaRecipient;
        }

        internal static POCD_MT000040Component1 CreateComponentOf(ISO8601DateTime effectiveDateTime)
        {
            var component = new POCD_MT000040Component1();
            component.encompassingEncounter = new POCD_MT000040EncompassingEncounter();

            component.encompassingEncounter.effectiveTime = CreateIntervalTimestamp(null, null, null, null, effectiveDateTime != null ? effectiveDateTime.ToString() : String.Empty, null);
            return component;
        }

        internal static POCD_MT000040Component1 CreateComponentOf(DateTime? effectiveDateTime)
        {
            var component = new POCD_MT000040Component1();
            component.encompassingEncounter = new POCD_MT000040EncompassingEncounter();

            component.encompassingEncounter.effectiveTime = CreateIntervalTimestamp(null, null, null, null, effectiveDateTime.HasValue ? effectiveDateTime.Value.ToString(DATE_TIME_FORMAT) : String.Empty, null);
            return component;
        }

        internal static POCD_MT000040Component1 CreateComponentOf(CdaInterval duration)
        {
            var component = new POCD_MT000040Component1();
            component.encompassingEncounter = new POCD_MT000040EncompassingEncounter();

            component.encompassingEncounter.effectiveTime = CreateIntervalTimestamp(duration);
            return component;
        }

        internal static POCD_MT000040Component1 CreateComponentOf(CdaInterval duration, NullFlavour? nullFlavour)
        {
          var component = new POCD_MT000040Component1();
          component.encompassingEncounter = new POCD_MT000040EncompassingEncounter();

            NullFlavor? nullFlavor = null;
            if (nullFlavour.HasValue) nullFlavor = (NullFlavor)Enum.Parse(typeof(NullFlavor), nullFlavour.GetAttributeValue<NameAttribute, string>(x => x.Code));

            component.encompassingEncounter.effectiveTime = CreateIntervalTimestamp(duration, nullFlavor);

          return component;
        }

        #region Internal Methods - Create Components

        /// <summary>
        /// Creates an XML element that contains a CDA reference to the eternal data that was passed into this method
        /// </summary>
        /// <param name="externalDataList">externalData</param>
        /// <param name="narrativeGenerator">narrativeGenerator</param>
        /// <returns>an XmlElement containing a CDA reference to the external data</returns>
        internal static POCD_MT000040Component3 CreateStructuredBodyFileComponent(List<ExternalData> externalDataList, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            if (externalDataList != null)
            {
                component = new POCD_MT000040Component3 {section = new POCD_MT000040Section()};

               var entryList = new List<POCD_MT000040Entry>();

                externalDataList.ForEach( externalData => entryList.Add(new POCD_MT000040Entry {observationMedia = CreateObservationMedia(externalData)}));

                component.section.entry = entryList.ToArray();
                component.section.title = CreateStructuredText("Attached Content", null);
                component.section.text = narrativeGenerator.CreateNarrative(externalDataList);
            }

            return component;
        }

      /// <summary>
      /// Creates a component for an E-Referral; specify the reason, time and duration of the referral.
      /// </summary>
      /// <param name="dateTime">The date / time associated with this referral</param>
      /// <param name="duration">The duration of the referral</param>
      /// <param name="reason">The reason for this referral</param>
      /// <param name="customNarrative">Provides the ability to supply a custom narrative </param>
      /// <param name="narrativeGenerator">The narrative generator</param>
      /// <returns>POCD_MT000040Component3</returns>
      internal static POCD_MT000040Component3 CreateComponentForReferralReason(ISO8601DateTime dateTime, CdaInterval duration,
                                                                               string reason,
                                                                               StrucDocText customNarrative,
                                                                               INarrativeGenerator narrativeGenerator)
        {
            //This section will not be generated if the reason for the referral is represented as an external file
            //E.g. if the reason for the referral is contained within a referenced PDF

            POCD_MT000040Component3 component = null;

            if (reason != null && !String.IsNullOrEmpty(reason))
            {
                component = new POCD_MT000040Component3 { section = CreateSectionCodeTitle("102.16347", CodingSystem.NCTIS, "Referral Detail") };

                var entryList = new List<POCD_MT000040Entry>();

                if (duration != null)
                {
                    var anyList = new List<ANY> {CreateIntervalTimestamp(duration)};

                    entryList.Add(CreateEntryObservationWithDuration(x_ActRelationshipEntry.COMP, CreateConceptDescriptor("103.16622", CodingSystem.NCTIS, null, "Referral Validity Duration", null), null, anyList, null, null));
                }

                if (dateTime != null)
                {
                    entryList.Add(CreateEntryObservation(x_ActRelationshipEntry.COMP, CreateConceptDescriptor("103.16620", CodingSystem.NCTIS, null, "Referral DateTime", null), null, null, new List<ANY> {CreateTimeStampElementIso(dateTime, null, false)}, null, null));
                }

                var reasonForReferral = new List<ANY>();

                if (!String.IsNullOrEmpty(reason))
                {
                    reasonForReferral.Add(CreateStructuredText(reason, null));
                }

                //Add an entry containing the referral reason and the referenced referral reason document if one was supplied.
                entryList.Add(CreateEntryObservation(x_ActRelationshipEntry.COMP, CreateConceptDescriptor("42349-1", CodingSystem.LOINC, null, "Reason for referral", null), dateTime, reasonForReferral, null, null));

                component.section.entry = entryList.ToArray();

                if (component.section != null )
                {
                  component.section.text = customNarrative ?? narrativeGenerator.CreateNarrative(dateTime, duration, reason, "Reason for Referral");
                }
            }

            return component;
        }

        internal static POCD_MT000040Component3 CreateComponent(IList<IParticipationAcdCustodian> custodianParticipations, StrucDocText customNarrative, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            if (custodianParticipations != null && custodianParticipations.Any())
            {
                component = new POCD_MT000040Component3();

                component.section = new POCD_MT000040Section
                                        {
                                            code = CreateCodedWithExtensionElement("101.16694", CodingSystem.NCTIS, null, "ACD Custodian Entries", null, null), title = new ST() {Text = new string[] {"ACD Custodian Entries"}}
                                        };

                var custodianEntries = new List<POCD_MT000040Entry>();

                foreach (var participation in custodianParticipations)
                {
                    if (participation != null)
                    {
                        var entry = new POCD_MT000040Entry();
                        entry.typeCode = x_ActRelationshipEntry.COMP;
                        entry.act = new POCD_MT000040Act()
                                        {
                                            classCode = x_ActClassDocumentEntryAct.INFRM,
                                            moodCode = x_DocumentActMood.EVN,
                                            code = CreateConceptDescriptor("102.16690", CodingSystem.NCTIS, null,  "ACD Custodian Entry", null)
                                        };

                        var performer = CreatePerformer(participation);

                        entry.act.performer = new [] {performer};

                        custodianEntries.Add(entry);
                    }
                }

                component.section.entry = custodianEntries.ToArray();
                component.section.text = customNarrative ?? narrativeGenerator.CreateNarrative(custodianParticipations);
            }

            return component;
        }

      /// <summary>
      /// Creates an adverse substance reactions component
      /// </summary>
      /// <param name="allergyAndAdverseReactions">List of adverse reactions</param>
      /// <param name="customNarrative">Provide a custom Narrative </param>
      /// <param name="narrativeGenerator">The narrative generator</param>
      /// <returns>POCD_MT000040Component3</returns>
      internal static POCD_MT000040Component3 CreateComponent(List<Reaction> allergyAndAdverseReactions, StrucDocText customNarrative, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            var entryList = new List<POCD_MT000040Entry>();
            if (allergyAndAdverseReactions != null && allergyAndAdverseReactions.Any())
            {
                component = new POCD_MT000040Component3
                {
                    section = CreateSectionCodeTitle("101.20113", CodingSystem.NCTIS, "Adverse Reactions")
                };
                component.section.title = new ST { Text = new [] { "Allergies and Adverse Reactions" } };

                foreach (var reaction in allergyAndAdverseReactions)
                {
                    var adverseReactionsRelationships = new List<POCD_MT000040EntryRelationship>();

                    if (reaction.ReactionEvent != null && reaction.ReactionEvent.Manifestations != null)
                    {
                        var manifestationRelationships = new List<POCD_MT000040EntryRelationship>();

                        foreach (var manifestation in reaction.ReactionEvent.Manifestations)
                        {
                          manifestationRelationships.Add(CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.MFST, true, CreateConceptDescriptor(manifestation), CreateEncapsulatedData(manifestation.DisplayName)));
                        }

                        adverseReactionsRelationships.Add(CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.CAUS, CreateConceptDescriptor("102.16474", CodingSystem.NCTIS, null, "Reaction Event", null), manifestationRelationships));
                    }

                    if (reaction.SubstanceOrAgent != null)
                        entryList.Add(CreateEntryActEvent(x_ActRelationshipEntry.COMP,
                                                          x_ActClassDocumentEntryAct.ACT, x_DocumentActMood.EVN,
                                                          CreateConceptDescriptor("102.15517", CodingSystem.NCTIS, null, "Adverse Reaction", null),
                                                          CreateParticipant2Array(CreateCodedWithExtensionElement(
                                                                                    reaction.SubstanceOrAgent.Code,
                                                                                    reaction.SubstanceOrAgent.CodeSystemCode,
                                                                                    reaction.SubstanceOrAgent.CodeSystemName,
                                                                                    reaction.SubstanceOrAgent.CodeSystemVersion, 
                                                                                    null,
                                                                                    reaction.SubstanceOrAgent.DisplayName,
                                                                                    reaction.SubstanceOrAgent.OriginalText,
                                                                                    null), 
                                                            null), adverseReactionsRelationships));
                }

                component.section.entry = entryList.ToArray();
            }

            if (component != null && component.section != null)
            {
                component.section.text = customNarrative ?? narrativeGenerator.CreateNarrative(allergyAndAdverseReactions);
            }

            return component;
        }

        /// <summary>
        /// Creates an adverse substance reactions component
        /// </summary>
        /// <param name="adverseSubstanceReactions">IAdverseSubstanceReactions</param>
        /// <param name="narrativeGenerator">The narrative generator</param>
        /// <param name="exclusionStatementCode">Exclusion statement code</param>
        /// <returns>POCD_MT000040Component3</returns>
        internal static POCD_MT000040Component3 CreateComponent(AdverseReactions adverseSubstanceReactions, INarrativeGenerator narrativeGenerator, string exclusionStatementCode)
        {
            POCD_MT000040Component3 component = null;

            var entryList = new List<POCD_MT000040Entry>();

            if (adverseSubstanceReactions != null)
            {
                component = new POCD_MT000040Component3 {section = CreateSectionCodeTitle("101.20113", CodingSystem.NCTIS, "Adverse Reactions")};

                // Adverse Substance Reaction
                if (adverseSubstanceReactions.AdverseSubstanceReaction != null)
                {
                    foreach (var adverserReaction in adverseSubstanceReactions.AdverseSubstanceReaction)
                    {
                        var adverseReactionsRelationships = new List<POCD_MT000040EntryRelationship>();

                        if (adverserReaction.ReactionEvent != null &&
                            adverserReaction.ReactionEvent.Manifestations != null)
                        {
                            var manifestationRelationships = new List<POCD_MT000040EntryRelationship>();

                            foreach (var manifestation in adverserReaction.ReactionEvent.Manifestations)
                            {
                              manifestationRelationships.Add(CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.MFST, true, CreateConceptDescriptor(manifestation), CreateEncapsulatedData(manifestation.DisplayName)));
                            }

                            adverseReactionsRelationships.Add(CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.CAUS, CreateConceptDescriptor("102.16474", CodingSystem.NCTIS, null, "Reaction Event", null),manifestationRelationships));
                        }

                        if (adverserReaction.SubstanceOrAgent != null)
                            entryList.Add(CreateEntryActEvent(x_ActRelationshipEntry.COMP,
                                                              x_ActClassDocumentEntryAct.ACT, x_DocumentActMood.EVN,
                                                              CreateConceptDescriptor("102.15517", CodingSystem.NCTIS, null, "Adverse Reaction", null),
                                                              CreateParticipant2Array(
                                                                  CreateCodedWithExtensionElement(
                                                                      adverserReaction.SubstanceOrAgent.Code,
                                                                      adverserReaction.SubstanceOrAgent.CodeSystemCode,
                                                                      adverserReaction.SubstanceOrAgent.CodeSystemName,
                                                                      adverserReaction.SubstanceOrAgent.CodeSystemVersion, 
                                                                      null,
                                                                      adverserReaction.SubstanceOrAgent.DisplayName,
                                                                      adverserReaction.SubstanceOrAgent.OriginalText,
                                                                      null), null), 
                                                              adverseReactionsRelationships));
                    }
                }
                else
                {
                    // Exclusions
                    if (adverseSubstanceReactions.ExclusionStatement != null)
                    {
                        entryList.Add(CreateExclusionStatement(adverseSubstanceReactions.ExclusionStatement, exclusionStatementCode));
                    }
                }

                component.section.entry = entryList.ToArray();
            }

            if (component != null && component.section != null)
            {
                component.section.text = adverseSubstanceReactions.CustomNarrativeAdverseReactions ?? narrativeGenerator.CreateNarrative(adverseSubstanceReactions);
            }

            return component;
        }

        /// <summary>
        /// Creates a Event Details Component
        /// </summary>
        /// <param name="eventDetails">A event details object</param>
        /// <param name="narrativeGenerator">The narrative generator</param>
        /// <returns>POCD_MT000040Component3</returns>
        internal static POCD_MT000040Component3 CreateComponent(EventDetails eventDetails, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            var entryList = new List<POCD_MT000040Entry>();

            if (eventDetails != null)
            {
                component = new POCD_MT000040Component3 { section = CreateSectionCodeTitle("101.16672", CodingSystem.NCTIS, "Event Details")};

                // Begin Reason for Encounter Description
                if (eventDetails.ClinicalSynopsisDescription != null)
                    entryList.Add(
                        CreateEntryActEvent(
                            CreateConceptDescriptor("102.15513", CodingSystem.NCTIS, null, "Clinical Synopsis", null),
                            CreateStructuredText(eventDetails.ClinicalSynopsisDescription, null)));

                component.section.entry = entryList.ToArray();

                component.section.text = eventDetails.CustomNarrativeEventDetails ?? narrativeGenerator.CreateNarrative(eventDetails);
            }

            return component;
        }

        /// <summary>
        /// Creates an Diagnoses Intervention
        /// </summary>
        /// <param name="diagnosesIntervention">Diagnoses Interventions</param>
        /// <param name="narrativeGenerator">The narrative generator</param>
        /// <returns>POCD_MT000040Component3</returns>
        internal static POCD_MT000040Component3 CreateComponent(DiagnosesIntervention diagnosesIntervention, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            var entryList = new List<POCD_MT000040Entry>();

            if (diagnosesIntervention != null)
            {
                component = new POCD_MT000040Component3 { section = CreateSectionCodeTitle("101.16117", CodingSystem.NCTIS, "Diagnoses/Interventions") };

                //PROBLEM / DIAGNOSIS
                if (diagnosesIntervention.ProblemDiagnosis != null && diagnosesIntervention.ProblemDiagnosis.Any())
                {
                    foreach (var diagnosis in diagnosesIntervention.ProblemDiagnosis) CreateProblemDiagnosisEntry(diagnosis as ProblemDiagnosis, ref entryList);
                }

                // PROCEDURES
                if (diagnosesIntervention.Procedures != null && diagnosesIntervention.Procedures.Any())
                {
                    entryList.AddRange(CreateProcedureEntries(diagnosesIntervention.Procedures));
                }

                // MEDICAL HISTORY ITEM
                if (diagnosesIntervention.MedicalHistoryItem != null && diagnosesIntervention.MedicalHistoryItem.Any())
                {
                    entryList.AddRange(CreateProcedureEntries(diagnosesIntervention.MedicalHistoryItem,
                                                              new CodableText
                                                                  {
                                                                      Code = "102.16627",
                                                                      CodeSystem = CodingSystem.NCTIS,
                                                                      DisplayName = "Medical History Item"
                                                                  }));
                }

                component.section.entry = entryList.ToArray();
                component.section.text = diagnosesIntervention.CustomNarrativeDiagnosesIntervention ?? narrativeGenerator.CreateNarrative(diagnosesIntervention);
            }
            return component;
        }

      /// <summary>
      /// Creates an Diagnoses Interventions
      /// </summary>
      /// <param name="requestedServices">A list of requested services</param>
      /// <param name="narrativeGenerator">The narrative generator</param>
      /// <returns>POCD_MT000040Component3</returns>
      internal static POCD_MT000040Component5[] CreateComponent(List<RequestedService> requestedServices, INarrativeGenerator narrativeGenerator)
        {
            var components = new List<POCD_MT000040Component5>();

            if (requestedServices != null && requestedServices.Any())
            {
                foreach (var requestedService in requestedServices)
                {
                    POCD_MT000040Component5 component = null;
                    var entryList = new List<POCD_MT000040Entry>();
                    var relationshipList = new List<POCD_MT000040EntryRelationship>();

                    component = new POCD_MT000040Component5
                                    {
                                        section = CreateSectionCodeTitle("102.20158", CodingSystem.NCTIS, "Requested Service")
                                    };

                    var documentActMood = (x_DocumentActMood)Enum.Parse(typeof (x_DocumentActMood), requestedService.ServiceBookingStatus != EventTypes.Undefined ? requestedService.ServiceBookingStatus.GetAttributeValue<NameAttribute, string>(x => x.Code) : String.Empty);

                    var entry = CreateEntryActEvent(x_ActRelationshipEntry.COMP, x_ActClassDocumentEntryAct.ACT,
                                                    documentActMood,
                                                    CreateConceptDescriptor(requestedService.RequestedServiceDescription),
                                                    null, 
                                                    null);


                    // Service Provider
                    if (requestedService.ServiceProvider != null)
                    {
                        entry.act.performer = new [] {CreatePerformer(requestedService.ServiceProvider)};
                    }

                    entryList.Add(entry);

                    // ServiceCommencementWindow & ServiceScheduled
                    var serviceItems = new Dictionary<ItemsChoiceType3, QTY>();

                    if (requestedService.ServiceScheduled != null)
                    {
                        serviceItems.Add(ItemsChoiceType3.center,
                                         new TS
                                             {
                                                 value = requestedService.ServiceScheduled.ToString()
                                             });

                    }

                    // ServiceCommencementWindow
                    if (requestedService.ServiceCommencementWindow != null)
                    {
                        entry.act.effectiveTime = CreateIntervalTimestamp(requestedService.ServiceCommencementWindow);
                    }

                    // Subject Of Care Instruction Description
                    if (requestedService.SubjectOfCareInstructionDescription != null)
                    {
                        relationshipList.Add(CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.COMP,
                                                                        x_ActClassDocumentEntryAct.INFRM,
                                                                        x_DocumentActMood.EVN, false,
                                                                        CreateConceptDescriptor("103.10146",
                                                                                                CodingSystem.NCTIS, null,
                                                                                                "Subject of Care Instruction Description",
                                                                                                null),
                                                                        CreateEncapsulatedData(requestedService.SubjectOfCareInstructionDescription, null), null));
                    }

                    // Subject Of Care Instruction Description
                    if (requestedService.RequestedServiceDateTime != null)
                    {
                        relationshipList.Add(CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.COMP,
                                                                        x_ActClassDocumentEntryAct.ACT,
                                                                        x_DocumentActMood.EVN, false,
                                                                        CreateConceptDescriptor("103.16635", CodingSystem.NCTIS, null, "Requested Service DateTime", null),
                                                                        null, null,
                                                                        requestedService.RequestedServiceDateTime));
                    }

                    entry.act.entryRelationship = relationshipList.ToArray();

                    component.section.text = requestedService.CustomNarrativeRequestedService ?? narrativeGenerator.CreateNarrative(requestedService);
                    component.section.entry = entryList.ToArray();
                    components.Add(component);
                }
            }

            return components.ToArray();
        }

      /// <summary>
      /// Creates a reviewed medications component
      /// </summary>
      /// <param name="medications">medications</param>
      /// <param name="customNarrative">Provide a custom Narrative</param>
      /// <param name="narrativeGenerator">The narrative generator</param>
      /// <returns>POCD_MT000040Component3</returns>
      internal static POCD_MT000040Component3 CreateComponent(List<IMedication> medications, StrucDocText customNarrative, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            var entryList = new List<POCD_MT000040Entry>();

            if (medications != null && medications.Any())
            {
                component = new POCD_MT000040Component3 { section = CreateSectionCodeTitle("101.16146", CodingSystem.NCTIS, "Medications") };

                var relationshipList = new List<POCD_MT000040EntryRelationship>();

                    foreach (var medication in medications)
                    {
                        // Medications History
                        relationshipList.Clear();

                        //Clinical Indication
                        if (!String.IsNullOrEmpty(medication.ClinicalIndication))
                        {
                            relationshipList.Add(CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.RSON,
                                                                            x_ActClassDocumentEntryAct.INFRM,
                                                                            x_DocumentActMood.EVN, false,
                                                                            CreateConceptDescriptor("103.10141",
                                                                                                    CodingSystem.NCTIS,
                                                                                                    null,
                                                                                                    "Clinical Indication",
                                                                                                    null),
                                                                            CreateStructuredText(medication.ClinicalIndication, null),
                                                                            null));
                        }

                        //Additional Comments
                        if (!String.IsNullOrEmpty(medication.Comment))
                        {
                            relationshipList.Add(CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.COMP,
                                                                            x_ActClassDocumentEntryAct.INFRM,
                                                                            x_DocumentActMood.EVN, false,
                                                                            CreateConceptDescriptor(
                                                                                    "103.16044",
                                                                                    CodingSystem.NCTIS, 
                                                                                    null,
                                                                                    "Comment",
                                                                                    null),
                                                                            CreateStructuredText(medication.Comment, null), null));
                        }

                        //medicine_list + directions_list
                        entryList.Add(CreateEntrySubstanceAdministrationEvent(x_ActRelationshipEntry.COMP,
                                                                              x_DocumentSubstanceMood.EVN, false,
                                                                              CreateStructuredText(medication.Directions, medication.DirectionsNullFlavour), 
                                                                              null, null, null,
                                                                              medication.Medicine == null ? null
                                                                                  : CreateCodedWithExtensionElement(
                                                                                      medication.Medicine.Code,
                                                                                      medication.Medicine.CodeSystemCode,
                                                                                      medication.Medicine.CodeSystemName,
                                                                                      medication.Medicine.CodeSystemVersion,
                                                                                      null,
                                                                                      medication.Medicine.DisplayName,
                                                                                      medication.Medicine.OriginalText,
                                                                                      null), 
                                                                              null, relationshipList));
                    }

                component.section.entry = entryList.ToArray();
                component.section.text = customNarrative ?? narrativeGenerator.CreateNarrative(medications);
            }
            return component;
        }

        /// <summary>
        /// Creates a reviewed medications component
        /// </summary>
        /// <param name="medications">medications</param>
        /// <param name="narrativeGenerator">The narrative generator</param>
        /// <returns>POCD_MT000040Component3</returns>
        internal static POCD_MT000040Component3 CreateComponent(IMedications medications, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            var entryList = new List<POCD_MT000040Entry>();

            if (medications != null)
            {
                component = new POCD_MT000040Component3  {section = CreateSectionCodeTitle("101.16146", CodingSystem.NCTIS, "Medications")};

                var relationshipList = new List<POCD_MT000040EntryRelationship>();

                if (medications.Medications != null)
                {
                    foreach (var medication in medications.Medications)
                    {
                        // Medications History
                        relationshipList.Clear();

                        //Clinical Indication
                        if (!String.IsNullOrEmpty(medication.ClinicalIndication))
                        {
                            relationshipList.Add(CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.RSON,
                                                                            x_ActClassDocumentEntryAct.INFRM,
                                                                            x_DocumentActMood.EVN, false,
                                                                            CreateConceptDescriptor("103.10141",
                                                                                                    CodingSystem.NCTIS,
                                                                                                    null,
                                                                                                    "Clinical Indication",
                                                                                                    null),
                                                                            CreateStructuredText(medication.ClinicalIndication, null),
                                                                            null));
                        }

                        //Additional Comments
                        if (!String.IsNullOrEmpty(medication.Comment))
                        {
                            relationshipList.Add(CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.COMP,
                                                                            x_ActClassDocumentEntryAct.INFRM,
                                                                            x_DocumentActMood.EVN, false,
                                                                            CreateConceptDescriptor(AdminCodes.AdditionalComments.GetAttributeValue <NameAttribute, String>(x => x.Code), 
                                                                                                    CodingSystem.NCTIS, null, AdminCodes.AdditionalComments.GetAttributeValue<NameAttribute, String>(x => x.Name), null),
                                                                            CreateStructuredText(medication.Comment, null), null));
                        }

                        //medicine_list + directions_list
                        entryList.Add(CreateEntrySubstanceAdministrationEvent(x_ActRelationshipEntry.COMP,
                                                                              x_DocumentSubstanceMood.EVN, false,
                                                                              CreateStructuredText(medication.Directions, medication.DirectionsNullFlavour), null,
                                                                              null, null,
                                                                              medication.Medicine == null ? null
                                                                                  : CreateCodedWithExtensionElement(
                                                                                      medication.Medicine.Code,
                                                                                      medication.Medicine.CodeSystemCode,
                                                                                      medication.Medicine.CodeSystemName,
                                                                                      medication.Medicine.CodeSystemVersion,
                                                                                      null,
                                                                                      medication.Medicine.DisplayName,
                                                                                      medication.Medicine.OriginalText,
                                                                                      null),
                                                                              null, 
                                                                              relationshipList));
                    }
                }

                // Exclusions
                if (medications.ExclusionStatement != null)
                {
                    entryList.Add(CreateExclusionStatement(medications.ExclusionStatement, "103.16302.120.1.2"));
                }

                component.section.entry = entryList.ToArray();
                component.section.text = medications.CustomNarrativeMedications ??  narrativeGenerator.CreateNarrative(medications);

            }
            return component;
        }

        /// <summary>
        /// Creates a medications component
        /// </summary>
        /// <param name="medications">IMedicationsEReferral</param>
        /// <param name="narrativeGenerator">The narrative generator</param>
        /// <returns>POCD_MT000040Component3</returns>
        internal static POCD_MT000040Component3 CreateComponent(IMedicationsEReferral medications, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            var entryList = new List<POCD_MT000040Entry>();

            if (medications != null)
            {
                component = new POCD_MT000040Component3 { section = CreateSectionCodeTitle("101.16146", CodingSystem.NCTIS, "Medications") };

                if (medications.MedicationsList != null)
                {
                    foreach (var medication in medications.MedicationsList)
                    {
                        // Medications History
                        entryList.Add(CreateEntrySubstanceAdministrationEvent(x_ActRelationshipEntry.COMP,
                                                                              x_DocumentSubstanceMood.EVN, false,
                                                                              CreateStructuredText(medication.Directions, medication.DirectionsNullFlavour), 
                                                                              null, null, null,
                                                                              medication.Medicine == null ? null
                                                                                  : CreateCodedWithExtensionElement(
                                                                                      medication.Medicine.Code,
                                                                                      medication.Medicine.CodeSystemCode,
                                                                                      medication.Medicine.CodeSystemName,
                                                                                      medication.Medicine.CodeSystemVersion,
                                                                                      null,
                                                                                      medication.Medicine.DisplayName,
                                                                                      medication.Medicine.OriginalText,
                                                                                      null), 
                                                                              null, null));
                    }
                }

                // Exclusions
                if (medications.ExclusionStatement != null)
                {
                    entryList.Add(CreateExclusionStatement(medications.ExclusionStatement, "103.16302.2.2.1"));
                }

                component.section.entry = entryList.ToArray();
                component.section.text = medications.CustomNarrativeMedications ?? narrativeGenerator.CreateNarrative(medications);
            }

            return component;
        }

      /// <summary>
      /// Creates a medications component
      /// </summary>
      /// <param name="medications">A list of Medication Items</param>
      /// <param name="customNarrative">Provide a custom Narrative </param>
      /// <param name="narrativeGenerator">The narrative generator</param>
      /// <returns>POCD_MT000040Component3</returns>
      internal static POCD_MT000040Component3 CreateComponent(List<IMedicationItem> medications, StrucDocText customNarrative, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            var entryList = new List<POCD_MT000040Entry>();

            if (medications != null && medications.Any())
            {
                component = new POCD_MT000040Component3 {section = CreateSectionCodeTitle("101.16146", CodingSystem.NCTIS, "Medications")};

                if (medications.Any())
                {
                    foreach (var medication in medications)
                    {
                        var relationshipList = new List<POCD_MT000040EntryRelationship>();

                        relationshipList.AddRange(CreateRelationshipForMedication(medication, "Comment"));

                        bool? negationInd = null;

                        if ((medication.ChangeType.HasValue && medication.ChangeType.Value == ChangeType.Ceased) && medication.RecommendationOrChange == RecomendationOrChange.TheChangeHasBeenMade)
                            negationInd = true;

                        // Medications
                        entryList.Add(CreateEntrySubstanceAdministrationEvent(x_ActRelationshipEntry.COMP,
                                                                              x_DocumentSubstanceMood.EVN, false,
                                                                              CreateStructuredText(medication.Directions, medication.DirectionsNullFlavour),
                                                                              null, null, null,
                                                                              medication.Medicine == null ? null
                                                                                  : CreateCodedWithExtensionElement(
                                                                                      medication.Medicine.Code,
                                                                                      medication.Medicine.CodeSystemCode,
                                                                                      medication.Medicine.CodeSystemName,
                                                                                      medication.Medicine.CodeSystemVersion,
                                                                                      null,
                                                                                      medication.Medicine.DisplayName,
                                                                                      medication.Medicine.OriginalText,
                                                                                      null), 
                                                                              null, relationshipList,
                                                                              negationInd, "active", null, null, null, null, null, null));
                    }
                }

                component.section.entry = entryList.ToArray();
                component.section.text = customNarrative ?? narrativeGenerator.CreateNarrative(medications);
            }
            return component;
        }

        /// <summary>
        /// Creates a medications component
        /// </summary>
        /// <param name="medications">IMedicationsSpecialistLetter</param>
        /// <param name="narrativeGenerator">The narrative generator</param>
        /// <returns>POCD_MT000040Component3</returns>
        internal static POCD_MT000040Component3 CreateComponent(IMedicationsSpecialistLetter medications, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            var entryList = new List<POCD_MT000040Entry>();

            if (medications != null)
            {
                component = new POCD_MT000040Component3 { section = CreateSectionCodeTitle("101.16146", CodingSystem.NCTIS, "Medications") };

                if (medications.MedicationsList != null)
                {
                    foreach (var medication in medications.MedicationsList)
                    {
                        var relationshipList = new List<POCD_MT000040EntryRelationship>();

                        relationshipList.AddRange(CreateRelationshipForMedication(medication, "Additional Comments"));

                        bool? negationInd = null;
                        if (medication.ChangeType == ChangeType.Ceased && medication.RecommendationOrChange == RecomendationOrChange.TheChangeHasBeenMade)
                            negationInd = true;

                        // Medications
                        entryList.Add(CreateEntrySubstanceAdministrationEvent(x_ActRelationshipEntry.COMP,
                                                                              x_DocumentSubstanceMood.EVN, false,
                                                                              CreateStructuredText(medication.Directions, medication.DirectionsNullFlavour),
                                                                              null, null, null,
                                                                              medication.Medicine == null ? null
                                                                                  : CreateCodedWithExtensionElement(
                                                                                      medication.Medicine.Code,
                                                                                      medication.Medicine.CodeSystemCode,
                                                                                      medication.Medicine.CodeSystemName,
                                                                                      medication.Medicine.CodeSystemVersion,
                                                                                      null,
                                                                                      medication.Medicine.DisplayName,
                                                                                      medication.Medicine.OriginalText,
                                                                                      null),
                                                                              null, 
                                                                              relationshipList, 
                                                                              negationInd, 
                                                                              "active", 
                                                                              null, null, null, null, null, null));
                    }
                }

                // Exclusions
                if (medications.ExclusionStatement != null)
                {
                    entryList.Add(CreateExclusionStatement(medications.ExclusionStatement, "103.16302.132.1.1"));
                }

                component.section.entry = entryList.ToArray();
                component.section.text = medications.CustomNarrativeMedications ?? narrativeGenerator.CreateNarrative(medications);
            }
            return component;
        }

        /// <summary>
        /// Creates a medical history component
        /// </summary>
        /// <param name="medicalHistory">IMedicalHistory</param>
        /// <param name="narrativeGenerator">The narrative generator</param>
        /// <returns>POCD_MT000040Component3</returns>
        internal static POCD_MT000040Component3 CreateComponent(IMedicalHistory medicalHistory, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            var entryList = new List<POCD_MT000040Entry>();

            if (medicalHistory != null)
            {
                component = new POCD_MT000040Component3 { section = CreateSectionCodeTitle("101.16117", CodingSystem.NCTIS, "Medical History") };

                //PROBLEM / DIAGNOSIS
                if (medicalHistory.ProblemDiagnosis != null && medicalHistory.ProblemDiagnosis.Any())
                    entryList.AddRange(CreateProblemDiagnosisEntries(medicalHistory.ProblemDiagnosis));

                // PROBLEM DIAGNOSIS EXCLUSIONS
                if (medicalHistory.ProblemDiagnosisExclusionStatement != null)
                    entryList.Add(CreateExclusionStatement(medicalHistory.ProblemDiagnosisExclusionStatement, "103.16302.120.1.3"));

                // PROCEDURES
                if (medicalHistory.Procedures != null && medicalHistory.Procedures.Any())
                    entryList.AddRange(CreateProcedureEntries(medicalHistory.Procedures));

                // PROCEDURE EXCLUSIONS
                if (medicalHistory.ProceduresExclusionStatement != null)
                    entryList.Add(CreateExclusionStatement(medicalHistory.ProceduresExclusionStatement, "103.16302.120.1.4"));

                //OTHER MEDICAL HISTORY
                if (medicalHistory.MedicalHistoryItems != null && medicalHistory.MedicalHistoryItems.Any())
                    entryList.AddRange(CreateProcedureEntries(medicalHistory.MedicalHistoryItems,
                                                              new CodableText
                                                                  {
                                                                      Code = "102.16627",
                                                                      CodeSystem = CodingSystem.NCTIS,
                                                                      DisplayName = "Other Medical History Item"
                                                                  }));

                component.section.entry = entryList.ToArray();
                component.section.text = medicalHistory.CustomNarrativeMedicalHistory ?? narrativeGenerator.CreateNarrative(medicalHistory);
            }

            return component;
        }

        /// <summary>
        /// Creates a medical history component
        /// </summary>
        /// <param name="medicalHistory">IMedicalHistory</param>
        /// <param name="narrativeGenerator">The narrative generator</param>
        /// <returns>POCD_MT000040Component3</returns>
        internal static POCD_MT000040Component3 CreateComponent(IMedicalHistoryWithoutExclusions medicalHistory, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            var entryList = new List<POCD_MT000040Entry>();

            if (medicalHistory != null)
            {
                component = new POCD_MT000040Component3
                                {section = CreateSectionCodeTitle("101.16117", CodingSystem.NCTIS, "Medical History")};

                //PROBLEM / DIAGNOSIS
                if (medicalHistory.ProblemDiagnosis != null && medicalHistory.ProblemDiagnosis.Any())
                    entryList.AddRange(CreateProblemDiagnosisEntries(medicalHistory.ProblemDiagnosis));

                // PROCEDURES
                if (medicalHistory.Procedures != null && medicalHistory.Procedures.Any())
                    entryList.AddRange(CreateProcedureEntries(medicalHistory.Procedures));

                //OTHER MEDICAL HISTORY
                if (medicalHistory.MedicalHistoryItems != null && medicalHistory.MedicalHistoryItems.Any())
                    entryList.AddRange(CreateProcedureEntries(medicalHistory.MedicalHistoryItems,
                                                              new CodableText
                                                                  {
                                                                      Code = "102.16627",
                                                                      CodeSystem = CodingSystem.NCTIS,
                                                                      DisplayName = "Other Medical History Item"
                                                                  }));

                component.section.entry = entryList.ToArray();
                component.section.text = medicalHistory.CustomNarrativeMedicalHistory ?? narrativeGenerator.CreateNarrative(medicalHistory);
            }

            return component;
        }

      /// <summary>
      /// Creates a document component for a list of IDocumentWithHealthEventEnded
      /// </summary>
      /// <param name="documents">List of documents</param>
      /// <param name="customNarrative">Provide a custom Narrative </param>
      /// <param name="documentSections">An enum representing the section for consolidated view document item </param>
      /// <param name="documentProvenance">The type of document </param>
      /// <param name="narrativeGenerator">The narrative generator</param>
      /// <returns>POCD_MT000040Component3</returns>
      internal static POCD_MT000040Component3 CreateComponent(List<IDocumentWithHealthEventEnded> documents, StrucDocText customNarrative, DocumentSections documentSections, DocumentProvenance documentProvenance, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            var entryList = new List<POCD_MT000040Entry>();

            component = new POCD_MT000040Component3
            {
               section = CreateSectionCodeTitle(documentSections.GetAttributeValue<NameAttribute, string>(x => x.Code),
                                                 (CodingSystem)Enum.Parse(typeof(CodingSystem), documentSections.GetAttributeValue<NameAttribute, string>(x => x.CodeSystem)),
                                                 documentSections.GetAttributeValue<NameAttribute, string>(x => x.Name),
                                                 documentSections.GetAttributeValue<NameAttribute, string>(x => x.Title),
                                                 null)
            };

            if (documents != null && documents.Any())
            {
              entryList.AddRange(documents.Select(document => CreateComponent(document as Document, documentProvenance)));
              component.section.entry = entryList.ToArray();
            }

            component.section.text = customNarrative ?? narrativeGenerator.CreateNarrative(documents);

            return component;
        }

      /// <summary>
      /// Creates a document component for a list of IDocuments
      /// </summary>
      /// <param name="documents">List of documents</param>
      /// <param name="customNarrative">Provide a custom Narrative  </param>
      /// <param name="documentSections">An enum representing the section for consolidated view document item </param>
      /// <param name="documentProvenance">The type of document </param>
      /// <param name="narrativeGenerator">The narrative generator</param>
      /// <returns>POCD_MT000040Component3</returns>
      internal static POCD_MT000040Component3 CreateComponent(List<IDocument> documents, StrucDocText customNarrative, DocumentSections documentSections, DocumentProvenance documentProvenance, INarrativeGenerator narrativeGenerator)
      {
        POCD_MT000040Component3 component = null;

        var entryList = new List<POCD_MT000040Entry>();

        component = new POCD_MT000040Component3 { section =  CreateSectionCodeTitle(documentSections.GetAttributeValue<NameAttribute, string>(x => x.Code),
                                                                                       (CodingSystem)Enum.Parse(typeof(CodingSystem), documentSections.GetAttributeValue<NameAttribute, string>(x => x.CodeSystem)),
                                                                                       documentSections.GetAttributeValue<NameAttribute, string>(x => x.Name),
                                                                                       documentSections.GetAttributeValue<NameAttribute, string>(x => x.Title),
                                                                                       null)
                                                  };
        if (documents != null)
        {
             entryList.AddRange(documents.Select(document => CreateComponent(document as Document, documentProvenance)));
             component.section.entry = entryList.ToArray();
        }

        component.section.text = customNarrative ?? narrativeGenerator.CreateNarrative(documents);

        return component;
      }

      /// <summary>
      /// Create Document
      /// </summary>
      /// <param name="document">The document</param>
      /// <param name="documentProvenance">The DocumentProvenance of the document </param>
      /// <returns>POCD_MT000040Entry</returns>
      internal static POCD_MT000040Entry CreateComponent(Document document, DocumentProvenance documentProvenance)
        {
              var entryRelationships = new List<POCD_MT000040EntryRelationship>();

              var entry = new POCD_MT000040Entry();

              if (document != null)
              {
                
             
               // Business Document Type
               entry.act = new POCD_MT000040Act
                              {
                                 id = CreateIdentifierArray(CreateGuid(), null),
                                 classCode = x_ActClassDocumentEntryAct.ACT,
                                 moodCode = x_DocumentActMood.EVN,
                                 effectiveTime = CreateIntervalTimestamp(document.DateTimeAuthored, null),
                                 code = CreateCodedWithExtensionElement(documentProvenance.GetAttributeValue<NameAttribute, string>(x => x.Code),
                                                                         (CodingSystem)Enum.Parse(typeof(CodingSystem), documentProvenance.GetAttributeValue<NameAttribute, string>(x => x.CodeSystem)),
                                                                         null,
                                                                         documentProvenance.GetAttributeValue<NameAttribute, string>(x => x.Name),
                                                                         null,
                                                                         null)
                              };

                // Author
                if (document.Author != null)
                   entry.act.performer = new [] { CreatePerformer(document.Author) }; 

                // Date Time Health Event Ended
                if (document.DateTimeHealthEventEnded != null)
                {
                  entryRelationships.Add(CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.COMP,
                                                                    x_ActClassDocumentEntryAct.ACT,
                                                                    x_DocumentActMood.EVN,
                                                                    false,
                                                                    CreateConceptDescriptor("103.15510.160.1.3", CodingSystem.NCTIS, null, "DateTime Health Event Ended", null),
                                                                    null,
                                                                    null,
                                                                    document.DateTimeHealthEventEnded)
                  );
                }

                // Document Link 
                if (document.Link != null)
                {
                    var referance = new POCD_MT000040Reference
                                    {
                                        seperatableInd = new BL 
                                                              {
                                                                value = true, 
                                                                valueSpecified = true
                                                              },
                                        typeCode = x_ActRelationshipExternalReference.REFR
                                    };

                      referance.externalDocument = new POCD_MT000040ExternalDocument
                                                   {
                                                       classCode = ActClassDocument.DOC,
                                                       moodCode = ActMood.EVN,
                                                       id = !document.Link.DocumentIdentifier.IsNullOrEmptyWhitespace() ? new[] { CreateIdentifierElement(document.Link.DocumentIdentifier, document.Link.DocumentIdentifierExtension, null,null,null) } : null,
                                                       templateId = new []
                                                        {    
                                                             !document.Link.TemplateId.HasValue ? null :
                                                             CreateIdentifierElement
                                                             (
                                                                 document.Link.TemplateId.Value.GetAttributeValue<NameAttribute, string>(x => x.Identifier),
                                                                 document.Link.TemplateId.Value.GetAttributeValue<NameAttribute, string>(x => x.Version),
                                                                 null
                                                             )
                                                        },
                                                       code = CreateCodedWithExtensionElement(document.BusinessDocumentType.GetAttributeValue<NameAttribute, string>(x => x.Code),
                                                                                               (CodingSystem)Enum.Parse(typeof(CodingSystem), document.BusinessDocumentType.GetAttributeValue<NameAttribute, string>(x => x.CodeSystem)),
                                                                                               null,
                                                                                               document.BusinessDocumentType.GetAttributeValue<NameAttribute, string>(x => x.Name),
                                                                                               document.BusinessDocumentType.GetAttributeValue<NameAttribute, string>(x => x.Title),
                                                                                               null)
                                                   };

                entry.act.entryRelationship = entryRelationships.ToArray();
                entry.act.reference = new [] { referance };

                }
          }

          return entry;
        }


      /// <summary>
      /// Creates a immunisations component
      /// </summary>
      /// <param name="immunisations">List of immunisations</param>
      /// <param name="customNarrative">Provide a custom Narrative </param>
      /// <param name="narrativeGenerator">The narrative generator</param>
      /// <returns>POCD_MT000040Component3</returns>
      internal static POCD_MT000040Component3 CreateComponent(List<IImmunisation> immunisations, StrucDocText customNarrative, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            var entryList = new List<POCD_MT000040Entry>();

            if (immunisations != null && immunisations.Any())
            {

                component = new POCD_MT000040Component3 { section = CreateSectionCodeTitle("101.16638", CodingSystem.NCTIS, "Immunisations") };

                entryList.AddRange(CreateAdministeredImmunisations(immunisations));

                component.section.entry = entryList.ToArray();
                component.section.text = customNarrative ?? narrativeGenerator.CreateNarrative(immunisations);
            }

            return component;
        }

        /// <summary>
        /// Creates a reviewed immunisations component
        /// </summary>
        /// <param name="imunisations">ReviewedImmunisations</param>
        /// <param name="narrativeGenerator">The narrative generator</param>
        /// <returns>POCD_MT000040Component3</returns>
        internal static POCD_MT000040Component3 CreateComponent(Immunisations imunisations, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            var entryList = new List<POCD_MT000040Entry>();

            if (imunisations != null)
            {
                component = new POCD_MT000040Component3 { section = CreateSectionCodeTitle("101.16638", CodingSystem.NCTIS, "Immunisations") };

                //ADMINISTERED IMMUNISATION
                if (imunisations.AdministeredImmunisation != null && imunisations.AdministeredImmunisation.Any())
                {
                    entryList.AddRange(CreateAdministeredImmunisations(imunisations.AdministeredImmunisation));
                }


                //EXCLUSION STATEMENT
                if (imunisations.ExclusionStatement != null)
                {
                    // "Immunisations - Exclusion Statement", ref strucDocTableList
                    entryList.Add(CreateExclusionStatement(imunisations.ExclusionStatement, "103.16302.120.1.5"));
                }

                component.section.entry = entryList.ToArray();
                component.section.text = imunisations.CustomNarrativeImmunisation ?? narrativeGenerator.CreateNarrative(imunisations);

            }
            return component;
        }

      /// <summary>
      /// Creates a administration observations component
      /// </summary>
      /// <param name="subjectOfCareParticipation">IParticipationSubjectOfCare</param>
      /// <param name="customNarrative">Provide a custom Narrative </param>
      /// <param name="patientId">Patient ID</param>
      /// <param name="narrativeGenerator">The narrative generator with which to generate teh narrative for this section / component</param>
      /// <returns>POCD_MT000040Component3</returns>
      internal static POCD_MT000040Component3 CreateAdministrativeObservations(IParticipationSubjectOfCare subjectOfCareParticipation, StrucDocText customNarrative, String patientId, INarrativeGenerator narrativeGenerator)
        {
            var component = new POCD_MT000040Component3
                                {
                                    section = CreateSectionCodeTitle("102.16080", CodingSystem.NCTIS, "Administrative Observations")
                                };

            var entryList = new List<POCD_MT000040Entry>();

            //DEMOGRAPHICS
            if (subjectOfCareParticipation != null && subjectOfCareParticipation.Participant != null && subjectOfCareParticipation.Participant.Person != null)
            {
                var person = subjectOfCareParticipation.Participant.Person;

                if (person.DateOfBirthCalculatedFromAge.HasValue || person.DateOfBirthAccuracyIndicator != null ||
                    person.Age.HasValue || person.AgeAccuracyIndicator != null || person.BirthPlurality.HasValue ||
                    person.DateOfDeathAccuracyIndicator != null ||
                    subjectOfCareParticipation.Participant.Entitlements != null)
                {
                    //Date of Birth calculated from age
                    entryList.Add(CreateAdministrationObservationDateOfBirthCalculatedFromAge(person.DateOfBirthCalculatedFromAge));

                    //Date of Birth accuracy indicatory
                    entryList.Add(CreateAdministrationObservationAge(person.DateOfBirthAccuracyIndicator, "Date of Birth", "102.16234"));

                    //Age Accuracy Indicator
                    entryList.Add(CreateAdministrationObservationAgeAccuracyIndicator(person.AgeAccuracyIndicator));

                    //Birth Plurality
                    entryList.Add(CreateAdministrationObservationBirthPlurality(person.BirthPlurality));

                    //Age
                    entryList.Add(CreateAdministrationObservationAge(person.Age, person.AgeUnitOfMeasure));

                    //Date of Death accuracy indicatory
                    entryList.Add(CreateAdministrationObservationAge(person.DateOfDeathAccuracyIndicator, "Date of Death", "102.16252"));

                    //Mothers Original Family Name
                    entryList.Add(CreateAdministrationObservationMothersOriginalFamilyName(person.MothersOriginalFamilyName));

                    //Source Of Death Notification
                    entryList.Add(CreateAdministrationObservationSourceOfDeathNotification(person.SourceOfDeathNotification));

                    // Entitlements
                    if (patientId != null && subjectOfCareParticipation.Participant.Entitlements != null &&
                        subjectOfCareParticipation.Participant.Entitlements.Any())
                    {
                        component.section.coverage2 = CreateEntitlements(subjectOfCareParticipation.Participant.Entitlements, patientId, RoleClass.PAT, ParticipationType.BEN).ToArray();
                    }
                }

                //NARRATIVE
                if (narrativeGenerator != null)
                {
                    component.section.text = new StrucDocText();
                    component.section.text = customNarrative ?? narrativeGenerator.CreateNarrative(subjectOfCareParticipation, patientId, true);
                }
                else
                {
                    component.section.text = null;
                    component.section.title = null;
                }

                component.section.entry = entryList.ToArray();
            }

            return component;
        }

      /// <summary>
      /// Creates a Diagnostic Investigations component
      /// </summary>
      /// <param name="diagnosticInvestigations">IDiagnosticInvestigations</param>
      /// <param name="cdaDocumentType">The document type </param>
      /// <param name="narrativeGenerator">The narrative generator</param>
      /// <returns>POCD_MT000040Component3</returns>
      internal static POCD_MT000040Component3 CreateComponent(IDiagnosticInvestigations diagnosticInvestigations, CDADocumentType? cdaDocumentType, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            var componentList = new List<POCD_MT000040Component5>();

            if (diagnosticInvestigations != null)
            {
                component = new POCD_MT000040Component3
                                {
                                    section = CreateSectionCodeTitle("101.20117", CodingSystem.NCTIS, "Diagnostic Investigations", "This section may contain the following subsections Pathology Test Result, Imaging Examination Result and Requested Service(s)."),
                                };

                if (diagnosticInvestigations.CustomNarrativeDiagnosticInvestigations != null) component.section.text = diagnosticInvestigations.CustomNarrativeDiagnosticInvestigations;

                // REQUESTED SERVICE
                if (diagnosticInvestigations.RequestedService != null && diagnosticInvestigations.RequestedService.Any())
                {
                    componentList.AddRange(CreateComponent(diagnosticInvestigations.RequestedService, narrativeGenerator).ToArray());
                }

                //PATHOLOGY TEST RESULTS
                if (diagnosticInvestigations.PathologyTestResult != null)
                {
                    foreach (var pathologyTestResult in diagnosticInvestigations.PathologyTestResult)
                    {
                        var relationshipList = new List<POCD_MT000040EntryRelationship>();
                        var entryList = new List<POCD_MT000040Entry>();

                        // Narrative
                        //Create the Pathology Test Result Component and section
                        var pathologyTestResultComponent = new POCD_MT000040Component5
                                                               {
                                                                   section = CreateSectionCodeTitle("102.16144", CodingSystem.NCTIS, "Pathology Test Result")
                                                               };

                        //Create relationships covering the test Specimen details
                        if (pathologyTestResult.PathologyTestSpecimenDetail != null)
                        {
                            relationshipList.AddRange(CreateRelationshipForEachSpecimenDetail(pathologyTestResult.PathologyTestSpecimenDetail, cdaDocumentType));
                        }

                        //Create relationships covering the test result groups
                        if (pathologyTestResult.PathologyTestResultGroup != null)
                        {
                            relationshipList.AddRange(CreateRelationshipForEachTestResultGroup(pathologyTestResult.PathologyTestResultGroup, cdaDocumentType));
                        }

                        //Create relationships covering the diagnostic Service
                        if (pathologyTestResult.DiagnosticService != null)
                        {
                            relationshipList.Add(
                                CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.COMP,
                                                                   CreateConceptDescriptor("310074003", CodingSystem.SNOMED, null, "pathology service", null, Constants.SnomedVersion20110531, null),
                                                                   CreateConceptDescriptor(pathologyTestResult.DiagnosticService.GetAttributeValue<NameAttribute, String>(x => x.Code),
                                                                   CodingSystem.HL7DiagnosticServiceSectionID, null, pathologyTestResult.DiagnosticService.GetAttributeValue<NameAttribute, String>(x => x.Name), null)));
                        }

                        //Create a relationship containing the status of the pathology test
                        if (pathologyTestResult.OverallTestResultStatus.HasValue)
                        {
                            relationshipList.Add(CreateRelationshipForTestResultStatus(pathologyTestResult.OverallTestResultStatus.Value));
                        }

                        //Create a relationship containing the provided clinical information
                        relationshipList.Add(CreateRelationshipForProvidedClinicalInformation(pathologyTestResult.ClinicalInformationProvided));

                        //pathological diagnosis
                        if (pathologyTestResult.PathologicalDiagnosis != null && pathologyTestResult.PathologicalDiagnosis.Any())
                        {
                            relationshipList.Add(CreateRelationshipForTestResultPathologicalDiagnosis(pathologyTestResult.PathologicalDiagnosis));
                        }

                        //Test conclusion
                        if (!String.IsNullOrEmpty(pathologyTestResult.Conclusion))
                        {
                            relationshipList.Add(CreateRelationshipForTestResultConculsion(pathologyTestResult.Conclusion));
                        }

                        //test comment
                        if (!String.IsNullOrEmpty(pathologyTestResult.Comment))
                        {
                            relationshipList.Add(CreateRelationshipForTestResultComment(pathologyTestResult.Comment));
                        }

                        //Test request details; includes the requested test name(s) and identifier(s)
                        if (pathologyTestResult.TestRequestDetails != null && pathologyTestResult.TestRequestDetails.Any())
                        {
                          relationshipList.AddRange(pathologyTestResult.TestRequestDetails.Select(testRequest => CreateRelationshipForTestRequestDetails(testRequest)));
                        }

                        //pathology test result date time
                        if (pathologyTestResult.TestResultDateTime != null)
                        {
                            relationshipList.Add(CreateRelationshipForTestResultDateTime(pathologyTestResult.TestResultDateTime));
                        }

                        //Added this relationship so as we can reference and display the test result representation 
                        //data within the narrative
                        var relationShip = CreateEntryRelationshipObservationMedia(x_ActRelationshipEntryRelationship.REFR, pathologyTestResult.TestResultRepresentation);

                        relationshipList.Add(relationShip);

                        //Create the observation entry with all the above relationships nested inside the observation
                        entryList.Add(CreateEntryObservation(x_ActRelationshipEntry.COMP,
                                                             CreateConceptDescriptor(pathologyTestResult.TestResultName),
                                                             null,
                                                             // Taken out DateTime now, because it did not appear to map to anything
                                                             new List<ANY>
                                                                 {
                                                                     pathologyTestResult.TestResultRepresentation !=
                                                                     null ? CreateEncapsulatedData(pathologyTestResult.TestResultRepresentation) : null
                                                                 }, 
                                                             null, 
                                                             relationshipList));

                        pathologyTestResultComponent.section.entry = entryList.ToArray();
                        componentList.Add(pathologyTestResultComponent);
                        pathologyTestResultComponent.section.text = pathologyTestResult.CustomNarrativePathologyTestResult ?? narrativeGenerator.CreateNarrative(pathologyTestResult);
                    }
                }

                //IMAGING EXAMINATION RESULTS
                if (diagnosticInvestigations.ImagingExaminationResult != null && diagnosticInvestigations.ImagingExaminationResult.Any())
                {
                    foreach (var imagingExaminationResult in diagnosticInvestigations.ImagingExaminationResult)
                    {
                        var relationshipList = new List<POCD_MT000040EntryRelationship>();
                        var entryList = new List<POCD_MT000040Entry>();

                        //Create the Imaging Examination Result Component and section
                        var imagingExaminationResultComponent = new POCD_MT000040Component5
                                                                    {
                                                                        section = CreateSectionCodeTitle("102.16145", CodingSystem.NCTIS, "Imaging Examination Result")
                                                                    };

                        //Anatomical location image
                        if (imagingExaminationResult.AnatomicalSite != null &&
                            imagingExaminationResult.AnatomicalSite.Any())
                        {
                            foreach (var anatomicalSite in imagingExaminationResult.AnatomicalSite.Where(anatomicalSite => anatomicalSite.Images != null && anatomicalSite.Images.Any()))
                            {
                              relationshipList.AddRange(CreateRelationshipsForEachImage(anatomicalSite.Images));
                            }
                        }

                        //Imaging examination result status
                        if (imagingExaminationResult.ExaminationResultStatus != null)
                        {
                            relationshipList.Add(CreateRelationshipForTestResultStatus(imagingExaminationResult.ExaminationResultStatus.Value));
                        }

                        //Clinical information provided
                        if (!String.IsNullOrEmpty(imagingExaminationResult.ClinicalInformationProvided))
                        {
                            relationshipList.Add(CreateRelationshipForProvidedClinicalInformation(imagingExaminationResult.ClinicalInformationProvided));
                        }

                        //Findings
                        if (!String.IsNullOrEmpty(imagingExaminationResult.Findings))
                        {
                            relationshipList.Add(CreateRelationshipForFindings(imagingExaminationResult.Findings));
                        }

                        //Examination result group
                        if (imagingExaminationResult.ResultGroup != null &&  imagingExaminationResult.ResultGroup.Any())
                        {
                            relationshipList.AddRange(CreateRelationshipForEachImagingResultGroup(imagingExaminationResult.ResultGroup));
                        }

                        //Examination result date / time 
                        if (imagingExaminationResult.ResultDateTime != null)
                        {
                            relationshipList.Add(CreateRelationshipForDateTime(imagingExaminationResult.ResultDateTime));
                        }

                        //Examination request details
                        if (imagingExaminationResult.ExaminationRequestDetails != null)
                        {
                            relationshipList.AddRange(CreateRelationshipForExaminationRequest(imagingExaminationResult.ExaminationRequestDetails));
                        }

                        //Create the observation entry with all the above relationships nested inside the observation
                        entryList.Add(CreateEntryObservation(x_ActRelationshipEntry.COMP,
                                                             CreateConceptDescriptor(
                                                                 imagingExaminationResult.ExaminationResultName),
                                                             new[]
                                                                 {
                                                                     CreateCodedWithExtensionElement(imagingExaminationResult.Modality)
                                                                 },
                                                             imagingExaminationResult.AnatomicalSite == null ? null : CreateConceptDescriptorsForAnatomicalSites(
                                                                     imagingExaminationResult.AnatomicalSite).ToArray(),
                                                             null, 
                                                             null, 
                                                             null, 
                                                             relationshipList,
                                                             imagingExaminationResult.ExaminationResultRepresentation));

                        imagingExaminationResultComponent.section.entry = entryList.ToArray();
                        imagingExaminationResultComponent.section.text = imagingExaminationResult.CustomNarrativeImagingExaminationResult ?? narrativeGenerator.CreateNarrative(imagingExaminationResult);

                        componentList.Add(imagingExaminationResultComponent);
                    }
                }

            if (diagnosticInvestigations.OtherTestResult != null && diagnosticInvestigations.OtherTestResult.Any())
            {
                componentList.AddRange(diagnosticInvestigations.OtherTestResult.Select(otherTestResult => CreateOtherTestResult(otherTestResult, narrativeGenerator)));
            }

              component.section.component = componentList.ToArray();
            }

            return component;
        }

      internal static POCD_MT000040Component5 CreateOtherTestResult(OtherTestResult otherTestResult, INarrativeGenerator narrativeGenerator)
      {
          POCD_MT000040Component5 otherTestResultComponent;

          var relationshipList = new List<POCD_MT000040EntryRelationship>();
          var entryList = new List<POCD_MT000040Entry>();

          //Create the otherTestResultComponent and section
          otherTestResultComponent = new POCD_MT000040Component5
          {
            section = CreateSectionCodeTitle("102.16029", CodingSystem.NCTIS, "Diagnostic Investigation")
          };

          if (otherTestResult.ReportStatus.HasValue)
            relationshipList.Add(CreateRelationshipForTestResultStatus(otherTestResult.ReportStatus.Value));

          // External Data
          if (otherTestResult.ReportContent != null && otherTestResult.ReportContent.ExternalData != null)
          {
            relationshipList.Add(new POCD_MT000040EntryRelationship
            {
              typeCode = x_ActRelationshipEntryRelationship.REFR,
              observationMedia = CreateObservationMedia(otherTestResult.ReportContent.ExternalData)
            });
          }

          //Create the observation entry with all the above relationships nested inside the observation
          var entry = CreateEntryObservation(x_ActRelationshipEntry.COMP,
                                            CreateConceptDescriptor(otherTestResult.ReportName),
                                            otherTestResult.ReportDate,
                                            relationshipList
                                            );

          // Report Content
          if (otherTestResult.ReportContent != null)
          {
            // Encapsulated Text
            if (!otherTestResult.ReportContent.Text.IsNullOrEmptyWhitespace())
            {
              entry.observation.value = new ANY[] { CreateEncapsulatedData(otherTestResult.ReportContent.Text) };
            }
            // External Data
            else if (otherTestResult.ReportContent.ExternalData != null)
            {
              entry.observation.value = new ANY[] { CreateEncapsulatedData(otherTestResult.ReportContent.ExternalData) };
            }
          }

          entryList.Add(entry);

          otherTestResultComponent.section.text = otherTestResult.CustomNarrative ?? narrativeGenerator.CreateNarrative(otherTestResult);
          otherTestResultComponent.section.entry = entryList.ToArray();

          return otherTestResultComponent;
        } 

        /// <summary>
        /// Creates a Response Details component
        /// </summary>
        /// <param name="responseDetails">IResponseDetails</param>
        /// <param name="narrativeGenerator">The narrative generator</param>
        /// <returns>POCD_MT000040Component3</returns>
        internal static POCD_MT000040Component3 CreateComponent(IResponseDetails responseDetails, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            var entryList = new List<POCD_MT000040Entry>();

            var componetList = new List<POCD_MT000040Component5>();

            if (responseDetails != null)
            {
                component = new POCD_MT000040Component3 { section = CreateSectionCodeTitle("101.16611", CodingSystem.NCTIS, "Response Details") };

                //Procedures
                if (responseDetails.Procedures != null && responseDetails.Procedures.Any())
                {
                  entryList.AddRange(responseDetails.Procedures.Select(procedure => CreateEntryProcedureEvent(CreateConceptDescriptor(procedure.ProcedureName))));
                }

                //Diagnosis
                if (responseDetails.Diagnoses != null && responseDetails.Diagnoses.Any())
                {
                    foreach (var diagnosis in responseDetails.Diagnoses)
                    {
                        entryList.Add(CreateEntryObservation(CreateConceptDescriptor("282291009", CodingSystem.SNOMED, null,"Diagnosis interpretation", null), CreateConceptDescriptor(diagnosis)));
                    }
                }

                //Other Diagnosis
                if (responseDetails.Diagnoses != null && responseDetails.Diagnoses.Any())
                {
                    if (responseDetails.OtherDiagnosisEntries != null)
                        foreach (var otherDiagnosis in responseDetails.OtherDiagnosisEntries)
                        {
                            entryList.Add(CreateEntryActEvent(CreateConceptDescriptor("102.15513.132.1.1", CodingSystem.NCTIS, null, "Other Diagnosis Procedure Entry", null), CreateStructuredText(otherDiagnosis, null)));
                        }
                }

                //Response narrative
                if (responseDetails.ResponseNarrative != null)
                {
                    entryList.Add(CreateEntryActEvent(CreateConceptDescriptor("102.15513.132.1.2", CodingSystem.NCTIS, null, "Response Narrative", null), CreateStructuredText(responseDetails.ResponseNarrative, null)));
                }

                component.section.component = componetList.ToArray();
            }

            if (component != null && entryList.Any())
            {
                component.section.entry = entryList.ToArray();
                component.section.text = responseDetails.CustomNarrativeResponseDetails ?? narrativeGenerator.CreateNarrative(responseDetails);
            }

            return component;
        }

        /// <summary>
        /// Creates a Recommendations component
        /// </summary>
        /// <param name="recommendations">IRecommendations</param>
        /// <param name="narrativeGenerator">narrative generator</param>
        /// <returns>POCD_MT000040Component3</returns>
        internal static POCD_MT000040Component3 CreateComponent(IRecommendations recommendations, INarrativeGenerator narrativeGenerator)
        {
            POCD_MT000040Component3 component = null;

            var entryList = new List<POCD_MT000040Entry>();

            var componetList = new List<POCD_MT000040Component5>();

            if (recommendations != null)
            {
                component = new POCD_MT000040Component3 {section = CreateSectionCodeTitle("101.16606", CodingSystem.NCTIS, "Recommendations")};

                //Recommendation
                if (recommendations.Recommendation != null && recommendations.Recommendation.Any())
                {
                    foreach (var recomendation in recommendations.Recommendation)
                    {
                        //performers
                        List<POCD_MT000040Performer2> performers = null;

                        if (recomendation.Addressee != null)
                        {
                            performers = new List<POCD_MT000040Performer2>();

                            var addressee = recomendation.Addressee;

                            if (addressee.Participant != null)
                            {
                                performers.Add(CreatePerformer(addressee));
                            }
                        }

                        entryList.Add(CreateEntryActEventInterval(CreateConceptDescriptor("102.20016", CodingSystem.NCTIS, null, "Recommendation", null),
                                                                  CreateStructuredText(recomendation.Narrative, null), performers, recomendation.TimeFrame,
                                                                  x_DocumentActMood.PRP));
                    }
                }

                component.section.component = componetList.ToArray();
            }

            // Exclusions
            if (recommendations != null && recommendations.ExclusionStatement != null)
            {
                entryList.Add(CreateExclusionStatement(recommendations.ExclusionStatement, "102.16134", "Recommendations Exclusion"));
            }

            if (component != null && entryList.Any())
            {
                component.section.entry = entryList.ToArray();
                component.section.text = recommendations.CustomNarrativeRecommendations ?? narrativeGenerator.CreateNarrative(recommendations);
            }

            return component;
        }

        /// <summary>
        /// Creates an PrescriptionItem
        /// </summary>
        /// <param name="item">IEPrescriptionItem</param>
        /// <param name="prescriber">IParticipationPrescriber</param>
        /// <param name="subjectOfCare">IParticipationSubjectOfCare</param>
        /// <param name="narrativeGenerator">The narrative generator</param>
        /// <returns>POCD_MT000040Component3</returns>
        internal static POCD_MT000040Component3 CreateComponent(PrescriptionItem item, IParticipationPrescriber prescriber, IParticipationSubjectOfCare subjectOfCare, INarrativeGenerator narrativeGenerator)
        {
          POCD_MT000040Component3 component = null;
          var entries = new List<POCD_MT000040Entry>();

          if (item != null)
          {
              component = new POCD_MT000040Component3
              {
                section = CreateSectionCodeTitle("102.16211", CodingSystem.NCTIS, "Prescription Item")
              };
          }

          // Begin DateTime Prescription Expires
          if (item != null)
          {
            var observation = CreateEntryObservation
              (
                null,
                CreateConceptDescriptor
                  (
                    EtpRecordSections.DateTimePrescriptionExpires.GetAttributeValue<NameAttribute, String>(x => x.Code),
                    CodingSystem.NCTIS,
                    null,
                    EtpRecordSections.DateTimePrescriptionExpires.GetAttributeValue<NameAttribute, String>(x => x.Name),
                    null
                  ),
                item.DateTimePrescriptionExpires,
                null,
                null,
                null
              );

            // allow null flavor if DateTime Prescription Expires omitted
            if (item.DateTimePrescriptionExpires == null)
              observation.observation.effectiveTime = new IVL_TS {nullFlavor = NullFlavor.NA, nullFlavorSpecified = true};

            entries.Add(observation);

          var relationships = new List<POCD_MT000040EntryRelationship>();

          //// Formula
          if (!item.Formula.IsNullOrEmptyWhitespace())
          {
            relationships.Add
                (
                    CreateEntryRelationshipACT
                        (
                            x_ActRelationshipEntryRelationship.COMP,
                            x_ActClassDocumentEntryAct.INFRM,
                            x_DocumentActMood.RQO,
                            false,
                            CreateConceptDescriptor
                                (
                                    EtpRecordSections.Formula.GetAttributeValue<NameAttribute, String>(x => x.Code),
                                    CodingSystem.NCTIS,
                                    null,
                                    EtpRecordSections.Formula.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                    null
                                ),
                            CreateEncapsulatedData(item.Formula),
                            CreateIdentifierArray(new UniqueId())
                        )
                );
          }

          // Supply
          var entryRelationship = new POCD_MT000040EntryRelationship
          {
            typeCode = x_ActRelationshipEntryRelationship.COMP,
            supply = new POCD_MT000040Supply
            {
              moodCode = x_DocumentSubstanceMood.RQO,
              id = CreateIdentifierArray(CreateGuid(), null),
              independentInd = new BL { value = false, valueSpecified = true },
              effectiveTime = item.DispensingInformation != null && item.DispensingInformation.MinimumIntervalBetweenRepeats != null ? new[]
                                   {
                                      // MinimumIntervalBetweenRepeats
                                      new PIVL_TS 
                                          {
                                              period = new PQ
                                                         {
                                                           value = item.DispensingInformation.MinimumIntervalBetweenRepeats.IntervalWidth.Value,
                                                           unit = item.DispensingInformation.MinimumIntervalBetweenRepeats.IntervalWidth.Unit.GetAttributeValue<NameAttribute, string>(x => x.Code)   
                                                         }
                                          }
                                   } : null,
              // Begin Brand Substitute allowed
              subjectOf2 = item.BrandSubstitutionPermitted.HasValue ?
                           CreateBrandSubstituteAllowed
                            (
                                ActClass.SUBST,
                                ActMood.PERM,
                                CreateCodedWithExtensionElement
                                (
                                     "TE",
                                     CodingSystem.HL7SubstanceAdminSubstitution,
                                     null,
                                     "Therapeutic",
                                     null,
                                     null
                                )
                             ) : null,
            entryRelationship = item.DispensingInformation != null && !item.DispensingInformation.QuantityDescription.IsNullOrEmptyWhitespace() ? new []
                                  {
                                     CreateEntryRelationshipACT
                                    (
                                        x_ActRelationshipEntryRelationship.COMP,
                                        x_ActClassDocumentEntryAct.INFRM,
                                        x_DocumentActMood.RQO,
                                        false,
                                        CreateConceptDescriptor(CreateCodableText("2456512002","2.16.840.1.113883.6.96","SNOMED CT", null, "Quantity Description", null)),
                                        CreateEncapsulatedData(item.DispensingInformation.QuantityDescription),
                                        CreateIdentifierArray(new UniqueId())
                                    ) 
                                  }: null

            },
          };

          relationships.Add(entryRelationship);

          // Reason For Therapeutic Good
          if (item.ClinicalIndication != null)
          {
            relationships.Add
                (
                    CreateEntryRelationshipACT
                        (
                            x_ActRelationshipEntryRelationship.RSON,
                            x_ActClassDocumentEntryAct.INFRM,
                            x_DocumentActMood.RQO,
                            false,
                            CreateConceptDescriptor
                                (
                                    EtpRecordSections.ReasonForTherapeuticGood.GetAttributeValue<NameAttribute, String>(x => x.Code),
                                    CodingSystem.NCTIS,
                                    null,
                                    EtpRecordSections.ReasonForTherapeuticGood.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                    null
                                ),
                            CreateEncapsulatedData(item.ClinicalIndication),
                            CreateIdentifierArray(new UniqueId())
                        )
                );
          }

          // Additional comments
          if (!String.IsNullOrEmpty(item.Comment))
          {
            relationships.Add(
                CreateEntryRelationshipACT
                    (
                        x_ActRelationshipEntryRelationship.COMP,
                        x_ActClassDocumentEntryAct.INFRM,
                        x_DocumentActMood.EVN,
                        false,
                        CreateConceptDescriptor
                            (
                                EtpRecordSections.AdditionalComments.GetAttributeValue<NameAttribute, String>(x => x.Code),
                                CodingSystem.NCTIS,
                                null,
                                EtpRecordSections.AdditionalComments.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                null
                            ),
                        CreateEncapsulatedData(item.Comment),
                        CreateIdentifierArray(new UniqueId())
                    )
                );
          }

          // Additional comments
          if (!String.IsNullOrEmpty(item.TherapeuticGoodStrength))
          {
            relationships.Add(
                CreateEntryRelationshipACT
                    (
                        x_ActRelationshipEntryRelationship.COMP,
                        x_ActClassDocumentEntryAct.INFRM,
                        x_DocumentActMood.RQO,
                        false,
                        CreateConceptDescriptor
                            (
                                "103.16769.170.1.1",
                                CodingSystem.NCTIS,
                                null,
                                EtpRecordSections.TherapeuticGoodStrength.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                null
                            ),
                        CreateEncapsulatedData(item.TherapeuticGoodStrength),
                        CreateIdentifierArray(new UniqueId())
                    )
                );
          }

          // Begin Prescription Item entry
          var entry = CreateEntrySubstanceAdministrationEvent
              (
                  null,
                  x_DocumentSubstanceMood.RQO,
                  true,
                  null,
                  null,
                  null,
                  null,
                  CreateCodedWithExtensionElement
                      (
                          item.TherapeuticGoodId
                      ),
                  item.DispensingInformation != null && item.DispensingInformation.MaximumNumberOfRepeats.HasValue ? item.DispensingInformation.MaximumNumberOfRepeats : null,
                  item.TherapeuticGoodGenericName,
                  item.Form,
                  item.Route,
                  item.PBSManufacturerCode,
                  relationships
              );

          // Prescription Item Id
          // root = Data Component Register - Set Prescription Item Identifier 
          if (item.PrescriptionItemIdentifier != null)
          entry.substanceAdministration.id = CreateIdentifierArray(item.PrescriptionItemIdentifier);

          // Directions
          if (!item.Directions.IsNullOrEmptyWhitespace())
          {
            entry.substanceAdministration.text = CreateEncapsulatedData(item.Directions);  
          }

          entries.Add(entry);
          }

          // Add component entry array
          if (component != null) component.section.entry = entries.ToArray();

          // List of Coverage2
          var coverages = new List<Coverage2>();
          // Entitlements Subject Of Care
          if (subjectOfCare.Participant.Entitlements != null && subjectOfCare.Participant.Entitlements.Count > 0)
          {
            coverages.AddRange(CreateEntitlements(subjectOfCare.Participant.Entitlements, subjectOfCare.Participant.UniqueIdentifier.ToString(), RoleClass.PAT, ParticipationType.BEN).ToArray());
          }
          // Entitlements Participation Prescriber
          if (prescriber.Participant.Person.Entitlements != null && prescriber.Participant.Person.Entitlements.Count > 0)
          {
            coverages.AddRange(CreateEntitlements(prescriber.Participant.Person.Entitlements, prescriber.Participant.UniqueIdentifier.ToString(), RoleClass.ASSIGNED, ParticipationType.HLD).ToArray());
          }

          if (component != null)
          {
            component.section.coverage2 = coverages.ToArray();
          }

          component.section.entry = entries.ToArray();
          component.section.text = item.CustomNarrativePrescriptionItem ?? narrativeGenerator.CreateNarrative(item, prescriber, subjectOfCare);

          return component;
        }

      /// <summary>
      /// Creates an Dispense Item
      /// </summary>
      /// <param name="item">IEPrescriptionItem</param>
        /// <param name="dispenser">IParticipationDispenser</param>
      /// <param name="dispenserOrganisation">IParticipationPrescriber</param>
      /// <param name="subjectOfCare">IParticipationSubjectOfCare</param>
      /// <param name="narrativeGenerator">The narrative generator</param>
      /// <returns>POCD_MT000040Component3</returns>
      internal static POCD_MT000040Component3 CreateComponent(DispenseItem item, IParticipationDispenser dispenser, IParticipationDispenserOrganisation dispenserOrganisation, IParticipationSubjectOfCare subjectOfCare, INarrativeGenerator narrativeGenerator)
        {
          POCD_MT000040Component3 component = null;
          var entries = new List<POCD_MT000040Entry>();

          if (item != null)
          {
            component = new POCD_MT000040Component3
            {
                section = CreateSectionCodeTitle("102.16210", CodingSystem.NCTIS, "Dispense Item")
            };

            var relationships = new List<POCD_MT000040EntryRelationship>();

            // Supply
            relationships.Add(new POCD_MT000040EntryRelationship
            {
              typeCode = x_ActRelationshipEntryRelationship.COMP,
              sequenceNumber = item.NumberOfThisDispense.HasValue ? new INT { value = item.NumberOfThisDispense.Value.ToString(CultureInfo.InvariantCulture) } : null,
              supply = new POCD_MT000040Supply
              {
                effectiveTime = new[] { new SXCM_TS { value = item.DateTimeOfDispenseEvent.ToString() } },
                moodCode = x_DocumentSubstanceMood.EVN,
                independentInd = new BL { value = false, valueSpecified = true },
                                                    product = new POCD_MT000040Product
                                                                {
                                                                 manufacturedProduct = new POCD_MT000040ManufacturedProduct
                                                                          {
                                                                            manufacturedMaterial = new POCD_MT000040Material
                                                                            {
                                                                               code = item.TherapeuticGoodId != null ? CreateCodedWithExtensionElement(item.TherapeuticGoodId) : null ,
                                                                               name = item.TherapeuticGoodGenericName.IsNullOrEmptyWhitespace() ? null :  new EN { Text = new[] { item.TherapeuticGoodGenericName } },
                                                                               formCode = item.Form != null ? CreateConceptDescriptor(item.Form) : null,
                                                                               desc = !item.AdditionalDispensedItemDescription.IsNullOrEmptyWhitespace() ? CreateStructuredText(item.AdditionalDispensedItemDescription, null) : null
                                                                            },
                                                                            manufacturerOrganization = item.PBSManufacturerCode != null ? new POCD_MT000040Organization
                                                                            {
                                                                               id = CreateIdentifierArray(item.PBSManufacturerCode)
                                                                            } : null
                                                                          },
                                                                },
                                                     id = item.DispenseItemIdentifier != null ? CreateIdentifierArray(item.DispenseItemIdentifier) : null,
                                                     entryRelationship = new [] 
                                                                         {
                                                                           !item.QuantityDescription.IsNullOrEmptyWhitespace() ? CreateEntryRelationshipACT
                                                                           (
                                                                              x_ActRelationshipEntryRelationship.COMP,
                                                                              x_ActClassDocumentEntryAct.INFRM,
                                                                              x_DocumentActMood.EVN,
                                                                              false,
                                                                              CreateConceptDescriptor(CreateCodableText("2456512002","2.16.840.1.113883.6.96","SNOMED CT", null, "Quantity Description", null)),
                                                                              CreateEncapsulatedData(item.QuantityDescription),
                                                                              CreateIdentifierArray(new UniqueId())
                                                                            ) : null,

                                                                           !item.UniquePharmacyPrescriptionNumber.IsNullOrEmptyWhitespace() ? CreateEntryRelationshipACT
                                                                           (
                                                                              x_ActRelationshipEntryRelationship.COMP,
                                                                              x_ActClassDocumentEntryAct.ACT,
                                                                              x_DocumentActMood.EVN,
                                                                              false,
                                                                              CreateConceptDescriptor(
                                                                                            CreateCodableText(EtpRecordSections.UniquePharmacyPrescriptionNumber.GetAttributeValue<NameAttribute, String>(x => x.Code),
                                                                                                              CodingSystem.NCTIS.GetAttributeValue<NameAttribute, String>(x => x.Code),
                                                                                                              CodingSystem.NCTIS.GetAttributeValue<NameAttribute, String>(x => x.Name), 
                                                                                                              null, 
                                                                                                              EtpRecordSections.UniquePharmacyPrescriptionNumber.GetAttributeValue<NameAttribute, String>(x => x.Name), 
                                                                                                              null)
                                                                                                      ),
                                                                              CreateEncapsulatedData(item.UniquePharmacyPrescriptionNumber),
                                                                              CreateIdentifierArray(new UniqueId())
                                                                            ) : null,
                                                                           !item.LabelInstruction.IsNullOrEmptyWhitespace() ? CreateEntryRelationshipACT
                                                                           (
                                                                              x_ActRelationshipEntryRelationship.COMP,
                                                                              x_ActClassDocumentEntryAct.INFRM,
                                                                              x_DocumentActMood.EVN,
                                                                              false,
                                                                              CreateConceptDescriptor(
                                                                                          CreateCodableText(EtpRecordSections.LabelInstruction.GetAttributeValue<NameAttribute, String>(x => x.Code), 
                                                                                                            CodingSystem.NCTIS.GetAttributeValue<NameAttribute, String>(x => x.Code), 
                                                                                                            CodingSystem.NCTIS.GetAttributeValue<NameAttribute, String>(x => x.Name), 
                                                                                                            null, 
                                                                                                            EtpRecordSections.LabelInstruction.GetAttributeValue<NameAttribute, String>(x => x.Name), 
                                                                                                            null)
                                                                                                   ), 
                                                                              CreateStructuredText(item.LabelInstruction, null),
                                                                              CreateIdentifierArray(new UniqueId())
                                                                            ) : null,
                                                                           item.BrandSubstitutionOccurred.HasValue ? CreateEntryRelationshipObservation
                                                                           (
                                                                              x_ActRelationshipEntryRelationship.COMP,
                                                                              false,
                                                                              CreateConceptDescriptor(
                                                                                          CreateCodableText(EtpRecordSections.BrandSubstitutionOccured.GetAttributeValue<NameAttribute, String>(x => x.Code), 
                                                                                                            CodingSystem.NCTIS.GetAttributeValue<NameAttribute, String>(x => x.Code), 
                                                                                                            CodingSystem.NCTIS.GetAttributeValue<NameAttribute, String>(x => x.Name), 
                                                                                                            null, 
                                                                                                            EtpRecordSections.BrandSubstitutionOccured.GetAttributeValue<NameAttribute, String>(x => x.Name), 
                                                                                                            null)
                                                                                                   ), 
                                                                              new List<ANY>{ new BL { value = item.BrandSubstitutionOccurred.Value, valueSpecified = true}}
                                                                            ) : null
                                                                         },
              },
            });

            // Comments
            if (!String.IsNullOrEmpty(item.Comment))
            {
              relationships.Add(
                  CreateEntryRelationshipACT
                      (
                          x_ActRelationshipEntryRelationship.COMP,
                          x_ActClassDocumentEntryAct.INFRM,
                          x_DocumentActMood.EVN,
                          false,
                          CreateConceptDescriptor
                              (
                                  EtpRecordSections.AdditionalComments.GetAttributeValue<NameAttribute, String>(x => x.Code),
                                  CodingSystem.NCTIS,
                                  null,
                                  EtpRecordSections.AdditionalComments.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                  null
                              ),
                          CreateEncapsulatedData(item.Comment),
                          CreateIdentifierArray(new UniqueId())
                      )
                  );
            }

            //// Formula
            if (!item.Formula.IsNullOrEmptyWhitespace())
            {
              relationships.Add
                  (
                      CreateEntryRelationshipACT
                          (
                              x_ActRelationshipEntryRelationship.COMP,
                              x_ActClassDocumentEntryAct.INFRM,
                              x_DocumentActMood.EVN,
                              false,
                              CreateConceptDescriptor
                                  (
                                      EtpRecordSections.Formula.GetAttributeValue<NameAttribute, String>(x => x.Code),
                                      CodingSystem.NCTIS,
                                      null,
                                      EtpRecordSections.Formula.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                      null
                                  ),
                              CreateEncapsulatedData(item.Formula),
                              CreateIdentifierArray(new UniqueId())
                          )
                  );
            }

            // Additional comments
            if (!String.IsNullOrEmpty(item.TherapeuticGoodStrength))
            {
              relationships.Add(
                  CreateEntryRelationshipACT
                      (
                          x_ActRelationshipEntryRelationship.COMP,
                          x_ActClassDocumentEntryAct.INFRM,
                          x_DocumentActMood.EVN,
                          false,
                          CreateConceptDescriptor
                              (
                                  EtpRecordSections.TherapeuticGoodStrength.GetAttributeValue<NameAttribute, String>(x => x.Code),
                                  CodingSystem.NCTIS,
                                  null,
                                  EtpRecordSections.TherapeuticGoodStrength.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                  null
                              ),
                          CreateEncapsulatedData(item.TherapeuticGoodStrength),
                          CreateIdentifierArray(new UniqueId())
                      )
                  );
            }

            // Begin Prescription Item entry
            var entry = CreateEntrySubstanceAdministrationEvent
                (
                    null,
                    x_DocumentSubstanceMood.RQO,
                    true,
                    item.Status.HasValue ? item.Status.Value.GetAttributeValue<NameAttribute, String>(x => x.Name) : null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    item.MaximumNumberOfRepeats != null && item.MaximumNumberOfRepeats.HasValue ? item.MaximumNumberOfRepeats : null,
                    null,
                    null,
                    null,
                    null,
                    relationships
                );

            // Prescription Item Id
            // root = Data Component Register - Set Prescription Item Identifier 
            if (item.PrescriptionItemIdentifier != null)
            {
              entry.substanceAdministration.id = CreateIdentifierArray(item.PrescriptionItemIdentifier);
            } else
            {
              entry.substanceAdministration.id = null;
            }

            entries.Add(entry);
          }

          // Add component entry array
          if (component != null) component.section.entry = entries.ToArray();

          // List of Coverage2
          var coverages = new List<Coverage2>();
          // Entitlements Subject Of Care
          if (subjectOfCare.Participant.Entitlements != null && subjectOfCare.Participant.Entitlements.Count > 0)
          {
            coverages.AddRange(CreateEntitlements(subjectOfCare.Participant.Entitlements, subjectOfCare.Participant.UniqueIdentifier.ToString(), RoleClass.PAT, ParticipationType.BEN).ToArray());
          }
          // Entitlements Participation Prescriber
          if (dispenserOrganisation.Participant.Entitlements != null && dispenserOrganisation.Participant.Entitlements.Count > 0)
          {
            coverages.AddRange(CreateEntitlements(dispenserOrganisation.Participant.Entitlements, dispenserOrganisation.Participant.UniqueIdentifier.ToString(), RoleClass.SDLOC, ParticipationType.HLD).ToArray());
          }

          if (component != null)
          {
            component.section.coverage2 = coverages.ToArray();
          }

          component.section.entry = entries.ToArray();
          component.section.text = item.CustomNarrativeDispenseItem ?? narrativeGenerator.CreateNarrative(item, dispenser, dispenserOrganisation, subjectOfCare);

          return component;
        }

        #region Create Component - Supporting Methods

        private static List<POCD_MT000040EntryRelationship> CreateRelationshipsForEachImage(
            ICollection<ExternalData> images)
        {
            List<POCD_MT000040EntryRelationship> relationshipList = null;

            if (images != null && images.Any())
            {
                relationshipList = new List<POCD_MT000040EntryRelationship>();

                foreach (var image in images)
                {

                    var relationShip = new POCD_MT000040EntryRelationship
                                           {
                                               typeCode = x_ActRelationshipEntryRelationship.REFR,
                                               observationMedia = CreateObservationMedia(image)
                                           };

                    relationshipList.Add(relationShip);
                }
            }

            return relationshipList;
        }

        private static List<POCD_MT000040EntryRelationship> CreateRelationshipForMedication(IMedicationItem medication,string commentDisplayName)
        {

            var changeTypeRelationshipList = new List<POCD_MT000040EntryRelationship>
                                                 {
                                                     CreateEntryRelationshipObservation(
                                                         x_ActRelationshipEntryRelationship.COMP,
                                                         CreateConceptDescriptor("103.16595", CodingSystem.NCTIS, null, "Recommendation or Change", null),
                                                         CreateConceptDescriptorFromEnum(medication.RecommendationOrChange,CodingSystem.NCTISRecommendationOrChangeValues, medication.RecommendationOrChangeNullFlavour)),
                                                         String.IsNullOrEmpty(medication.ChangeReason)
                                                         ? null
                                                         : CreateEntryRelationshipACT(
                                                             x_ActRelationshipEntryRelationship.RSON,
                                                             x_ActClassDocumentEntryAct.INFRM, x_DocumentActMood.EVN,
                                                             false,
                                                             CreateConceptDescriptor("103.10177", CodingSystem.NCTIS,null, "Change Reason", null),
                                                             CreateStructuredText(medication.ChangeReason, null), null),
                                                 };


            var relationshipList = new List<POCD_MT000040EntryRelationship>
                                       {
                                           String.IsNullOrEmpty(medication.ClinicalIndication)
                                               ? null
                                               : CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.RSON,
                                                                            x_ActClassDocumentEntryAct.INFRM,
                                                                            x_DocumentActMood.EVN, false,
                                                                            CreateConceptDescriptor("103.10141",
                                                                                                    CodingSystem.NCTIS,
                                                                                                    null,
                                                                                                    "Clinical Indication",
                                                                                                    null),
                                                                            CreateStructuredText(
                                                                                medication.ClinicalIndication, null),
                                                                            null),
                                           String.IsNullOrEmpty(medication.Comment)
                                               ? null
                                               : CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.COMP,
                                                                            x_ActClassDocumentEntryAct.INFRM,
                                                                            x_DocumentActMood.EVN, false,
                                                                            CreateConceptDescriptor("103.16044",
                                                                                                    CodingSystem.NCTIS,
                                                                                                    null,
                                                                                                    commentDisplayName,
                                                                                                    null),
                                                                            CreateStructuredText(medication.Comment,
                                                                                                 null),
                                                                            CreateIdentifierArray(CreateGuid())),
                                           CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.SPRT,
                                                                              true,
                                                                              CreateConceptDescriptor("103.16593",
                                                                                                      CodingSystem.NCTIS,
                                                                                                      null,
                                                                                                      "Change Type",
                                                                                                      null),
                                                                              medication.ChangeDescription,
                                                                              new List<ANY>
                                                                                  {
                                                                                      CreateConceptDescriptorFromEnum(medication.ChangeType, CodingSystem.NCTISChangeTypeValues, medication.ChangeTypeNullFlavour)
                                                                                  },
                                                                              changeTypeRelationshipList)
                                       };

            return relationshipList;
        }

        private static POCD_MT000040EntryRelationship CreateRelationshipForFindings(String findings)
        {
            POCD_MT000040EntryRelationship relationship = null;

            if (!String.IsNullOrEmpty(findings))
            {
                relationship = CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.REFR,
                                                                  CreateConceptDescriptor("103.16503",CodingSystem.NCTIS, null,"Findings", null), null,
                                                                  CreateStructuredText(findings, null));
            }

            return relationship;
        }

        private static List<POCD_MT000040EntryRelationship> CreateRelationshipForEachImagingResultGroup(ICollection<IImagingResultGroup> resultGroups)
        {
            List<POCD_MT000040EntryRelationship> relationshipList = null;

            if (resultGroups != null && resultGroups.Any())
            {
                relationshipList = new List<POCD_MT000040EntryRelationship>();

                foreach (var resultGroup in resultGroups)
                {
                    var relationShip = CreateEntryRelationshipOrganiser(x_ActRelationshipEntryRelationship.COMP,
                                                                        x_ActClassDocumentEntryOrganizer.BATTERY,
                                                                        ActMood.EVN, null,
                                                                        CreateConceptDescriptor(resultGroup.ResultGroupName), null,
                                                                        resultGroup.Results, resultGroup.AnatomicalSite,
                                                                        StatusCode.Completed);

                    relationshipList.Add(relationShip);
                }
            }

            return relationshipList;
        }

        private static List<POCD_MT000040Entry> CreateAdministeredImmunisations(ICollection<IImmunisation> immunisations)
        {
            var entryList = new List<POCD_MT000040Entry>();

            if (immunisations != null && immunisations.Any())
            {
                entryList = new List<POCD_MT000040Entry>();

                foreach (var imunisation in immunisations)
                {
                    //Build a list of administed imunisations sequence numbers
                    var relationships = new List<POCD_MT000040EntryRelationship>();
                    if (imunisation.SequenceNumber.HasValue)
                    {
                        relationships.Add(CreateEntryRelationshipSupply(ActClassSupply.SPLY,
                                                                        x_ActRelationshipEntryRelationship.COMP,
                                                                        x_DocumentSubstanceMood.EVN, false, null, null,
                                                                        null, imunisation.SequenceNumber, false, null));
                    }

                    //Create the administration event, and pass in the imunisation sequence numbers
                    if (imunisation.Medicine != null)
                    {
                        entryList.Add(CreateEntrySubstanceAdministrationEvent(x_ActRelationshipEntry.COMP,
                                                                              x_DocumentSubstanceMood.EVN, false, null,
                                                                              null, null, imunisation.DateTime,
                                                                              CreateCodedWithExtensionElement(
                                                                                  imunisation.Medicine.Code,
                                                                                  imunisation.Medicine.CodeSystemCode,
                                                                                  imunisation.Medicine.CodeSystemName,
                                                                                  imunisation.Medicine.CodeSystemVersion, 
                                                                                  null,
                                                                                  imunisation.Medicine.DisplayName,
                                                                                  imunisation.Medicine.OriginalText,
                                                                                  null), 
                                                                              null, relationships));
                    }
                }
            }

            return entryList;
        }

        private static POCD_MT000040Entry CreateAdministrationObservationAge(DateAccuracyIndicator dateAccuracyIndicator, String accuracyIndicatorType, String accuracyIndicatorTypeCode)
        {
            POCD_MT000040Entry entry = null;

            if (dateAccuracyIndicator != null)
            {
                var dateAccuracyIndicatorEnum = dateAccuracyIndicator.ConvertToEnum();

                var anyList = new List<ANY>();

                //person.DateOfBirthAccuracyIndicator
                anyList.Clear();
                anyList.Add(CreateCodeSystem(dateAccuracyIndicatorEnum.ToString(), null, null, null, dateAccuracyIndicatorEnum.GetAttributeValue<NameAttribute, String>(x => x.Name), null, null));
                entry = CreateEntryObservation(x_ActRelationshipEntry.DRIV,
                                               CreateConceptDescriptor(accuracyIndicatorTypeCode, CodingSystem.NCTIS, null, accuracyIndicatorType + " Accuracy Indicator", null), 
                                               null, anyList, null, null);
            }

            return entry;
        }

        private static POCD_MT000040Entry CreateAdministrationObservationMothersOriginalFamilyName(IPersonName personName)
        {
            POCD_MT000040Entry entry = null;

            if (personName != null)
            {
                var anyList = new List<ANY>();

                //person.DateOfBirthAccuracyIndicator
                anyList.Clear();
                anyList.Add(CreatePersonName(personName));
                entry = CreateEntryObservation(x_ActRelationshipEntry.DRIV, CreateConceptDescriptor("103.10245", CodingSystem.NCTIS, null,"Mother's Original Family Name", null), null, anyList, null, null);
            }

            return entry;
        }

        private static POCD_MT000040Entry CreateAdministrationObservationSourceOfDeathNotification(SourceOfDeathNotification? sourceOfDeathNotification)
        {
            POCD_MT000040Entry entry = null;

            if (sourceOfDeathNotification.HasValue)
            {
                var anyList = new List<ANY>();

                anyList.Clear();
                anyList.Add(CreateConceptDescriptor(sourceOfDeathNotification.GetAttributeValue<NameAttribute, String>(x => x.Code),
                                                    CodingSystem.HealthCareClientSourceOfDeathNotification,
                                                    null,
                                                    sourceOfDeathNotification.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                                    null
                                                   ));
                entry = CreateEntryObservation(x_ActRelationshipEntry.DRIV, CreateConceptDescriptor("103.10243",  CodingSystem.NCTIS, null, "Source of Death Notification", null), null, anyList, null, null);
            }

            return entry;
        }

        private static POCD_MT000040Entry CreateAdministrationObservationAge(Int32? age, AgeUnitOfMeasure? ageUnitOfMeasure)
        {
            POCD_MT000040Entry entry = null;

            if (age.HasValue)
            {
                var anyList = new List<ANY>();

                anyList.Clear();
                anyList.Add(new PQ
                                {
                                    value = age.Value.ToString(CultureInfo.InvariantCulture),
                                    unit = ageUnitOfMeasure.HasValue ? ageUnitOfMeasure.Value.GetAttributeValue<NameAttribute, String>(x => x.Code) : AgeUnitOfMeasure.Year.GetAttributeValue<NameAttribute, String>(x => x.Code),
                                });
                entry = CreateEntryObservation(x_ActRelationshipEntry.DRIV, CreateConceptDescriptor("103.20109", CodingSystem.NCTIS, null, "Age", null), null, anyList, null, null);
            }

            return entry;
        }

        private static POCD_MT000040Entry CreateAdministrationObservationBirthPlurality(Int32? birthPlurality)
        {
            POCD_MT000040Entry entry = null;

            if (birthPlurality.HasValue)
            {
                var anyList = new List<ANY>();

                anyList.Clear();
                anyList.Add(CreateIntegerElement(birthPlurality, NullFlavor.NA, false));
                entry = CreateEntryObservation(x_ActRelationshipEntry.DRIV, CreateConceptDescriptor("103.16249", CodingSystem.NCTIS, null, "Birth Plurality", null), null, anyList, null, null);
            }

            return entry;
        }

        private static POCD_MT000040Entry CreateAdministrationObservationAgeAccuracyIndicator(Boolean? ageAccuracyIndicator)
        {
            POCD_MT000040Entry entry = null;

            if (ageAccuracyIndicator.HasValue)
            {
                var anyList = new List<ANY>();

                anyList.Clear();
                anyList.Add(CreateBoolean(ageAccuracyIndicator.Value, true));

                entry = CreateEntryObservation(x_ActRelationshipEntry.DRIV, CreateConceptDescriptor("103.16279", CodingSystem.NCTIS, null, "Age Accuracy Indicator", null), null, anyList, null, null);
            }

            return entry;
        }

        private static POCD_MT000040Entry CreateAdministrationObservationDateOfBirthCalculatedFromAge(Boolean? dateOfBirthCalculatedFromAge)
        {
            POCD_MT000040Entry entry = null;

            if (dateOfBirthCalculatedFromAge.HasValue)
            {
                var anyList = new List<ANY>();

                anyList.Clear();

                anyList.Add(CreateBoolean(dateOfBirthCalculatedFromAge.Value, true, NullFlavor.NA, false));

                entry = CreateEntryObservation(x_ActRelationshipEntry.DRIV, CreateConceptDescriptor("103.16233", CodingSystem.NCTIS, null, "Date of Birth is Calculated From Age", null),null, anyList, null, null);
            }

            return entry;
        }

        private static List<Coverage2> CreateEntitlements(ICollection<Entitlement> entitlements, String id, RoleClass roleClass, ParticipationType participationType)
        {
            List<Coverage2> coverageList = null;

            if (entitlements != null && entitlements.Any())
            {
                coverageList = new List<Coverage2>();

                foreach (var entitlement in entitlements)
                {
                    ICodableText codeableTextEntry = null;

                    if (entitlement.Type != EntitlementType.Undefined)
                    {
                        codeableTextEntry = new CodableText
                                                {
                                                    Code = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Code),
                                                    DisplayName = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                                    OriginalText = entitlement.Type.GetAttributeValue<NameAttribute, String>( x => x.Name),
                                                    CodeSystem = CodingSystem.NCTISEntitlementTypeValues
                                                };
                    }

                    var cdaEntitlement = new HL7.CDA.Entitlement
                                             {
                                                 classCode = EntityClass.COV,
                                                 moodCode = ActMood.EVN,
                                                 id = entitlement.Id == null ? null : CreateIdentifierElement(
                                                             entitlement.Id.AssigningAuthorityName == HealthIdentifierType.HPII.GetAttributeValue<NameAttribute, String>(x => x.Code) ||
                                                             entitlement.Id.AssigningAuthorityName == HealthIdentifierType.HPIO.GetAttributeValue<NameAttribute, String>(x => x.Code) ||
                                                             entitlement.Id.AssigningAuthorityName == HealthIdentifierType.IHI.GetAttributeValue <NameAttribute, String>(x => x.Code) ? 
                                                             HEALTH_IDENTIFIER_QUALIFIER + entitlement.Id.Root : entitlement.Id.Root, entitlement.Id.Extension, null,
                                                             entitlement.Id.AssigningAuthorityName, null),
                                                 code = CreateConceptDescriptor(codeableTextEntry),
                                                 effectiveTime = CreateIntervalTimestamp(entitlement.ValidityDuration)
                                             };

                    var coverage = new Coverage2 {entitlement = cdaEntitlement, typeCode = "COVBY",};

                    var participantRole =  CreateParticipantRole(new Identifier {Root = String.IsNullOrEmpty(id) ? String.Empty : id}, roleClass);

                    cdaEntitlement.participant = new[] {CreateParticipant(participantRole, participationType)};

                    coverageList.Add(coverage);
                }
            }

            return coverageList;
        }

        private static POCD_MT000040EntryRelationship CreateRelationshipForTestResultStatus(ResultStatus resultStatus)
        {
            return CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.COMP, false,
                                                      CreateConceptDescriptor("308552006", CodingSystem.SNOMED, null, "report status", null, Constants.SnomedVersion20110531, null),
                                                      new List<ANY>
                                                          {
                                                              CreateConceptDescriptor(resultStatus.GetAttributeValue<NameAttribute, String>(x => x.Code), CodingSystem.NCTISResultStatusValues, null,
                                                                                      resultStatus.GetAttributeValue<NameAttribute, String>(x => x.Name), null)
                                                          }, 
                                                      false);
        }

        private static POCD_MT000040EntryRelationship CreateRelationshipForTestResultPathologicalDiagnosis(ICollection<ICodableText> pathologicalDiagnosis)
        {
            POCD_MT000040EntryRelationship relationship = null;

            if (pathologicalDiagnosis != null && pathologicalDiagnosis.Any())
            {
                var conceptDescriptorList = pathologicalDiagnosis.Select(diagosis => CreateConceptDescriptor(diagosis)).Cast<ANY>().ToList();

              relationship = CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.REFR, false,
                                                                  CreateConceptDescriptor("88101002",
                                                                                          CodingSystem.SNOMED, null,
                                                                                          "Pathology diagnosis", null, 
                                                                                          Constants.SnomedVersion20110531, 
                                                                                          null),
                                                                  conceptDescriptorList);

            }

            return relationship;
        }

        private static Subject1 CreatePolicy(ActClass actClass, ActMood actMood, String id, CD conceptDescriptor)
        {
            Subject1 subject1 = null;

            if (conceptDescriptor != null)
            {
                subject1 = new Subject1
                               {
                                   policy =
                                       new Policy
                                           {
                                               id = String.IsNullOrEmpty(id) ? null : CreateIdentifierElement(id, null, null),
                                               classCode = actClass,
                                               moodCode = actMood,
                                               code = conceptDescriptor
                                           }
                               };
            }
            return subject1;
        }

        private static Coverage CreatePolicyOrAccount(ActClass actClass, ActMood actMood, String id, CD conceptDescriptor)
        {
            Coverage coverage = null;

            if (conceptDescriptor != null)
            {
                coverage = new Coverage
                               {
                                   policyOrAccount =
                                       new PolicyOrAccount
                                           {
                                               id = String.IsNullOrEmpty(id) ? null : CreateIdentifierElement(id, null, null),
                                               classCode = actClass,
                                               moodCode = actMood,
                                               code = conceptDescriptor
                                           }
                               };
            }
            return coverage;
        }

        private static Subject2 CreateBrandSubstituteAllowed(ActClass actClass, ActMood actMood, CE codedWithExtensionElement)
        {
            Subject2 subject2 = null;

            if (codedWithExtensionElement != null)
            {
                subject2 = new Subject2
                               {
                                   substitutionPermission = new SubstitutionPermission {classCode = actClass, moodCode = actMood, code = codedWithExtensionElement}
                               };
            }
            return subject2;
        }

        private static POCD_MT000040EntryRelationship CreateRelationshipForTestResultConculsion(String conclusion)
        {
            POCD_MT000040EntryRelationship relationship = null;

            if (!String.IsNullOrEmpty(conclusion))
            {
                relationship = CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.REFR, false,
                                                                  CreateConceptDescriptor("386344002",
                                                                                          CodingSystem.SNOMED, null,
                                                                                          "Laboratory findings data interpretation",
                                                                                          null, 
                                                                                          Constants.SnomedVersion20110531,
                                                                                          null),
                                                                  new List<ANY> {CreateStructuredText(conclusion, null)});
            }

            return relationship;
        }

        private static POCD_MT000040EntryRelationship CreateRelationshipForTestResultComment(String comment)
        {
            return CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.COMP, x_ActClassDocumentEntryAct.INFRM,
                                              x_DocumentActMood.EVN, null,
                                              CreateConceptDescriptor("103.16468", CodingSystem.NCTIS, null, "Test Comment", null),
                                              CreateStructuredText(comment, null), null);
        }

        private static POCD_MT000040EntryRelationship CreateRelationshipForTestResultDateTime(ISO8601DateTime dateTime)
        {
            POCD_MT000040EntryRelationship relationship = null;

            if (dateTime != null)
            {
                relationship = CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.COMP, false,
                                                                  dateTime,
                                                                  CreateConceptDescriptor("103.16605",
                                                                                          CodingSystem.NCTIS, null,
                                                                                          "Pathology Test Result DateTime",
                                                                                          null));
            }
            return relationship;
        }

        private static POCD_MT000040EntryRelationship CreateRelationshipForTestRequestDetails(ITestRequest request)
        {


            POCD_MT000040EntryRelationship relationship = null;

            if (request != null)
            {
                relationship = CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.SUBJ,
                                                          x_ActClassDocumentEntryAct.ACT, x_DocumentActMood.EVN, true,
                                                          CreateConceptDescriptor("102.16160", CodingSystem.NCTIS, null, "Test Request Details", null), null,
                                                          CreateIdentifierArray(request.LaboratoryTestResultIdentifier));

                var entryRelationships = new List<POCD_MT000040EntryRelationship>();

                if (request.TestsRequested != null)
                {
                    foreach (var testRequested in request.TestsRequested)
                    {
                        entryRelationships.Add(
                            CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.COMP,
                                                               ActClassObservation.OBS, x_ActMoodDocumentObservation.RQO,
                                                               false, null,
                                                               CreateConceptDescriptor("103.11017", CodingSystem.NCTIS, null, "Test Requested Name", null),
                                                               null, null,
                                                               new List<ANY>() {CreateConceptDescriptor(testRequested)},
                                                               null));
                    }
                }

                relationship.act.entryRelationship = entryRelationships.ToArray();
            }

            return relationship;
        }

        private static List<POCD_MT000040EntryRelationship> CreateRelationshipForEachTestResultGroup(IEnumerable<ITestResultGroup> testResultGroups, CDADocumentType? cdaDocumentType)
        {
            List<POCD_MT000040EntryRelationship> relationshipList = null;

            if (testResultGroups != null)
            {
                relationshipList = new List<POCD_MT000040EntryRelationship>();

                //Create Organizer and relationships, these are nested within the observation entry below
                foreach (var testResultGroup in testResultGroups)
                {
                    var entryRelationshipOrganiser =
                        CreateEntryRelationshipOrganiser(x_ActRelationshipEntryRelationship.COMP,
                                                         x_ActClassDocumentEntryOrganizer.BATTERY, ActMood.EVN, false,
                                                         CreateConceptDescriptor(testResultGroup.ResultGroupName), null,
                                                         StatusCode.Completed, testResultGroup, cdaDocumentType);

                    relationshipList.Add(entryRelationshipOrganiser);
                }
            }

            return relationshipList;
        }


        private static ICodableText CreateTestSpecimenDetailCode(CDADocumentType? documentType)
        {
            var code = "102.16156.2.2.1";

            if (documentType.HasValue)
            {
                switch (documentType.Value)
                {
                    case CDADocumentType.SpecialistLetter: code = "102.16156.132.1.1";
                        break;
                }
            }

            return CreateCodableText(code, CodingSystem.NCTIS, "Test Specimen Detail", null);
        }

        private static ICodableText CreateResultGroupSpecimenDetailCode(CDADocumentType? documentType)
        {
            var code = "102.16156.2.2.2";

            if (documentType.HasValue)
            {
                switch (documentType.Value)
                {
                    case CDADocumentType.SpecialistLetter: code = "102.16156.132.1.2";
                        break;
                }
            }

            return CreateCodableText(code, CodingSystem.NCTIS, "Result Group Specimen Detail", null);
        }

        private static List<POCD_MT000040EntryRelationship> CreateRelationshipForEachSpecimenDetail(ICollection<SpecimenDetail> specimenDetails, CDADocumentType? documentType)
        {
            var relationshipList = new List<POCD_MT000040EntryRelationship>();

            if (specimenDetails != null && specimenDetails.Any())
            {
                foreach (var specimenDetail in specimenDetails)
                {
                    relationshipList.Add(new POCD_MT000040EntryRelationship
                                             {
                                                 typeCode = x_ActRelationshipEntryRelationship.SUBJ,
                                                 observation =
                                                 CreateSpecimenDetail(specimenDetail, CreateTestSpecimenDetailCode(documentType))
                                             });
                }
            }
            return relationshipList;
        }

        #endregion

        #endregion

        #region internal Methods - Authors

        /// <summary>
        /// Returns Qualifications 
        /// </summary>
        /// <param name="qualification">A qualification string</param>
        /// <returns>Qualifications</returns>
        internal static Qualifications CreateQualifications(String qualification)
        {
            var qualifications = new Qualifications();
            qualifications.classCode = EntityClass.QUAL;
            qualifications.code = CreateCodedWithExtensionElement(null, null, null, null, qualification, null);

            return qualifications;
        }

        /// <summary>
        /// Creates an author from a participation
        /// </summary>
        /// <param name="participationAuthor">IParticipationConsumerAuthor</param>
        /// <returns>POCD_MT000040Author</returns>
        internal static POCD_MT000040Author CreateAuthor(IParticipationConsumerAuthor participationAuthor, Guid? subjectOfCareIdentifier)
        {
            var returnAuthor = new POCD_MT000040Author();

            if (participationAuthor != null && participationAuthor.Participant != null)
            {
                var author = participationAuthor.Participant;

                if (participationAuthor.AuthorParticipationPeriodOrDateTimeAuthored != null)
                {
                  returnAuthor.time = CreateTimeStampElementIso(participationAuthor.AuthorParticipationPeriodOrDateTimeAuthored, null, true);
                }
                else
                {
                    returnAuthor.time = CreateTimeStampElement(null, NullFlavor.NA, true);
                }

                returnAuthor.assignedAuthor = new POCD_MT000040AssignedAuthor { id = CreateIdentifierArray(CreateGuid(), null) };

                returnAuthor.typeCode = ParticipationType.AUT;
                returnAuthor.typeCodeSpecified = true;

                if (participationAuthor.Role != null)
                {
                    returnAuthor.assignedAuthor.code = CreateCodedWithExtensionElement(participationAuthor.Role);
                }

                returnAuthor.assignedAuthor.addr = CreateAddressArray(author.Addresses);

                returnAuthor.assignedAuthor.telecom = CreateTelecomunicationArray(author.ElectronicCommunicationDetails);

                returnAuthor.assignedAuthor.assignedPerson = new POCD_MT000040Person
                {
                    name = author.Person != null ? CreatePersonNameArray(author.Person.PersonNames) : null
                };

                if (author.Person != null && author.Person.Identifiers != null)
                {
                    returnAuthor.assignedAuthor.assignedPerson.asEntityIdentifier = CreateEntityIdentifier(author.Person.Identifiers).ToArray();
                }

                // NOTE : RelationshipToSubjectOfCare overrights participationAuthor.Role because of a bug in the SPEC
                if (author.Person != null && author.RelationshipToSubjectOfCare != null)
                {
                    returnAuthor.assignedAuthor.code = CreateCodedWithExtensionElement
                            (
                                  author.RelationshipToSubjectOfCare
                            );

                    // 2011 Addendum changes
                    //returnAuthor.assignedAuthor.assignedPerson.personalRelationship = new []
                    //{
                    //    new PersonalRelationship
                    //    {
                    //        classCode = RoleClass.PRS,
                    //        classCodeSpecified = true,
                    //        code = CreateConceptDescriptor
                    //        (
                    //               author.Person.RelationshipToSubjectOfCare.GetAttributeValue<NameAttribute, string>(x => x.Code),
                    //               CodingSystem.HL7PersonalRelationshipRoleType,
                    //               null,
                    //               author.Person.RelationshipToSubjectOfCare.GetAttributeValue<NameAttribute, string>(x => x.Name), 
                    //               null
                    //        ),
                    //        asPersonalRelationship = new POCD_MT000040Patient
                    //        {
                    //             classCode = EntityClass.PSN,
                    //             classCodeSpecified = true,
                    //             determinerCode  = EntityDeterminer.INSTANCE,
                    //             determinerCodeSpecified  = true,
                    //             id = subjectOfCareIdentifier.HasValue ? CreateIdentifierElement(subjectOfCareIdentifier.ToString(), null)  : CreateIdentifierElement(CreateGuid()) 
                    //        }
                    //    }
                    //};
                }
            }

            return returnAuthor;
        }

        /// <summary>
        /// Creates an author from a participation - author and a role
        /// </summary>
        /// <param name="authorAuthoringDevice">AuthorAuthoringDevice</param>
        /// <returns>POCD_MT000040Author</returns>
        internal static POCD_MT000040Author CreateAuthor(AuthorAuthoringDevice authorAuthoringDevice)
        {
          var returnAuthor = new POCD_MT000040Author();

          if (authorAuthoringDevice != null)
          {
            if (authorAuthoringDevice.DateTimeAuthored != null)
               returnAuthor.time = CreateIntervalTimestamp(authorAuthoringDevice.DateTimeAuthored.ToString(), null, null, null, null,null);
            else
              returnAuthor.time = CreateTimeStampElement(null, NullFlavor.NA, true);

            returnAuthor.assignedAuthor = new POCD_MT000040AssignedAuthor { id = CreateIdentifierArray(CreateGuid(), null) };

            returnAuthor.typeCode = ParticipationType.AUT;
            returnAuthor.typeCodeSpecified = true;

            if (authorAuthoringDevice.Role != null) returnAuthor.assignedAuthor.code = CreateCodedWithExtensionElement(authorAuthoringDevice.Role);

            returnAuthor.assignedAuthor.assignedAuthoringDevice = new POCD_MT000040AuthoringDevice  
            {
                asEntityIdentifier = (authorAuthoringDevice.Identifiers != null && authorAuthoringDevice.Identifiers.Any()) ? 
                                      CreateEntityIdentifier(authorAuthoringDevice.Identifiers).ToArray() : null,
                softwareName = !authorAuthoringDevice.SoftwareName.IsNullOrEmptyWhitespace() ? new SC { Text = new [] { authorAuthoringDevice.SoftwareName } } : null
            };
          }

          return returnAuthor;
        }

        /// <summary>
        /// Creates an author from a participation - author and a role
        /// </summary>
        /// <param name="participationAuthor">IParticipationDocumentAuthor</param>
        /// <returns>POCD_MT000040Author</returns>
        internal static POCD_MT000040Author CreateAuthor(IParticipationDocumentAuthor participationAuthor)
        {
            var returnAuthor = new POCD_MT000040Author();

            if (participationAuthor != null && participationAuthor.Participant != null)
            {
                var author = participationAuthor.Participant;

                if (participationAuthor.AuthorParticipationPeriodOrDateTimeAuthored != null)
                {
                  returnAuthor.time = CreateTimeStampElementIso(participationAuthor.AuthorParticipationPeriodOrDateTimeAuthored, null, true);
                }
                else
                {
                    returnAuthor.time = CreateTimeStampElement(null, NullFlavor.NA, true);
                }

                returnAuthor.assignedAuthor = new POCD_MT000040AssignedAuthor{id = CreateIdentifierArray(CreateGuid(), null)};

                returnAuthor.typeCode = ParticipationType.AUT;
                returnAuthor.typeCodeSpecified = true;

                if (participationAuthor.Role != null)
                {
                    returnAuthor.assignedAuthor.code = CreateCodedWithExtensionElement(participationAuthor.Role);
                }

                returnAuthor.assignedAuthor.addr = CreateAddressArray(author.Addresses);

                returnAuthor.assignedAuthor.telecom = CreateTelecomunicationArray(author.ElectronicCommunicationDetails);

                returnAuthor.assignedAuthor.assignedPerson = new POCD_MT000040Person
                                                                 {
                                                                     name = author.Person != null ? CreatePersonNameArray(author.Person.PersonNames) : null
                                                                 };

                if (author.Person != null && author.Person.Identifiers != null)
                {
                    returnAuthor.assignedAuthor.assignedPerson.asEntityIdentifier =
                        CreateEntityIdentifier(author.Person.Identifiers).ToArray();
                }

                if (participationAuthor.Participant.Person != null)
                {
                    if (participationAuthor.Participant.Person.Organisation != null)
                    {
                        returnAuthor.assignedAuthor.assignedPerson.asEmployment =
                            CreateEmployment(participationAuthor.Participant.Person.Organisation);
                    }
                }
            }

            return returnAuthor;
        }

        /// <summary>
        /// Creates an author from an IParticipationPrescriber
        /// </summary>
        /// <param name="participationAuthor">IParticipationConsumerAuthor</param>
        /// <returns>POCD_MT000040Author</returns>
        internal static POCD_MT000040Author CreateAuthor(IParticipationPrescriber participationAuthor)
        {
          var returnAuthor = new POCD_MT000040Author();

          if (participationAuthor != null && participationAuthor.Participant != null)
          {
            var author = participationAuthor.Participant;

            if (participationAuthor.PrescriptionWritten != null)
              returnAuthor.time = CreateTimeStampElementIso(participationAuthor.PrescriptionWritten, null, true);
            else
              returnAuthor.time = CreateTimeStampElement(null, NullFlavor.NA, true);

            returnAuthor.assignedAuthor = new POCD_MT000040AssignedAuthor { id = CreateIdentifierArray(participationAuthor.Participant.UniqueIdentifier.ToString(), null) };
            returnAuthor.typeCode = ParticipationType.AUT;
            returnAuthor.typeCodeSpecified = true;
            if (participationAuthor.Role != null) returnAuthor.assignedAuthor.code = CreateCodedWithExtensionElement(participationAuthor.Role);
            returnAuthor.assignedAuthor.addr = CreateAddressArray(author.Addresses);
            returnAuthor.assignedAuthor.telecom = CreateTelecomunicationArray(author.ElectronicCommunicationDetails);

            returnAuthor.assignedAuthor.assignedPerson = new POCD_MT000040Person
            {
              name = author.Person != null ? CreatePersonNameArray(author.Person.PersonNames) : null
            };

            if (author.Person != null && author.Person.Identifiers != null)

              returnAuthor.assignedAuthor.assignedPerson.asEntityIdentifier = CreateEntityIdentifier(author.Person.Identifiers).ToArray();

            if (participationAuthor.Participant.Person != null)
            {
              if (participationAuthor.Participant.Person.Occupation != null)
              {
                returnAuthor.assignedAuthor.assignedPerson.asEmployment = new Employment
                                                                            {
                                                                              jobCode = CreateCodedWithExtensionElement(
                                                                                              participationAuthor.Participant.Person.Occupation.Value.GetAttributeValue<NameAttribute, string>(x => x.Code),
                                                                                              CodingSystem.ANZSCO, null,
                                                                                              participationAuthor.Participant.Person.Occupation.Value.GetAttributeValue<NameAttribute, string>(x => x.Name), 
                                                                                              null, 
                                                                                              null)

                                                                            };
              }

              if (participationAuthor.Participant.Person.Qualifications != null)
                returnAuthor.assignedAuthor.assignedPerson.asQualifications = CreateQualifications(participationAuthor.Participant.Person.Qualifications);
            }
          }

          return returnAuthor;
        }

        /// <summary>
        /// Creates an author from an IParticipationDispenser
        /// </summary>
        /// <param name="participationAuthor">IParticipationDispenser</param>
        /// <returns>POCD_MT000040Author</returns>
        internal static POCD_MT000040Author CreateAuthor(IParticipationDispenser participationAuthor)
        {
          var returnAuthor = new POCD_MT000040Author();

          if (participationAuthor != null && participationAuthor.Participant != null)
          {
            var author = participationAuthor.Participant;

            if (participationAuthor.DateTimeAuthenticated != null)
              returnAuthor.time = CreateTimeStampElementIso(participationAuthor.DateTimeAuthenticated, null, true);
            else
              returnAuthor.time = CreateTimeStampElement(null, NullFlavor.NA, true);

            returnAuthor.assignedAuthor = new POCD_MT000040AssignedAuthor { id = CreateIdentifierArray(participationAuthor.Participant.UniqueIdentifier.ToString(), null) };
            returnAuthor.typeCode = ParticipationType.AUT;
            returnAuthor.typeCodeSpecified = true;
            returnAuthor.assignedAuthor.addr = CreateAddressArray(author.Addresses);
            returnAuthor.assignedAuthor.telecom = CreateTelecomunicationArray(author.ElectronicCommunicationDetails);

            if (participationAuthor.Role != null) returnAuthor.assignedAuthor.code = CreateCodedWithExtensionElement(participationAuthor.Role);

            returnAuthor.assignedAuthor.assignedPerson = new POCD_MT000040Person
            {
              name = author.Person != null ? CreatePersonNameArray(author.Person.PersonNames) : null
            };

            if (author.Person != null && author.Person.Identifiers != null)
              returnAuthor.assignedAuthor.assignedPerson.asEntityIdentifier = CreateEntityIdentifier(author.Person.Identifiers).ToArray();


            if (participationAuthor.Participant.Person.Qualifications != null)
              returnAuthor.assignedAuthor.assignedPerson.asQualifications = CreateQualifications(participationAuthor.Participant.Person.Qualifications);

            }
          return returnAuthor;
        }

        internal static POCD_MT000040Component1 CreateComponentOf(IParticipationDispenserOrganisation organisationParticipation)
        {
          var location = new POCD_MT000040Location();
          location.typeCode = ParticipationTargetLocation.LOC;
          location.healthCareFacility = new POCD_MT000040HealthCareFacility();
          location.healthCareFacility.code = CreateCodedWithExtensionElement(
                                                      "PHARM",
                                                      CodingSystem.HL7ServiceDeliveryLocationRoleType, 
                                                      null,
                                                      "Pharmacy",
                                                      null,
                                                      null);

          if (organisationParticipation.Participant != null)
          {
            location.healthCareFacility.id = CreateIdentifierArray(organisationParticipation.Participant.UniqueIdentifier.ToString(), null);

            if (organisationParticipation.Participant.Organisation != null)
            {
              location.healthCareFacility.serviceProviderOrganization = CreateOrganisation(organisationParticipation.Participant.Organisation);

              if (organisationParticipation.Participant.Addresses != null && organisationParticipation.Participant.Addresses.Any())
                location.healthCareFacility.serviceProviderOrganization.asOrganizationPartOf.wholeOrganization.addr = CreateAddressArray(organisationParticipation.Participant.Addresses);

              if (organisationParticipation.Participant.ElectronicCommunicationDetails != null && organisationParticipation.Participant.ElectronicCommunicationDetails.Any())
                location.healthCareFacility.serviceProviderOrganization.asOrganizationPartOf.wholeOrganization.telecom = CreateTelecomunicationArray(organisationParticipation.Participant.ElectronicCommunicationDetails);
            }            
          }


          var component = new POCD_MT000040Component1();
          component.encompassingEncounter = new POCD_MT000040EncompassingEncounter();
          component.encompassingEncounter.effectiveTime = new IVL_TS { nullFlavor = NullFlavor.NA, nullFlavorSpecified = true };
          component.encompassingEncounter.location = location;

          return component;
        }

        internal static POCD_MT000040Component1 CreateComponentOf(IParticipationPrescriberOrganisation organisationParticipation)
        {
          var location = new POCD_MT000040Location();
          location.typeCode = ParticipationTargetLocation.LOC;
          location.healthCareFacility = new POCD_MT000040HealthCareFacility();
          location.healthCareFacility.code = CreateCodedWithExtensionElement(organisationParticipation.Role);

          location.healthCareFacility.id = organisationParticipation.Participant != null ? CreateIdentifierArray(organisationParticipation.Participant.UniqueIdentifier.ToString(), null) : null;

          if (organisationParticipation.Participant != null)
            if (organisationParticipation.Participant.Organisation != null)
            {
                location.healthCareFacility.serviceProviderOrganization = CreateOrganisation(organisationParticipation.Participant.Organisation);

                if (organisationParticipation.Participant.Addresses != null && organisationParticipation.Participant.Addresses.Any() )
                  location.healthCareFacility.serviceProviderOrganization.asOrganizationPartOf.wholeOrganization.addr = CreateAddressArray(organisationParticipation.Participant.Addresses);

                if (organisationParticipation.Participant.ElectronicCommunicationDetails != null && organisationParticipation.Participant.ElectronicCommunicationDetails.Any())
                  location.healthCareFacility.serviceProviderOrganization.asOrganizationPartOf.wholeOrganization.telecom = CreateTelecomunicationArray(organisationParticipation.Participant.ElectronicCommunicationDetails);
            }

          var component = new POCD_MT000040Component1();
          component.encompassingEncounter = new POCD_MT000040EncompassingEncounter();
          component.encompassingEncounter.effectiveTime = new IVL_TS { nullFlavor = NullFlavor.NA, nullFlavorSpecified = true };
          component.encompassingEncounter.location = location;

          return component;
        }

        /// <summary>
        /// Creates the employment details.
        /// </summary>
        /// <param name="organisation">Employment organisation details.</param>
        /// <returns>Employment</returns>
        private static Employment CreateEmployment(IEmploymentOrganisation organisation)
        {
            Employment employment = new Employment();

            employment.employerOrganization = CreateOrganisation(organisation);

            if (organisation.Occupation != null)
            {
                employment.jobCode =
                    CreateCodedWithExtensionElement(
                        organisation.Occupation.GetAttributeValue<NameAttribute, string>(x => x.Code),
                        CodingSystem.ANZSCO, null,
                        organisation.Occupation.GetAttributeValue<NameAttribute, string>(x => x.Name), null, null);
            }

            if (organisation.PositionInOrganisation != null)
            {
                employment.code = CreateCodedWithExtensionElement(organisation.PositionInOrganisation);
            }

            if (organisation.EmploymentType != null)
            {
                employment.jobClassCode = CreateCodedWithExtensionElement(organisation.EmploymentType);
            }

            return employment;
        }

        /// <summary>
        /// Creates an array of authors
        /// </summary>
        /// <param name="createOnDateTime">Date / Time thae document was created</param>
        /// <returns>POCD_MT000040Author array</returns>
        internal static POCD_MT000040Author[] CreateAuthors(DateTime? createOnDateTime)
        {
            List<POCD_MT000040Author> returnAuthors = null;

            if (createOnDateTime.HasValue)
            {
                returnAuthors = new List<POCD_MT000040Author>();

                returnAuthors.Add(new POCD_MT000040Author
                                      {
                                          time = CreateTimeStampElement(createOnDateTime, null, true),
                                          assignedAuthor =
                                          new POCD_MT000040AssignedAuthor
                                          {
                                              nullFlavor = NullFlavor.NA,
                                              nullFlavorSpecified = true,
                                              id = CreateIdentifierArray(String.Empty, NullFlavor.NA)
                                          },
                                      });
            }
            if (returnAuthors != null)
                return returnAuthors.ToArray();
            else
                return null;
        }

        #endregion

        #region internal Methods - Participants


        /// <summary>
        /// Creates a participant.
        /// </summary>
        /// <param name="participation">Patient nominated contact.</param>
        /// <returns>CDA participant.</returns>
        internal static POCD_MT000040Participant1 CreateParticipant(IParticipationPatientNominatedContact participation)
        {
            POCD_MT000040Participant1 returnParticipant = null;

            if (participation != null && participation.Participant != null)
            {
                Guid guid = ((IParticipant) participation.Participant).UniqueIdentifier;

                returnParticipant = new POCD_MT000040Participant1
                                        {
                                            typeCode = ParticipationType.IRCP,
                                            functionCode = null,
                                            associatedEntity =
                                                new POCD_MT000040AssociatedEntity
                                                    {
                                                        classCode = RoleClassAssociative.CON,
                                                        id = CreateIdentifierArray(guid.ToString(), null, null),
                                                        associatedPerson =
                                                            participation.Participant.Person != null && 
                                                            (participation.Participant.Person.PersonNames != null || participation.Participant.Person.Identifiers != null) ? 
                                                            new POCD_MT000040Person
                                                                      {
                                                                          // PersonName
                                                                          name = participation.Participant.Person == null ? null: CreatePersonNameArray(participation.Participant.Person.PersonNames),
                                                                          // EntityIdentifier
                                                                          asEntityIdentifier = participation.Participant.Person == null || participation.Participant.Person.Identifiers == null ? null : CreateEntityIdentifier(participation.Participant.Person.Identifiers).ToArray()
                                                                      }
                                                                : null,
                                                        // Addresses
                                                        addr = CreateAddressArray(participation.Participant.Addresses),
                                                        // Organisation
                                                        scopingOrganization = participation.Participant.Organisation == null ? null : CreateOrganisation(participation.Participant.Organisation)
                                                    }
                                        };

                if (participation.Role != null)
                {
                    returnParticipant.associatedEntity.code = CreateCodedWithExtensionElement(participation.Role);
                }

                if (participation.Participant.Addresses != null && participation.Participant.Addresses.Any())
                {
                    returnParticipant.associatedEntity.addr = CreateAddressArray(participation.Participant.Addresses.ConvertAll(address => address));
                }

                returnParticipant.associatedEntity.telecom = CreateTelecomunicationArray(participation.Participant.ElectronicCommunicationDetails);
            }

            return returnParticipant;
        }

        /// <summary>
        /// Creates a participant from a particiaption and a role
        /// </summary>
        /// <param name="participation">IParticipation</param>
        /// <param name="roleClassAssociative">roleClassAssociative</param>
        /// <param name="participationType">participationType</param>
        /// <param name="functionCode">functionCode</param>
        /// <returns>POCD_MT000040Participant1</returns>
        internal static POCD_MT000040Participant1 CreateParticipant(IParticipation participation,
                                                                    ParticipationType participationType,
                                                                    RoleClassAssociative roleClassAssociative,
                                                                    CE functionCode)
        {
            POCD_MT000040Participant1 returnParticipant = null;

            if (participation != null && participation.Participant != null)
            {
                returnParticipant = new POCD_MT000040Participant1
                                        {
                                            time = CreateIntervalTimestamp(participation.ParticipationPeriod),
                                            typeCode = participationType,
                                            functionCode = functionCode,                                            
                                            associatedEntity =
                                                new POCD_MT000040AssociatedEntity
                                                    {
                                                        classCode = roleClassAssociative,
                                                        id = CreateIdentifierArray((participation.Participant).UniqueIdentifier.ToString(), null, null),
                                                        associatedPerson = participation.Participant.Person != null && participation.Participant.Person.PersonNames != null &&
                                                                           participation.Participant.Person.Identifiers != null
                                                                      ? new POCD_MT000040Person
                                                                      { 
                                                                    // PersonName
                                                                          name = participation.Participant.Person == null ? null
                                                                          : CreatePersonNameArray(participation.Participant.Person.PersonNames),
                                                                          // EntityIdentifier
                                                                          asEntityIdentifier = participation.Participant.Person == null ? null
                                                                          : CreateEntityIdentifier(participation.Participant.Person.Identifiers).ToArray()
                                                                      }
                                                                : null,
                                                        // Addresses
                                                        addr = CreateAddressArray(participation.Participant.Addresses),
                                                        // Organisation
                                                        scopingOrganization = participation.Participant.Organisation == null ? null : CreateOrganisation( participation.Participant.Organisation)
                                                    }
                                        };

                if (participation.Role != null)
                {
                    returnParticipant.associatedEntity.code = CreateCodedWithExtensionElement(participation.Role);
                }

                if (participation.Participant.Addresses != null && participation.Participant.Addresses.Any())
                {
                    returnParticipant.associatedEntity.addr =
                        CreateAddressArray(participation.Participant.Addresses.ConvertAll(address => address));
                }

                returnParticipant.associatedEntity.telecom =
                    CreateTelecomunicationArray(participation.Participant.ElectronicCommunicationDetails);

                if (participation.Participant.Person != null)
                {
                    // Set the Person Organisation
                    if (participation.Participant.Person.Organisation != null)
                    {
                        returnParticipant.associatedEntity.associatedPerson.asEmployment =
                            CreateEmployment(participation.Participant.Person.Organisation);
                    }
                }

            }

            return returnParticipant;
        }


        /// <summary>
        /// Creates a participant from a particiaption and a role
        /// </summary>
        /// <returns>POCD_MT000040Participant2</returns>
        internal static POCD_MT000040Participant2 CreateParticipant2(IParticipation participation, ParticipationType participationType, RoleClassRoot roleClassRoot)
        {
          POCD_MT000040Participant2 returnParticipant = null;

          if (participation != null && participation.Participant != null)
          {
            returnParticipant = new POCD_MT000040Participant2
            { 

              time = CreateIntervalTimestamp(participation.ParticipationPeriod),
              typeCode =  participationType,
              participantRole = new POCD_MT000040ParticipantRole
                                  {
                                    classCode = roleClassRoot,
                                    code =  CreateCodedWithExtensionElement(participation.Role),
                                    playingEntity = new POCD_MT000040PlayingEntity
                                                      {
                                                         classCode = EntityClassRoot.PSN,
                                                         // PersonName
                                                         name = participation.Participant.Person == null ? null : CreatePersonNameArray(participation.Participant.Person.PersonNames),
                                                         // EntityIdentifier
                                                         asEntityIdentifier = participation.Participant.Person == null ? null : CreateEntityIdentifier(participation.Participant.Person.Identifiers).ToArray()
                                                      },
                                    // Addresses
                                    addr = CreateAddressArray(participation.Participant.Addresses),
                                    // Electronic Communication Details
                                    telecom = participation.Participant.ElectronicCommunicationDetails != null ?  CreateTelecomunicationArray(participation.Participant.ElectronicCommunicationDetails) : null,
                                    // Organisation
                                    scopingEntity = participation.Participant.Organisation != null ? CreateOrganisationEntity(participation.Participant.Organisation) : null,
                                    },
              };
          }

          return returnParticipant;
        }

        /// <summary>
        /// Creates a participant.
        /// </summary>
        /// <param name="participation"></param>
        /// <returns>Participant.</returns>
        internal static POCD_MT000040Participant2 CreateServiceRequesterForMedicareXMLMockup(IParticipation participation)
        {
            POCD_MT000040Participant2 returnParticipant = null;

            if (participation != null && participation.Participant != null)
            {
                POCD_MT000040Entity scopingEntity = null;

                if (participation.Participant.Person.Organisation != null)
                {
                    var wholeEntity = new Entity()
                    {
                        asEntityIdentifier = CreateEntityIdentifierArray(participation.Participant.Person.Organisation.Identifiers),
                        name = new ON[] { CreateName(participation.Participant.Person.Organisation.Name, participation.Participant.Person.Organisation.NameUsage) }
                    };

                    var asOrganizationPartOf = new OrganizationPartOf()
                    {
                        wholeEntity = wholeEntity
                    };

                    scopingEntity = new POCD_MT000040Entity()
                    {
                        asOrganizationPartOf = asOrganizationPartOf,
                        classCode = EntityClassRoot.ORG,
                        name = new ON[] { CreateName(participation.Participant.Person.Organisation.Department, null) }
                    };
                }

                var playingEntity = new POCD_MT000040PlayingEntity()
                {
                    asEntityIdentifier = CreateEntityIdentifierArray(participation.Participant.Person.Identifiers),
                    name = CreatePersonNameArray(participation.Participant.Person.PersonNames),
                    classCode = EntityClassRoot.PSN,
                };

                POCD_MT000040ParticipantRole participantRole = new POCD_MT000040ParticipantRole()
                {
                    classCode = (RoleClassRoot)Enum.Parse(typeof(RoleClassRoot), participation.RoleType.GetAttributeValue<NameAttribute,string>(a => a.Code)),
                    code = CreateCodedWithExtensionElement(participation.Role),
                    addr = participation.Participant.Addresses == null ? null : CreateAddressArray(participation.Participant.Addresses),
                    telecom = participation.Participant.ElectronicCommunicationDetails == null ? null : CreateTelecomunicationArray(participation.Participant.ElectronicCommunicationDetails),
                    playingEntity = playingEntity,
                    scopingEntity = scopingEntity
                };

                returnParticipant = new POCD_MT000040Participant2
                {
                    time = CreateIntervalTimestamp(participation.ParticipationPeriod),
                    typeCode = ParticipationType.REFB,
                    participantRole = participantRole
                };
            }

            return returnParticipant;
        }

        /// <summary>
        /// Creates a name.
        /// </summary>
        /// <param name="name">Name.</param>
        /// <param name="usage">Name usage.</param>
        /// <returns>ON.</returns>
        private static ON CreateName(string name, OrganisationNameUsage? usage)
        {
            ON on = new ON();
            on.Text = new[] { name };

            if (usage != null)
            {
                string nameUsageVal = usage.Value.GetAttributeValue<NameAttribute, string>(a => a.Code);
                EntityNameUse nameUsage = (EntityNameUse)Enum.Parse(typeof(EntityNameUse), nameUsageVal);
                
                on.use = new[] { nameUsage };
            }

            return on;
        }

        /// <summary>
        /// Creates a participant from a participation - referee
        /// </summary>
        /// <param name="participation">IParticipationReferee</param>
        /// <returns>POCD_MT000040Participant1</returns>
        internal static POCD_MT000040Participant1 CreateParticipant(IParticipationReferee participation)
        {
            POCD_MT000040Participant1 returnParticipant = null;

            if (participation != null && participation.Participant != null)
            {
                var castedParticipation = (IParticipation) participation;
                castedParticipation.Participant = (IParticipant) participation.Participant;

                if (castedParticipation.Participant != null)
                {
                    if (participation.Participant.Person != null)
                        castedParticipation.Participant.Person = participation.Participant.Person;
                    if (participation.Participant.Addresses != null)
                        castedParticipation.Participant.Addresses = participation.Participant.Addresses;
                    if (participation.Participant.Organisation != null)
                        castedParticipation.Participant.Organisation = participation.Participant.Organisation;
                }

                returnParticipant = CreateParticipant(castedParticipation, ParticipationType.REFT, RoleClassAssociative.PROV, null);
            }

            return returnParticipant;
        }

        /// <summary>
        /// Creates a participant from a participation - usualGP
        /// </summary>
        /// <param name="participation">IParticipationUsualGP</param>
        /// <returns>POCD_MT000040Participant1</returns>
        internal static POCD_MT000040Participant1 CreateParticipant(IParticipationUsualGP participation)
        {
            POCD_MT000040Participant1 returnParticipant = null;

            if (participation != null && participation.Participant != null)
            {
                var castedParticipation = (IParticipation) participation;
                castedParticipation.Participant = (IParticipant) participation.Participant;

                if (castedParticipation.Participant != null)
                {
                    if (participation.Participant.Person != null)
                        castedParticipation.Participant.Person = participation.Participant.Person;
                    if (participation.Participant.Addresses != null)
                        castedParticipation.Participant.Addresses = participation.Participant.Addresses;
                    if (participation.Participant.Organisation != null)
                        castedParticipation.Participant.Organisation = participation.Participant.Organisation;
                }

                var functionCode = CreateCodedWithExtensionElement("PCP", null, null, "Primary Care Physician", null,  null);

                returnParticipant = CreateParticipant(castedParticipation, ParticipationType.PART, RoleClassAssociative.PROV, functionCode);
            }

            return returnParticipant;
        }

        /// <summary>
        /// Creates a participant from a participation - usualGP
        /// </summary>
        /// <param name="participation">IParticipationUsualGP</param>
        /// <returns>POCD_MT000040Participant1</returns>
        internal static POCD_MT000040Participant1 CreateParticipant(IParticipationReferrer participation)
        {
            POCD_MT000040Participant1 returnParticipant = null;

            if (participation != null && participation.Participant != null)
            {
                var castedParticipation = (IParticipation) participation;
                castedParticipation.Participant = (IParticipant) participation.Participant;

                if (castedParticipation.Participant != null)
                {
                    if (participation.Participant.Person != null)
                        castedParticipation.Participant.Person = participation.Participant.Person;
                    if (participation.Participant.Addresses != null)
                        castedParticipation.Participant.Addresses = participation.Participant.Addresses;
                }

                var functionCode = CreateCodedWithExtensionElement("PCP", null, null, "Primary Care Physician", null, null);

                returnParticipant = CreateParticipant(castedParticipation, ParticipationType.REFB, RoleClassAssociative.PROV, functionCode);
            }

            return returnParticipant;
        }

        /// <summary>
        /// Creates a participant from a participation - referee
        /// </summary>
        /// <param name="participation">IParticipationReferee</param>
        /// <returns>POCD_MT000040Participant1</returns>
        internal static POCD_MT000040Participant2 CreateParticipant2(IParticipationServiceRequester participation)
        {
          POCD_MT000040Participant2 returnParticipant = null;

          if (participation != null && participation.Participant != null)
          {
            var castedParticipation = (IParticipation)participation;
            castedParticipation.Participant = (IParticipant)participation.Participant;

            if (castedParticipation.Participant != null)
            {
              if (participation.Participant.Person != null)
              {
                castedParticipation.Participant.Person = new Person();

                if (participation.Participant.Person.Identifiers != null)
                {
                   castedParticipation.Participant.Person.Identifiers = participation.Participant.Person.Identifiers;
                }

                if (participation.Participant.Person.PersonNames != null)
                {
                  castedParticipation.Participant.Person.PersonNames = participation.Participant.Person.PersonNames;
                }
              }

              if (participation.Participant.Addresses != null)
                castedParticipation.Participant.Addresses = participation.Participant.Addresses;
              if (participation.Participant.Organisation != null)
                castedParticipation.Participant.Organisation = participation.Participant.Organisation;
            }

            returnParticipant = CreateParticipant2(castedParticipation, ParticipationType.REFB, RoleClassRoot.PART);
          }

          return returnParticipant;
        }

        /// <summary>
        /// Creates a Participation Service Provider
        /// </summary>
        /// <param name="participation">A IParticipationServiceProvider</param>
        /// <returns>POCD_MT000040Performer2</returns>
        internal static POCD_MT000040Performer2 CreatePerformer(IParticipationServiceProvider participation)
        {
            POCD_MT000040Performer2 performer = null;

            if (participation != null && participation.Participant != null)
            {
                var castedParticipation = (IParticipation) participation;
                castedParticipation.Participant = (IParticipant) participation.Participant;

                if (castedParticipation.Participant != null)
                {
                    if (participation.Participant.Person != null)
                        castedParticipation.Participant.Person = participation.Participant.Person;
                    if (participation.Participant.Addresses != null)
                        castedParticipation.Participant.Addresses = participation.Participant.Addresses;
                    if (participation.Participant.Organisation != null)
                        castedParticipation.Participant.Organisation = participation.Participant.Organisation;
                }

                performer = CreatePerformer(castedParticipation, ParticipationPhysicalPerformer.PRF);
            }
            return performer;
        }

        /// <summary>
        /// Creates a Participation Document Author
        /// </summary>
        /// <param name="participation">A IParticipationDocumentAuthor</param>
        /// <returns>POCD_MT000040Performer2</returns>
        internal static POCD_MT000040Performer2 CreatePerformer(IParticipationDocumentAuthor participation)
        {
          POCD_MT000040Performer2 performer = null;

          if (participation != null && participation.Participant != null)
          {
            var castedParticipation = (IParticipation)participation;
            castedParticipation.Participant = (IParticipant)participation.Participant;

            if (castedParticipation.Participant != null)
            {
              if (participation.Participant.Person != null)
              {
                castedParticipation.Participant.Person = participation.Participant.Person;

                if (participation.Participant.Person.Organisation != null)
                  castedParticipation.Participant.Person.Organisation = participation.Participant.Person.Organisation;

              }
              if (participation.Participant.Addresses != null)
                castedParticipation.Participant.Addresses = participation.Participant.Addresses;

            }

            performer = CreatePerformer(castedParticipation, ParticipationPhysicalPerformer.PRF);
          }
          return performer;
        }

        /// <summary>
        /// Creates a Participation ACD Custodian Entry Participation
        /// </summary>
        /// <param name="participation">A IParticipationAcdCustodian</param>
        /// <returns>POCD_MT000040Performer2</returns>
        internal static POCD_MT000040Performer2 CreatePerformer(IParticipationAcdCustodian participation)
        {
            POCD_MT000040Performer2 performer = null;

            if (participation != null && participation.Participant != null)
            {
                var castedParticipation = (IParticipation)participation;
                castedParticipation.Participant = (IParticipant)participation.Participant;

                if (castedParticipation.Participant != null)
                {
                    if (participation.Participant.Person != null)
                        castedParticipation.Participant.Person = participation.Participant.Person;
                    if (participation.Participant.Addresses != null)
                        castedParticipation.Participant.Addresses = participation.Participant.Addresses.Cast<IAddress>().ToList();
                    if (participation.Participant.Organisation != null)
                        castedParticipation.Participant.Organisation = participation.Participant.Organisation;
                }

                performer = CreatePerformer(castedParticipation, ParticipationPhysicalPerformer.PRF);

                if (castedParticipation.Participant != null)
                {
                    if (participation.Participant.Person != null)
                    {
                        if (participation.Participant.Person.Gender != null)
                        {
                            performer.assignedEntity.assignedPerson.administrativeGenderCode =
                                CreateCodedWithExtensionElement(
                                    participation.Participant.Person.Gender.GetAttributeValue<NameAttribute, string>(x => x.Code), 
                                    CodingSystem.Gender, null, participation.Participant.Person.Gender.GetAttributeValue<NameAttribute, string>(x => x.Name), null, null);
                        }

                        if (participation.Participant.Person.DateOfBirth != null)
                        {
                            performer.assignedEntity.assignedPerson.birthTime =
                                CreateTimeStampElementIso(participation.Participant.Person.DateOfBirth, null, true);
                        }
                    }
                }
            }
            return performer;
        }

        /// <summary>
        /// Creates a Addressee
        /// </summary>
        /// <param name="participation">A POCD_MT000040Performer2</param>
        /// <returns>IParticipationAddressee</returns>
        internal static POCD_MT000040Performer2 CreatePerformer(IParticipationAddressee participation)
        {
            POCD_MT000040Performer2 performer = null;

            if (participation != null && participation.Participant != null)
            {
                var castedParticipation = (IParticipation) participation;
                castedParticipation.Participant = (IParticipant) participation.Participant;

                if (castedParticipation.Participant != null)
                {
                    if (participation.Participant.Person != null)
                        castedParticipation.Participant.Person = participation.Participant.Person;
                    if (participation.Participant.Addresses != null)
                        castedParticipation.Participant.Addresses = participation.Participant.Addresses;
                    if (participation.Participant.Organisation != null)
                        castedParticipation.Participant.Organisation = participation.Participant.Organisation;
                }

                performer = CreatePerformer(castedParticipation, ParticipationPhysicalPerformer.PRF);
            }
            return performer;
        }


        /// <summary>
        /// Creates a Participation Service Provider
        /// </summary>
        /// <returns>POCD_MT000040Performer2</returns>
        internal static POCD_MT000040Performer2 CreatePerformer(IParticipation participation, ParticipationPhysicalPerformer typeCode)
        {
            POCD_MT000040Performer2 performer = null;

            // Set up the organisation for the Personor Organisation
            if (participation != null)
            {
                // Set up HealthProfessional
                if (participation.Participant != null)
                {
                    performer = new POCD_MT000040Performer2
                    {
                        time = participation.ParticipationPeriod == null ? (participation.AuthorParticipationPeriodOrDateTimeAuthored != null ? CreateIntervalTimestamp(participation.AuthorParticipationPeriodOrDateTimeAuthored.ToString(),null,null,null,null,null) : null) : CreateIntervalTimestamp(participation.ParticipationPeriod),
                        typeCode = typeCode,
                        typeCodeSpecified = true,
                        assignedEntity =
                            new POCD_MT000040AssignedEntity
                            {
                                code = CreateCodedWithExtensionElement(participation.Role),
                                id = CreateIdentifierArray(CreateGuid(), null, null),
                                // Create assigned person
                                assignedPerson = (participation.Participant.Person == null) ? null : new POCD_MT000040Person
                                    {
                                        asEntityIdentifier = participation.Participant.Person.Identifiers != null ? 
                                            CreateEntityIdentifier(participation.Participant.Person.Identifiers).ToArray() : null,
                                        name = CreatePersonNameArray(participation.Participant.Person.PersonNames),
                                        asEmployment = participation.Participant.Person.Organisation == null ? null : CreateEmployment(
                                            participation.Participant.Person.Organisation)
                                    },
                                // Create Address
                                addr = CreateAddressArray(participation.Participant.Addresses),
                                telecom =
                                    CreateTelecomunicationArray(
                                        participation.Participant.ElectronicCommunicationDetails),
                                // Create Organization
                                representedOrganization =
                                    participation.Participant.Organisation == null
                                        ? null
                                        : CreateOrganisation(participation.Participant.Organisation)
                            }
                    };

                }
            }
            return performer;
        }

        #endregion

        #region internal Methods - Subject Of Care

        /// <summary>
        /// Creates a subject of care
        /// </summary>
        /// <param name="subjectOfCareParticipation">IParticipationSubjectOfCare</param>
        /// <returns>POCD_MT000040RecordTarget</returns>
        internal static POCD_MT000040RecordTarget CreateSubjectOfCare(
            IParticipationSubjectOfCare subjectOfCareParticipation)
        {
            POCD_MT000040RecordTarget patient = null;

            if (subjectOfCareParticipation != null)
            {
                var subjectOfCare = subjectOfCareParticipation.Participant;

                if (subjectOfCare != null)
                {
                    var identifier = CreateIdentifierArray(subjectOfCare.UniqueIdentifier.ToString(), null);

                    patient = new POCD_MT000040RecordTarget
                                  {
                                      patientRole = new POCD_MT000040PatientRole {id = identifier, classCode = RoleClass.PAT, classCodeSpecified = true},
                                      typeCode = ParticipationType.RCT,
                                      typeCodeSpecified = true
                                  };
                }

                if (patient != null)
                {
                    patient.patientRole.addr = CreateAddressArray(subjectOfCare.Addresses);

                    patient.patientRole.telecom =
                        CreateTelecomunicationArray(subjectOfCare.ElectronicCommunicationDetails);

                    if (subjectOfCare.Person != null)
                    {
                        patient.patientRole.patient = new POCD_MT000040Patient
                                                          {
                                                              name = CreatePersonNameArray(subjectOfCare.Person.PersonNames),
                                                              administrativeGenderCode = subjectOfCare.Person.Gender != null ? CreateCodedWithExtensionElement(
                                                                          subjectOfCare.Person.Gender.GetAttributeValue<NameAttribute, string>(x => x.Code),
                                                                          CodingSystem.Gender, null,
                                                                          subjectOfCare.Person.Gender.GetAttributeValue<NameAttribute, string>(x => x.Name), null,
                                                                          null) : null,
                                                              birthTime = CreateTimeStampElementIso(subjectOfCare.Person.DateOfBirth, null, true),
                                                          };

                        if (subjectOfCare.Person.IndigenousStatus != IndigenousStatus.Undefined)
                        {
                            patient.patientRole.patient.ethnicGroupCode = CreateCodedWithExtensionElement(
                                    subjectOfCare.Person.IndigenousStatus.GetAttributeValue<NameAttribute, string>(x => x.Code), CodingSystem.METEOR, null,
                                    subjectOfCare.Person.IndigenousStatus.GetAttributeValue<NameAttribute, string>(x => x.Name), null, null);
                        }

                        if (subjectOfCare.Person.BirthOrder.HasValue)
                        {
                            patient.patientRole.patient.multipleBirthInd = CreateBoolean(true, true, NullFlavor.NA, false);
                            patient.patientRole.patient.multipleBirthOrderNumber = CreateIntegerElement(subjectOfCare.Person.BirthOrder.Value, NullFlavor.NA, false);
                        }

                        if (subjectOfCare.Person.DateOfDeath != null)
                        {
                            patient.patientRole.patient.deceasedInd = CreateBoolean(true, true, NullFlavor.NA, false);
                            patient.patientRole.patient.deceasedTime =  CreateTimeStampElementIso(subjectOfCare.Person.DateOfDeath, null, true);
                        }

                        if (subjectOfCare.Person.CountryOfBirth != Country.Undefined ||
                            subjectOfCare.Person.StateOfBirth != AustralianState.Undefined)
                        {
                            patient.patientRole.patient.birthplace = new POCD_MT000040Birthplace
                                                                         {
                                                                             place = new POCD_MT000040Place {addr = new AD()}
                                                                         };

                            if (subjectOfCare.Person.CountryOfBirth != Country.Undefined)
                                patient.patientRole.patient.birthplace.place.addr.country = new[]
                                                                                                {
                                                                                                    new adxpcountry
                                                                                                        {
                                                                                                            Text = new[]
                                                                                                                    {
                                                                                                                        subjectOfCare.Person.CountryOfBirth.GetAttributeValue<NameAttribute,string>(x => x.Name)
                                                                                                                    }
                                                                                                        }
                                                                                                };

                            if (subjectOfCare.Person.StateOfBirth != AustralianState.Undefined)
                                patient.patientRole.patient.birthplace.place.addr.state = new[] { new adxpstate
                                                                                                      { 
                                                                                                          Text = new[]
                                                                                                               { 
                                                                                                                    subjectOfCare.Person.StateOfBirth.GetAttributeValue<NameAttribute,string>(x =>x.Code)
                                                                                                               }
                                                                                                      }
                                                                                              };
                        }

                        if (subjectOfCare.Person.Identifiers != null)
                        {
                            patient.patientRole.patient.asEntityIdentifier = CreateEntityIdentifierArray(subjectOfCare.Person.Identifiers);
                        }
                    }
                }
            }

            return patient;
        }

        #endregion

        #endregion

        #region Private Methods

        private static POCD_MT000040EntryRelationship CreateRelationshipForProvidedClinicalInformation(
            String providedClinicalInformation)
        {
            POCD_MT000040EntryRelationship relationship = null;

            if (!String.IsNullOrEmpty(providedClinicalInformation))
            {
                relationship = CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.COMP,
                                                          x_ActClassDocumentEntryAct.INFRM, x_DocumentActMood.EVN, false,
                                                          CreateConceptDescriptor("55752-0", CodingSystem.LOINC, null, "Clinical Information", null),
                                                          CreateStructuredText(providedClinicalInformation, null), null);
            }

            return relationship;
        }

        private static POCD_MT000040EntryRelationship CreateRelationshipForProvidedClinicalInformation(
            String providedClinicalInformation, ref List<StrucDocTable> strucDocTableList)
        {
            POCD_MT000040EntryRelationship relationship = null;

            if (!String.IsNullOrEmpty(providedClinicalInformation))
            {
                relationship = CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.COMP,
                                                          x_ActClassDocumentEntryAct.INFRM, x_DocumentActMood.EVN, false,
                                                          CreateConceptDescriptor("55752-0", CodingSystem.LOINC, null,"Clinical Information", null),
                                                          CreateStructuredText(providedClinicalInformation, null), null);
            }

            return relationship;
        }

        private static POCD_MT000040EntryRelationship CreateRelationshipForDateTime(ISO8601DateTime dateTime)
        {
            POCD_MT000040EntryRelationship relationship = null;

            if (dateTime != null)
            {
                relationship = new POCD_MT000040EntryRelationship
                                   {
                                       typeCode = x_ActRelationshipEntryRelationship.COMP,
                                       observation = CreateObservation(ActClassObservation.OBS, x_ActMoodDocumentObservation.EVN,
                                                                       CreateConceptDescriptor("103.16589", CodingSystem.NCTIS, null,
                                                                        "Imaging Examination Result DateTime",null), dateTime, null)
                                   };
            }
            return relationship;
        }

        private static List<POCD_MT000040EntryRelationship> CreateRelationshipForExaminationRequest(
            ICollection<IImagingExaminationRequest> request)
        {
            List<POCD_MT000040EntryRelationship> relationships = null;

            if (request != null && request.Any())
            {
                relationships = new List<POCD_MT000040EntryRelationship>();

                foreach (var imageExaminationRequest in request)
                {

                    POCD_MT000040EntryRelationship relationship = null;

                    //Populate the narrative for the date / time
                    relationship = CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.SUBJ,
                                                              x_ActClassDocumentEntryAct.ACT, x_DocumentActMood.EVN,
                                                              true,
                                                              CreateConceptDescriptor("102.16511", CodingSystem.NCTIS,
                                                                                      null,
                                                                                      "Examination Request Details",
                                                                                      null), null, null);

                    //Relationship entrie
                    var relationshipList = relationship.act.entryRelationship != null ? relationship.act.entryRelationship.ToList(): new List<POCD_MT000040EntryRelationship>();

                    var studyIdentifierEntryRelationships = new List<POCD_MT000040EntryRelationship>();

                    // Examination Requested Name
                    if (imageExaminationRequest.ExaminationRequestedName != null && imageExaminationRequest.ExaminationRequestedName.Any())
                    {
                        foreach (var examinationRequestedName in imageExaminationRequest.ExaminationRequestedName)
                        {
                            relationshipList.Add(CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.REFR,
                                                                                     CreateConceptDescriptor("103.16512",
                                                                                                             CodingSystem.NCTIS, null,
                                                                                                             "Examination Requested Name",
                                                                                                             null), null,
                                                                                     CreateStructuredText(examinationRequestedName, null)));
                        }
                    }

                    //Report ID
                    if (imageExaminationRequest.ReportIdentifier != null)
                    {
                        relationshipList.Add(CreateEntryRelationshipObservation(
                            x_ActRelationshipEntryRelationship.COMP, ActClassObservation.OBS,
                            x_ActMoodDocumentObservation.EVN,
                            CreateConceptDescriptor("103.16514", CodingSystem.NCTIS, null, "Report Identifier", null),
                            CreateIdentifierArray(imageExaminationRequest.ReportIdentifier)));
                    }

                    //Image Details
                    if (imageExaminationRequest.ImageDetails != null && imageExaminationRequest.ImageDetails.Any())
                    {
                        foreach (var imageDetail in imageExaminationRequest.ImageDetails)
                        {
                            studyIdentifierEntryRelationships.Add(
                                CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.COMP,
                                                                   ActClassObservation.OBS,
                                                                   x_ActMoodDocumentObservation.EVN, true,
                                                                   imageDetail.DateTime,
                                                                   CreateConceptDescriptor("103.16515", CodingSystem.NCTIS, null,"Image Details", null), null,
                                                                   CreateIdentifierArray(imageDetail.ImageIdentifier),
                                                                   new List<ANY>
                                                                       {
                                                                           CreateConceptDescriptor(imageDetail.ImageViewName)
                                                                       },
                                                                   new List<POCD_MT000040EntryRelationship>
                                                                       {
                                                                           imageDetail.SeriesIdentifier != null ? CreateEntryRelationshipACT(
                                                                                   x_ActRelationshipEntryRelationship.REFR,
                                                                                   x_ActClassDocumentEntryAct.ACT,
                                                                                   x_DocumentActMood.EVN, true,
                                                                                   CreateConceptDescriptor("103.16517",
                                                                                                           CodingSystem.
                                                                                                               NCTIS,
                                                                                                           null,
                                                                                                           "DICOM Series Identifier",
                                                                                                           null), null,
                                                                                   CreateIdentifierArray(imageDetail.SeriesIdentifier))
                                                                               : null,
                                                                           !String.IsNullOrEmpty(imageDetail.SubjectPosition) ? CreateEntryRelationshipObservation(
                                                                                   x_ActRelationshipEntryRelationship.REFR,
                                                                                   CreateConceptDescriptor("103.16519",
                                                                                                           CodingSystem.
                                                                                                           NCTIS,
                                                                                                           null,
                                                                                                           "Subject Position",
                                                                                                           null),
                                                                                   CreateStructuredText(imageDetail.SubjectPosition, null))
                                                                               : null,
                                                                           imageDetail.Image != null ? CreateEntryRelationshipObservationMedia(x_ActRelationshipEntryRelationship.SPRT, imageDetail.Image) : null
                                                                       }));
                        }
                    }

                    //DICOM study ID
                    if (imageExaminationRequest.StudyIdentifier != null)
                    {
                        relationshipList.Add(CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.SUBJ,
                                                                        x_ActClassDocumentEntryAct.ACT,
                                                                        x_DocumentActMood.EVN, true,
                                                                        CreateConceptDescriptor("103.16513",
                                                                                                CodingSystem.NCTIS, null,
                                                                                                "DICOM Study Identifier",
                                                                                                null), null,
                                                                        CreateIdentifierArray(
                                                                            imageExaminationRequest.StudyIdentifier),
                                                                        studyIdentifierEntryRelationships));
                    }

                    relationship.act.entryRelationship = relationshipList.ToArray();
                    relationships.Add(relationship);
                }
            }
            return relationships;
        }

        private static List<POCD_MT000040Entry> CreateProblemDiagnosisEntries(
            ICollection<ProblemDiagnosis> problemDiagnosisList)
        {
            var entryList = new List<POCD_MT000040Entry>();

            if (problemDiagnosisList != null && problemDiagnosisList.Any())
            {
                foreach (var diagnosis in problemDiagnosisList)
                {
                    CreateProblemDiagnosisEntry(diagnosis, ref entryList);
                }
            }

            return entryList;
        }

        private static List<POCD_MT000040Entry> CreateProblemDiagnosisEntries(
            ICollection<IProblemDiagnosis> problemDiagnosisList)
        {
            var entryList = new List<POCD_MT000040Entry>();

            if (problemDiagnosisList != null && problemDiagnosisList.Any())
            {
                foreach (var diagnosis in problemDiagnosisList)
                {
                    CreateProblemDiagnosisEntry(diagnosis, ref entryList);
                }
            }

            return entryList;
        }

        private static void CreateProblemDiagnosisEntry(ProblemDiagnosis problemDiagnosis,
                                                        ref List<POCD_MT000040Entry> entryList)
        {
            var relationshipList = new List<POCD_MT000040EntryRelationship>();

            var dateOfResolutionRemission = problemDiagnosis.DateOfResolutionRemission != null && problemDiagnosis.DateOfResolutionRemission != null ? problemDiagnosis.DateOfResolutionRemission.ToString(): String.Empty;

            //Date of resolution / Remission
            if (problemDiagnosis.DateOfResolutionRemission != null)
                relationshipList.Add(CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.SUBJ, false,
                                                                        null,
                                                                        CreateConceptDescriptor("103.15510",
                                                                                                CodingSystem.NCTIS, null,
                                                                                                "Date of Resolution/Remission",
                                                                                                null), null, null,
                                                                        CreateIntervalTimestamp(null, null, null, null, dateOfResolutionRemission, null), null));

            //Problem / Diagnosis comment
            if (!String.IsNullOrEmpty(problemDiagnosis.Comment))
                relationshipList.Add(CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.COMP,
                                                                x_ActClassDocumentEntryAct.INFRM, x_DocumentActMood.EVN,
                                                                false,
                                                                CreateConceptDescriptor("103.16545", CodingSystem.NCTIS,
                                                                                        null,
                                                                                        "Problem/Diagnosis Comment",
                                                                                        null),
                                                                CreateStructuredText(problemDiagnosis.Comment, null),
                                                                null));

            //Date of Onset + Problem interpretation
            entryList.Add(CreateEntryObservation(x_ActRelationshipEntry.COMP,
                                                 CreateConceptDescriptor("282291009", CodingSystem.SNOMED, null, "Diagnosis interpretation", null),
                                                 problemDiagnosis.DateOfOnset,
                                                 new List<ANY>
                                                     {
                                                         CreateConceptDescriptor(problemDiagnosis.ProblemDiagnosisIdentification)
                                                     }, null,
                                                 relationshipList));
        }

        private static void CreateProblemDiagnosisEntry(IProblemDiagnosis problemDiagnosis, ref List<POCD_MT000040Entry> entryList)
        {
            var relationshipList = new List<POCD_MT000040EntryRelationship>();

            var dateOfResolutionRemission = problemDiagnosis.DateOfResolutionRemission != null
                                                ? problemDiagnosis.DateOfResolutionRemission.ToString()
                                                : String.Empty;

            //Date of resolution / Remission
            if (problemDiagnosis.DateOfResolutionRemission != null)
                relationshipList.Add(CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.SUBJ, false,
                                                                        null,
                                                                        CreateConceptDescriptor("103.15510",
                                                                                                CodingSystem.NCTIS, null,
                                                                                                "Date of Resolution/Remission",
                                                                                                null), null, null,
                                                                        CreateIntervalTimestamp(null, null, null, null,
                                                                                                dateOfResolutionRemission,
                                                                                                null), null));

            //Problem / Diagnosis comment
            if (!String.IsNullOrEmpty(problemDiagnosis.Comment))
                relationshipList.Add(CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.COMP,
                                                                x_ActClassDocumentEntryAct.INFRM, x_DocumentActMood.EVN,
                                                                false,
                                                                CreateConceptDescriptor("103.16545", CodingSystem.NCTIS,
                                                                                        null,
                                                                                        "Problem/Diagnosis Comment",
                                                                                        null),
                                                                CreateStructuredText(problemDiagnosis.Comment, null),
                                                                null));

            //Date of Onset + Problem interpretation
            entryList.Add(CreateEntryObservation(x_ActRelationshipEntry.COMP,
                                                 CreateConceptDescriptor("282291009", CodingSystem.SNOMED, null,
                                                                         "Diagnosis interpretation", null),
                                                 problemDiagnosis.DateOfOnset,
                                                 new List<ANY>
                                                     {
                                                         CreateConceptDescriptor(
                                                             problemDiagnosis.ProblemDiagnosisIdentification)
                                                     }, null,
                                                 relationshipList));
        }

        private static IEnumerable<POCD_MT000040Entry> CreateProcedureEntries(
            List<IMedicalHistoryItem> medicalHistoryItems, ICodableText medicalHistoryItemDescriptor)
        {
            var entryList = new List<POCD_MT000040Entry>();

            if (medicalHistoryItems != null && medicalHistoryItems.Any())
            {
                foreach (var medicalHistory in medicalHistoryItems)
                {
                    var relationships = new List<POCD_MT000040EntryRelationship>();

                    if (medicalHistory.ItemComment != null)
                    {
                        relationships.Add(CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.COMP,
                                                                     x_ActClassDocumentEntryAct.INFRM,
                                                                     x_DocumentActMood.EVN, false,
                                                                     CreateConceptDescriptor("103.16630",
                                                                                             CodingSystem.NCTIS, null,
                                                                                             "Medical History Item Comment",
                                                                                             null),
                                                                     CreateStructuredText(medicalHistory.ItemComment, null), null));
                    }

                    entryList.Add(CreateEntryActEvent(x_ActRelationshipEntry.COMP, x_ActClassDocumentEntryAct.ACT,
                                                      x_DocumentActMood.EVN,
                                                      CreateConceptDescriptor(medicalHistoryItemDescriptor),
                                                      medicalHistory.ItemDescription, null,
                                                      medicalHistory.DateTimeInterval,
                                                      null, null, null, relationships));
                }
            }

            return entryList;
        }

        private static List<POCD_MT000040Entry> CreateProcedureEntries(ICollection<Procedure> procedureList)
        {
            var entryList = new List<POCD_MT000040Entry>();

            if (procedureList != null && procedureList.Any())
            {
                foreach (var procedure in procedureList)
                {
                    var relationshipList = new List<POCD_MT000040EntryRelationship>
                                               {
                                                   String.IsNullOrEmpty(procedure.Comment) ? null
                                                       : CreateEntryRelationshipACT(
                                                           x_ActRelationshipEntryRelationship.COMP,
                                                           x_ActClassDocumentEntryAct.INFRM, x_DocumentActMood.EVN,
                                                           false,
                                                           CreateConceptDescriptor("103.15595", CodingSystem.NCTIS, null, "Procedure Comment", null),
                                                           CreateStructuredText(procedure.Comment, null), null)
                                               };

                    //Procedure code and start date.
                    entryList.Add(CreateEntryProcedureEvent(x_ActRelationshipEntry.COMP,
                                                            CreateConceptDescriptor(procedure.ProcedureName),
                                                            procedure.Start, relationshipList));
                }
            }

            return entryList;
        }

        private static POCD_MT000040Entry CreateMedicalHistoryReviewEntry(DateTime? reviewDateTime)
        {
            var entry = new POCD_MT000040Entry();

            if (reviewDateTime.HasValue)
            {
                entry = CreateEntryActEvent(x_ActRelationshipEntry.COMP, x_ActClassDocumentEntryAct.ACT,
                                            x_DocumentActMood.EVN,
                                            CreateConceptDescriptor("102.16576.120.1.3", CodingSystem.NCTIS, null,
                                                                    "Medical History Review", null),
                                            reviewDateTime.Value.ToString(DATE_TIME_SHORT_FORMAT));
            }

            return entry;
        }

        private static POCD_MT000040Entry CreateExclusionStatement(string exclusionStatement, string exclusionStatementCode, string displayName)
        {
            var entry = new POCD_MT000040Entry();

            if (exclusionStatement != null)
            {
                entry = CreateEntryObservation(x_ActRelationshipEntry.COMP,
                                               CreateConceptDescriptor(exclusionStatementCode, CodingSystem.NCTIS, null, displayName, null), null,
                                               new List<ANY> {CreateStructuredText(exclusionStatement, null)}, null,
                                               null);
            }
            return entry;
        }

        private static POCD_MT000040Entry CreateExclusionStatement(Statement exclusionStatement, string exclusionStatementCode)
        {
            var entry = new POCD_MT000040Entry();

            if (exclusionStatement != null)
            {
                entry = CreateEntryObservation(x_ActRelationshipEntry.COMP,
                                               CreateConceptDescriptor(exclusionStatementCode, CodingSystem.NCTIS, null,"Global Statement", null), null,
                                               new List<ANY>
                                                   {
                                                       CreateConceptDescriptor(exclusionStatement.Value != null ? exclusionStatement.Value.GetAttributeValue<NameAttribute, string>(x => x.Code) : String.Empty, CodingSystem.NCTISGlobalStatementValues,
                                                       null,
                                                       exclusionStatement.Value != null ? exclusionStatement.Value.GetAttributeValue<NameAttribute, string>(x => x.Name) : String.Empty, null)
                                                   }, null, null);
            }
            return entry;
        }

        #region Private - Address

        /// <summary>
        /// Creates a CDA address array from an address
        /// </summary>
        /// <param name="address">IAddress</param>
        /// <returns>AD array</returns>
        private static AD[] CreateAddressArray(IAddress address)
        {
            AD[] addressArray = null;

            if (address != null)
            {
                addressArray = new[] {CreateAddress(address)};
            }

            return addressArray;
        }

        /// <summary>
        /// Creates a CDA address array from a list of addresses
        /// </summary>
        /// <param name="addresses">IAddress</param>
        /// <returns>AD array</returns>
        private static AD[] CreateAddressArray(IEnumerable<IAddress> addresses)
        {
            AD[] addressArray = null;

            if (addresses != null && addresses.Count() > 0)
            {
                var addressList = new List<AD>();

                foreach (var address in addresses)
                {
                    addressList.Add(CreateAddress(address));
                }

                addressArray = addressList.ToArray();
            }

            return addressArray;
        }

        /// <summary>
        /// Creates a CD address array from a list of Australian addresses
        /// </summary>
        /// <param name="addresses">list of Australian addresses</param>
        /// <returns>AD array</returns>
        private static AD[] CreateAddressArray(IEnumerable<IAddressAustralian> addresses)
        {
            AD[] addressArray = null;

            if (addresses != null && addresses.Count() > 0)
            {
                var addressList = new List<AD>();

                foreach (var address in addresses)
                {
                    addressList.Add(CreateAddress((IAddress) address));
                }

                addressArray = addressList.ToArray();
            }


            return addressArray;
        }

        /// <summary>
        /// Creates a CDA address from an address
        /// </summary>
        /// <param name="address">IAddress</param>
        /// <returns>AD</returns>
        private static AD CreateAddress(IAddress address)
        {
            AD returnValue = null;

            if (address != null)
            {
                returnValue = new AD();

                if (address.AddressAbsentIndicator.HasValue)
                {
                    if (address.AddressAbsentIndicator.Value == AddressAbsentIndicator.NoFixedAddressIndicator)
                    {
                        returnValue.nullFlavor = NullFlavor.NA;
                    }
                    else if (address.AddressAbsentIndicator.Value == AddressAbsentIndicator.Masked)
                    {
                        returnValue.nullFlavor = NullFlavor.MSK;
                    }
                    else if (address.AddressAbsentIndicator.Value == AddressAbsentIndicator.NotKnown)
                    {
                        returnValue.nullFlavor = NullFlavor.UNK;
                    }

                    returnValue.nullFlavorSpecified = true;

                    return returnValue;
                }

                //// NoFixedAddress
                //if (address.NoFixedAddress != null && address.NoFixedAddress.Value)
                //{
                //    returnValue.nullFlavorSpecified = true;
                //    returnValue.nullFlavor = NullFlavor.NA;
                //}

                // Use
                if (address.AddressPurpose != AddressPurpose.Undefined)
                {
                    returnValue.use = new[]
                                          {
                                              (PostalAddressUse)
                                              Enum.Parse(typeof (PostalAddressUse),
                                                         address.AddressPurpose.GetAttributeValue<NameAttribute, string>
                                                             (a => a.Code))
                                          };
                }

                //if (!returnValue.nullFlavorSpecified)
                //{
                    if (address.AustralianAddress != null)
                    {
                        FillAustralianAddress(returnValue, address.AustralianAddress);
                    }
                    else if (address.InternationalAddress != null)
                    {
                        FillInternationalAddress(returnValue, address.InternationalAddress);
                    }
                //}
            }

            return returnValue;
        }

        /// <summary>
        /// Takes in an CDA addres object and an Australian address, and populates the CDA address object
        /// from the Australian address
        /// </summary>
        /// <param name="address">CDA Address</param>
        /// <param name="ausAddress">Australian Address</param>
        private static void FillAustralianAddress(AD address, AustralianAddress ausAddress)
        {
            var addressLine = String.Empty;

            // Unstructured Australian address line
            if (ausAddress.UnstructuredAddressLines != null)
            {
                address.streetAddressLine = new adxpstreetAddressLine[ausAddress.UnstructuredAddressLines.Count];

                for (var x = 0; x < ausAddress.UnstructuredAddressLines.Count; x++)
                {
                    address.streetAddressLine[x] = new adxpstreetAddressLine
                                                       {Text = new[] {ausAddress.UnstructuredAddressLines[x]}};
                }
            }

            // Unit type
            if (ausAddress.UnitType != UnitType.Undefined)
            {
                address.unitType = new[]
                                       {
                                           new adxpunitType
                                               {
                                                   Text =
                                                       new[]
                                                           {
                                                               ausAddress.UnitType.GetAttributeValue
                                                                   <NameAttribute, string>(x => x.Code)
                                                           }
                                               }
                                       };
            }


            // Unit number
            if (!string.IsNullOrEmpty(ausAddress.UnitNumber))
            {
                address.unitID = new[] {new adxpunitID {Text = new[] {ausAddress.UnitNumber}}};
            }

            // Street number
            if (ausAddress.StreetNumber.HasValue)
            {
                address.houseNumber = new[] {new adxphouseNumber {Text = new[] {ausAddress.StreetNumber.ToString()}}};
            }

            // Street name
            if (!string.IsNullOrEmpty(ausAddress.StreetName))
            {
                address.streetName = new[] {new adxpstreetName {Text = new[] {ausAddress.StreetName}}};
            }

            // Street type
            if (ausAddress.StreetType != StreetType.Undefined)
            {
                address.streetNameType = new[]
                                             {
                                                 new adxpstreetNameType
                                                     {
                                                         Text =
                                                             new[]
                                                                 {
                                                                     ausAddress.StreetType.GetAttributeValue
                                                                         <NameAttribute, string>(x => x.Code)
                                                                 }
                                                     }
                                             };

            }

            // Additional locator elements
            var adds = new List<adxpadditionalLocator>();

            if (!string.IsNullOrEmpty(ausAddress.AddressSiteName))
                adds.Add(new adxpadditionalLocator {Text = new[] {ausAddress.AddressSiteName}});

            if (ausAddress.LevelType != AustralianAddressLevelType.Undefined)
                adds.Add(new adxpadditionalLocator
                             {Text = new[] {ausAddress.LevelType.GetAttributeValue<NameAttribute, string>(x => x.Code)}});

            if (!string.IsNullOrEmpty(ausAddress.LevelNumber))
                adds.Add(new adxpadditionalLocator {Text = new[] {ausAddress.LevelNumber}});

            if (!string.IsNullOrEmpty(ausAddress.LotNumber))
                adds.Add(new adxpadditionalLocator {Text = new[] {ausAddress.LotNumber}});

            if (ausAddress.DeliveryPointId.HasValue)
                adds.Add(new adxpadditionalLocator {Text = new[] {ausAddress.DeliveryPointId.ToString()}});

            if (adds.Any())
            {
                address.additionalLocator = adds.ToArray();
            }

            // Australian postal delivery type and postal delivery number
            var deliveryLines = new List<adxpdeliveryAddressLine>();

            if (ausAddress.PostalDeliveryType != PostalDeliveryType.Undefined)
            {
                if (ausAddress.PostalDeliveryType != PostalDeliveryType.Undefined)
                    deliveryLines.Add(new adxpdeliveryAddressLine
                                          {
                                              Text =
                                          new[]
                                              {
                                                  ausAddress.PostalDeliveryType.GetAttributeValue<NameAttribute, string>
                                          (x => x.Code),
                                                  (String.IsNullOrEmpty(ausAddress.PostalDeliveryNumber)
                                                       ? String.Empty
                                                       : ausAddress.PostalDeliveryNumber)
                                              }
                                          });
            }

            if (deliveryLines.Any())
                address.deliveryAddressLine = deliveryLines.ToArray();

            // Suburb + town + locality
            if (!string.IsNullOrEmpty(ausAddress.SuburbTownLocality))
                address.city = new[] {new adxpcity {Text = new[] {ausAddress.SuburbTownLocality}}};

            // State
            if (ausAddress.State != AustralianState.Undefined)
            {
                address.state = new[] {new adxpstate {Text = new[] {ausAddress.State.ToString()}}};
            }

            // Postcode
            if (!string.IsNullOrEmpty(ausAddress.PostCode))
            {
                address.postalCode = new[] {new adxppostalCode {Text = new[] {ausAddress.PostCode}}};
            }
            //Country
            address.country = new[] {new adxpcountry {Text = new[] {"Australia"}}};

            if (address.streetAddressLine == null && !String.IsNullOrEmpty(addressLine))
            {
                address.streetAddressLine = new adxpstreetAddressLine[1];

                address.streetAddressLine[0] = new adxpstreetAddressLine {Text = new[] {addressLine}};
            }
        }

        /// <summary>
        /// Takes in an CDA addres object and an International address, and populates the CDA address object
        /// from the International address
        /// </summary>
        /// <param name="address">CDA Address</param>
        /// <param name="intAddress">International Address</param>
        private static void FillInternationalAddress(AD address, InternationalAddress intAddress)
        {
            if (intAddress.AddressLine != null)
            {
                address.streetAddressLine = new adxpstreetAddressLine[intAddress.AddressLine.Count];
                for (var x = 0; x < intAddress.AddressLine.Count; x++)
                {
                    address.streetAddressLine[x] = new adxpstreetAddressLine {Text = new[] {intAddress.AddressLine[x]}};
                }
            }

            if (!string.IsNullOrEmpty(intAddress.StateProvince))
                address.state = new[] {new adxpstate {Text = new[] {intAddress.StateProvince}}};

            if (!string.IsNullOrEmpty(intAddress.PostCode))
                address.postalCode = new[] {new adxppostalCode {Text = new[] {intAddress.PostCode}}};

            if (intAddress.Country != Country.Undefined)
            {
                address.country = new[]
                                      {
                                          new adxpcountry
                                              {
                                                  Text =
                                                      new[]
                                                          {
                                                              intAddress.Country.GetAttributeValue
                                                                  <NameAttribute, string>(a => a.Name)
                                                          }
                                              }
                                      };
            }

        }

        #endregion

        #region Private Entry - Substance administration

        private static POCD_MT000040Entry CreateEntrySubstanceAdministration()
        {
            var entry = new POCD_MT000040Entry();

            entry.typeCode = x_ActRelationshipEntry.DRIV;
            entry.substanceAdministration = new POCD_MT000040SubstanceAdministration();
            entry.substanceAdministration.moodCode = x_DocumentSubstanceMood.RQO;
            entry.substanceAdministration.classCode = ActClass.SBADM;
            entry.substanceAdministration.statusCode = CreateCodeSystem("active", null, null, null, null, null, null);

            return entry;
        }

        #endregion

        #region Private Entry - Observation

        private static POCD_MT000040Entry CreateEntryObservation(CD code, ANY any)
        {
            return CreateEntryObservation(code, new List<ANY> {any});
        }

        internal static POCD_MT000040Entry CreateEntryObservation(CD code, List<ANY> anyList)
        {
            var entry = new POCD_MT000040Entry
                            {
                                observation =
                                    new POCD_MT000040Observation
                                        {
                                            classCode = ActClassObservation.OBS,
                                            moodCode = x_ActMoodDocumentObservation.EVN,
                                            id = CreateIdentifierArray(CreateGuid(), null)
                                        }
                            };

            if (code != null)
            {
                entry.observation.code = code;
            }

            if (anyList != null)
            {
                entry.observation.value = anyList.ToArray();
            }

            return entry;
        }

        internal static POCD_MT000040Entry CreateEntryObservation(x_ActRelationshipEntry actRelationshipEntry, CD code,
                                                                 CE methodCode, CD targetSiteCode,
                                                                 DateTime? effectiveTime, List<ANY> anyList, CE ceCode,
                                                                 List<POCD_MT000040EntryRelationship> entryRelationshipList)
        {
            var entry = new POCD_MT000040Entry
                            {
                                typeCode = actRelationshipEntry,
                                observation =
                                    new POCD_MT000040Observation
                                        {
                                            classCode = ActClassObservation.OBS,
                                            moodCode = x_ActMoodDocumentObservation.EVN,
                                            id = CreateIdentifierArray(CreateGuid(), null)
                                        }
                            };

            if (code != null)
            {
                entry.observation.code = code;
            }

            if (targetSiteCode != null)
            {
                entry.observation.targetSiteCode = new[] {targetSiteCode};
            }

            if (methodCode != null)
            {
                entry.observation.methodCode = new[] {methodCode};
            }

            if (effectiveTime.HasValue)
            {
                entry.observation.effectiveTime = new IVL_TS {value = effectiveTime.Value.ToString(DATE_TIME_FORMAT)};
            }

            if (anyList != null)
            {
                entry.observation.value = anyList.ToArray();
            }

            if (ceCode != null)
            {
                entry.observation.participant = CreateParticipant2Array(ceCode, EntityDeterminer.INSTANCE);
            }

            if (entryRelationshipList != null)
            {
                entry.observation.entryRelationship = entryRelationshipList.ToArray();
            }

            return entry;
        }

        private static POCD_MT000040Entry CreateEntryObservation(x_ActRelationshipEntry actRelationshipEntry, CD code,
                                                                 CE[] methodCode, CD[] targetSiteCode,
                                                                 DateTime? effectiveTime, List<ANY> anyList, CE ceCode,
                                                                 List<POCD_MT000040EntryRelationship>
                                                                     entryRelationshipList, string text)
        {
            var entry = new POCD_MT000040Entry
                            {
                                typeCode = actRelationshipEntry,
                                observation =
                                    new POCD_MT000040Observation
                                        {
                                            classCode = ActClassObservation.OBS,
                                            moodCode = x_ActMoodDocumentObservation.EVN,
                                            id = CreateIdentifierArray(CreateGuid(), null)
                                        }
                            };

            if (code != null)
            {
                entry.observation.code = code;
            }

            if (targetSiteCode != null)
            {
                entry.observation.targetSiteCode = targetSiteCode;
            }

            if (methodCode != null)
            {
                entry.observation.methodCode = methodCode;
            }

            if (effectiveTime.HasValue)
            {
                entry.observation.effectiveTime = new IVL_TS {value = effectiveTime.Value.ToString(DATE_TIME_FORMAT)};
            }

            if (anyList != null)
            {
                entry.observation.value = anyList.ToArray();
            }

            if (ceCode != null)
            {
                entry.observation.participant = CreateParticipant2Array(ceCode, EntityDeterminer.INSTANCE);
            }

            if (entryRelationshipList != null)
            {
                entry.observation.entryRelationship = entryRelationshipList.ToArray();
            }

            if (text != null)
                entry.observation.text = CreateEncapsulatedData(text);

            return entry;
        }

        private static POCD_MT000040Entry CreateEntryObservation(x_ActRelationshipEntry actRelationshipEntry, CD code,
                                                                 ISO8601DateTime effectiveTime, List<ANY> anyList, CE ceCode,
                                                                 List<POCD_MT000040EntryRelationship>
                                                                     entryRelationshipList, BodyWeight bodyWeight)
        {
            var entry = CreateEntryObservation(actRelationshipEntry, code, effectiveTime, anyList, ceCode,
                                               entryRelationshipList);

            if (bodyWeight != null)
            {
                entry.observation.value = new ANY[]
                                              {
                                                  new PQ
                                                      {
                                                          unit = bodyWeight.UnitOfMeasure,
                                                          value =
                                                              bodyWeight.Weight == null
                                                                  ? null
                                                                  : bodyWeight.Weight.Value.ToString()
                                                      }
                                              };
            }

            return entry;
        }

        private static POCD_MT000040Entry CreateEntryObservation(x_ActRelationshipEntry actRelationshipEntry, CD code,
                                                                 ISO8601DateTime effectiveTime, List<ANY> anyList, CE ceCode,
                                                                 List<POCD_MT000040EntryRelationship>
                                                                     entryRelationshipList, BodyHeight bodyHeight)
        {
            var entry = CreateEntryObservation(actRelationshipEntry, code, effectiveTime, anyList, ceCode,
                                               entryRelationshipList);

            if (bodyHeight != null)
            {
                entry.observation.value = new ANY[]
                                              {
                                                  new PQ
                                                      {
                                                          unit = bodyHeight.UnitOfMeasure,
                                                          value =
                                                              bodyHeight.Height == null
                                                                  ? null
                                                                  : bodyHeight.Height.Value.ToString()
                                                      }
                                              };
            }

            return entry;
        }

        private static POCD_MT000040Entry CreateEntryObservation(x_ActRelationshipEntry actRelationshipEntry,
                                                                  CD code,
                                                                  ISO8601DateTime effectiveTime,
                                                                  List<POCD_MT000040EntryRelationship> entryRelationshipList)
        {

          var entry = new POCD_MT000040Entry
          {
            typeCode = actRelationshipEntry,
            observation =
                new POCD_MT000040Observation
                {
                  classCode = ActClassObservation.OBS,
                  moodCode = x_ActMoodDocumentObservation.EVN,
                  id = CreateIdentifierArray(CreateGuid(), null)
                }
          };

          if (code != null)
          {
            entry.observation.code = code;
          }

          if (effectiveTime != null)
          {
            entry.observation.effectiveTime = CreateIntervalTimestamp(null, null, null, null, effectiveTime.ToString(), null);
          }

          if (entryRelationshipList.Any())
          {
            entry.observation.entryRelationship = entryRelationshipList.ToArray();
          }

          return entry;
        }


        private static POCD_MT000040Entry CreateEntryObservation(x_ActRelationshipEntry? actRelationshipEntry, CD code,
                                                                 ISO8601DateTime effectiveTime, List<ANY> anyList, CE ceCode,
                                                                 List<POCD_MT000040EntryRelationship> entryRelationshipList)
        {
            var entry = new POCD_MT000040Entry
                            {
                                observation =
                                    new POCD_MT000040Observation
                                        {
                                            classCode = ActClassObservation.OBS,
                                            moodCode = x_ActMoodDocumentObservation.EVN,
                                            id = CreateIdentifierArray(CreateGuid(), null)
                                        }
                            };

            if (actRelationshipEntry.HasValue)
            {
                entry.typeCode = (x_ActRelationshipEntry) actRelationshipEntry.Value;
            }

            if (code != null)
            {
                entry.observation.code = code;
            }

            if (effectiveTime != null)
            {
                entry.observation.effectiveTime = new IVL_TS {value = effectiveTime.ToString()};
            }

            if (anyList != null && anyList.Any())
            {
                entry.observation.value = anyList.ToArray();
            }

            if (ceCode != null)
            {
                entry.observation.participant = CreateParticipant2Array(ceCode, EntityDeterminer.INSTANCE);
            }

            if (entryRelationshipList != null)
            {
                entry.observation.entryRelationship = entryRelationshipList.ToArray();
            }

            return entry;
        }

        private static POCD_MT000040Entry CreateEntryObservationWithDuration(
            x_ActRelationshipEntry actRelationshipEntry, CD code, CdaInterval duration, List<ANY> anyList, CE ceCode,
            List<POCD_MT000040EntryRelationship> entryRelationshipList)
        {
            return CreateEntryObservation(actRelationshipEntry, code, duration != null ? duration.Low : null,
                                          duration != null ? duration.High : null, anyList, ceCode, entryRelationshipList);
        }

        private static POCD_MT000040Entry CreateEntryObservation(x_ActRelationshipEntry actRelationshipEntry, CD code,
                                                                 ISO8601DateTime effectiveTimeHigh, ISO8601DateTime effectiveTimeLow,
                                                                 List<ANY> anyList, CE ceCode,
                                                                 List<POCD_MT000040EntryRelationship>
                                                                     entryRelationshipList)
        {
            var entry = new POCD_MT000040Entry
                            {
                                typeCode = actRelationshipEntry,
                                observation =
                                    new POCD_MT000040Observation
                                        {
                                            classCode = ActClassObservation.OBS,
                                            moodCode = x_ActMoodDocumentObservation.EVN,
                                            id = CreateIdentifierArray(CreateGuid(), null)
                                        }
                            };

            if (code != null)
            {
                entry.observation.code = code;
            }

            Dictionary<ItemsChoiceType3, QTY> items = new Dictionary<ItemsChoiceType3, QTY>();
            if (effectiveTimeHigh != null || effectiveTimeLow != null)
            {
                if (effectiveTimeHigh != null)
                {
                    items.Add(ItemsChoiceType3.high,
                              new IVXB_TS
                                  {
                                      //inclusive = false,
                                      nullFlavor = NullFlavor.NA,
                                      nullFlavorSpecified = false,
                                      value = effectiveTimeHigh.ToString()
                                  });
                }

                if (effectiveTimeLow != null)
                {
                    items.Add(ItemsChoiceType3.low,
                              new IVXB_TS
                                  {
                                      //inclusive = false,
                                      nullFlavor = NullFlavor.NA,
                                      nullFlavorSpecified = false,
                                      value = effectiveTimeLow.ToString()
                                  });
                }

                if (items.Any())
                {
                    entry.observation.effectiveTime = new IVL_TS();
                    entry.observation.effectiveTime.ItemsElementName = items.Keys.ToArray();
                    entry.observation.effectiveTime.Items = items.Values.ToArray();
                }
            }

            if (anyList != null && anyList.Any())
            {
                entry.observation.value = anyList.ToArray();
            }

            if (ceCode != null)
            {
                entry.observation.participant = CreateParticipant2Array(ceCode, EntityDeterminer.INSTANCE);
            }

            if (entryRelationshipList != null)
            {
                entry.observation.entryRelationship = entryRelationshipList.ToArray();
            }

            return entry;
        }

        #endregion

        #region Private Entry Relationship - Observation

        private static POCD_MT000040Observation CreateObservation(ActClassObservation actClassObservation,
                                                                  x_ActMoodDocumentObservation
                                                                      actMoodDocumentObservation, String text)
        {
            return CreateObservation(actClassObservation, actMoodDocumentObservation, null, null, text);
        }

        private static POCD_MT000040Observation CreateObservation(ActClassObservation actClassObservation,
                                                                  x_ActMoodDocumentObservation
                                                                  actMoodDocumentObservation, CD code,
                                                                  ISO8601DateTime effectiveTime, String text)
        {
            var observation = new POCD_MT000040Observation
                                  {
                                      classCode = actClassObservation,
                                      moodCode = actMoodDocumentObservation,
                                      id = CreateIdentifierArray(CreateGuid(), null)
                                  };

            if (code != null)
            {
                observation.code = code;
            }

            if (!String.IsNullOrEmpty(text))
            {
                observation.text = CreateStructuredText(text, null);
            }

            if (effectiveTime != null)
            {
                observation.effectiveTime = CreateIntervalTimestamp(null, null, null, null,
                                                                    effectiveTime.ToString(),
                                                                    null);
            }
            return observation;
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipSubstanceAdministration(x_ActRelationshipEntryRelationship actRelationshipEntry,
                                                                                                     ActClass actClass,
                                                                                                     x_DocumentSubstanceMood documentSubstanceMood,
                                                                                                     ISO8601DateTime effectiveTime,
                                                                                                     int? numberOfRepeats
                                                                                                     )
        {
          POCD_MT000040EntryRelationship entryRelationship = null;

            entryRelationship = new POCD_MT000040EntryRelationship
                                                    {
                                                         typeCode = actRelationshipEntry,
                                                         substanceAdministration = new POCD_MT000040SubstanceAdministration
                                                                                     {
                                                                                        classCode = actClass,
                                                                                        moodCode = documentSubstanceMood,
                                                                                        effectiveTime = effectiveTime != null ? new[] { new SXCM_TS { value = effectiveTime.ToString() } } : null,
                                                                                        repeatNumber = new IVL_INT
                                                                                        {
                                                                                            ItemsElementName = new [] { ItemsChoiceType5.high },
                                                                                            Items = numberOfRepeats.HasValue ? new[] { new IVXB_INT { value = numberOfRepeats.Value.ToString(CultureInfo.InvariantCulture) } } : null,
                                                                                        },
                                                                                        consumable = new POCD_MT000040Consumable
                                                                                                       {
                                                                                                         manufacturedProduct = new POCD_MT000040ManufacturedProduct
                                                                                                                                 {
                                                                                                                                   manufacturedMaterial = new POCD_MT000040Material() 
                                                                                                                                 },
                                                                                                       }
                                                                                     },
                                                      };

          return entryRelationship;
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipObservation(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, Boolean? inversion, CD code,
            List<ANY> values)
        {
            return CreateEntryRelationshipObservation(actRelationshipEntryRelationship, ActClassObservation.OBS,
                                                      x_ActMoodDocumentObservation.EVN, inversion, null, code, null,
                                                      null, values, null);
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipObservation(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, Boolean? inversion, CD code,
            List<ANY> values, Boolean showObservationId)
        {
            var entryRelationshipObservation = CreateEntryRelationshipObservation(actRelationshipEntryRelationship,
                                                                                  ActClassObservation.OBS,
                                                                                  x_ActMoodDocumentObservation.EVN,
                                                                                  inversion, null, code, null, null,
                                                                                  values, null);

            if (!showObservationId) entryRelationshipObservation.observation.id = null;

            return entryRelationshipObservation;
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipObservation(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, Boolean? inversion, CD code,
            String text, List<ANY> values, List<POCD_MT000040EntryRelationship> entryRelationshipList)
        {
            var entryRelationshipObservation = CreateEntryRelationshipObservation(actRelationshipEntryRelationship,
                                                                                  ActClassObservation.OBS,
                                                                                  x_ActMoodDocumentObservation.EVN,
                                                                                  inversion, null, code, CreateEncapsulatedData(text), null,
                                                                                  values, entryRelationshipList);

            return entryRelationshipObservation;
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipObservation(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, CD code, ANY value)
        {
            return CreateEntryRelationshipObservation(actRelationshipEntryRelationship, null, null, code, null, null,
                                                      value, null);
        }

        internal static POCD_MT000040EntryRelationship CreateEntryRelationshipObservation(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, CD code, ANY value, String text)
        {
            return CreateEntryRelationshipObservation(actRelationshipEntryRelationship, null, null, code, text, null,
                                                      value, null);
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipObservation(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, CD code, ANY value, ST text)
        {
            var entryRelationshipObservation = CreateEntryRelationshipObservation(actRelationshipEntryRelationship, null,
                                                                                  null, code, null, null, value, null);

            if (text != null) entryRelationshipObservation.observation.text = text;

            return entryRelationshipObservation;
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipObservation(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, Boolean? inversion, CD code,
            ED text)
        {
            return CreateEntryRelationshipObservation(actRelationshipEntryRelationship, ActClassObservation.OBS,
                                                      x_ActMoodDocumentObservation.EVN, inversion, null, code, text,
                                                      null, null, null);
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipObservation(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, CD code)
        {
            return CreateEntryRelationshipObservation(actRelationshipEntryRelationship, null, null, code, null, null,
                                                      null, null);
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipObservation(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, CD code,
            List<POCD_MT000040EntryRelationship> entryRelationshipList)
        {
            return CreateEntryRelationshipObservation(actRelationshipEntryRelationship, null, null, code, null, null,
                                                      null, entryRelationshipList);
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipObservation(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, Boolean? inversion,
            ISO8601DateTime effectiveTime, CD code)
        {
            return CreateEntryRelationshipObservation(actRelationshipEntryRelationship, ActClassObservation.OBS,
                                                      x_ActMoodDocumentObservation.EVN, inversion, effectiveTime, code,
                                                      null, null, null, null);
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipObservation(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, Boolean? inversion,
            ISO8601DateTime effectiveTime, CD code, ICollection<II> id)
        {
            return CreateEntryRelationshipObservation(actRelationshipEntryRelationship, ActClassObservation.OBS,
                                                      x_ActMoodDocumentObservation.EVN, inversion, effectiveTime, code,
                                                      null, id, null, null);
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipObservation(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, Boolean? inversion, CD code)
        {
            return CreateEntryRelationshipObservation(actRelationshipEntryRelationship, ActClassObservation.OBS,
                                                      x_ActMoodDocumentObservation.EVN, inversion, null, code, null,
                                                      null, null, null);
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipObservation(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, Boolean? inversion,
            ISO8601DateTime effectiveTime, CD code, String text, ICollection<II> id, ANY value,
            List<POCD_MT000040EntryRelationship> entryRelationshipList)
        {
            return CreateEntryRelationshipObservation(actRelationshipEntryRelationship, ActClassObservation.OBS,
                                                      x_ActMoodDocumentObservation.EVN, inversion, effectiveTime, code,
                                                      CreateEncapsulatedData(text), id, new List<ANY> { value }, entryRelationshipList);
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipObservationMedia(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, ExternalData externalData)
        {
            POCD_MT000040EntryRelationship imageEntryRelationship = null;

            if (externalData != null)
            {
                imageEntryRelationship = new POCD_MT000040EntryRelationship
                                             {
                                                 typeCode = actRelationshipEntryRelationship,
                                                 observationMedia = CreateObservationMedia(externalData)
                                             };
            }

            return imageEntryRelationship;
        }


        private static POCD_MT000040EntryRelationship CreateEntryRelationshipObservation(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, ActClassObservation classCode,
            x_ActMoodDocumentObservation moodCode, CD code, ICollection<II> id)
        {
            return CreateEntryRelationshipObservation(actRelationshipEntryRelationship, classCode, moodCode, false, null,
                                                      code, null, id, null, null);
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipObservation(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, ActClassObservation classCode,
            x_ActMoodDocumentObservation moodCode, Boolean? inversion, ISO8601DateTime effectiveTime, CD code, ED text,
            ICollection<II> id, List<ANY> values, List<POCD_MT000040EntryRelationship> entryRelationshipList)
        {
            II[] ident = null;

            if (id == null || id.Count == 0)
            {
                ident = CreateIdentifierArray(CreateGuid(), null);
            }
            else
            {
                ident = id.ToArray();
            }

            var entityRelationship = new POCD_MT000040EntryRelationship
                                         {
                                             typeCode = actRelationshipEntryRelationship,
                                             inversionInd = true,
                                             inversionIndSpecified = inversion.HasValue && inversion.Value,
                                             observation =
                                                 new POCD_MT000040Observation
                                                     {
                                                         classCode = classCode,
                                                         moodCode = moodCode,
                                                         id = ident,
                                                         code = code
                                                     }
                                         };

            if (text != null)
            {
                entityRelationship.observation.text = text;
            }

            if (values != null && values.Any())
            {
                entityRelationship.observation.value = values.ToArray();
            }

            if (effectiveTime != null)
            {
                entityRelationship.observation.effectiveTime = CreateIntervalTimestamp(effectiveTime, null);
            }

            if (entryRelationshipList != null)
            {
                entityRelationship.observation.entryRelationship = entryRelationshipList.ToArray();
            }

            return entityRelationship;
        }

        private static POCD_MT000040Observation CreateSpecimenDetail(SpecimenDetail specimenDetail, ICodableText code)
        {
            POCD_MT000040Observation observation = null;

            if (specimenDetail != null)
            {
                observation = new POCD_MT000040Observation
                                  {
                                      classCode = ActClassObservation.OBS,
                                      moodCode = x_ActMoodDocumentObservation.EVN,
                                      code = CreateConceptDescriptor(code),
                                      id = CreateIdentifierArray(CreateGuid(), null)
                                  };

                if (specimenDetail.CollectionProcedure != null)
                {
                    observation.methodCode =
                        new List<CE> {CreateCodedWithExtensionElement(specimenDetail.CollectionProcedure)}.ToArray
                            ();
                }

                if (specimenDetail.CollectionDateTime != null)
                {
                    observation.effectiveTime = new IVL_TS
                                                    {
                                                        value = specimenDetail.CollectionDateTime.ToString()
                                                    };
                }

                //Anatomical Site
                if (specimenDetail.AnatomicalSite != null && specimenDetail.AnatomicalSite.Any())
                {
                    observation.targetSiteCode =
                        CreateConceptDescriptorsForAnatomicalSites(specimenDetail.AnatomicalSite).ToArray();
                }

                var entryRelationshipList = new List<POCD_MT000040EntryRelationship>();

                SpecimenDetailEntryRelationships(specimenDetail, ref entryRelationshipList);

                observation.specimen = new List<POCD_MT000040Specimen> {CreateSpecimenDetailIdentifiers(specimenDetail)}.ToArray();

                //Sub entry Relationship
                if (entryRelationshipList != null)
                {
                    observation.entryRelationship = entryRelationshipList.ToArray();
                }

                if (specimenDetail.CollectionDateTime != null)
                {
                    observation.effectiveTime = CreateIntervalTimestamp(specimenDetail.CollectionDateTime, null);
                }
            }

            return observation;
        }

        private static void SpecimenDetailEntryRelationships(SpecimenDetail specimenDetail, ref List<POCD_MT000040EntryRelationship> entryRelationshipList)
        {
            if (specimenDetail != null)
            {
                if (entryRelationshipList == null)
                {
                    return;
                }

                if (specimenDetail.PhysicalDetails != null)
                foreach (var physicalDetails in specimenDetail.PhysicalDetails)
                {
                    if (physicalDetails.Image != null)
                    {
                        var imageEntryRelationship = new POCD_MT000040EntryRelationship
                                                         {
                                                             typeCode = x_ActRelationshipEntryRelationship.SPRT,
                                                             observationMedia = CreateObservationMedia(physicalDetails.Image)
                                                         };
                        entryRelationshipList.Add(imageEntryRelationship);
                    }
                }

                //Anatomical location image
                if (specimenDetail.AnatomicalSite != null && specimenDetail.AnatomicalSite.Any())
                {
                    foreach (var anatomicalSite in specimenDetail.AnatomicalSite)
                    {
                        if (anatomicalSite.Images != null && anatomicalSite.Images.Any())
                        {
                            foreach (var image in anatomicalSite.Images)
                            {
                                entryRelationshipList.Add
                                    (
                                        new POCD_MT000040EntryRelationship
                                        {
                                            typeCode = x_ActRelationshipEntryRelationship.SPRT,
                                            observationMedia = CreateObservationMedia(image)
                                        }
                                    );
                            }
                        }
                    }
                }

                if (specimenDetail.SamplingPreconditions != null)
                {
                    var samplingPreconditionsRelationship = new POCD_MT000040EntryRelationship
                                                                {
                                                                    typeCode = x_ActRelationshipEntryRelationship.COMP,
                                                                    observation =
                                                                        new POCD_MT000040Observation
                                                                            {
                                                                                classCode = ActClassObservation.OBS,
                                                                                moodCode =
                                                                                    x_ActMoodDocumentObservation.EVN,
                                                                                code = CreateConceptDescriptor("103.16171", CodingSystem.NCTIS, null, "Sampling Preconditions", null),
                                                                                value = new List<ANY>
                                                                                        {
                                                                                            CreateConceptDescriptor(specimenDetail.SamplingPreconditions)
                                                                                        }.ToArray()
                                                                            }
                                                                };

                    entryRelationshipList.Add(samplingPreconditionsRelationship);
                }

                if (!String.IsNullOrEmpty(specimenDetail.CollectionSetting))
                {
                    var collectionSettingRelationship = new POCD_MT000040EntryRelationship
                                                            {
                                                                typeCode = x_ActRelationshipEntryRelationship.COMP,
                                                                observation =
                                                                    new POCD_MT000040Observation
                                                                        {
                                                                            classCode = ActClassObservation.OBS,
                                                                            moodCode = x_ActMoodDocumentObservation.EVN,
                                                                            code =
                                                                                CreateConceptDescriptor("103.16529",
                                                                                                        CodingSystem.
                                                                                                            NCTIS, null,
                                                                                                        "Collection Setting",
                                                                                                        null),
                                                                            value =
                                                                                new ANY[]
                                                                                    {
                                                                                        CreateStructuredText(
                                                                                            specimenDetail.
                                                                                                CollectionSetting, null)
                                                                                    }
                                                                        }
                                                            };
                    entryRelationshipList.Add(collectionSettingRelationship);
                }

                if (specimenDetail.ReceivedDateTime != null)
                {
                    var collectionSettingRelationship = new POCD_MT000040EntryRelationship
                                                            {
                                                                typeCode = x_ActRelationshipEntryRelationship.COMP,
                                                                observation =
                                                                    new POCD_MT000040Observation
                                                                        {
                                                                            classCode = ActClassObservation.OBS,
                                                                            moodCode = x_ActMoodDocumentObservation.EVN,
                                                                            value =
                                                                                new ANY[]
                                                                                    {
                                                                                        new TS
                                                                                            {
                                                                                                value =
                                                                                                    specimenDetail.
                                                                                                        ReceivedDateTime
                                                                                                        .ToString()
                                                                                            }
                                                                                    },
                                                                            code =
                                                                                CreateConceptDescriptor("103.11014",
                                                                                                        CodingSystem.
                                                                                                            NCTIS, null,
                                                                                                        "DateTime Received",
                                                                                                        null)
                                                                        },
                                                            };
                    entryRelationshipList.Add(collectionSettingRelationship);
                }

                if (specimenDetail.ParentSpecimenIdentifier != null)
                {
                    var specimenIdentifierRelationship = new POCD_MT000040EntryRelationship
                                                             {
                                                                 typeCode = x_ActRelationshipEntryRelationship.COMP,
                                                                 observation =
                                                                     new POCD_MT000040Observation
                                                                         {
                                                                             classCode = ActClassObservation.OBS,
                                                                             moodCode = x_ActMoodDocumentObservation.EVN,
                                                                             code =
                                                                                 CreateConceptDescriptor("103.16187",
                                                                                                         CodingSystem.
                                                                                                             NCTIS, null,
                                                                                                         "Parent Specimen Identifier",
                                                                                                         null),
                                                                             specimen =
                                                                                 new List<POCD_MT000040Specimen>
                                                                                     {
                                                                                         new POCD_MT000040Specimen
                                                                                             {
                                                                                                 specimenRole =
                                                                                                     new POCD_MT000040SpecimenRole
                                                                                                         {
                                                                                                             id =
                                                                                                                 new II
                                                                                                                     []
                                                                                                                     {
                                                                                                                         CreateIdentifierElement(specimenDetail.ParentSpecimenIdentifier)
                                                                                                                     }
                                                                                                         }
                                                                                             }
                                                                                     }.ToArray()
                                                                         },
                                                             };

                    entryRelationshipList.Add(specimenIdentifierRelationship);
                }
            }
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipACT(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationshipTypeCode,
            x_ActClassDocumentEntryAct classCode, x_DocumentActMood moodCode, Boolean? inversion, CD code, ED text,
            II[] identifier)
        {

            var entryRelationship = CreateEntryRelationshipACT(
              actRelationshipEntryRelationshipTypeCode,
              classCode, moodCode, inversion, code, text,
              identifier, null as IVL_TS);

            return entryRelationship;
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipACT(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationshipTypeCode,
            x_ActClassDocumentEntryAct classCode, x_DocumentActMood moodCode, Boolean? inversion, CD code, ED text,
            II[] identifier, IVL_TS effectiveTime)
        {

            var entryRelationship = new POCD_MT000040EntryRelationship
                                        {
                                            typeCode = actRelationshipEntryRelationshipTypeCode,
                                            inversionInd = true,
                                            inversionIndSpecified = inversion.HasValue ? inversion.Value : false,
                                            act =
                                                new POCD_MT000040Act
                                                    {
                                                        classCode = classCode,
                                                        moodCode = moodCode,
                                                        id = identifier,
                                                        code = code,
                                                        text = text,
                                                        effectiveTime = effectiveTime
                                                    },
                                        };

            return entryRelationship;
        }


        private static POCD_MT000040EntryRelationship CreateEntryRelationshipACT(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationshipTypeCode,
            x_ActClassDocumentEntryAct classCode, x_DocumentActMood moodCode, Boolean? inversion, CD code, ED text,
            II[] identifier, List<POCD_MT000040EntryRelationship> entryRelationships)
        {

            var entryRelationship = new POCD_MT000040EntryRelationship
                                        {
                                            typeCode = actRelationshipEntryRelationshipTypeCode,
                                            inversionInd = true,
                                            inversionIndSpecified = inversion.HasValue ? inversion.Value : false,
                                            act =
                                                new POCD_MT000040Act
                                                    {
                                                        classCode = classCode,
                                                        moodCode = moodCode,
                                                        id = identifier,
                                                        code = code,
                                                        text = text,
                                                        entryRelationship = entryRelationships.ToArray()
                                                    }
                                        };

            return entryRelationship;
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship actRelationshipEntryRelationshipTypeCode, x_ActClassDocumentEntryAct classCode, x_DocumentActMood moodCode, Boolean? inversion, CD code, ED text, II[] identifier, ISO8601DateTime effectiveDateTime)
        {
            var entryRelationship = new POCD_MT000040EntryRelationship
            {
                typeCode = actRelationshipEntryRelationshipTypeCode,
                inversionInd = true,
                inversionIndSpecified = inversion.HasValue ? inversion.Value : false,
                act =
                    new POCD_MT000040Act
                    {
                        classCode = classCode,
                        moodCode = moodCode,
                        id = identifier,
                        code = code,
                        text = text,
                        effectiveTime = effectiveDateTime != null ? CreateIntervalTimestamp(null, null, null, null, effectiveDateTime.ToString(), null) : null
                    }
            };

            return entryRelationship;
        }


        private static POCD_MT000040EntryRelationship CreateEntryRelationshipACT(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationshipTypeCode,
            x_ActClassDocumentEntryAct classCode, x_DocumentActMood moodCode, Boolean? inversion, CD code, ED text,
            II[] identifier, DateTime? effectiveDateTime)
        {
            var entryRelationship = new POCD_MT000040EntryRelationship
                                        {
                                            typeCode = actRelationshipEntryRelationshipTypeCode,
                                            inversionInd = true,
                                            inversionIndSpecified = inversion.HasValue ? inversion.Value : false,
                                            act =
                                                new POCD_MT000040Act
                                                    {
                                                        classCode = classCode,
                                                        moodCode = moodCode,
                                                        id = identifier,
                                                        code = code,
                                                        text = text,
                                                        effectiveTime =
                                                            effectiveDateTime.HasValue
                                                                ? CreateIntervalTimestamp(null, null, null, null,
                                                                                          effectiveDateTime.Value.
                                                                                              ToString(DATE_TIME_FORMAT),
                                                                                          null)
                                                                : null
                                                    }
                                        };

            return entryRelationship;
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipACT(x_ActClassDocumentEntryAct classCode,
                                                                                 x_DocumentActMood moodCode, CD code,
                                                                                 ST text, DateTime? effectiveTime)
        {

            var entryRelationship = new POCD_MT000040EntryRelationship
                                        {
                                            act =
                                                new POCD_MT000040Act
                                                    {
                                                        classCode = classCode,
                                                        moodCode = moodCode,
                                                        id = CreateIdentifierArray(CreateGuid(), null),
                                                        code = code,
                                                        text = text
                                                    }
                                        };

            if (effectiveTime.HasValue)
            {
                entryRelationship.act.effectiveTime = CreateIntervalTimestamp(effectiveTime, null);
            }

            return entryRelationship;
        }

        #endregion

        #region Private Entry Relationship - Organizer

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipOrganiser(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationshipTypeCode,
            x_ActClassDocumentEntryOrganizer classCode, ActMood moodCode, Boolean? inversion, CD code, ED text,
            CS testStatus, ITestResultGroup testResultGroup, CDADocumentType? cdaDocumentType)
        {
            var entryRelationship = new POCD_MT000040EntryRelationship
                                        {
                                            typeCode = actRelationshipEntryRelationshipTypeCode,
                                            inversionInd = true,
                                            inversionIndSpecified = inversion.HasValue ? inversion.Value : false,
                                            organizer =
                                                new POCD_MT000040Organizer
                                                    {
                                                        author = null,
                                                        classCode = classCode,
                                                        code = code,
                                                        component = null,
                                                        effectiveTime = null,
                                                        id = CreateIdentifierArray(CreateGuid(), null),
                                                        informant = null,
                                                        moodCode = moodCode,
                                                        nullFlavor = NullFlavor.NA,
                                                        nullFlavorSpecified = false,
                                                        statusCode = testStatus
                                                    },
                                        };

            var component4List = new List<POCD_MT000040Component4>();

            if (testResultGroup != null && testResultGroup.ResultGroupSpecimenDetail != null)
            {
                component4List.Add(new POCD_MT000040Component4
                                       {
                                           observation = CreateSpecimenDetail(testResultGroup.ResultGroupSpecimenDetail, CreateResultGroupSpecimenDetailCode(cdaDocumentType))
                                       });
            }

            if (testResultGroup != null && testResultGroup.Results != null && testResultGroup.Results.Any())
            {
                foreach (var testResult in testResultGroup.Results)
                {
                    var component4 = new POCD_MT000040Component4
                                         {
                                             observation =
                                                 new POCD_MT000040Observation
                                                     {
                                                         classCode = ActClassObservation.OBS,
                                                         moodCode = x_ActMoodDocumentObservation.EVN,
                                                         id = CreateIdentifierArray(CreateGuid(), null),
                                                         code = CreateConceptDescriptor(testResult.ResultName)
                                                     }
                                         };

                    //REFERENCE RANGE DETAILS
                    if ((testResult.ResultValueReferenceRangeDetails != null &&
                         testResult.ResultValueReferenceRangeDetails.Any()) || testResult.ResultValue != null)
                    {
                        component4.observation.value =
                            new List<ANY> {CreateResultValueAny(testResult.ResultValue, null)}.ToArray();

                        component4.observation.interpretationCode =
                            new List<CE> {CreateCodedWithExtensionElement(testResult.ResultValueStatus, null)}.ToArray();


                        if (testResult.ResultValueReferenceRangeDetails != null &&
                            testResult.ResultValueReferenceRangeDetails.Any())
                        {
                            var referenceRange = new List<POCD_MT000040ReferenceRange>();

                            foreach (var resultValueReferenceRangeDetail in testResult.ResultValueReferenceRangeDetails)
                            {
                                referenceRange.Add(new POCD_MT000040ReferenceRange
                                                       {
                                                           typeCode = ActRelationshipType.REFV,
                                                           typeCodeSpecified = true,
                                                           observationRange =
                                                       new POCD_MT000040ObservationRange
                                                           {
                                                               classCode = ActClassObservation.OBS,
                                                               moodCode = ActMood.EVNCRT,
                                                               moodCodeSpecified = true,
                                                               code =
                                                       CreateConceptDescriptor(
                                                           resultValueReferenceRangeDetail.
                                                               ResultValueReferenceRangeMeaning),
                                                               value =
                                                       CreateIntervalPhysicalQuantity(
                                                           resultValueReferenceRangeDetail.Range
                                                       )
                                                           },
                                                       });
                            }
                            component4.observation.referenceRange = referenceRange.ToArray();
                        }
                    }

                    var relationships = new List<POCD_MT000040EntryRelationship>();

                    //Create a relationship containing the status of the pathology test
                    if (testResult.ResultStatus != null)
                    {
                        relationships.Add(CreateRelationshipForTestResultStatus(testResult.ResultStatus.Value));
                    }

                    //COMMENTS
                    if (testResult.Comments != null && testResult.Comments.Any())
                    {
                        foreach (var comment in testResult.Comments)
                        {
                            relationships.Add(CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.COMP,
                                                                         x_ActClassDocumentEntryAct.INFRM,
                                                                         x_DocumentActMood.EVN, false,
                                                                         CreateConceptDescriptor("281296001",
                                                                                                 CodingSystem.SNOMED,
                                                                                                 null, 
                                                                                                 "result comments",
                                                                                                 null, 
                                                                                                 Constants.SnomedVersion20110531, 
                                                                                                 null),
                                                                         CreateStructuredText(comment, null), null));
                        }
                    }

                    //REFERENCE RANGE GUIDANCE
                    if (testResult.ReferenceRangeGuidance != null)
                    {
                        relationships.Add(CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.COMP,
                                                                     x_ActClassDocumentEntryAct.INFRM,
                                                                     x_DocumentActMood.EVN, false,
                                                                     CreateConceptDescriptor("281298000",
                                                                                             CodingSystem.SNOMED, null,
                                                                                             "reference range comments",
                                                                                             null,
                                                                                             Constants.SnomedVersion20110531,
                                                                                             null),
                                                                     CreateStructuredText(testResult.ReferenceRangeGuidance, null), null));
                    }

                    component4.observation.entryRelationship = relationships.ToArray();

                    component4List.Add(component4);
                }

                entryRelationship.organizer.component = component4List.ToArray();
            }

            return entryRelationship;
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipOrganiser(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationshipTypeCode,
            x_ActClassDocumentEntryOrganizer classCode, ActMood moodCode, Boolean? inversion, CD code, ED text,
            StatusCode overallTestStatus, ITestResultGroup testResultGroup, CDADocumentType? cdaDocumentType)
        {
            var testStatus = CreateCodeSystem(overallTestStatus.GetAttributeValue<NameAttribute, String>(x => x.Name), null, null, null, null, null, null);

            return CreateEntryRelationshipOrganiser(actRelationshipEntryRelationshipTypeCode, classCode, moodCode,inversion, code, text, testStatus, testResultGroup, cdaDocumentType);
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipOrganiser(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationshipTypeCode,
            x_ActClassDocumentEntryOrganizer classCode, ActMood moodCode, Boolean? inversion, CD code, ED text,
            ICollection<IImagingResult> imagingResults, AnatomicalSite anatomicalSite, CS testStatus)
        {
            var entryRelationship = new POCD_MT000040EntryRelationship
                                        {
                                            typeCode = actRelationshipEntryRelationshipTypeCode,
                                            inversionInd = true,
                                            inversionIndSpecified = inversion.HasValue ? inversion.Value : false,
                                            organizer =
                                                new POCD_MT000040Organizer
                                                    {
                                                        author = null,
                                                        classCode = classCode,
                                                        code = code,
                                                        component = null,
                                                        effectiveTime = null,
                                                        id = CreateIdentifierArray(CreateGuid(), null),
                                                        informant = null,
                                                        moodCode = moodCode,
                                                        nullFlavor = NullFlavor.NA,
                                                        nullFlavorSpecified = false,
                                                        statusCode = testStatus
                                                    },
                                        };

            //Imaging Results
            if (imagingResults != null && imagingResults.Any())
            {
                var component4List = new List<POCD_MT000040Component4>();

                foreach (var imagingResult in imagingResults)
                {
                    var component4 = new POCD_MT000040Component4
                                         {
                                             observation =
                                                 new POCD_MT000040Observation
                                                     {
                                                         classCode = ActClassObservation.OBS,
                                                         moodCode = x_ActMoodDocumentObservation.EVN,
                                                         id = CreateIdentifierArray(CreateGuid(), null),
                                                         code = CreateConceptDescriptor(imagingResult.ResultName)
                                                     }
                                         };

                    //REFERENCE RANGE DETAILS
                    if ((imagingResult.ResultValueReferenceRangeDetails != null &&
                         imagingResult.ResultValueReferenceRangeDetails.Any()) || imagingResult.ResultValue != null)
                    {
                        component4.observation.value =
                            new List<ANY> {CreateResultValueAny(imagingResult.ResultValue, null)}.ToArray();

                        component4.observation.interpretationCode =
                            new List<CE> {CreateCodedWithExtensionElement(imagingResult.ResultValueStatus, null)}.
                                ToArray();


                        if (imagingResult.ResultValueReferenceRangeDetails != null &&
                            imagingResult.ResultValueReferenceRangeDetails.Any())
                        {
                            var referenceRange = new List<POCD_MT000040ReferenceRange>();

                            foreach (
                                var resultValueReferenceRangeDetail in imagingResult.ResultValueReferenceRangeDetails)
                            {
                                referenceRange.Add(new POCD_MT000040ReferenceRange
                                                       {
                                                           typeCode = ActRelationshipType.REFV,
                                                           typeCodeSpecified = true,
                                                           observationRange =
                                                       new POCD_MT000040ObservationRange
                                                           {
                                                               classCode = ActClassObservation.OBS,
                                                               moodCode = ActMood.EVNCRT,
                                                               moodCodeSpecified = true,
                                                               code =
                                                       CreateConceptDescriptor(
                                                           resultValueReferenceRangeDetail.
                                                               ResultValueReferenceRangeMeaning),
                                                               value =
                                                       CreateIntervalPhysicalQuantity(
                                                           resultValueReferenceRangeDetail.Range
                                                       //Result ResultValue Reference Range; the data range for the associated meaning
                                                       )
                                                           },
                                                       });
                            }
                            component4.observation.referenceRange = referenceRange.ToArray();
                        }
                    }

                    //COMMENTS
                    var relationships = new List<POCD_MT000040EntryRelationship>();

                    if (imagingResult.Comments != null && imagingResult.Comments.Any())
                    {
                        foreach (var comment in imagingResult.Comments)
                        {
                            relationships.Add(CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.COMP,
                                                                         x_ActClassDocumentEntryAct.INFRM,
                                                                         x_DocumentActMood.EVN, false,
                                                                         CreateConceptDescriptor("281296001",
                                                                                                 CodingSystem.SNOMED,
                                                                                                 null, 
                                                                                                 "result comments",
                                                                                                 null, 
                                                                                                 Constants.SnomedVersion20110531,
                                                                                                 null),
                                                                         CreateStructuredText(comment, null), null));
                        }
                    }

                    //ANATOMICAL SITE
                    if (anatomicalSite != null)
                    {
                        component4.observation.targetSiteCode = new[]
                                                                    {
                                                                        CreateConceptDescriptorForAnatomicalSite(
                                                                            anatomicalSite)
                                                                    };

                        if (anatomicalSite.Images != null && anatomicalSite.Images.Any())
                        {
                            foreach (var image in anatomicalSite.Images)
                            {
                                relationships.Add(
                                    CreateEntryRelationshipObservationMedia(x_ActRelationshipEntryRelationship.REFR,
                                                                            image));
                            }
                        }
                    }

                    component4.observation.entryRelationship = relationships.ToArray();

                    component4List.Add(component4);
                }

                entryRelationship.organizer.component = component4List.ToArray();
            }

            return entryRelationship;
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipOrganiser(
            x_ActRelationshipEntryRelationship actRelationshipEntryRelationshipTypeCode,
            x_ActClassDocumentEntryOrganizer classCode, ActMood moodCode, Boolean? inversion, CD code, ED text,
            ICollection<IImagingResult> imagingResults, AnatomicalSite anatomicalSite, StatusCode overallTestStatus)
        {
            var testStatus = CreateCodeSystem(overallTestStatus.GetAttributeValue<NameAttribute, String>(x => x.Name), null, null, null, null, null, null);

            return CreateEntryRelationshipOrganiser(actRelationshipEntryRelationshipTypeCode, classCode, moodCode, inversion, code, text, imagingResults, anatomicalSite, testStatus);
        }

        private static POCD_MT000040EntryRelationship CreateEntryRelationshipOrganiserObservation(x_ActRelationshipEntryRelationship actRelationshipEntryRelationship, CD code, string statusCode, List<POCD_MT000040Component4> components)
        {
          var entryRelationship = new POCD_MT000040EntryRelationship
          {
            typeCode = actRelationshipEntryRelationship,
            organizer = new POCD_MT000040Organizer
                          {  
                            classCode = x_ActClassDocumentEntryOrganizer.CLUSTER,
                            moodCode = ActMood.EVN,
                            code = code ?? null,
                            component = components != null ? components.ToArray() : null,
                            statusCode = new CS { code = statusCode }
                          }
          };

          return entryRelationship;
        }

        private static POCD_MT000040Component4 CreateComponentObservation(CD code, List<ANY> any)
        {
          var component = new POCD_MT000040Component4
          {
            observation =
              new POCD_MT000040Observation
              {
                classCode = ActClassObservation.OBS,
                moodCode = x_ActMoodDocumentObservation.EVN,
                code = code ?? null,
                value = any != null ? any.ToArray() : null
              }
          };

          return component;
        }

      #endregion

        #region Private Entry - Act


        private static POCD_MT000040Entry CreateEntryActEvent(x_ActRelationshipEntry actRelationshipEntry,
                                                              x_ActClassDocumentEntryAct classCode,
                                                              x_DocumentActMood moodCode, CD code, String actText,
                                                              String effectiveTimeValue, CdaInterval interval,
                                                              POCD_MT000040Performer2[] performer,
                                                              POCD_MT000040Participant2[] participant,
                                                              POCD_MT000040Author[] author,
                                                              List<POCD_MT000040EntryRelationship> relationshipList)
        {
            var entry = new POCD_MT000040Entry
            {
                typeCode = actRelationshipEntry,
                act =
                    new POCD_MT000040Act
                    {
                        classCode = classCode,
                        moodCode = moodCode,
                        id = CreateIdentifierArray(CreateGuid(), null)
                    }
            };

            if (code != null)
            {
                entry.act.code = code;
            }

            if (!String.IsNullOrEmpty(actText)) //Needs to be ST overriding ED
            {
                entry.act.text = CreateStructuredText(actText, null);
            }

            if (!String.IsNullOrEmpty(effectiveTimeValue))
            {
                entry.act.effectiveTime = new IVL_TS { value = effectiveTimeValue };
            }

            if (interval != null)
            {
                entry.act.effectiveTime = CreateIntervalTimestamp(interval);
            }

            if (performer != null)
            {
                entry.act.performer = performer;
            }

            if (participant != null)
            {
                entry.act.participant = participant;
            }

            if (author != null)
            {
                entry.act.author = author;
            }

            if (relationshipList != null)
            {
                entry.act.entryRelationship = relationshipList.ToArray();
            }

            return (entry);
        }


        private static POCD_MT000040Entry CreateEntryActEvent(x_ActRelationshipEntry actRelationshipEntry,
                                                              x_ActClassDocumentEntryAct classCode,
                                                              x_DocumentActMood moodCode, CD code, String actText,
                                                              String effectiveTimeValue, String effectiveTimeHigh,
                                                              String effectiveTimeLow,
                                                              POCD_MT000040Performer2[] performer,
                                                              POCD_MT000040Participant2[] participant,
                                                              POCD_MT000040Author[] author,
                                                              List<POCD_MT000040EntryRelationship> relationshipList)
        {
            var entry = new POCD_MT000040Entry
                            {
                                typeCode = actRelationshipEntry,
                                act =
                                    new POCD_MT000040Act
                                        {
                                            classCode = classCode,
                                            moodCode = moodCode,
                                            id = CreateIdentifierArray(CreateGuid(), null)
                                        }
                            };

            if (code != null)
            {
                entry.act.code = code;
            }

            if (!String.IsNullOrEmpty(actText)) //Needs to be ST overriding ED
            {
                entry.act.text = CreateStructuredText(actText, null);
            }

            if (!String.IsNullOrEmpty(effectiveTimeValue))
            {
                entry.act.effectiveTime = new IVL_TS {value = effectiveTimeValue};
            }

            if (!String.IsNullOrEmpty(effectiveTimeLow))
            {
                entry.act.effectiveTime = CreateIntervalTimestamp(effectiveTimeLow, effectiveTimeHigh, null, null, null,
                                                                  null);
            }

            if (performer != null)
            {
                entry.act.performer = performer;
            }

            if (participant != null)
            {
                entry.act.participant = participant;
            }

            if (author != null)
            {
                entry.act.author = author;
            }

            if (relationshipList != null)
            {
                entry.act.entryRelationship = relationshipList.ToArray();
            }

            return (entry);
        }


        private static POCD_MT000040Entry CreateEntryActEvent(x_ActRelationshipEntry actRelationshipEntry,
                                                              x_ActClassDocumentEntryAct classCode,
                                                              x_DocumentActMood moodCode, CD code,
                                                              POCD_MT000040Participant2[] participant,
                                                              List<POCD_MT000040EntryRelationship> relationshipList,
                                                              DateTime? effectiveTime)
        {
            return CreateEntryActEvent(actRelationshipEntry, classCode, moodCode, code, null, null, null,
                                       effectiveTime.HasValue ? effectiveTime.Value.ToString() : null, null, participant,
                                       null, relationshipList);
        }


        private static POCD_MT000040Entry CreateEntryActEvent(x_ActRelationshipEntry actRelationshipEntry,
                                                              x_ActClassDocumentEntryAct classCode,
                                                              x_DocumentActMood moodCode, CD code,
                                                              POCD_MT000040Participant2[] participant,
                                                              List<POCD_MT000040EntryRelationship> relationshipList)
        {
            return CreateEntryActEvent(actRelationshipEntry, classCode, moodCode, code, null, null, null, null, null,
                                       participant, null, relationshipList);

        }

        private static POCD_MT000040Entry CreateEntryActEvent(x_ActRelationshipEntry actRelationshipEntry,
                                                              x_ActClassDocumentEntryAct classCode,
                                                              x_DocumentActMood moodCode, CD code,
                                                              POCD_MT000040Participant2[] participant)
        {
            return CreateEntryActEvent(actRelationshipEntry, classCode, moodCode, code, null, null, null, null, null,
                                       participant, null, null);

        }

        private static POCD_MT000040Entry CreateEntryActEvent(x_ActRelationshipEntry actRelationshipEntry,
                                                              x_ActClassDocumentEntryAct classCode,
                                                              x_DocumentActMood moodCode, CD code,
                                                              String effectiveTimeValue)
        {
            return CreateEntryActEvent(actRelationshipEntry, classCode, moodCode, code, null, effectiveTimeValue, null,
                                       null, null, null, null, null);

        }

        private static POCD_MT000040Entry CreateEntryActEvent(CD code, ED ecapsulatedData)
        {
            return CreateEntryActEvent(code, ecapsulatedData, null, x_DocumentActMood.EVN);
        }

        private static POCD_MT000040Entry CreateEntryActEvent(CD code, ST text)
        {
            var entry = new POCD_MT000040Entry
                            {
                                act =
                                    new POCD_MT000040Act
                                        {
                                            classCode = x_ActClassDocumentEntryAct.ACT,
                                            moodCode = x_DocumentActMood.EVN,
                                            id = CreateIdentifierArray(CreateGuid(), null)
                                        }
                            };

            if (code != null)
            {
                entry.act.code = code;
            }

            if (text != null)
            {
                entry.act.text = text;
            }

            return entry;
        }

        private static POCD_MT000040Entry CreateEntryLink(x_DocumentActMood documentActMood, CD code, Link documentLink )
        {
            var entry = new POCD_MT000040Entry
            {
                act = new POCD_MT000040Act
                      {
                          classCode = x_ActClassDocumentEntryAct.ACT,
                          moodCode = documentActMood,
                          id = CreateIdentifierArray(CreateGuid(), null),
                          code = code,
                          reference = new [] { new POCD_MT000040Reference
                                                 {
                                                    typeCode = x_ActRelationshipExternalReference.REFR,
                                                    seperatableInd = new BL { value = true, valueSpecified = true },
                          externalDocument = new POCD_MT000040ExternalDocument
                                                   {
                                                       classCode = ActClassDocument.DOC,
                                                       moodCode = ActMood.EVN,
                                                       id = !documentLink.DocumentIdentifier.IsNullOrEmptyWhitespace() ? new[] { CreateIdentifierElement(documentLink.DocumentIdentifier, documentLink.DocumentIdentifierExtension, null,null,null) } : null,
                                                       templateId = new []
                                                        {    
                                                             !documentLink.TemplateId.HasValue ? null :
                                                             CreateIdentifierElement
                                                             (
                                                                 documentLink.TemplateId.Value.GetAttributeValue<NameAttribute, string>(x => x.Identifier),
                                                                 documentLink.TemplateId.Value.GetAttributeValue<NameAttribute, string>(x => x.Version),
                                                                 null
                                                             )
                                                        }
                                                   }
                                                 } 
                                              }
                      }
            };
          return entry;
        }


        private static POCD_MT000040Entry CreateEntryActEventInterval(CD code, ED ecapsulatedData,
                                                              List<POCD_MT000040Performer2> addresseePerformers,
                                                              CdaInterval duration, x_DocumentActMood actMoodCode)
        {
            POCD_MT000040Performer2[] performers = null;

            if (addresseePerformers != null && addresseePerformers.Any())
            {
                performers = addresseePerformers.ToArray();
            }

            var entry = new POCD_MT000040Entry
            {
                act =
                    new POCD_MT000040Act
                    {
                        classCode = x_ActClassDocumentEntryAct.ACT,
                        moodCode = actMoodCode,
                        performer = performers,
                        id = CreateIdentifierArray(CreateGuid(), null)
                    }
            };

            if (code != null)
            {
                entry.act.code = code;
            }

            if (ecapsulatedData != null)
            {
                entry.act.text = ecapsulatedData;
            }

            if (duration != null)
            {
                entry.act.effectiveTime = CreateIntervalTimestamp(duration);
            }

            return entry;
        }


        private static POCD_MT000040Entry CreateEntryActEvent(CD code, ED ecapsulatedData,
                                                              List<POCD_MT000040Performer2> addresseePerformers,
                                                              x_DocumentActMood actMoodCode)
        {
            POCD_MT000040Performer2[] performers = null;

            if (addresseePerformers != null && addresseePerformers.Any())
            {
                performers = addresseePerformers.ToArray();
            }

            var entry = new POCD_MT000040Entry
                            {
                                act =
                                    new POCD_MT000040Act
                                        {
                                            classCode = x_ActClassDocumentEntryAct.ACT,
                                            moodCode = actMoodCode,
                                            performer = performers,
                                            id = CreateIdentifierArray(CreateGuid(), null)
                                        }
                            };

            if (code != null)
            {
                entry.act.code = code;
            }

            if (ecapsulatedData != null)
            {
                entry.act.text = ecapsulatedData;
            }

            return entry;
        }

        #endregion

        private static II CreateIdentifierElement(InstanceIdentifier identifier)
        {
            var ii = new II();

            ii.root = identifier.Root;

            if (!string.IsNullOrEmpty(identifier.Extension))
                ii.extension = identifier.Extension;

            if (!string.IsNullOrEmpty(identifier.AssigningAuthorityName))
                ii.assigningAuthorityName = identifier.AssigningAuthorityName;

            return ii;
        }

        private static II[] CreateIdentifierArray(InstanceIdentifier identifier)
        {
            if (identifier == null) return null;
            return new II[] { CreateIdentifierElement(identifier) };
        }

        private static II[] CreateIdentifierArray(string root, NullFlavor? nullFlavor)
        {
            var ii = new List<II> {CreateIdentifierElement(root, nullFlavor)};
            return ii.ToArray();
        }

        private static II CreateIdentifierElement(string root, NullFlavor? nullFlavor)
        {
            var ii = new II();

            if (!String.IsNullOrEmpty(root))
            {
                ii.root = root;
            }

            if (nullFlavor.HasValue)
            {
                ii.nullFlavor = nullFlavor.Value;
                ii.nullFlavorSpecified = true;
            }
            else
            {
                ii.nullFlavor = NullFlavor.NA;
                ii.nullFlavorSpecified = false;
            }

            return ii;
        }

        private static II[] CreateIdentifierArray(string root, string extension, NullFlavor? nullFlavor)
        {
            var ii = new List<II> {CreateIdentifierElement(root, extension, nullFlavor)};
            return ii.ToArray();
        }

        private static II CreateIdentifierElement(string root, string extension, NullFlavor? nullFlavor)
        {
            var ii = new II();

            if (!String.IsNullOrEmpty(root))
            {
                ii.root = root;
            }

            if (!String.IsNullOrEmpty(extension))
            {
                ii.extension = extension;
            }

            if (nullFlavor.HasValue)
            {
                ii.nullFlavor = nullFlavor.Value;
                ii.nullFlavorSpecified = true;
            }
            else
            {
                ii.nullFlavor = NullFlavor.NA;
                ii.nullFlavorSpecified = false;
            }

            return ii;
        }

        private static II[] CreateIdentifierArray(string root, string extension, bool? displayable, string authorityName, NullFlavor? nullFlavor)
        {
            var ii = new List<II> {CreateIdentifierElement(root, extension, displayable, authorityName, nullFlavor)};
            return ii.ToArray();
        }

        private static II CreateIdentifierElement(string root, string extension, bool? displayable, string authorityName, NullFlavor? nullFlavor)
        {
            var ii = new II();

            if (!root.IsNullOrEmptyWhitespace())
            {
                ii.root = root;
            }
            if (!extension.IsNullOrEmptyWhitespace())
            {
                ii.extension = extension;
            }

            if (!authorityName.IsNullOrEmptyWhitespace())
            {
                ii.assigningAuthorityName = authorityName;
            }

            if (displayable.HasValue)
            {
                ii.displayable = displayable.Value;
                ii.displayableSpecified = displayable.Value;
            }

            if (nullFlavor.HasValue)
            {
                ii.nullFlavor = nullFlavor.Value;
                ii.nullFlavorSpecified = true;
            }
            else
            {
                ii.nullFlavor = NullFlavor.NA;
                ii.nullFlavorSpecified = false;
            }

            return ii;
        }

        private static II[] CreateIdentifierArray(UniqueId identifier)
        {
            II[] identifierArray = null;

            if (identifier != null)
            {
                var ii = new List<II> {CreateIdentifierElement(identifier)};

                identifierArray = ii.ToArray();
            }

            return identifierArray;
        }

        private static II[] CreateIdentifierArray(String identifier)
        {
            II[] identifierArray = null;

            if (identifier != null)
            {
                var ii = new List<II> {CreateIdentifierElement(identifier)};

                identifierArray = ii.ToArray();
            }

            return identifierArray;
        }

        internal static II CreateIdentifierElement(UniqueId identifier)
        {
            II ident = null;

            if (identifier != null)
            {
                var ii = new II {root = identifier.ToString().Replace("urn:uuid:", "")};

                ident = ii;
            }

            return ident;
        }

        private static II CreateIdentifierElement(String identifier)
        {
            II ident = null;

            if (identifier != null)
            {
                var ii = new II {root = identifier};

                ident = ii;
            }

            return ident;
        }

        private static II[] CreateIdentifierArray(Identifier identifier)
        {
            II[] identifierArray = null;

            if (identifier != null)
            {
                var ii = new List<II> {CreateIdentifierElement(identifier)};

                identifierArray = ii.ToArray();
            }

            return identifierArray;
        }

        private static II CreateIdentifierElement(Identifier identifier)
        {
            II ident = null;

            if (identifier != null)
            {
                var ii = new II();

                if (!string.IsNullOrEmpty(identifier.Root))
                {
                    ii.root = identifier.Root;
                }

                if (!string.IsNullOrEmpty(identifier.Extension))
                {
                    ii.extension = identifier.Extension;
                }

                if (!string.IsNullOrEmpty(identifier.AssigningAuthorityName))
                {
                    ii.assigningAuthorityName = identifier.AssigningAuthorityName;
                }
                ident = ii;
            }

            return ident;
        }

        internal static CE CreateCodedWithExtensionElement(string code, string codeSystemCode, string codeSystemName, string codeSystemVersion, string valueSet, string displayName, string originalText, NullFlavour? nullFlavor)
        {
            var codedWithExtension = new CE();

            if (!String.IsNullOrEmpty(code) || !string.IsNullOrEmpty(codeSystemCode) || !String.IsNullOrEmpty(valueSet) ||
                !String.IsNullOrEmpty(displayName) || !String.IsNullOrEmpty(originalText))
            {
                if (!String.IsNullOrEmpty(code))
                {
                    codedWithExtension.code = code;
                    codedWithExtension.codeSystem = codeSystemCode;
                    codedWithExtension.codeSystemName = codeSystemName;
                }

                if (!String.IsNullOrEmpty(displayName))
                {
                    codedWithExtension.displayName = displayName;
                }

                if (!String.IsNullOrEmpty(originalText))
                {
                    codedWithExtension.originalText = CreateEncapsulatedData(originalText, MediaType.TXT);
                }
            }

            var version = codeSystemVersion;
            if (!String.IsNullOrEmpty(version))
            {
                codedWithExtension.codeSystemVersion = version;
            }

            codedWithExtension.nullFlavor = NullFlavor.NA;
            codedWithExtension.nullFlavorSpecified = false;

            if (nullFlavor.HasValue)
            {
               codedWithExtension.nullFlavor = (NullFlavor)Enum.Parse(typeof(NullFlavor), nullFlavor.GetAttributeValue<NameAttribute, string>(x => x.Code));
               codedWithExtension.nullFlavorSpecified = true;
            }

            return codedWithExtension;
        }

        internal static CE CreateCodedWithExtensionElement(string code, CodingSystem? codingSystem, string valueSet, string displayName, string originalText, NullFlavour? nullFlavor)
        {
            if (codingSystem.HasValue)
            {
                return CreateCodedWithExtensionElement(code,
                                                       codingSystem.GetAttributeValue<NameAttribute, string>(x => x.Code),
                                                       codingSystem.GetAttributeValue<NameAttribute, string>(x => x.Name),
                                                       codingSystem.GetAttributeValue<NameAttribute, string>(x => x.Version),
                                                       valueSet,
                                                       displayName,
                                                       originalText,
                                                       nullFlavor
                    );
            }
 
            return CreateCodedWithExtensionElement(code,
                                                   null,
                                                   null,
                                                   null,
                                                   valueSet,
                                                   displayName,
                                                   originalText,
                                                   nullFlavor
                );
        }

        internal static CE CreateCodedWithExtensionElement(ICodableText code)
        {
            CE ce = null;

            if (code != null)
            {
              ce = CreateCodedWithExtensionElement(code.Code, code.CodeSystemCode, code.CodeSystemName, code.CodeSystemVersion, null, code.DisplayName, code.OriginalText, code.NullFlavour);
            }

            return ce;
        }

        private static CE CreateCodedWithExtensionElement(HL7ObservationInterpretationNormality? status, NullFlavour? nullflavor)
        {
            CE ce = null;

            if (status.HasValue)
            {
                ce = CreateCodedWithExtensionElement((Enum) status, nullflavor);
            }

            return ce;
        }

        private static CE CreateCodedWithExtensionElement(NullFlavour? nullflavor)
        {
          CE ce = null;

          if (nullflavor.HasValue)
          {
            ce = CreateCodedWithExtensionElement(null, null, null, null, null, nullflavor);
          }

          return ce;
        }

        private static CE CreateCodedWithExtensionElement(Enum status, NullFlavour? nullflavor)
        {
            CE ce = null;

            if (status != null)
            {
                ce = CreateCodedWithExtensionElement(status.GetAttributeValue<NameAttribute, String>(x => x.Code),
                                                     CodingSystem.HL7ObservationInterpretationNormality, null,
                                                     status.GetAttributeValue<NameAttribute, String>(x => x.Name), null, nullflavor);

            }
            return ce;
        }

        private static ANY CreateResultValueAny(ResultValue value, NullFlavor? nullFlavor)
        {
            ANY any = null;

            if (value != null)
            {
                PQ physicalQuantity = null;
                CD conceptDescriptor = null;
                IVL_PQ intervalPhysicalQuantity = null;

                if (value.ValueAsCodableText != null)
                {
                    if (value.ValueAsCodableText != null)
                    {
                        conceptDescriptor = CreateConceptDescriptor(value.ValueAsCodableText);
                    }
                }
                else if (value.ValueAsQuantity != null)
                {
                    physicalQuantity = new PQ {nullFlavor = NullFlavor.NA, nullFlavorSpecified = false};

                    if (value.ValueAsQuantity != null)
                    {
                        physicalQuantity.unit = value.ValueAsQuantity.Units;
                        physicalQuantity.value = value.ValueAsQuantity.Value;
                    }
                }
                else if (value.ValueAsQuantityRange != null)
                {
                    intervalPhysicalQuantity = CreateIntervalPhysicalQuantity(value.ValueAsQuantityRange);
                }

                if (physicalQuantity != null)
                {
                    if (nullFlavor.HasValue)
                    {
                        physicalQuantity.nullFlavor = nullFlavor.Value;
                        physicalQuantity.nullFlavorSpecified = true;
                    }

                    any = physicalQuantity;
                }
                else if (intervalPhysicalQuantity != null)
                {
                    if (nullFlavor.HasValue)
                    {
                        intervalPhysicalQuantity.nullFlavor = nullFlavor.Value;
                        intervalPhysicalQuantity.nullFlavorSpecified = true;
                    }

                    any = intervalPhysicalQuantity;
                }
                else if (conceptDescriptor != null)
                {
                    any = conceptDescriptor;
                }
            }

            return any;
        }

        private static PQ CreatePhysicalQuantity(QuantityRange quantity)
        {
            PQ physicalQuantity = null;

            if (quantity != null)
            {
                physicalQuantity = new PQ
                                       {
                                           nullFlavor = NullFlavor.NA,
                                           nullFlavorSpecified = false,
                                           unit = quantity.Units,
                                           value = !String.IsNullOrEmpty(quantity.High) ? quantity.High : quantity.Low
                                       };
            }

            return physicalQuantity;
        }

        internal static PQ CreatePhysicalQuantity(Quantity quantity)
        {
            PQ physicalQuantity = null;

            if (quantity != null)
            {
                if (quantity.Value != null)
                {
                    if (quantity.Value != null || quantity.Units != null)
                    {
                        physicalQuantity = new PQ
                                               {
                                                   nullFlavor = NullFlavor.NA,
                                                   nullFlavorSpecified = false,
                                                   unit = quantity.Units,
                                                   value = quantity.Value
                                               };
                    }
                }
            }
            return physicalQuantity;
        }

        private static PQ CreatePhysicalQuantity(String units, String value)
        {
            PQ physicalQuantity = null;

            if (value != null || units != null)
            {
                physicalQuantity = new PQ
                                       {
                                           nullFlavor = NullFlavor.NA,
                                           nullFlavorSpecified = false,
                                           unit = units,
                                           value = value
                                       };
            }
            return physicalQuantity;
        }

        private static TS CreateTimeStampElement(DateTime? dateTime, NullFlavor? nullFlavor, Boolean? dateOnly)
        {
            TS timeStamp = null;

            if (dateTime.HasValue)
            {
                if (dateOnly.HasValue && dateOnly.Value)
                {
                    timeStamp = new TS {value = dateTime.Value.ToString(DATE_TIME_SHORT_FORMAT)};
                }
                else
                {
                    timeStamp = new TS {value = dateTime.Value.ToString(DATE_TIME_FORMAT)};
                }
            }

            if (nullFlavor.HasValue)
            {
                if (timeStamp == null) timeStamp = new TS();

                timeStamp.nullFlavor = nullFlavor.Value;
                timeStamp.nullFlavorSpecified = true;
            }

            return timeStamp;
        }

        private static TS CreateTimeStampElementIso(ISO8601DateTime dateTime, NullFlavor? nullFlavor, Boolean? dateOnly)
        {
            TS timeStamp = null;

            if (dateTime != null)
            {
                timeStamp = new TS { value = dateTime.ToString() };
            }

            if (nullFlavor.HasValue)
            {
                if (timeStamp == null) timeStamp = new TS();

                timeStamp.nullFlavor = nullFlavor.Value;
                timeStamp.nullFlavorSpecified = true;
            }

            return timeStamp;
        }


        private static INT CreateIntegerElement(Int32? value, NullFlavor nullFlavor, Boolean nullFlavorSpecified)
        {
            INT integer = null;

            if (value.HasValue)
            {
                integer = new INT {value = value.Value.ToString()};

                if (nullFlavorSpecified)
                {
                    integer.nullFlavor = nullFlavor;
                    integer.nullFlavorSpecified = true;
                }
            }

            return integer;
        }

        private static CS CreateCodeSystem(string code, string codeSystem, string codeSystemName, string valueSet, string displayName, string originalText, NullFlavour? nullFlavor)
        {
            CS cs = null;

            if (!String.IsNullOrEmpty(code) || !String.IsNullOrEmpty(codeSystem) ||
                !String.IsNullOrEmpty(codeSystemName) || !String.IsNullOrEmpty(valueSet) ||
                !String.IsNullOrEmpty(displayName) || !String.IsNullOrEmpty(originalText))
            {
                cs = new CS();

                if (!String.IsNullOrEmpty(code))
                {
                    cs.code = code;
                }

                if (!String.IsNullOrEmpty(codeSystem))
                {
                    cs.codeSystem = codeSystem;
                }

                if (!String.IsNullOrEmpty(codeSystemName))
                {
                    cs.codeSystemName = codeSystemName;
                }

                if (!String.IsNullOrEmpty(displayName))
                {
                    cs.displayName = displayName;
                }

                cs.originalText = CreateEncapsulatedData(originalText);
            }

            cs.nullFlavor = NullFlavor.NA;
            cs.nullFlavorSpecified = false;

            if (nullFlavor.HasValue)
            {
               cs.nullFlavor = (NullFlavor)Enum.Parse(typeof(NullFlavor), nullFlavor.GetAttributeValue<NameAttribute, string>(x => x.Code));
               cs.nullFlavorSpecified = true;
            }


            return cs;
        }

        private static ED CreateEncapsulatedData(String originalText)
        {
            ED returnValue = null;

            if (!String.IsNullOrEmpty(originalText))
            {
                returnValue = CreateEncapsulatedData(originalText, MediaType.TXT);
            }

            return returnValue;
        }


        private static ED CreateEncapsulatedData(ExternalData externalData)
        {
            ED ed = null;

            if (externalData != null)
            {
                ed = new ED
                         {
                             mediaType =
                                 externalData.ExternalDataMediaType.HasValue
                                     ? externalData.ExternalDataMediaType.GetAttributeValue<NameAttribute, string>(
                                         x => x.Name)
                                     : null,
                             reference =
                                 externalData.FileStorageType == FileStorageType.Reference
                                     ? new TEL {value = Path.GetFileName(externalData.Path)}
                                     : null,
                             representation =
                                 externalData.FileStorageType == FileStorageType.Embed
                                     ? BinaryDataEncoding.B64
                                     : BinaryDataEncoding.TXT,
                             Text =
                                 externalData.FileStorageType == FileStorageType.Embed
                                     ? new[] {externalData.ConvertToBase64String()}
                                     : null,
                             integrityCheck = externalData.DigestValue ?? null,
                             integrityCheckAlgorithm =
                                 (IntegrityCheckAlgorithm)
                                 Enum.Parse(typeof (IntegrityCheckAlgorithm),
                                            (externalData.DigestCheckAlgorithm != null
                                                 ? externalData.DigestCheckAlgorithm.Value.ToString()
                                                 : DigestCheckAlgorithm.SHA1.ToString()))
                         };
            }

            return ed;
        }

        private static ED CreateEncapsulatedData(String text, MediaType? mediaType)
        {
            ED ed = null;

            if (!String.IsNullOrEmpty(text))
            {
                String mediaTypeAsString = null;

                if (mediaType.HasValue)
                {
                    mediaTypeAsString = mediaType.GetAttributeValue<NameAttribute, string>(x => x.Name);
                }

                ed = new ED {Text = new[] {text}, mediaType = mediaTypeAsString};
            }

            return ed;
        }

        private static TEL[] CreateTelecomunicationArray(
            List<ElectronicCommunicationDetail> electronicCommunicationDetails)
        {
            TEL[] telArray = null;

            if (electronicCommunicationDetails != null && electronicCommunicationDetails.Any())
            {
                var telecomunicationsList = new List<TEL>();

                electronicCommunicationDetails.ForEach(
                    electronicCommunicationDetail =>
                    telecomunicationsList.Add(CreateTelecomunication(electronicCommunicationDetail)));

                telArray = telecomunicationsList.ToArray();
            }

            return telArray;
        }

        private static TEL CreateTelecomunication(ElectronicCommunicationDetail electronicCommunicationDetail)
        {
            TEL telecomunication = null;

            if (electronicCommunicationDetail != null && !String.IsNullOrEmpty(electronicCommunicationDetail.Address))
            {
                telecomunication = new TEL();

                if (electronicCommunicationDetail.Usage != null)
                {
                    var usage = new List<TelecommunicationAddressUse>();
                    foreach (var use in electronicCommunicationDetail.Usage)
                    {
                        usage.Add((TelecommunicationAddressUse)
                                    Enum.Parse(typeof(TelecommunicationAddressUse),
                                    use.GetAttributeValue<NameAttribute, string>(x => x.Code)));
                    }

                    telecomunication.use = usage.ToArray();
                }

                telecomunication.value = electronicCommunicationDetail.Address;
            }

            return telecomunication;
        }

        private static TEL CreateTelecomunication(IEnumerable<ElectronicCommunicationDetail> electronicCommunicationDetails)
        {
            TEL telecomunication = null;

            if (electronicCommunicationDetails != null)
            {
                foreach (var telecom in electronicCommunicationDetails)
                {
                    if (!String.IsNullOrEmpty(telecom.Address))
                    {
                        telecomunication = new TEL();

                        if (telecom.Usage != null)
                        {
                            var usage = new List<TelecommunicationAddressUse>();
                            foreach (var use in telecom.Usage)
                            {
                                usage.Add((TelecommunicationAddressUse)
                                            Enum.Parse(typeof(TelecommunicationAddressUse),
                                            use.GetAttributeValue<NameAttribute, string>(x => x.Code)));
                            }

                            telecomunication.use = usage.ToArray();
                        }

                        telecomunication.value = telecom.Address;
                    }
                }

            }
            return telecomunication;
        }

        private static TEL[] CreateTelecomunicationArray(TelecommunicationAddressUse? telecommunicationAddressUse, string telecom)
        {

            TEL[] telArray = null;

            if (telecommunicationAddressUse.HasValue)
            {
                List<TEL> telecomunicationsList = null;

                if (!String.IsNullOrEmpty(telecom))
                {
                    telecomunicationsList = new List<TEL> {CreateTelecomunication(telecommunicationAddressUse, telecom)};
                }

                if (telecomunicationsList != null)
                {
                    telArray = telecomunicationsList.ToArray();
                }
            }


            return telArray;
        }

        private static TEL CreateTelecomunication(TelecommunicationAddressUse? telecommunicationAddressUse,
                                                  string telecom)
        {
            TEL telecomunication = null;

            if (!String.IsNullOrEmpty(telecom))
            {
                if (telecommunicationAddressUse != null)
                    telecomunication = new TEL {use = new[] {telecommunicationAddressUse.Value}, value = telecom};
            }

            return telecomunication;
        }

        private static PN[] CreatePersonNameArray(List<IPersonName> personNames)
        {
            List<PN> names = new List<PN>();

            if (personNames != null && personNames.Any())
            {
                foreach (var personName in personNames)
                {
                    names.Add(CreatePersonName(personName));
                }
            }

            return names.ToArray();
        }

        private static PN CreatePersonName(IPersonName personName)
        {
            PN participantName = null;

            if (personName != null)
            {
                participantName = new PN();

                if (personName.NameUsages != null)
                {
                    List<EntityNameUse> uses = new List<EntityNameUse>();
                    foreach (var usage in personName.NameUsages)
                    {
                        uses.Add(
                            (EntityNameUse)
                            Enum.Parse(typeof (EntityNameUse),
                                       usage.GetAttributeValue<NameAttribute, string>(x => x.Code)));
                    }
                    participantName.use = uses.ToArray();
                }

                if (personName.Titles != null && personName.Titles.Any())
                {
                    var titleArrary = new String[personName.Titles.Count];

                    for (var i = 0; i < personName.Titles.Count; i++)
                    {
                        titleArrary[i] = personName.Titles[i];
                    }

                    participantName.prefix = new enprefix[1];
                    participantName.prefix[0] = new enprefix {Text = titleArrary};
                }

                if (!String.IsNullOrEmpty(personName.FamilyName))
                {
                    participantName.family = new enfamily[1];
                    participantName.family[0] = new enfamily {Text = new[] {personName.FamilyName}};
                }

                if (personName.GivenNames != null && personName.GivenNames.Any())
                {
                    participantName.given = (from g in personName.GivenNames select new engiven {Text = new string[] {g}}).ToArray();
                }

                if (personName.NameSuffix != null && personName.NameSuffix.Any())
                {
                    participantName.suffix = (from g in personName.NameSuffix select new ensuffix { Text = new string[] { g } }).ToArray();
                }

            }

            return participantName;
        }

        private static PN[] CreatePersonNameArray(EntityNameUse entityNameUse, bool entityNameUseSpecified,
                                                  List<string> titles, List<String> givenNames, string family)
        {
            var participantNameList = new List<PN>();

            var participantName = new PN();

            if (entityNameUseSpecified)
            {
                participantName.use = new EntityNameUse[1];
                participantName.use[0] = entityNameUse;
            }

            if (titles != null && titles.Any())
            {
                var titleArrary = new String[titles.Count];

                for (int i = 0; i < titles.Count; i++)
                {
                    titleArrary[i] = titles[i];
                }

                participantName.prefix = new enprefix[1];
                participantName.prefix[0] = new enprefix {Text = titleArrary};
            }

            if (!String.IsNullOrEmpty(family))
            {
                participantName.family = new enfamily[1];
                participantName.family[0] = new enfamily {Text = new[] {family}};
            }

            if (givenNames != null && givenNames.Any())
            {
                participantName.given = new engiven[1];
                participantName.given[0] = new engiven {Text = givenNames.ToArray()};
            }

            participantNameList.Add(participantName);

            return participantNameList.ToArray();
        }

        private static ON[] CreateOrganisationNameArray(string name, OrganisationNameUsage? entityNameUse)
        {
            ON[] organisationNameArray = null;

            if (!String.IsNullOrEmpty(name) || entityNameUse.HasValue)
            {
                var organisationNameList = new List<ON> {CreateOrganisationName(name, entityNameUse)};

                organisationNameArray = organisationNameList.ToArray();
            }
            return organisationNameArray;
        }

        private static ON CreateOrganisationName(string name, string nameUseCode)
        {
            ON returnOrganisationName = null;

            if (!String.IsNullOrEmpty(name))
            {
                returnOrganisationName = new ON {Text = new[] {name}};

                if (!string.IsNullOrEmpty(nameUseCode))
                {
                    returnOrganisationName.use = new EntityNameUse[1];
                    returnOrganisationName.use[0] = (EntityNameUse) Enum.Parse(typeof (EntityNameUse), nameUseCode);
                }
            }

            return returnOrganisationName;
        }

        private static ON CreateOrganisationName(string name)
        {
            ON on = null;

            if (!String.IsNullOrEmpty(name))
                on = new ON {Text = new[] {name}};

            return on;
        }

        private static POCD_MT000040Organization CreateOrganisation(IOrganisationName organisation)
        {
            var org = new POCD_MT000040Organization();

            org.asEntityIdentifier = organisation.Identifiers == null
                                         ? null
                                         : CreateEntityIdentifierArray(organisation.Identifiers);

            if (!String.IsNullOrEmpty(organisation.Name))
            {
                var on = new ON();
                if (!String.IsNullOrEmpty(organisation.Name))
                {
                    on.Text = new[] {organisation.Name};
                }

                org.name = new [] {on};
            }

            return org;
        }

        private static POCD_MT000040Entity CreateOrganisationEntity(IOrganisation organisation)
        {
          var org = new POCD_MT000040Entity
          {
                
            classCode = EntityClassRoot.ORG,
            asOrganizationPartOf =
                new OrganizationPartOf
                {
                  wholeEntity =
                      new Entity
                      {
                        asEntityIdentifier = organisation.Identifiers == null ? null : CreateEntityIdentifierArray(organisation.Identifiers)
                      }
                }
          };

          if (!String.IsNullOrEmpty(organisation.Name) ||
              (organisation.NameUsage != null && organisation.NameUsage.Value != OrganisationNameUsage.Undefined))
          {
            var on = new ON();
            if (!String.IsNullOrEmpty(organisation.Name))
            {
              on.Text = new[] { organisation.Name };
            }

            if (organisation.NameUsage.HasValue && organisation.NameUsage.Value != OrganisationNameUsage.Undefined)
            {
              on.use = new[]
                                 {
                                     (EntityNameUse) Enum.Parse(typeof (EntityNameUse),organisation.NameUsage != OrganisationNameUsage.Undefined ? organisation.NameUsage.GetAttributeValue<NameAttribute, string>(x => x.Code): String.Empty)
                                 };
            }
            org.asOrganizationPartOf.wholeEntity.name = new ON[] { on };
          }

          if (!String.IsNullOrEmpty(organisation.Department))
            org.name = new[] { new ON { Text = new[] { organisation.Department } } };

          return org;
        }

        private static POCD_MT000040Organization CreateOrganisation(IOrganisation organisation)
        {
            var org = new POCD_MT000040Organization
                          {   id = CreateIdentifierArray(new UniqueId()),
                              asOrganizationPartOf =
                                  new POCD_MT000040OrganizationPartOf
                                      {
                                          wholeOrganization =
                                              new POCD_MT000040Organization
                                                  {
                                                      asEntityIdentifier = organisation.Identifiers == null ? null : CreateEntityIdentifierArray(organisation.Identifiers)
                                                  }
                                      }
                          };

            if (!String.IsNullOrEmpty(organisation.Name) ||
                (organisation.NameUsage != null && organisation.NameUsage.Value != OrganisationNameUsage.Undefined))
            {
                var on = new ON();
                if (!String.IsNullOrEmpty(organisation.Name))
                {
                    on.Text = new[] {organisation.Name};
                }

                if (organisation.NameUsage.HasValue && organisation.NameUsage.Value != OrganisationNameUsage.Undefined)
                {
                    on.use = new[]
                                 {
                                     (EntityNameUse) Enum.Parse(typeof (EntityNameUse),organisation.NameUsage != OrganisationNameUsage.Undefined ? organisation.NameUsage.GetAttributeValue<NameAttribute, string>(x => x.Code): String.Empty)
                                 };
                }
                org.asOrganizationPartOf.wholeOrganization.name = new ON[] {on};
            }

            if (!String.IsNullOrEmpty(organisation.Department))
                org.name = new[] {new ON {Text = new[] {organisation.Department}}};

            return org;
        }

        private static ON CreateOrganisationName(string name, OrganisationNameUsage? entityNameUse)
        {
            ON returnOrganisationName = null;

            if (!String.IsNullOrEmpty(name))
            {
                returnOrganisationName = new ON {Text = new[] {name}};

                if (entityNameUse.HasValue)
                {
                    returnOrganisationName.use = new EntityNameUse[1];
                    returnOrganisationName.use[0] = (EntityNameUse)Enum.Parse(typeof (EntityNameUse),entityNameUse.Value.GetAttributeValue<NameAttribute, string>(a => a.Code));
                }
            }

            return returnOrganisationName;
        }

        private static BL CreateBoolean(bool value, bool valueSpecified, NullFlavor nullFlavor, bool nullFlavorSpecified)
        {
            var bl = new BL();

            if (valueSpecified)
            {
                bl.value = value;
                bl.valueSpecified = true;
            }

            if (nullFlavorSpecified)
            {
                bl.nullFlavor = nullFlavor;
                bl.nullFlavorSpecified = true;
            }

            return bl;
        }

        internal static BL CreateBoolean(bool value, bool valueSpecified)
        {
            var bl = new BL();

            if (valueSpecified)
            {
                bl.value = value;
                bl.valueSpecified = true;
            }
            return bl;
        }

        private static EntityIdentifier[] CreateEntityIdentifierArray(string root, string extension,
                                                                      string assigningAuthorityName,
                                                                      string identifierGeo, String code,
                                                                      CodingSystem codingSystem)
        {
            var entityIdentifierList = new List<EntityIdentifier>
                                           {
                                               CreateEntityIdentifier(root, extension, assigningAuthorityName, identifierGeo, code, codingSystem)
                                           };

            return entityIdentifierList.ToArray();
        }

        private static EntityIdentifier CreateEntityIdentifier(string root, string extension,
                                                               string assigningAuthorityName, string identifierGeo,
                                                               String code, CodingSystem codingSystem)
        {
            EntityIdentifier entityidentifier = null;
            if (!String.IsNullOrEmpty(extension))
            {
                entityidentifier = new EntityIdentifier {classCode = EntityClass.IDENT, id = new II()};

                if (!String.IsNullOrEmpty(root))
                {
                    entityidentifier.id.root = root;
                }

                if (!String.IsNullOrEmpty(extension))
                {
                    entityidentifier.id.extension = extension;
                }

                if (!String.IsNullOrEmpty(identifierGeo))
                {
                    entityidentifier.assigningGeographicArea = new GeographicArea {name = CreateStructuredText(identifierGeo, null)};
                }

                if (!String.IsNullOrEmpty(assigningAuthorityName))
                {
                    entityidentifier.id.assigningAuthorityName = assigningAuthorityName;
                }

                if (!String.IsNullOrEmpty(code))
                {
                    entityidentifier.code = CreateCodedWithExtensionElement(code, codingSystem, null, null, null, null);
                }
            }

            return entityidentifier;
        }


        internal static EntityIdentifier[] CreateEntityIdentifierArray(string root, string extension,string assigningAuthorityName, string identifierGeo)
        {
            var entityIdentifierList = new List<EntityIdentifier>
                                           {
                                               CreateEntityIdentifier(root, extension, assigningAuthorityName, identifierGeo)
                                           };

            return entityIdentifierList.ToArray();
        }

        private static EntityIdentifier CreateEntityIdentifier(string root, string extension, string assigningAuthorityName, string identifierGeo)
        {
            EntityIdentifier entityidentifier = null;
            if (!String.IsNullOrEmpty(root))
            {
                entityidentifier = new EntityIdentifier {classCode = EntityClass.IDENT, id = new II()};

                if (!String.IsNullOrEmpty(root))
                {
                    entityidentifier.id.root = root;
                }

                if (!String.IsNullOrEmpty(extension))
                {
                    entityidentifier.id.extension = extension;
                }

                if (!String.IsNullOrEmpty(assigningAuthorityName))
                {
                    entityidentifier.id.assigningAuthorityName = assigningAuthorityName;
                }

                entityidentifier.assigningGeographicArea = new GeographicArea {name = CreateStructuredText(identifierGeo, null)};
            }

            return entityidentifier;
        }


        /// <summary>
        /// Create Entity Identifier Array
        /// </summary>
        /// <param name="identifiers">A list of Identifiers</param>
        /// <returns>EntityIdentifier array</returns>
        private static EntityIdentifier[] CreateEntityIdentifierArray(IEnumerable<Identifier> identifiers)
        {
            var entityIdentifierList = new List<EntityIdentifier>();

            foreach (var identifier in identifiers)
            {
                entityIdentifierList.Add(CreateEntityIdentifier(identifier));
            }
            ;

            return entityIdentifierList.ToArray();
        }

        private static List<EntityIdentifier> CreateEntityIdentifier(List<Identifier> identifiers)
        {
            List<EntityIdentifier> entityidentifiers = null;

            if (identifiers != null)
            {
                entityidentifiers = new List<EntityIdentifier>();

                foreach (var identifier in identifiers)
                {
                    if (identifier != null) entityidentifiers.Add(CreateEntityIdentifier(identifier));
                }
            }
            return entityidentifiers;
        }


        internal static EntityIdentifier CreateEntityIdentifier(Identifier identifier)
        {
            EntityIdentifier entityidentifier = null;

            if (!String.IsNullOrEmpty(identifier.Root))
            {
                entityidentifier = new EntityIdentifier {classCode = EntityClass.IDENT, id = new II()};

                if (!String.IsNullOrEmpty(identifier.Root))
                {
                    entityidentifier.id.root = identifier.Root;
                }

                if (!String.IsNullOrEmpty(identifier.Extension))
                {
                    entityidentifier.id.extension = identifier.Extension;
                }

                if (!String.IsNullOrEmpty(identifier.AssigningAuthorityName))
                {
                    entityidentifier.id.assigningAuthorityName = identifier.AssigningAuthorityName;
                }

                if (!String.IsNullOrEmpty(identifier.AssigningGeographicArea))
                {
                    entityidentifier.assigningGeographicArea = new GeographicArea
                                                                   {
                                                                       name = CreateStructuredText(identifier.AssigningGeographicArea, null)
                                                                   };
                }

                if (identifier.Code != null)
                {
                    entityidentifier.code = CreateCodedWithExtensionElement(identifier.Code);
                }
            }

            return entityidentifier;
        }

        public static ST CreateStructuredText(string value, NullFlavour? nullFlavour)
        {
             NullFlavor? nullFlavor = null;
             if (nullFlavour != null)
                nullFlavor = (NullFlavor)Enum.Parse(typeof(NullFlavor), nullFlavour.GetAttributeValue<NameAttribute, string>(x => x.Code));

             ST st = null;

             if (nullFlavor.HasValue)
             {
               st = new ST(); 
               st.nullFlavor = nullFlavor.Value;
               st.nullFlavorSpecified = true;
               return st;
             }

             if (!String.IsNullOrEmpty(value))
             {
               st = new ST { Text = new[] { value } };
             }

             return (st);
        }


        private static ST CreateStructuredText(ICodableText value, NullFlavor? nullFlavor)
        {
            ST st = null;

            if (nullFlavor.HasValue)
            {
              st = new ST(); 
              st.nullFlavor = nullFlavor.Value;
              st.nullFlavorSpecified = true;
              return st;
            }

            if (value != null)
            {
                st = new ST {Text = new[] {value.NarrativeText}};
            }

            return (st);
        }

        internal static CD CreateConceptDescriptor(string code, CodingSystem? codingSystem, string valueSet, string displayName, string originalText, string codeSystemVersion, NullFlavour? nullFlavor)
        {
            CD cd = null;

            if (nullFlavor.HasValue)
            {
              return new CD
                       {
                          nullFlavor = (NullFlavor)Enum.Parse(typeof(NullFlavor), nullFlavor.GetAttributeValue<NameAttribute, string>(x => x.Code)),
                          nullFlavorSpecified = true
                       };
            }

            if (!String.IsNullOrEmpty(code) || codingSystem.HasValue || !String.IsNullOrEmpty(valueSet) || !String.IsNullOrEmpty(displayName) || !String.IsNullOrEmpty(originalText))
            {
                cd = new CD();

                if (!String.IsNullOrEmpty(code))
                {
                    cd.code = code;
                    cd.codeSystem = codingSystem != null
                                        ? !String.IsNullOrEmpty(codingSystem.GetAttributeValue<NameAttribute, string>(x => x.Code)) 
                                        ? codingSystem.GetAttributeValue<NameAttribute, string>(x => x.Code) : null
                                        : null;
                    cd.codeSystemName = codingSystem != null
                                            ? !String.IsNullOrEmpty(codingSystem.GetAttributeValue<NameAttribute, string>(x => x.Name))
                                                  ? codingSystem.GetAttributeValue<NameAttribute, string>(x => x.Name) : null
                                            : null;

                    cd.codeSystemVersion = !string.IsNullOrEmpty(codeSystemVersion) ? codeSystemVersion : null;
                }

                if (!String.IsNullOrEmpty(displayName))
                {
                    cd.displayName = displayName;
                }

                if (!String.IsNullOrEmpty(originalText))
                {
                    cd.originalText = CreateEncapsulatedData(originalText, MediaType.TXT);
                }

                if (codingSystem.HasValue == false && string.IsNullOrEmpty(originalText))
                {
                    cd.nullFlavor = NullFlavor.OTH;
                    cd.nullFlavorSpecified = true;
                }
            }

            return cd;
        }

        internal static CD CreateConceptDescriptor(string code, CodingSystem? codingSystem, string valueSet, string displayName, string originalText)
        {
            return CreateConceptDescriptor(code, codingSystem, valueSet, displayName, originalText, null, null);
        }

        private static CD CreateConceptDescriptor(string code, string codeSystem, string codeSystemName, string valueSet, string displayName, string originalText, NullFlavour? nullFlavor)
        {
            CD cd = null;

            if (nullFlavor.HasValue)
            {
              return new CD
              {
                nullFlavor = (NullFlavor)Enum.Parse(typeof(NullFlavor), nullFlavor.GetAttributeValue<NameAttribute, string>(x => x.Code)),
                nullFlavorSpecified = true
              };
            }

            if (!String.IsNullOrEmpty(code) || !String.IsNullOrEmpty(valueSet) || !String.IsNullOrEmpty(codeSystem) ||
                !String.IsNullOrEmpty(codeSystemName) || !String.IsNullOrEmpty(displayName) ||
                !String.IsNullOrEmpty(originalText))
            {
                cd = new CD();

                if (!String.IsNullOrEmpty(code))
                {
                    cd.code = code;
                }

                if (!String.IsNullOrEmpty(codeSystem))
                {
                    cd.codeSystem = codeSystem;
                }

                if (!String.IsNullOrEmpty(codeSystemName))
                {
                    cd.codeSystemName = codeSystemName;
                }

                if (!String.IsNullOrEmpty(displayName))
                {
                    cd.displayName = displayName;
                }

                if (!String.IsNullOrEmpty(originalText))
                {
                    cd.originalText = CreateEncapsulatedData(originalText, MediaType.TXT);
                }
            }

            return cd;
        }

        internal static CD CreateConceptDescriptor(ICodableText codableText)
        {
            CD cd = null;

            if (codableText != null)
            {
                if (codableText.NullFlavour.HasValue)
                {
                  return new CD
                  {
                      nullFlavor = (NullFlavor)Enum.Parse(typeof(NullFlavor), codableText.NullFlavour.Value.GetAttributeValue<NameAttribute, string>(x => x.Code)),
                      nullFlavorSpecified = true
                  };
                }

                cd = new CD();

                if (!String.IsNullOrEmpty(codableText.Code) && codableText.CodeSystemCode != null)
                {
                    cd.code = codableText.Code;
                    cd.codeSystem = codableText.CodeSystemCode;
                    cd.codeSystemName = codableText.CodeSystemName;
                    var version = codableText.CodeSystemVersion;
                    if (!String.IsNullOrEmpty(version))
                    {
                        cd.codeSystemVersion = version;
                    }
                }

                if (!String.IsNullOrEmpty(codableText.DisplayName))
                {
                    cd.displayName = codableText.DisplayName;
                }

                if (!String.IsNullOrEmpty(codableText.OriginalText))
                {
                    cd.originalText = CreateEncapsulatedData(codableText.OriginalText, MediaType.TXT);
                }

                if (string.IsNullOrEmpty(codableText.CodeSystemCode) && string.IsNullOrEmpty(codableText.OriginalText))
                {
                    cd.nullFlavor = NullFlavor.OTH;
                    cd.nullFlavorSpecified = true;
                }

                if (codableText.Translations != null && codableText.Translations.Any())
                {
                    var translations = new List<CD>();

                    codableText.Translations.ForEach(
                        translation => translations.Add(CreateConceptDescriptor(translation)));

                    cd.translation = translations.ToArray();
                }
            }

            return cd;
        }

        private static CD CreateConceptDescriptor(ICodableTranslation codableTranslation)
        {
            CD cd = null;

            if (codableTranslation != null)
            {

                if (codableTranslation.NullFlavour.HasValue)
                {
                  return new CD
                  {
                    nullFlavor = (NullFlavor)Enum.Parse(typeof(NullFlavor), codableTranslation.NullFlavour.Value.GetAttributeValue<NameAttribute, string>(x => x.Code)),
                    nullFlavorSpecified = true
                  };
                }

                cd = new CD();

                if (codableTranslation.HasCodeSystem)
                {
                    cd.code = codableTranslation.Code;
                    cd.codeSystem = codableTranslation.CodeSystemCode;
                    cd.codeSystemName = codableTranslation.CodeSystemName;
                    var version = codableTranslation.CodeSystemVersion;
                    if (!String.IsNullOrEmpty(version))
                    {
                        cd.codeSystemVersion = version;
                    }
                }

                if (!String.IsNullOrEmpty(codableTranslation.DisplayName))
                {
                    cd.displayName = codableTranslation.DisplayName;
                }

                if (!String.IsNullOrEmpty(codableTranslation.OriginalText))
                {
                    cd.originalText = CreateEncapsulatedData(codableTranslation.OriginalText, MediaType.TXT);
                }

                if (!codableTranslation.HasCodeSystem && string.IsNullOrEmpty(codableTranslation.OriginalText))
                {
                    cd.nullFlavor = NullFlavor.OTH;
                    cd.nullFlavorSpecified = true;
                }
            }

            return cd;
        }

        private static CD CreateConceptDescriptorFromEnum(Enum value, Enum codingSystem, NullFlavour? nullFlavor)
        {
            if (nullFlavor.HasValue)
            {
                return new CD
                {
                    nullFlavor = (NullFlavor)Enum.Parse(typeof(NullFlavor), nullFlavor.GetAttributeValue<NameAttribute, string>(x => x.Code)),
                    nullFlavorSpecified = true
                };
            }

            return new CD
                       {
                           code = value.GetAttributeValue<NameAttribute, String>(x => x.Code),
                           displayName = value.GetAttributeValue<NameAttribute, String>(x => x.Name),
                           codeSystem = codingSystem.GetAttributeValue<NameAttribute, String>(x => x.Code),
                           codeSystemName = codingSystem.GetAttributeValue<NameAttribute, String>(x => x.Name),
                       };
        }

        public static CV CreateCodedValue(string code, CodingSystem? codingSystem, string displayName, string originalText, string codeSystemVersion, NullFlavour? nullFlavor)
       {
           CV cv = null;

           if (nullFlavor.HasValue)
           {
             return new CV
               {
                 nullFlavor = (NullFlavor)Enum.Parse(typeof(NullFlavor), nullFlavor.GetAttributeValue<NameAttribute, string>(x => x.Code)),
                 nullFlavorSpecified = true
               };
           }

           if (!String.IsNullOrEmpty(code) || codingSystem.HasValue || !String.IsNullOrEmpty(displayName) || !String.IsNullOrEmpty(originalText))
           {
               cv = new CV();

               if (!String.IsNullOrEmpty(code))
               {
                   cv.code = code;
                   cv.codeSystem = codingSystem != null ? codingSystem.GetAttributeValue<NameAttribute, string>(x => x.Code) : null;
                   cv.codeSystemName = codingSystem != null ? codingSystem.GetAttributeValue<NameAttribute, string>(x => x.Name) : null;

                   if (!String.IsNullOrEmpty(codeSystemVersion))
                   {
                       cv.codeSystemVersion = codeSystemVersion;
                   }
               }

               if (!String.IsNullOrEmpty(displayName))
               {
                   cv.displayName = displayName;
               }

               if (!String.IsNullOrEmpty(originalText))
               {
                   cv.originalText = CreateEncapsulatedData(originalText, MediaType.TXT);
               }

               if (codingSystem.HasValue == false && string.IsNullOrEmpty(originalText))
               {
                   cv.nullFlavor = NullFlavor.OTH;
                   cv.nullFlavorSpecified = true;
               }
           }

           return cv;
       }

        public static CV CreateCodedValue(string code, CodingSystem? codingSystem, string displayName, string originalText, NullFlavour? nullFlavor)
        {
          return CreateCodedValue(code, codingSystem, displayName, originalText, null, nullFlavor);
        }

        public static CV CreateCodedValue(ICodableText codableText)
        {
            CV cv = null;

            if (codableText != null)
            {

              if (codableText.NullFlavour.HasValue)
              {
                  return new CV
                  {
                    nullFlavor = (NullFlavor)Enum.Parse(typeof(NullFlavor), codableText.NullFlavour.Value.GetAttributeValue<NameAttribute, string>(x => x.Code)),
                    nullFlavorSpecified = true
                  };
              }

                cv = new CV();

                if (codableText.HasCodeSystem)
                {
                    cv.code = codableText.Code;
                    cv.codeSystem = codableText.CodeSystemCode;
                    cv.codeSystemName = codableText.CodeSystemName;
                    var version = codableText.CodeSystemVersion;
                    if (!String.IsNullOrEmpty(version))
                    {
                        cv.codeSystemVersion = version;
                    }
                }

                if (!String.IsNullOrEmpty(codableText.DisplayName))
                {
                    cv.displayName = codableText.DisplayName;
                }

                if (!String.IsNullOrEmpty(codableText.OriginalText))
                {
                    cv.originalText = CreateEncapsulatedData(codableText.OriginalText, MediaType.TXT);
                }

                if (!codableText.HasCodeSystem && string.IsNullOrEmpty(codableText.OriginalText))
                {
                    cv.nullFlavor = NullFlavor.OTH;
                    cv.nullFlavorSpecified = true;
                }
            }

            return cv;
        }

        private static IVL_PQ CreateIntervalPhysicalQuantity(QuantityRange quantityRange)
        {
            IVL_PQ pq = null;

            if (quantityRange != null)
            {
                pq = new IVL_PQ();

                pq.ItemsElementName = new ItemsChoiceType[2];
                pq.Items = new PQ[2];

                pq.ItemsElementName[0] = ItemsChoiceType.low;
                pq.Items[0] = new IVXB_PQ {unit = quantityRange.Units, value = quantityRange.Low};

                pq.ItemsElementName[1] = ItemsChoiceType.high;
                pq.Items[1] = new IVXB_PQ {unit = quantityRange.Units, value = quantityRange.High};
            }

            return pq;
        }

        public static IVL_TS CreateIntervalTimestamp(CdaInterval interval)
        {
            return CreateIntervalTimestamp(interval, null);
        }

        private static IVL_TS CreateIntervalTimestamp(CdaInterval interval, NullFlavor? nullFlavor)
        {
            IVL_TS timestamp = null;

            if (nullFlavor.HasValue)
            {
                return new IVL_TS
                         {
                           nullFlavor = nullFlavor.Value,
                           nullFlavorSpecified = true
                         };
            }

            if (interval != null && (interval.Low != null || interval.High != null || interval.Center != null || interval.IntervalWidth != null))
            {
                Dictionary<ItemsChoiceType3, QTY> values = new Dictionary<ItemsChoiceType3, QTY>();

                timestamp = new IVL_TS();
                
                if (interval.Low != null)
                {
                    values.Add(ItemsChoiceType3.low, new IVXB_TS { value = interval.Low.ToString() });
                }            
                if (interval.High != null)
                {
                    values.Add(ItemsChoiceType3.high, new IVXB_TS {value = interval.High.ToString()});
                }
                if (interval.IntervalWidth != null)
                {
                    values.Add(ItemsChoiceType3.width, new PQ {value = interval.IntervalWidth.Value, unit = interval.IntervalWidth.Unit.GetAttributeValue<NameAttribute, string>(x => x.Code)});
                }
                if (interval.Center != null)
                {
                    values.Add(ItemsChoiceType3.center, new TS { value = interval.Center.ToString() });
                }

                if (values.Any())
                {
                    timestamp.Items = values.Values.ToArray();
                    timestamp.ItemsElementName = values.Keys.ToArray();
                }
            }

            return timestamp;
        }

        internal static IVL_TS CreateIntervalTimestamp(string low, string high, string width, string center, string value, NullFlavor? nullFlavor)
        {
            IVL_TS timestamp = null;

            if (!String.IsNullOrEmpty(low) || !String.IsNullOrEmpty(low) || !String.IsNullOrEmpty(high) || !String.IsNullOrEmpty(center) || !String.IsNullOrEmpty(value) || nullFlavor.HasValue)
            {
                Dictionary<ItemsChoiceType3, QTY> values = new Dictionary<ItemsChoiceType3, QTY>();

                timestamp = new IVL_TS();
                
                if (!String.IsNullOrEmpty(low))
                    values.Add(ItemsChoiceType3.low, new IVXB_TS { value = low });
                if (!String.IsNullOrEmpty(high))
                    values.Add(ItemsChoiceType3.high, new IVXB_TS { value = high });
                if (!String.IsNullOrEmpty(width))
                    values.Add(ItemsChoiceType3.width, new PQ { value = width });
                if (!String.IsNullOrEmpty(center))
                    values.Add(ItemsChoiceType3.center, new TS { value = center });

                if (values.Any())
                {
                    timestamp.Items = values.Values.ToArray();
                    timestamp.ItemsElementName = values.Keys.ToArray();
                }

                if (!String.IsNullOrEmpty(value))
                    timestamp.value = value;

                timestamp.nullFlavor = NullFlavor.NA;
                timestamp.nullFlavorSpecified = false;

                if (nullFlavor.HasValue)
                {
                    timestamp.nullFlavor = nullFlavor.Value;
                    timestamp.nullFlavorSpecified = true;
                }
            }

            return timestamp;
        }

        private static IVL_TS CreateIntervalTimestamp(ISO8601DateTime dateTime, NullFlavor? nullFlavor)
        {
            IVL_TS timestamp = null;

            if (dateTime != null|| nullFlavor.HasValue)
            {
                timestamp = new IVL_TS();

                if (dateTime != null)
                {
                    timestamp.value = dateTime.ToString();
                }

                if (nullFlavor.HasValue)
                {
                    timestamp.nullFlavor = nullFlavor.Value;
                    timestamp.nullFlavorSpecified = true;
                }
            }
            return timestamp;
        }


        private static IVL_TS CreateIntervalTimestamp(DateTime? dateTime, NullFlavor? nullFlavor)
        {
            IVL_TS timestamp = null;

            if (dateTime.HasValue || nullFlavor.HasValue)
            {
                timestamp = new IVL_TS();

                if (dateTime.HasValue)
                {
                    timestamp.value = dateTime.Value.ToString(DATE_TIME_FORMAT);
                }

                if (nullFlavor.HasValue)
                {
                    timestamp.nullFlavor = nullFlavor.Value;
                    timestamp.nullFlavorSpecified = true;
                }
            }
            return timestamp;
        }

        internal static POCD_MT000040Section CreateSectionCodeTitle(string code, CodingSystem? codeSystem, string value)
        {
            return CreateSectionCodeTitle(code, codeSystem, value, value, null);
        }

        internal static POCD_MT000040Section CreateSectionCodeTitle(string code, CodingSystem? codeSystem, string value, string narrative)
        {
          return CreateSectionCodeTitle(code, codeSystem, value, value, narrative);
        }

        internal static POCD_MT000040Section CreateSectionCodeTitle(MedicareInformationViewSections medicareInformationViewSections)
        {
          return CreateSectionCodeTitle(medicareInformationViewSections.GetAttributeValue<NameAttribute, string>(x => x.Code),
                                              (CodingSystem)Enum.Parse(typeof(CodingSystem), medicareInformationViewSections.GetAttributeValue<NameAttribute, string>(x => x.CodeSystem)),
                                              medicareInformationViewSections.GetAttributeValue<NameAttribute, string>(x => x.Name),
                                              medicareInformationViewSections.GetAttributeValue<NameAttribute, string>(x => x.Title),
                                              null);
        }

        internal static POCD_MT000040Section CreateSectionCodeTitle(string code, CodingSystem? codeSystem, string displayName, string title, string narrative)
        {
            var section = new POCD_MT000040Section
            {
              code = CreateCodedWithExtensionElement(code, codeSystem, null, displayName, null, null),
                title = new ST
                {
                    Text = new[]
                    {
                          title
                    }
                },
                text = narrative != null ? new StrucDocText { paragraph = new [] { new StrucDocParagraph { Text = new [] { narrative } } } } : new StrucDocText(),
                id = CreateIdentifierElement(CreateGuid(), null)
            };

            return (section);
        }

        private static HL7.CDA.Participant CreateParticipant(ParticipantRole participantRole, ParticipationType? participationType)
        {
            var participant = new HL7.CDA.Participant
            {
                participantRole = participantRole
            };

            if (participationType.HasValue)
            {
                participant.typeCode = participationType.Value;
                participant.typeCodeSpecified = true;
            }

            return participant;
        }

        private static ParticipantRole CreateParticipantRole(Identifier identifier, RoleClass? classCode)
        {
            var participantRole = new ParticipantRole
            {
                id = CreateIdentifierElement(identifier)
            };

            if (classCode.HasValue)
            {
                participantRole.classCode = classCode.Value;
                participantRole.classCodeSpecified = true;
            }

            return participantRole;
        }

        private static POCD_MT000040Participant2 CreateParticipant2(CE code, EntityDeterminer? determinerCode)
        {
            var participant = new POCD_MT000040Participant2
            {
                typeCode = ParticipationType.CAGNT,
                participantRole = new POCD_MT000040ParticipantRole
                {
                                        
                    classCode = RoleClassRoot.ROL,
                    playingEntity = new POCD_MT000040PlayingEntity
                    {
                        classCode = EntityClassRoot.ENT
                    }
                }
            };

            if (determinerCode != null)
            {
                participant.participantRole.playingEntity.determinerCode = (EntityDeterminer)determinerCode;
                participant.participantRole.playingEntity.determinerCodeSpecified = true;
            }

            participant.participantRole.playingEntity.code = code;

            return participant;
        }

        private static POCD_MT000040Participant2[] CreateParticipant2Array(CE code, EntityDeterminer? determinerCode)
        {
            var participantList = new List<POCD_MT000040Participant2>
                                      {
                                          CreateParticipant2(code, determinerCode)
                                      };

            return participantList.ToArray();
        }

        private static POCD_MT000040Entry CreateEntrySubstanceAdministrationEvent(x_ActRelationshipEntry? actRelationshipEntry, x_DocumentSubstanceMood substanceMood, bool showStatusCode, ST text, string low, string high, ISO8601DateTime effectiveTime, CE CEcode, int? repeatNumber, List<POCD_MT000040EntryRelationship> relationships)
        {
          return CreateEntrySubstanceAdministrationEvent(actRelationshipEntry, substanceMood, showStatusCode, text, low, high, effectiveTime, CEcode, repeatNumber, relationships, null, "active", null, null, null, null, null, null);
        }

        private static POCD_MT000040Entry CreateEntrySubstanceAdministrationEvent(x_ActRelationshipEntry? actRelationshipEntry, x_DocumentSubstanceMood substanceMood, bool showStatusCode, ST text, string low, string high, ISO8601DateTime effectiveTime, CE CEcode, int? repeatNumber, string genericName, ICodableText formCode, ICodableText routeCode, Identifier manufacturerOrganizationId, List<POCD_MT000040EntryRelationship> relationships)
        {
          return CreateEntrySubstanceAdministrationEvent(actRelationshipEntry, substanceMood, showStatusCode, text, low, high, effectiveTime, CEcode, repeatNumber, relationships, null, "active", null, null, genericName, formCode, routeCode, manufacturerOrganizationId);
        }

        private static POCD_MT000040Entry CreateEntrySubstanceAdministrationEvent(x_ActRelationshipEntry? actRelationshipEntry, x_DocumentSubstanceMood substanceMood, bool showStatusCode, string statusCode, ST text, string low, string high, ISO8601DateTime effectiveTime, CE CEcode, int? repeatNumber, string genericName, ICodableText formCode, ICodableText routeCode, Identifier manufacturerOrganizationId, List<POCD_MT000040EntryRelationship> relationships)
        {
          return CreateEntrySubstanceAdministrationEvent(actRelationshipEntry, substanceMood, showStatusCode, text, low, high, effectiveTime, CEcode, repeatNumber, relationships, null, statusCode, null, null, genericName, formCode, routeCode, manufacturerOrganizationId);
        }

        private static POCD_MT000040Entry CreateEntrySubstanceAdministrationEvent(x_ActRelationshipEntry? actRelationshipEntry, x_DocumentSubstanceMood substanceMood, bool showStatusCode, ST text, string low, string high, ISO8601DateTime effectiveTime, CE CEcode, int? repeatNumber, List<POCD_MT000040EntryRelationship> relationships, string statusCode)
        {
          return CreateEntrySubstanceAdministrationEvent(actRelationshipEntry, substanceMood, showStatusCode, text, low, high, effectiveTime, CEcode, repeatNumber, relationships, null, statusCode, null, null, null, null, null, null);
        }

        private static POCD_MT000040Entry CreateEntrySubstanceAdministrationEvent(x_ActRelationshipEntry? actRelationshipEntry, x_DocumentSubstanceMood substanceMood, bool showStatusCode, ST text, string low, string high, ISO8601DateTime effectiveTime, CE CEcode, int? repeatNumber, List<POCD_MT000040EntryRelationship> relationships, Boolean? negationIndicator, string statusCode, List<Subject1> subjects, string id, string genericName, ICodableText formCode, ICodableText routeCode, Identifier manufacturerOrganizationId)
        {
            var entry = new POCD_MT000040Entry
            {
                substanceAdministration = new POCD_MT000040SubstanceAdministration
                {
                    classCode = ActClass.SBADM,
                    moodCode = substanceMood,
                    id = CreateIdentifierArray
                        (
                            String.IsNullOrEmpty(id) ? CreateGuid() : id,
                            null
                        ),
                    negationInd = negationIndicator.HasValue && negationIndicator.Value,
                    negationIndSpecified = negationIndicator.HasValue,
                    consumable = new POCD_MT000040Consumable
                    {
                      manufacturedProduct = new POCD_MT000040ManufacturedProduct
                      {
                        manufacturedMaterial = new POCD_MT000040Material
                        {
                          code = CEcode,
                          name = genericName.IsNullOrEmptyWhitespace() ? null :  new EN { Text = new[] { genericName } },
                          formCode = CreateConceptDescriptor(formCode)
                        },
                        manufacturerOrganization =  manufacturerOrganizationId != null ? new POCD_MT000040Organization
                                                    {
                                                       id = CreateIdentifierArray(manufacturerOrganizationId)
                                                    }  : null
                      }
                    }
                }
            };



            if (actRelationshipEntry.HasValue)
            {
                entry.typeCode = actRelationshipEntry.Value;
            }

            if (showStatusCode)
            {
                entry.substanceAdministration.statusCode = CreateCodeSystem(statusCode, null, null, null, null, null, null);
            }

            if (text != null)
            {
                entry.substanceAdministration.text = text;
            }

            if (routeCode != null)
            {
                entry.substanceAdministration.routeCode = CreateCodedWithExtensionElement(routeCode);
            }

            if (!String.IsNullOrEmpty(low) || !String.IsNullOrEmpty(high))
            {
                entry.substanceAdministration.effectiveTime = new[]
                                                                  {
                                                                      CreateIntervalTimestamp
                                                                      (
                                                                            low, 
                                                                            high, 
                                                                            null, 
                                                                            null,
                                                                            null, 
                                                                            null
                                                                       )
                                                                  };
            }
            if (effectiveTime != null)
            {
                entry.substanceAdministration.effectiveTime = new[]
                                                                  {
                                                                      new SXCM_TS
                                                                          {
                                                                              value = effectiveTime.ToString()
                                                                          }
                                                                  };
            }

            if (relationships != null)
            {
                entry.substanceAdministration.entryRelationship = relationships.ToArray();
            }

            if (subjects != null && subjects.Any())
            {
                entry.substanceAdministration.consumable.manufacturedProduct.subjectOf1 = subjects.ToArray();
            }

            if (repeatNumber.HasValue)
            {
              entry.substanceAdministration.repeatNumber = new IVL_INT
              {
                  ItemsElementName = new [] { ItemsChoiceType5.high },
                  Items = new[] { new IVXB_INT { value = repeatNumber.Value.ToString(CultureInfo.InvariantCulture) } }
              };
            }

            return entry;
        }


        private static POCD_MT000040Entry CreateEntrySubstanceAdministrationEvent(x_ActRelationshipEntry actRelationshipEntry, x_DocumentSubstanceMood substanceMood, bool showStatusCode, ST text, CdaInterval interval, DateTime? effectiveTime, CE CEcode, int? repeatNumber, List<POCD_MT000040EntryRelationship> relationships)
        {
            return CreateEntrySubstanceAdministrationEvent(actRelationshipEntry, substanceMood, showStatusCode, text, interval, effectiveTime, CEcode, repeatNumber, relationships, null, "active", null, null);
        }

        private static POCD_MT000040Entry CreateEntrySubstanceAdministrationEvent(x_ActRelationshipEntry actRelationshipEntry, x_DocumentSubstanceMood substanceMood, bool showStatusCode, ST text, CdaInterval interval, DateTime? effectiveTime, CE CEcode, int? repeatNumber, List<POCD_MT000040EntryRelationship> relationships, String statusCode)
        {
            return CreateEntrySubstanceAdministrationEvent(actRelationshipEntry, substanceMood, showStatusCode, text, interval, effectiveTime, CEcode, repeatNumber, relationships, null, statusCode, null, null);
        }

        private static POCD_MT000040Entry CreateEntrySubstanceAdministrationEvent(x_ActRelationshipEntry actRelationshipEntry, x_DocumentSubstanceMood substanceMood, bool showStatusCode, ST text, CdaInterval interval, DateTime? effectiveTime, CE CEcode, int? repeatNumber, List<POCD_MT000040EntryRelationship> relationships, Boolean? negationIndicator, String statusCode, List<Subject1> subjects, String id)
        {
            var entry = new POCD_MT000040Entry
            {
                typeCode = actRelationshipEntry,
                substanceAdministration = new POCD_MT000040SubstanceAdministration
                {
                    classCode = ActClass.SBADM,
                    moodCode = substanceMood,
                    id = CreateIdentifierArray
                        (
                            String.IsNullOrEmpty(id) ? CreateGuid() : id,
                            null
                        ),
                    negationInd = negationIndicator.HasValue ? negationIndicator.Value : false,
                    negationIndSpecified = negationIndicator.HasValue
                }
            };

            if (showStatusCode)
            {
                entry.substanceAdministration.statusCode = CreateCodeSystem(statusCode, null, null, null, null, null, null);
            }

            if (text != null)
            {
                entry.substanceAdministration.text = text;
            }

            if (interval != null)
            {
                entry.substanceAdministration.effectiveTime = new[]
                                                                  {
                                                                      CreateIntervalTimestamp
                                                                      (
                                                                           interval
                                                                       )
                                                                  };
            }
            if (effectiveTime.HasValue)
            {
                entry.substanceAdministration.effectiveTime = new[]
                                                                  {
                                                                      new SXCM_TS
                                                                          {
                                                                              value = effectiveTime.Value.ToString(DATE_TIME_FORMAT)
                                                                          }
                                                                  };
            }

            entry.substanceAdministration.consumable = new POCD_MT000040Consumable
            {
                manufacturedProduct = new POCD_MT000040ManufacturedProduct
                {
                    manufacturedMaterial = new POCD_MT000040Material
                    {
                        code = CEcode
                    }
                }
            };

            if (relationships != null)
            {
                entry.substanceAdministration.entryRelationship = relationships.ToArray();
            }

            if (subjects != null && subjects.Any())
            {
                entry.substanceAdministration.consumable.manufacturedProduct.subjectOf1 = subjects.ToArray();
            }

            if (repeatNumber.HasValue)
            {
                entry.substanceAdministration.repeatNumber = new IVL_INT();
                entry.substanceAdministration.repeatNumber.ItemsElementName = new ItemsChoiceType5[] { ItemsChoiceType5.high };
                entry.substanceAdministration.repeatNumber.Items = new INT[] { new INT { value = repeatNumber.Value.ToString() } };
            }

            return entry;
        }

        private static POCD_MT000040Specimen CreateSpecimenDetailIdentifiers(SpecimenDetail specimenDetail)
        {
            POCD_MT000040Specimen specimen = null;

            if (specimenDetail != null)
            {
                if (specimenDetail.SpecimenIdentifier != null ||
                    specimenDetail.SpecimenDescription != null ||
                    specimenDetail.ParentSpecimenIdentifier != null ||
                    specimenDetail.PhysicalDetails != null ||
                    specimenDetail.ContainerIdentifier != null ||
                    specimenDetail.SpecimenTissueType != null)
                {

                    var physicalDetailsList = new List<List<String>>();

                    specimen = new POCD_MT000040Specimen
                                   {
                                       specimenRole = new POCD_MT000040SpecimenRole
                                                          {
                                                              id = specimenDetail.SpecimenIdentifier == null ? null : CreateIdentifierArray(specimenDetail.SpecimenIdentifier)
                                                          }
                                   };

                    if (
                        specimenDetail.SpecimenIdentifier != null ||
                        specimenDetail.SpecimenDescription != null ||
                        specimenDetail.ContainerIdentifier != null ||
                        specimenDetail.PhysicalDetails != null
                        )
                    {
                        specimen.specimenRole.specimenPlayingEntity = new POCD_MT000040PlayingEntity
                                                                          {
                                                                              code = CreateCodedWithExtensionElement(specimenDetail.SpecimenTissueType),
                                                                              desc = CreateStructuredText(specimenDetail.SpecimenDescription, null),
                                                                              asSpecimenInContainer = specimenDetail.ContainerIdentifier == null ? null : new SpecimenInContainer
                                                                                                          {
                                                                                                              classCode = EntityClass.CONT,
                                                                                                              container = new Container
                                                                                                                              {
                                                                                                                                  id = CreateIdentifierElement(specimenDetail.ContainerIdentifier)
                                                                                                                              }
                                                                                                          }
                                                                          };
                    }


                    if (specimenDetail.PhysicalDetails != null)
                    {
                        var pqList = new List<PQ>();

                        foreach (var physicalDetail in specimenDetail.PhysicalDetails)
                        {
                            if (physicalDetail.Volume != null)
                                pqList.Add(CreatePhysicalQuantity(physicalDetail.Volume));
                            if (physicalDetail.Weight != null)
                                pqList.Add(CreatePhysicalQuantity(physicalDetail.Weight));

                            // Narrative
                            physicalDetailsList.Add
                                (
                                new List<string> 
                                    {
                                        physicalDetail.Weight == null ? physicalDetail.Volume == null ? String.Empty : physicalDetail.Volume.Units : physicalDetail.Weight.Units,
                                        physicalDetail.Volume == null ? physicalDetail.Weight == null ? String.Empty : physicalDetail.Weight.Value : physicalDetail.Volume.Value
                                    }
                                );
                        }

                        specimen.specimenRole.specimenPlayingEntity.quantity = pqList.ToArray();
                    }
                }
            }

            return specimen;
        }

        private static POCD_MT000040Entry CreateEntryProcedureEvent(x_ActRelationshipEntry actRelationshipEntry, CD code, 
            ISO8601DateTime effectiveTime, List<POCD_MT000040EntryRelationship> relationships)
        {
            var entry = new POCD_MT000040Entry
            {
                typeCode = actRelationshipEntry,
                procedure = new POCD_MT000040Procedure
                {
                    classCode = ActClass.PROC,
                    moodCode = x_DocumentProcedureMood.EVN,
                    id = CreateIdentifierArray
                        (
                            CreateGuid(),
                            null
                        ),
                    code = code
                }
            };

            if (effectiveTime != null)
            {
                entry.procedure.effectiveTime = new IVL_TS
                {
                    value = effectiveTime.ToString()
                };
            }
            if (relationships != null)
            {
                entry.procedure.entryRelationship = relationships.ToArray();
            }

            return (entry);
        }

        private static POCD_MT000040Entry CreateEntryProcedureEvent(CD code)
        {
            var entry = new POCD_MT000040Entry
            {
                procedure = new POCD_MT000040Procedure
                {
                    classCode = ActClass.PROC,
                    moodCode = x_DocumentProcedureMood.EVN,
                    id = CreateIdentifierArray
                        (
                            CreateGuid(),
                            null
                        ),
                    code = code
                }
            };

            return (entry);
        }

        private static Coverage2 CreateCoverage2(string typeCode, Nehta.HL7.CDA.Entitlement entitlement)
        {
            var coverage = new Coverage2
            {
                typeCode = typeCode,
                entitlement = entitlement
            };

            return coverage;
        }

        private static string CreateGuid()
        {
            return
                (
                    new UniqueId().ToString().Replace("urn:uuid:", "")
                );
        }

        private static string ConvertUniqueIdToString(UniqueId uniqueId)
        {
            return
                (
                    uniqueId.ToString().Replace("urn:uuid:", "")
                );
        }

        /// <summary>
        /// Converts an XML document to UTF-8.
        /// </summary>
        /// <param name="document"></param>
        /// <returns></returns>
        private static XmlDocument ConvertDocumentToUtf8(XmlDocument document)
        {
            XmlDocument convertedDoc = new XmlDocument();
            XmlDeclaration xmlDeclaration = convertedDoc.CreateXmlDeclaration("1.0", null, null);
            xmlDeclaration.Encoding = "UTF-8";
            xmlDeclaration.Standalone = "yes";
            convertedDoc.LoadXml(document.DocumentElement.OuterXml);
            XmlElement root = convertedDoc.DocumentElement;
            convertedDoc.InsertBefore(xmlDeclaration, root);

            return convertedDoc;
        }

        /// <summary>
        /// Inserts the XSLT processing instruction into a document.
        /// </summary>
        /// <param name="document"></param>
        /// <param name="stylesheet"></param>
        /// <returns></returns>
        private static XmlDocument InsertXsltProcessingInstruction(XmlDocument document, string stylesheet)
        {
            XmlElement root = document.DocumentElement;
            XmlProcessingInstruction xslt = document.CreateProcessingInstruction("xml-stylesheet", "href=\"" + stylesheet + "\" type=\"text/xsl\"");
            document.InsertBefore(xslt, root);

            return document;
        }

        private static XmlDocument SerializeXML(Object cdaDocument, string elementName, CDADocumentExtensionVersion version)
        {
            var returnXmlDocument = new XmlDocument { PreserveWhitespace = true };
            
            var xmlTypeAttribute = (XmlTypeAttribute)Attribute.GetCustomAttribute(cdaDocument.GetType(), typeof(XmlTypeAttribute));

            if (xmlTypeAttribute != null)
            {
                var stringBuilder = new StringBuilder();

                var xmlSerializerNamespaces = new XmlSerializerNamespaces();
                xmlSerializerNamespaces.Add(String.Empty, String.Empty);
                xmlSerializerNamespaces.Add(String.Empty, xmlTypeAttribute.Namespace);
                xmlSerializerNamespaces.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
                xmlSerializerNamespaces.Add("ext", "http://ns.electronichealth.net.au/Ci/Cda/Extensions/3.0");

                var defaultNamespace = xmlTypeAttribute.Namespace;

                var xmlSerializer = new XmlSerializer(cdaDocument.GetType(), defaultNamespace);

                using (var xmlWriter = XmlWriter.Create(stringBuilder))
                {
                    if (xmlWriter != null)
                    {
                        try
                        {
                            xmlSerializer.Serialize(xmlWriter, cdaDocument, xmlSerializerNamespaces);

                            returnXmlDocument.LoadXml(stringBuilder.ToString());

                            var styleSheet = ConfigurationManager.AppSettings["XSLStylesheet"];

                            returnXmlDocument = ConvertDocumentToUtf8(returnXmlDocument);

                            // Convert the document to UTF8 and insert the XSLT processing instruction
                            if (!string.IsNullOrEmpty(styleSheet))
                                returnXmlDocument = InsertXsltProcessingInstruction(returnXmlDocument, styleSheet);

                            Assembly assembly = Assembly.Load("CDA.GeneratedCode");
                            FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
  
                            // Version nummber for XML
                            XmlComment productVersionComment, CCAValidatorComment;
                            productVersionComment = returnXmlDocument.CreateComment(string.Format(@"Generated using 'NEHTA Vendor Library - CDA' version {0}", assembly.GetName().Version));
                            CCAValidatorComment = returnXmlDocument.CreateComment(fvi.Comments);

                            //Add the new node to the document.
                            XmlElement root = returnXmlDocument.DocumentElement;
                            returnXmlDocument.InsertBefore(productVersionComment, root);
                            returnXmlDocument.InsertBefore(CCAValidatorComment, root);

                        }
                        catch (Exception ex)
                        {
                            if (
                                    ex.InnerException != null &&
                                    ex.InnerException.Message.Contains("is an invalid character") &&
                                    ex.InnerException.TargetSite != null &&
                                    ex.InnerException.TargetSite.Name == "InvalidXmlChar"
                                )
                            {
                                //Throw a friendly exception explaining that the cdaDocument to serialize contains some invalid text characters
                                throw new Exception("Invalid Xml Character: Please cleanse the data; It is possible that one of the string properties within the CDA Document contains invalid charactrers and can not be serialized", ex);
                            }
                            else
                            {
                                throw;
                            }
                        }
                    }
                }
            }
            return (returnXmlDocument);
        }

        private static ICodableText CreateCodableText(MedicareInformationViewSections medicareInformationViewSections)
        {
            return new CodableText
            {
              DisplayName = medicareInformationViewSections.GetAttributeValue<NameAttribute, string>(x => x.Name),
              Code = medicareInformationViewSections.GetAttributeValue<NameAttribute, string>(x => x.Code),
              CodeSystemCode = ((CodingSystem)Enum.Parse(typeof(CodingSystem), medicareInformationViewSections.GetAttributeValue<NameAttribute, string>(x => x.CodeSystem))).GetAttributeValue<NameAttribute, string>(x => x.Code),
              CodeSystemName = ((CodingSystem)Enum.Parse(typeof(CodingSystem), medicareInformationViewSections.GetAttributeValue<NameAttribute, string>(x => x.CodeSystem))).GetAttributeValue<NameAttribute, string>(x => x.Name),
              CodeSystemVersion = ((CodingSystem)Enum.Parse(typeof(CodingSystem), medicareInformationViewSections.GetAttributeValue<NameAttribute, string>(x => x.CodeSystem))).GetAttributeValue<NameAttribute, string>(x => x.Version),
              OriginalText = medicareInformationViewSections.GetAttributeValue<NameAttribute, string>(x => x.Title)
            };
        }


        private static ICodableText CreateCodableText(String code, CodingSystem? codeSystem, String displayName, String originalText)
        {
            if (codeSystem.HasValue)
            {
                return new CodableText
                {
                    DisplayName = displayName,
                    Code = code,
                    CodeSystemCode = codeSystem.Value.GetAttributeValue<NameAttribute, string>(a => a.Code),
                    CodeSystemName = codeSystem.Value.GetAttributeValue<NameAttribute, string>(a => a.Name),
                    CodeSystemVersion = codeSystem.Value.GetAttributeValue<NameAttribute, string>(a => a.Version),
                    OriginalText = originalText
                };
            }
            else
            {
                return new CodableText()
                {
                    OriginalText = originalText
                };
            }
        }

        private static ICodableText CreateCodableText(String code, String codeSystemCode, String codeSystemName, String codeSystemVersion, String displayName, String originalText)
        {
            return new CodableText
            {
              DisplayName = displayName,
              Code = code,
              CodeSystemCode = codeSystemCode,
              CodeSystemName = codeSystemName,
              CodeSystemVersion = codeSystemVersion,
              OriginalText = originalText
            };
        }

        private static List<CD> CreateConceptDescriptorsForAnatomicalSites(ICollection<AnatomicalSite> anatomicalSites)
        {
            List<CD> componentDescriptionList = null;

            if (anatomicalSites != null && anatomicalSites.Any())
            {
                componentDescriptionList = new List<CD>();

                foreach (var anatomicalSite in anatomicalSites)
                {
                    if (!string.IsNullOrEmpty(anatomicalSite.Description) || 
                       (anatomicalSite.AnatomicalLocation != null && anatomicalSite.AnatomicalLocation.NameOfLocation != null) || 
                       (anatomicalSite.AnatomicalLocation != null && anatomicalSite.AnatomicalLocation.Side != null))
                    {
                        CD cd;
                        if (anatomicalSite.AnatomicalLocation != null)
                        {
                            cd = CreateConceptDescriptor(anatomicalSite.AnatomicalLocation.NameOfLocation);

                            if (cd == null)
                            {
                                cd = new CD();
                            }
                        }
                        else
                        {
                            cd = new CD();
                        }

                        if (!string.IsNullOrEmpty(anatomicalSite.Description))
                        {
                            cd.originalText = CreateEncapsulatedData(anatomicalSite.Description);
                        }

                        if (anatomicalSite.AnatomicalLocation != null && anatomicalSite.AnatomicalLocation.Side != null)
                        {
                            var conceptDescriptor = CreateCodedValue("78615007", CodingSystem.SNOMED, "with laterality", null, Constants.SnomedVersion20110531, null);
                            cd.qualifier = new List<CR> 
                                           {
                                               new CR
                                                   {
                                                       name = conceptDescriptor,
                                                       value = CreateConceptDescriptor(anatomicalSite.AnatomicalLocation.Side)
                                                   }
                                           }.ToArray();
                        }

                        componentDescriptionList.Add(cd);
                    }

                }
            }

            return componentDescriptionList;
        }

        private static CD CreateConceptDescriptorForAnatomicalSite(AnatomicalSite anatomicalSite)
        {
            CD cd = null;

            if (anatomicalSite != null)
            {
                if (anatomicalSite.AnatomicalLocation != null)
                {
                    cd = CreateConceptDescriptor(anatomicalSite.AnatomicalLocation.NameOfLocation);

                    cd.originalText = CreateEncapsulatedData(anatomicalSite.Description);

                        var cardioVasciluar = CreateCodedValue
                            (
                                "78615007",
                                CodingSystem.SNOMED,
                                "with laterality",
                                null, 
                                Constants.SnomedVersion20110531,
                                null
                            );

                        cd.qualifier = new List<CR> 
                                           {
                                               new CR 
                                                   { 
                                                       name =  cardioVasciluar,
                                                       value = CreateConceptDescriptor(anatomicalSite.AnatomicalLocation.Side)
                                                   }
                                           }.ToArray();
                    }
            }

            return cd;
        }

        private static POCD_MT000040ObservationMedia CreateObservationMedia(ExternalData media)
        {
            POCD_MT000040ObservationMedia observationMedia = null;

            if (media != null)
            {
                var mediaId = CreateGuid();

                observationMedia = new POCD_MT000040ObservationMedia
                                       {
                                           ID = media.ID,
                                           classCode = ActClassObservation.OBS,
                                           moodCode = ActMood.EVN,
                                           id = CreateIdentifierArray(mediaId, null),
                                           value = CreateEncapsulatedData(media)
                                       };
            }

            return observationMedia;
        }

        /// <summary>
        /// Update the title of of the Component Section
        /// </summary>
        /// <param name="component">The component with the title to be replaced </param>
        /// <param name="title">The title to be updated</param>
        /// <returns></returns>
        public static POCD_MT000040Component3 UpdateComponentTitle(POCD_MT000040Component3 component, string title)
        {
          component.section.title = CreateStructuredText(title , null);
          return component;
        }

        #region MedicareInformationView

       /// <summary>
       /// Creates a Medicare View Exclusion Statement
       /// </summary>
       /// <param name="medicareInformationViewExclusionStatement">The Medicare View Exclusion Statement</param>
       /// <param name="narrativeGenerator">The narrative generator</param>
       /// <returns>POCD_MT000040Component3</returns>
       internal static POCD_MT000040Component3 CreateComponent(MedicareInformationViewExclusionStatement medicareInformationViewExclusionStatement, INarrativeGenerator narrativeGenerator)
        {
          POCD_MT000040Component3 component = null;

          if (medicareInformationViewExclusionStatement != null && !medicareInformationViewExclusionStatement.GeneralStatement.IsNullOrEmptyWhitespace())
          {
            var entryList = new List<POCD_MT000040Entry>();

            component = new POCD_MT000040Component3
            {
               section = CreateSectionCodeTitle(MedicareInformationViewSections.MedicareInformationViewExclusionStatement),
            };

            component.section.title = CreateStructuredText(medicareInformationViewExclusionStatement.SectionTitle, null);

            entryList.Add(CreateExclusionStatement(medicareInformationViewExclusionStatement.GeneralStatement, "103.16135.172.1.3", "General Statement"));
            component.section.entry = entryList.ToArray();

              // Narrative
            component.section.text = medicareInformationViewExclusionStatement.CustomNarrative ?? narrativeGenerator.CreateNarrative(medicareInformationViewExclusionStatement);
          }

          return component;
        }

       /// <summary>
       /// Creates a Medicare DVA Funded Services 
       /// </summary>
       /// <param name="medicareDvaFundedServicesHistory">The Medicare DVA Funded Services </param>
       /// <param name="narrativeGenerator">The narrative generator</param>
       /// <returns>POCD_MT000040Component3</returns>
       internal static POCD_MT000040Component3 CreateComponent(MedicareDVAFundedServicesHistory medicareDvaFundedServicesHistory, INarrativeGenerator narrativeGenerator)
       {
         var entryList = new List<POCD_MT000040Entry>();

         POCD_MT000040Component3 component = null;
         var components = new List<POCD_MT000040Component5>();

         if (medicareDvaFundedServicesHistory != null)
         {
           component = new POCD_MT000040Component3
           {
             section = CreateSectionCodeTitle(MedicareInformationViewSections.MedicareDVAFundedServicesHistory)
           };

           if (medicareDvaFundedServicesHistory.ExclusionStatement != null)
           {
             entryList.Add(CreateExclusionStatement(medicareDvaFundedServicesHistory.ExclusionStatement.GeneralStatement, "102.16134.172.1.5", "General Statement"));

             var section = CreateSectionCodeTitle
                           (
                                      MedicareInformationViewSections.MedicareDVAFundedServicesExclusionStatement.GetAttributeValue<NameAttribute, string>(x => x.Code),
                                      CodingSystem.NCTIS,
                                      MedicareInformationViewSections.MedicareDVAFundedServicesExclusionStatement.GetAttributeValue<NameAttribute, string>(x => x.Name),
                                      medicareDvaFundedServicesHistory.ExclusionStatement.SectionTitle,
                                      null
                           );

             section.text = medicareDvaFundedServicesHistory.ExclusionStatement.CustomNarrative ?? narrativeGenerator.CreateNarrative(medicareDvaFundedServicesHistory.ExclusionStatement);

             section.entry = entryList.ToArray();

             components.Add(new POCD_MT000040Component5 { section = section });
           }


           if (medicareDvaFundedServicesHistory.MedicarDVAFundedServices != null)
           {
             var medicarDVAFundedServicesComponent = new POCD_MT000040Component5();

             medicarDVAFundedServicesComponent.section = CreateSectionCodeTitle
                           (
                               MedicareInformationViewSections.MedicareDVAFundedServices
                           );

             if (medicareDvaFundedServicesHistory.MedicarDVAFundedServices.MedicareDVAFundedService != null &&
                 medicareDvaFundedServicesHistory.MedicarDVAFundedServices.MedicareDVAFundedService.Any()
                 )
             {
               entryList.AddRange(medicareDvaFundedServicesHistory.MedicarDVAFundedServices.MedicareDVAFundedService.Select(medicareDVAFundedService => CreateMedicareDVAFundedService(medicareDVAFundedService)));
             }

             if (medicareDvaFundedServicesHistory.MedicarDVAFundedServices.MedicareDVAFundedServicesDocumentProvenance != null)
             {
               entryList.Add(CreateEntryLink(x_DocumentActMood.EVN,
                                             CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.MedicareDVAFundedServicesDocumentProvenance)),
                                             medicareDvaFundedServicesHistory.MedicarDVAFundedServices.MedicareDVAFundedServicesDocumentProvenance));
             }

             medicarDVAFundedServicesComponent.section.entry = entryList.ToArray();

             medicarDVAFundedServicesComponent.section.text = medicareDvaFundedServicesHistory.MedicarDVAFundedServices.CustomNarrative ?? narrativeGenerator.CreateNarrative(medicareDvaFundedServicesHistory.MedicarDVAFundedServices);

             components.Add(medicarDVAFundedServicesComponent);
           }

           // Add components 
           component.section.component = components.ToArray();

           // Narrative
           component.section.text = null;
         }
         return component;
       }

      /// <summary>
      /// Creates a Pharmaceutical Benefit Items Component
      /// </summary>
       /// <param name="pharmaceuticalBenefitsHistory">The PharmaceuticalBenefitsHistory </param>
      /// <param name="narrativeGenerator">The narrative generator</param>
      /// <returns>POCD_MT000040Component3</returns>
      internal static POCD_MT000040Component3 CreateComponent(PharmaceuticalBenefitsHistory pharmaceuticalBenefitsHistory, INarrativeGenerator narrativeGenerator)
       {
         POCD_MT000040Component3 component = null;

         var entryList = new List<POCD_MT000040Entry>();
         var components = new List<POCD_MT000040Component5>();

         if (pharmaceuticalBenefitsHistory != null)
         {
           component = new POCD_MT000040Component3
           {
              section = CreateSectionCodeTitle(MedicareInformationViewSections.PharmaceuticalBenefitHistory)
           };

           if (pharmaceuticalBenefitsHistory.ExclusionStatement != null)
           {
             entryList.Add(CreateExclusionStatement(pharmaceuticalBenefitsHistory.ExclusionStatement.GeneralStatement, "102.16134.172.1.4", "General Statement"));

             var section = CreateSectionCodeTitle
                           (
                                      MedicareInformationViewSections.PharmaceuticalBenefitItemsExclusionStatement.GetAttributeValue<NameAttribute, string>(x => x.Code),
                                      CodingSystem.NCTIS,
                                      MedicareInformationViewSections.PharmaceuticalBenefitItemsExclusionStatement.GetAttributeValue<NameAttribute, string>(x => x.Name),
                                      pharmaceuticalBenefitsHistory.ExclusionStatement.SectionTitle,
                                      null
                           );

             section.text = pharmaceuticalBenefitsHistory.ExclusionStatement.CustomNarrative ?? narrativeGenerator.CreateNarrative(pharmaceuticalBenefitsHistory.ExclusionStatement);

             section.entry = entryList.ToArray();

             components.Add(new POCD_MT000040Component5 { section = section } );
           }

           if (pharmaceuticalBenefitsHistory.PharmaceuticalBenefitItems != null)
           {
             var pharmaceuticalBenefitItemsComponent= new POCD_MT000040Component5();

             pharmaceuticalBenefitItemsComponent.section = CreateSectionCodeTitle
                           (
                               MedicareInformationViewSections.PharmaceuticalBenefitsItems
                           );

             if (pharmaceuticalBenefitsHistory.PharmaceuticalBenefitItems.PharmaceuticalBenefitItemList != null &&
                 pharmaceuticalBenefitsHistory.PharmaceuticalBenefitItems.PharmaceuticalBenefitItemList.Any()
                 )
                 {
                   foreach (var pharmaceuticalBenefitItem in pharmaceuticalBenefitsHistory.PharmaceuticalBenefitItems.PharmaceuticalBenefitItemList)
                   {
                      entryList.Add(CreatePharmaceuticalBenefitItem(pharmaceuticalBenefitItem, narrativeGenerator));
                   }
                 }

             if (pharmaceuticalBenefitsHistory.PharmaceuticalBenefitItems.PharmaceuticalBenefitItemsDocumentProvenanceLink != null)
             {
               entryList.Add(CreateEntryLink(x_DocumentActMood.EVN, 
                                             CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.PharmaceuticalBenefitItemsDocumentProvenance)), 
                                             pharmaceuticalBenefitsHistory.PharmaceuticalBenefitItems.PharmaceuticalBenefitItemsDocumentProvenanceLink));
             }


             pharmaceuticalBenefitItemsComponent.section.entry = entryList.ToArray();

             pharmaceuticalBenefitItemsComponent.section.text = pharmaceuticalBenefitsHistory.PharmaceuticalBenefitItems.CustomNarrative ?? narrativeGenerator.CreateNarrative(pharmaceuticalBenefitsHistory.PharmaceuticalBenefitItems);

             components.Add(pharmaceuticalBenefitItemsComponent);
           }
    
            // Add components 
           component.section.component = components.ToArray();
 
           // Narrative
           component.section.text = null;
         }
         return component;
       }

      /// <summary>
      /// Creates a MedicareDVAFundedService
      /// </summary>
      /// <param name="medicareDVAFundedService">The MedicareDVAFundedService </param>
      /// <returns>POCD_MT000040Entry</returns>
      internal static POCD_MT000040Entry CreateMedicareDVAFundedService(MedicareDVAFundedService medicareDVAFundedService)
      {
        POCD_MT000040Entry entry = null;

        POCD_MT000040Performer2 serviceProvider = null;
        POCD_MT000040Participant2 serviceRequester = null;

        if (medicareDVAFundedService != null)
        {
          var entryRelationship = new List<POCD_MT000040EntryRelationship>();

          if (medicareDVAFundedService.ServiceInHospitalIndicator.HasValue)
            entryRelationship.Add(CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.SUBJ,
                                                                     false,
                                                                     CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.ServiceInHospitalIndicator)),
                                                                     new List<ANY> { CreateBoolean(medicareDVAFundedService.ServiceInHospitalIndicator.Value, true) }));


          if (medicareDVAFundedService.ServiceProvider != null)
          {
             serviceProvider = CreatePerformer(medicareDVAFundedService.ServiceProvider);
          }

          if (medicareDVAFundedService.ServiceRequester != null)
          {
             serviceRequester = CreateParticipant2(medicareDVAFundedService.ServiceRequester);
          }

          entry = new POCD_MT000040Entry
                    {
                      encounter = new POCD_MT000040Encounter
                                    {
                                      classCode = ActClass.ENC,
                                      moodCode = x_DocumentEncounterMood.EVN,
                                      id = CreateIdentifierArray( CreateGuid() , null),
                                      code = CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.MedicareMBSDVAItem)),
                                      effectiveTime = medicareDVAFundedService.DateOfService != null ?  CreateIntervalTimestamp(medicareDVAFundedService.DateOfService, null) : null,
                                      performer = serviceProvider != null ? new [] { serviceProvider } : null,
                                      participant = serviceRequester != null ? new[] { serviceRequester } : null,
                                      entryRelationship = entryRelationship.Any() ? entryRelationship.ToArray() : null
                                    }
                    
                    };
        }

        return entry;
      }



      /// <summary>
      /// Creates a Pharmaceutical Benefit Items Component
      /// </summary>
      /// <param name="pharmaceuticalBenefitItem">The PharmaceuticalBenefitItem </param>
      /// <param name="narrativeGenerator">The narrative generator</param>
      /// <returns>POCD_MT000040Component3</returns>
      internal static POCD_MT000040Entry CreatePharmaceuticalBenefitItem(PharmaceuticalBenefitItem pharmaceuticalBenefitItem, INarrativeGenerator narrativeGenerator)
      {
        POCD_MT000040Entry entry = null;

        if (pharmaceuticalBenefitItem != null)
        {
          var entryRelationship = new List<POCD_MT000040EntryRelationship>();

          if (!pharmaceuticalBenefitItem.ItemFormAndStrength.IsNullOrEmptyWhitespace())
          entryRelationship.Add(CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.SUBJ,
                                                                   false,
                                                                   CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.ItemFormAndStrength)),
                                                                   new List<ANY> { CreateStructuredText(pharmaceuticalBenefitItem.ItemFormAndStrength, null) }));

          if (pharmaceuticalBenefitItem.DateOfPrescribing != null || pharmaceuticalBenefitItem.NumberOfRepeats.HasValue)
          {
            entryRelationship.Add(CreateEntryRelationshipSubstanceAdministration(
                                                          x_ActRelationshipEntryRelationship.REFR, 
                                                          ActClass.SBADM, 
                                                          x_DocumentSubstanceMood.RQO, 
                                                          pharmaceuticalBenefitItem.DateOfPrescribing, 
                                                          pharmaceuticalBenefitItem.NumberOfRepeats));
          }
                                                                     
          entry = new POCD_MT000040Entry
                    {
                      supply = new POCD_MT000040Supply
                                 {
                                   classCode = ActClassSupply.SPLY,
                                   moodCode = x_DocumentSubstanceMood.EVN,
                                   code = CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.PharmaceuticalBenefitsItem)),
                                   effectiveTime = pharmaceuticalBenefitItem.DateOfSupply != null ? new[] { new SXCM_TS { value = pharmaceuticalBenefitItem.DateOfSupply.ToString() } } : null,
                                   quantity = pharmaceuticalBenefitItem.Quantity.HasValue? CreatePhysicalQuantity(null, pharmaceuticalBenefitItem.Quantity.Value.ToString(CultureInfo.InvariantCulture)) : null,
                                   product = new POCD_MT000040Product
                                               {
                                                 typeCode = ParticipationType.PRD,
                                                 manufacturedProduct = new POCD_MT000040ManufacturedProduct
                                                                         {
                                                                            classCode = RoleClassManufacturedProduct.MANU,
                                                                            manufacturedMaterial = new POCD_MT000040Material
                                                                                                     {
                                                                                                       code = pharmaceuticalBenefitItem.PBSRPBSItemCode == null ? null : CreateCodedWithExtensionElement(CreateCodableText(pharmaceuticalBenefitItem.PBSRPBSItemCode, CodingSystem.PBSCode, pharmaceuticalBenefitItem.ItemGenericName, null)),
                                                                                                       name = pharmaceuticalBenefitItem.Brand.IsNullOrEmptyWhitespace() ? null : new EN { Text = new [] { pharmaceuticalBenefitItem.Brand } }
                                                                                                     },
                                                                            manufacturerOrganization = new POCD_MT000040Organization
                                                                                                         {
                                                                                                           id = pharmaceuticalBenefitItem.PBSRPBSManufacturerCode == null ? null : CreateIdentifierArray("1.2.36.1.2001.1005.23", pharmaceuticalBenefitItem.PBSRPBSManufacturerCode, null)
                                                                                                         },
                                                                         }
                                               },
                                   entryRelationship = entryRelationship.ToArray()
                                 }
                    
                    };
        }

        return entry;
      }

      /// <summary>
      /// Creates a Australian Childhood Immunisation Register Component
      /// </summary>
      /// <param name="australianChildhoodImmunisationRegisterHistory">The Medicare DVA Funded Services </param>
      /// <param name="narrativeGenerator">The narrative generator</param>
      /// <returns>POCD_MT000040Component3</returns>
      internal static POCD_MT000040Component3 CreateComponent(AustralianChildhoodImmunisationRegisterHistory australianChildhoodImmunisationRegisterHistory, INarrativeGenerator narrativeGenerator)
      {
        POCD_MT000040Component3 component = null;
        var components = new List<POCD_MT000040Component5>();
 

        if (australianChildhoodImmunisationRegisterHistory != null)
        {
          component = new POCD_MT000040Component3
          {
            section = CreateSectionCodeTitle(MedicareInformationViewSections.AustralianChildhoodImmunisationRegisterHistory)
          };

          if (australianChildhoodImmunisationRegisterHistory.ExclusionStatement != null)
          {
            var entries = new List<POCD_MT000040Entry>();
            entries.Add(CreateExclusionStatement(australianChildhoodImmunisationRegisterHistory.ExclusionStatement.GeneralStatement, "103.16135.172.1.1", "General Statement"));

            var section = CreateSectionCodeTitle
                          (
                                     MedicareInformationViewSections.AustralianChildhoodImmunisationRegisterHistoryExclusionStatement.GetAttributeValue<NameAttribute, string>(x => x.Code),
                                     CodingSystem.NCTIS,
                                     MedicareInformationViewSections.AustralianChildhoodImmunisationRegisterHistoryExclusionStatement.GetAttributeValue<NameAttribute, string>(x => x.Name),
                                     australianChildhoodImmunisationRegisterHistory.ExclusionStatement.SectionTitle,
                                     null
                          );

            section.text = australianChildhoodImmunisationRegisterHistory.ExclusionStatement.CustomNarrative ?? narrativeGenerator.CreateNarrative(australianChildhoodImmunisationRegisterHistory.ExclusionStatement);
            section.entry = entries.ToArray();
            components.Add(new POCD_MT000040Component5 { section = section });
          }

          if (australianChildhoodImmunisationRegisterHistory.AustralianChildhoodImmunisationRegisterEntries != null)
          {
            var entries = new List<POCD_MT000040Entry>();

            if (australianChildhoodImmunisationRegisterHistory.AustralianChildhoodImmunisationRegisterEntries.AustralianChildhoodImmunisationRegisterDocumentProvenanceLink != null)
            {
              entries.Add(CreateEntryLink(x_DocumentActMood.EVN,
                                            CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.AustralianChildhoodImmunisationRegisterEntriesDocumentProvenance)),
                                            australianChildhoodImmunisationRegisterHistory.AustralianChildhoodImmunisationRegisterEntries.AustralianChildhoodImmunisationRegisterDocumentProvenanceLink));
            }

            var section = CreateSectionCodeTitle(MedicareInformationViewSections.AustralianChildhoodImmunisationRegisterEntries);
            foreach (var australianChildhoodImmunisationRegisterEntry in australianChildhoodImmunisationRegisterHistory.AustralianChildhoodImmunisationRegisterEntries.AustralianChildhoodImmunisationRegisterEntry)
            {
              if (australianChildhoodImmunisationRegisterEntry.VaccineAdministrationEntry != null)
              entries.Add(CreateVaccineAdministrationEntry(australianChildhoodImmunisationRegisterEntry.VaccineAdministrationEntry));

              List<POCD_MT000040EntryRelationship> entryRelationship = null;
              if (australianChildhoodImmunisationRegisterEntry.VaccineCancellationReason != null && australianChildhoodImmunisationRegisterEntry.VaccineCancellationReason.Any())
              {
                 entryRelationship = australianChildhoodImmunisationRegisterEntry.VaccineCancellationReason.Select(vaccineCancellationReason => CreateVaccineCancellationReason(vaccineCancellationReason)).ToList();
              }

              if (australianChildhoodImmunisationRegisterEntry.VaccineCancellationEntry != null)
                entries.Add(CreateVaccineCancellationEntry(australianChildhoodImmunisationRegisterEntry.VaccineCancellationEntry, entryRelationship));
            }
            section.text = australianChildhoodImmunisationRegisterHistory.AustralianChildhoodImmunisationRegisterEntries.CustomNarrative ?? narrativeGenerator.CreateNarrative(australianChildhoodImmunisationRegisterHistory.AustralianChildhoodImmunisationRegisterEntries);
            section.entry = entries.ToArray();

            components.Add(new POCD_MT000040Component5 { section = section });

          }

          component.section.component = components.ToArray();

          // Narrative
          component.section.text = null;
        }

        return component;
      }

      /// <summary>
      /// Creates a Vaccine Administration Entry
      /// </summary>
      /// <param name="vaccineAdministrationEntry">The Vaccine Administration Entry </param>
      /// <returns>POCD_MT000040Entry</returns>
      internal static POCD_MT000040Entry CreateVaccineAdministrationEntry(VaccineAdministrationEntry vaccineAdministrationEntry)
      {
        POCD_MT000040Entry entry = null;
        List<POCD_MT000040EntryRelationship> entryRelationship = null;

        if (vaccineAdministrationEntry.VaccineDoseNumber.HasValue)
        {
          entryRelationship = new List<POCD_MT000040EntryRelationship>();
          entryRelationship.Add(CreateEntryRelationshipSupply(ActClassSupply.SPLY,
                                                              x_ActRelationshipEntryRelationship.COMP,
                                                              x_DocumentSubstanceMood.EVN,
                                                              false,
                                                              null,
                                                              null,
                                                              null,
                                                              vaccineAdministrationEntry.VaccineDoseNumber.Value,
                                                              false,
                                                              null));
        }

        entry = new POCD_MT000040Entry();
        entry.substanceAdministration = new POCD_MT000040SubstanceAdministration
                                        {
                                           moodCode = x_DocumentSubstanceMood.EVN,
                                           classCode = ActClass.SBADM,
                                           id = CreateIdentifierArray(CreateGuid(), null, null),
                                           effectiveTime = vaccineAdministrationEntry.DateVaccinationReceived != null ? new[] { new SXCM_TS { value = vaccineAdministrationEntry.DateVaccinationReceived.ToString() } } : null,
                                           consumable = new POCD_MT000040Consumable
                                           {
                                                 manufacturedProduct = new POCD_MT000040ManufacturedProduct
                                                 {
                                                   manufacturedMaterial = new POCD_MT000040Material
                                                   {
                                                     code = vaccineAdministrationEntry.VaccineType != null ? CreateCodedWithExtensionElement(vaccineAdministrationEntry.VaccineType) : null,
                                                     asIngredient = vaccineAdministrationEntry.MedicareAntigenCode != null ? CreateMedicareAntigenCodes(vaccineAdministrationEntry.MedicareAntigenCode) : null
                                                   }
                                                 }
                                           },
                                           entryRelationship = entryRelationship != null ? entryRelationship.ToArray() : null
                                        };
        return entry;
      }

      /// <summary>
      /// Creates a Vaccine Cancellation Entry
      /// </summary>
      /// <param name="vaccineAdministrationEntry">The Vaccine Cancellation Entry</param>
      /// <returns>POCD_MT000040Entry</returns>
      internal static POCD_MT000040Entry CreateVaccineCancellationEntry(VaccineCancellationEntry vaccineAdministrationEntry, List<POCD_MT000040EntryRelationship> entryRelationshipList)
      {
        POCD_MT000040Entry entry = null;

        if (entryRelationshipList == null)
        {
          entryRelationshipList = new List<POCD_MT000040EntryRelationship>(); 
        }

        if (vaccineAdministrationEntry.VaccineDoseNumber.HasValue)
        {
          entryRelationshipList.Add(CreateEntryRelationshipSupply(ActClassSupply.SPLY,
                                                              x_ActRelationshipEntryRelationship.COMP,
                                                              x_DocumentSubstanceMood.EVN,
                                                              false,
                                                              null,
                                                              null,
                                                              null,
                                                              vaccineAdministrationEntry.VaccineDoseNumber.Value,
                                                              false,
                                                              null));
        }

        entry = new POCD_MT000040Entry();
        entry.substanceAdministration = new POCD_MT000040SubstanceAdministration
        {
          statusCode = new CS { code = "Cancelled"},
          moodCode = x_DocumentSubstanceMood.EVN,
          classCode = ActClass.SBADM,
          id = CreateIdentifierArray(CreateGuid(), null, null),
          effectiveTime = vaccineAdministrationEntry.DateVaccinationCancelled != null ? new[] { new SXCM_TS { value = vaccineAdministrationEntry.DateVaccinationCancelled.ToString() } } : null,
          consumable = new POCD_MT000040Consumable
          {
            manufacturedProduct = new POCD_MT000040ManufacturedProduct
            {
              manufacturedMaterial = new POCD_MT000040Material
              {
                code = vaccineAdministrationEntry.VaccineType != null ? CreateCodedWithExtensionElement(vaccineAdministrationEntry.VaccineType) : null,
                asIngredient = CreateMedicareAntigenCodes(vaccineAdministrationEntry.MedicareAntigenCode)
              }
            }
          },
          entryRelationship = entryRelationshipList.ToArray()
        };
        return entry;
      }

      /// <summary>
      /// Creates a Vaccine Cancellation Reason
      /// </summary>
      /// <param name="vaccineAdministrationEntry">The Vaccine Cancellation Reason</param>
      /// <returns>POCD_MT000040EntryRelationship</returns>
      internal static POCD_MT000040EntryRelationship CreateVaccineCancellationReason(VaccineCancellationReason vaccineAdministrationEntry)
      {
        POCD_MT000040Entry entry = null;
        var entryRelationshipList = new List<POCD_MT000040EntryRelationship>();

        CD cd;
        if (vaccineAdministrationEntry.VaccineType.HasValue)
        {
          cd = CreateConceptDescriptor(
                        CreateCodableText(
                                          vaccineAdministrationEntry.VaccineType.Value.GetAttributeValue<NameAttribute, string>(x => x.Code), 
                                          CodingSystem.VaccineCancellationReasonTypeValues,
                                          vaccineAdministrationEntry.VaccineType.Value.GetAttributeValue<NameAttribute, string>(x => x.Name),
                                          vaccineAdministrationEntry.VaccineType.Value.GetAttributeValue<NameAttribute, string>(x => x.Comment))
                                        );
        } 
          else
        {
          cd  = CreateConceptDescriptor(null, null as string, null, null, null, null, vaccineAdministrationEntry.VaccineTypeNullFlavour);
        }


        entryRelationshipList.Add(CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.COMP,
                                                               x_ActClassDocumentEntryAct.INFRM,
                                                               x_DocumentActMood.EVN,
                                                               null,
                                                               cd,
                                                               null, 
                                                               null,
                                                               CreateIntervalTimestamp(vaccineAdministrationEntry.VaccineCancellationReasonPeriod)));

        var entryRelationship = CreateEntryRelationshipACT(x_ActRelationshipEntryRelationship.RSON,
                                                         x_ActClassDocumentEntryAct.INFRM,
                                                         x_DocumentActMood.EVN,
                                                         null,
                                                         CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.Comment)),
                                                         CreateEncapsulatedData(vaccineAdministrationEntry.VaccineCancellationReasonComment),
                                                         CreateIdentifierArray(CreateGuid()), 
                                                         entryRelationshipList);


        return entryRelationship;
      }

      /// <summary>
      /// Creates a Medicare Antigen Codes
      /// </summary>
      /// <param name="medicareAntigenCodes">The Medicare Antigen Codes </param>
      /// <returns>POCD_MT000040Component3</returns>
      internal static Ingredient[] CreateMedicareAntigenCodes(List<ICodableText> medicareAntigenCodes)
      {
          List<Ingredient> ingredients = null;

          if (medicareAntigenCodes != null && medicareAntigenCodes.Any())
          {
            ingredients = new List<Ingredient>();
            foreach(var medicareAntigenCode in medicareAntigenCodes)
            {
              ingredients.Add(new Ingredient
                               {
                                 classCode = RoleClassRoot.INGR,
                                 ingredientManufacturedMaterial = new ManufacturedMaterial
                                                                    {
                                                                      classCode = EntityClass.MMAT,
                                                                      determinerCode = EntityDeterminer.KIND,
                                                                      code = CreateCodedValue(medicareAntigenCode)
                                                                    }
                                }
                             );
            }
          }

        return ingredients == null ? null : ingredients.ToArray();
      }

      /// <summary>
      /// Creates a Australian Organ Donor Register Component 
      /// </summary>
      /// <param name="australianOrganDonorRegisterDecisionInformation">The Australian OrganDonor Register Component </param>
      /// <param name="narrativeGenerator">The narrative generator</param>
      /// <returns>POCD_MT000040Component3</returns>
      internal static POCD_MT000040Component3 CreateComponent(AustralianOrganDonorRegisterDecisionInformation australianOrganDonorRegisterDecisionInformation, INarrativeGenerator narrativeGenerator)
      {
        POCD_MT000040Component3 component = null;

        var entryList = new List<POCD_MT000040Entry>();
        var components = new List<POCD_MT000040Component5>();

        if (australianOrganDonorRegisterDecisionInformation != null)
        {
          component = new POCD_MT000040Component3
          {
             section = CreateSectionCodeTitle(MedicareInformationViewSections.AustralianOrganDonorRegisterComponent),
          };

          if (australianOrganDonorRegisterDecisionInformation.ExclusionStatement != null)
          {
            entryList.Add(CreateExclusionStatement(australianOrganDonorRegisterDecisionInformation.ExclusionStatement.GeneralStatement, "103.16135.172.1.2", "General Statement"));

            var section = CreateSectionCodeTitle
                          (
                                     MedicareInformationViewSections.AustralianOrganDonorRegisterDetailsExclusionStatement.GetAttributeValue<NameAttribute, string>(x => x.Code),
                                     CodingSystem.NCTIS,
                                     MedicareInformationViewSections.AustralianOrganDonorRegisterDetailsExclusionStatement.GetAttributeValue<NameAttribute, string>(x => x.Name),
                                     australianOrganDonorRegisterDecisionInformation.ExclusionStatement.SectionTitle,
                                     null
                          );

            section.entry = entryList.ToArray();
            section.text = australianOrganDonorRegisterDecisionInformation.ExclusionStatement.CustomNarrative ?? narrativeGenerator.CreateNarrative(australianOrganDonorRegisterDecisionInformation.ExclusionStatement);
            components.Add(new POCD_MT000040Component5 { section = section });
          }

          if (australianOrganDonorRegisterDecisionInformation.AustralianOrganDonorRegisterDetails != null)
          {

            var pharmaceuticalBenefitItemsComponent = new POCD_MT000040Component5();

            pharmaceuticalBenefitItemsComponent.section = CreateSectionCodeTitle
                          (
                              MedicareInformationViewSections.AustralianOrganDonorRegisterDetails
                          );

            if (australianOrganDonorRegisterDecisionInformation.AustralianOrganDonorRegisterDetails != null)
            {
              entryList.Add(CreateAustralianOrganDonorRegisterEntry(australianOrganDonorRegisterDecisionInformation.AustralianOrganDonorRegisterDetails.AustralianOrganDonorRegisterEntry));

              if (australianOrganDonorRegisterDecisionInformation.AustralianOrganDonorRegisterDetails.AustralianOrganDonorRegisterDetailsProvenanceLink != null)
                 {
                  entryList.Add(CreateEntryLink(x_DocumentActMood.EVN,
                                                CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.AustralianOrganDonorRegisterDetailsDocumentProvenance)),
                                                australianOrganDonorRegisterDecisionInformation.AustralianOrganDonorRegisterDetails.AustralianOrganDonorRegisterDetailsProvenanceLink));
                 }
            }

            pharmaceuticalBenefitItemsComponent.section.entry = entryList.ToArray();

            pharmaceuticalBenefitItemsComponent.section.text = australianOrganDonorRegisterDecisionInformation.AustralianOrganDonorRegisterDetails.CustomNarrative ?? narrativeGenerator.CreateNarrative(australianOrganDonorRegisterDecisionInformation.AustralianOrganDonorRegisterDetails);

            components.Add(pharmaceuticalBenefitItemsComponent);
          }

          component.section.component = components.ToArray();

          // Narrative
          component.section.text = null;
        }

        return component;
      }

      /// <summary>
      /// Create Australian Organ Donor Register Entry
      /// </summary>
      /// <param name="australianOrganDonorRegisterEntry">The Australian Organ Donor Register Entry</param>
      /// <returns>POCD_MT000040Entry</returns>
      internal static POCD_MT000040Entry CreateAustralianOrganDonorRegisterEntry(AustralianOrganDonorRegisterEntry australianOrganDonorRegisterEntry)
      {
        POCD_MT000040Entry entry = null;

        if (australianOrganDonorRegisterEntry != null)
        {
          var entryRelationshipList = new List<POCD_MT000040EntryRelationship>();
          var components = new List<POCD_MT000040Component4>();

          if (australianOrganDonorRegisterEntry.DonationDecision.HasValue)
          {
            entryRelationshipList.Add(CreateEntryRelationshipObservation(x_ActRelationshipEntryRelationship.SUBJ,
                                                                         null ,
                                                                         CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.DonationDecision)),
                                                                         new List<ANY> { CreateBoolean(australianOrganDonorRegisterEntry.DonationDecision.Value, true) }
                                                                         ));
          }

          if (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.BoneTissueIndicator.HasValue)
          {
            components.Add(CreateComponentObservation(CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.BoneTissueIndicator)),
                                                                                  new List<ANY> { CreateBoolean(australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.BoneTissueIndicator.Value, true) }
                                                                                 ));
          }

          if (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.EyeTissueIndicator.HasValue)
          {
            components.Add(CreateComponentObservation(CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.EyeTissueIndicator)),
                                                                                  new List<ANY> { CreateBoolean(australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.EyeTissueIndicator.Value, true) }
                                                                                 ));
          }

          if (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.HeartIndicator.HasValue)
          {
            components.Add(CreateComponentObservation(CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.HeartIndicator)),
                                                                                  new List<ANY> { CreateBoolean(australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.HeartIndicator.Value, true) }
                                                                                 ));
          }


          if (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.HeartValveIndicator.HasValue)
          {
            components.Add(CreateComponentObservation(CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.HeartValveIndicator)),
                                                                                  new List<ANY> { CreateBoolean(australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.HeartValveIndicator.Value, true) }
                                                                                 ));
          }

          if (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.KidneyIndicator.HasValue)
          {
            components.Add(CreateComponentObservation(CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.KidneyIndicator)),
                                                                                  new List<ANY> { CreateBoolean(australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.KidneyIndicator.Value, true) }
                                                                                 ));
          }

          if (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.LiverIndicator.HasValue)
          {
            components.Add(CreateComponentObservation(CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.LiverIndicator)),
                                                                                  new List<ANY> { CreateBoolean(australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.LiverIndicator.Value, true) }
                                                                                 ));
          }

          if (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.LungsIndicator.HasValue)
          {
            components.Add(CreateComponentObservation(CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.LungsIndicator)),
                                                                                  new List<ANY> { CreateBoolean(australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.LungsIndicator.Value, true) }
                                                                                 ));
          }

          if (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.PancreasIndicator.HasValue)
          {
            components.Add(CreateComponentObservation(CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.PancreasIndicator)),
                                                                                  new List<ANY> { CreateBoolean(australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.PancreasIndicator.Value, true) }
                                                                                 ));
          }

          if (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.SkinTissueIndicator.HasValue)
          {
            components.Add(CreateComponentObservation(CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.SkinTissueIndicator)),
                                                                                  new List<ANY> { CreateBoolean(australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.SkinTissueIndicator.Value, true) }
                                                                                 ));
          }


          if ((australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.BoneTissueIndicator.HasValue) ||
           (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.EyeTissueIndicator.HasValue) || 
           (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.HeartIndicator.HasValue) ||
           (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.HeartValveIndicator.HasValue) ||
           (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.KidneyIndicator.HasValue) ||
           (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.LiverIndicator.HasValue) ||
           (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.LungsIndicator.HasValue) ||
           (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.PancreasIndicator.HasValue) ||
           (australianOrganDonorRegisterEntry.OrganAndTissueDonationDetails.SkinTissueIndicator.HasValue))
          {
            entryRelationshipList.Add(CreateEntryRelationshipOrganiserObservation(
                                              x_ActRelationshipEntryRelationship.SUBJ,
                                              CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.OrganAndTissueDonationDetails)),
                                              StatusCode.Completed.GetAttributeValue<NameAttribute, string>(x => x.Name), 
                                              components)
                                                                                  
                                     );
          }

          entry = CreateEntryObservation(x_ActRelationshipEntry.COMP, 
                                        CreateConceptDescriptor(CreateCodableText(MedicareInformationViewSections.AustralianOrganDonorRegisterEntry)),  
                                        null, 
                                        australianOrganDonorRegisterEntry.DateOfInitialRegistration,
                                        null,
                                        null,
                                        entryRelationshipList);
        }

        return entry;
      }

      #endregion

      #endregion
    }
}



