/*
 * 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 implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using CDA.Generator.Common.SCSModel.ConsolidatedView.Entities;
using Nehta.VendorLibrary.CDA.Common.Enums;
using Nehta.VendorLibrary.CDA.Generator.Enums;
using Nehta.VendorLibrary.CDA.SCSModel;
using Nehta.VendorLibrary.Common;
using Nehta.VendorLibrary.CDA.Common;
using Nehta.HL7.CDA;
using Nehta.VendorLibrary.CDA.SCSModel.DischargeSummary;

namespace Nehta.VendorLibrary.CDA.Generator
{
    /// <summary>
    /// This CDAGenerator class is used to convert the various SCS and CDA model objects 
    /// into an actual CDA Document
    /// </summary>
    public class CDAGenerator
    {
        #region Properties

        private static INarrativeGenerator _narrativeGenerator;
        /// <summary>
        /// This property holds the narrative generator
        /// 
        /// The narrative generator is used to generate the narrative for each section within the 
        /// CDA document
        /// </summary>
        public static INarrativeGenerator NarrativeGenerator
        {
            get
            {
                if (_narrativeGenerator == null)
                {
                    _narrativeGenerator = new CDANarrativeGenerator(); 
                }

                return _narrativeGenerator;
            }
            set
            {
                _narrativeGenerator = value;
            }
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Instantiates a CDAGenerator, this is the base from which all CDA document models are converted
        /// into CDA XML documents.
        /// </summary>
        public CDAGenerator() : this(new CDANarrativeGenerator())
        {
           
        }

        /// <summary>
        /// Instantiates a CDAGenerator, this is the base from which all CDA document models are converted
        /// into CDA XML documents.
        /// </summary>
        public CDAGenerator(INarrativeGenerator narrativeGenerator)
        {
            if(narrativeGenerator == null)
            {
                throw new ArgumentException("The narravite Generator must not be null");
            }

            NarrativeGenerator = narrativeGenerator;
        }
        #endregion

        #region Public Methods


        /// <summary>
        /// Generates an event summary CDA (XML) document from the event summary model
        /// </summary>
        /// <param name="eventSummary">EventSummary</param>
        /// <returns>XmlDocument (CDA - EventSummary)</returns>
        public static XmlDocument GenerateEventSummary(EventSummary eventSummary)
        {
            var vb = new ValidationBuilder();

            if (vb.ArgumentRequiredCheck("eventSummary", eventSummary))
            {
                eventSummary.Validate("eventSummary", vb.Messages);

                LogoSetupAndValidation(eventSummary.LogoPath, eventSummary.IncludeLogo, vb);
            }

            if (vb.Messages.Any())
            {
                var ve = new ValidationException(vb.Messages);
                var messageString = ve.GetMessagesString();

                throw new ValidationException(vb.Messages);
            }

            var authors = new List<POCD_MT000040Author>();
            var recipients = new List<POCD_MT000040InformationRecipient>();
            var components = new List<POCD_MT000040Component3>();
            var patients = new List<POCD_MT000040RecordTarget>();
            var participants = new List<POCD_MT000040Participant1>();
            var authenticators = new List<POCD_MT000040Authenticator>();
            POCD_MT000040NonXMLBody nonXmlBody = null;

            //SETUP the clinical document object
            var clinicalDocument = CDAGeneratorHelper.CreateDocument
                (  
                    eventSummary.DocumentCreationTime,
                    CDADocumentType.EventSummary,
                    eventSummary.CDAContext.DocumentId,
                    eventSummary.CDAContext.SetId,
                    eventSummary.CDAContext.Version,
                    DocumentStatus.Final
                );

            //SETUP the Legal Authenticator
            POCD_MT000040LegalAuthenticator legalAuthenticator = null;
            if (eventSummary.CDAContext.LegalAuthenticator != null)
            {
                legalAuthenticator = CDAGeneratorHelper.CreateLegalAuthenticator(eventSummary.CDAContext.LegalAuthenticator);
            }

            //SETUP the Custodian
            clinicalDocument.custodian = CDAGeneratorHelper.CreateCustodian(eventSummary.CDAContext.Custodian);

            //SETUP the patient
            patients.Add(CDAGeneratorHelper.CreateSubjectOfCare(eventSummary.SCSContext.SubjectOfCare));
            clinicalDocument.recordTarget = patients.ToArray();

            //SETUP the author
            authors.Add(CDAGeneratorHelper.CreateAuthor(eventSummary.SCSContext.Author));
            clinicalDocument.author = authors.ToArray();

            //SETUP encompassing encounter
            clinicalDocument.componentOf = CDAGeneratorHelper.CreateComponentOf(eventSummary.SCSContext.EncounterPeriod,eventSummary.SCSContext.EncounterPeriodNullFlavor);

            //XML BODY FILE
            components.Add
                (
                    CDAGeneratorHelper.CreateStructuredBodyFileComponent(eventSummary.SCSContent.StructuredBodyFiles, NarrativeGenerator)
                );

            // Setup EventDetails
            components.Add(CDAGeneratorHelper.CreateComponent(eventSummary.SCSContent.EventDetails, NarrativeGenerator));

            // Setup Adverse Reactions
            components.Add(CDAGeneratorHelper.CreateComponent((SCSModel.Common.AdverseReactions)eventSummary.SCSContent.AdverseReactions, NarrativeGenerator, null));

            // Setup Medications
            components.Add(CDAGeneratorHelper.CreateComponent(eventSummary.SCSContent.Medications,eventSummary.SCSContent.CustomNarrativeMedications, NarrativeGenerator));

            // Setup Diagnoses Interventions
            components.Add(CDAGeneratorHelper.CreateComponent(eventSummary.SCSContent.DiagnosesIntervention, NarrativeGenerator));

            // Setup Diagnostic Investigations
            components.Add(CDAGeneratorHelper.CreateComponent(eventSummary.SCSContent.DiagnosticInvestigations, CDADocumentType.EventSummary, NarrativeGenerator));

            // Setup Immunisations
            components.Add(CDAGeneratorHelper.CreateComponent(eventSummary.SCSContent.Immunisations,eventSummary.SCSContent.CustomNarrativeImmunisations ,NarrativeGenerator));

            //STRUCTURED BODY
            //SETUP administrative observations component
            if (((eventSummary.ShowAdministrativeObservations.HasValue && eventSummary.ShowAdministrativeObservations.Value) || 
                  !eventSummary.ShowAdministrativeObservations.HasValue))
                components.Add
                    (
                        CDAGeneratorHelper.CreateAdministrativeObservations
                            (
                                eventSummary.SCSContext.SubjectOfCare,
                                eventSummary.SCSContent.CustomNarrativeAdministrativeObservations,
                                clinicalDocument.recordTarget[0].patientRole.id[0].root,
                                NarrativeGenerator
                            )
                    );

            // Generate and return the Specialist SpecialistLetter
            return CDAGeneratorHelper.CreateXml(clinicalDocument, authors, legalAuthenticator, authenticators, recipients, participants, components, nonXmlBody, eventSummary.IncludeLogo, CDADocumentExtensionVersion.V3);
        }

        /// <summary>
        /// Generates a Consumer Entered Health Summary CDA (XML) document
        /// </summary>
        /// <param name="consumerEnteredHealthSummary">The ConsumerEnteredHealthSummary object</param>
        /// <returns>XmlDocument (CDA - ConsumerEnteredHealthSummary)</returns>
        public static XmlDocument GenerateConsumerEnteredHealthSummary(ConsumerEnteredHealthSummary consumerEnteredHealthSummary)
        {
            var vb = new ValidationBuilder();

            if (vb.ArgumentRequiredCheck("consumerEnteredHealthSummary", consumerEnteredHealthSummary))
            {
                consumerEnteredHealthSummary.Validate("consumerEnteredHealthSummary", vb.Messages);

                LogoSetupAndValidation(consumerEnteredHealthSummary.LogoPath, consumerEnteredHealthSummary.IncludeLogo, vb);
            }

            if (vb.Messages.Any())
            {
                var ve = new ValidationException(vb.Messages);
                var messageString = ve.GetMessagesString();

                throw new ValidationException(vb.Messages);
            }

            var authors = new List<POCD_MT000040Author>();
            var recipients = new List<POCD_MT000040InformationRecipient>();
            var participants = new List<POCD_MT000040Participant1>();
            var components = new List<POCD_MT000040Component3>();
            var patients = new List<POCD_MT000040RecordTarget>();
            var authenticators = new List<POCD_MT000040Authenticator>();
            POCD_MT000040NonXMLBody nonXmlBody = null;

            //SETUP the clinical document object
            var clinicalDocument = CDAGeneratorHelper.CreateDocument
                (
                    consumerEnteredHealthSummary.DocumentCreationTime,
                    CDADocumentType.ConsumerEnteredHealthSummary,
                    consumerEnteredHealthSummary.CDAContext.DocumentId,
                    consumerEnteredHealthSummary.CDAContext.SetId,
                    consumerEnteredHealthSummary.CDAContext.Version,
                    consumerEnteredHealthSummary.DocumentStatus
                );

            //SETUP the Legal Authenticator
            var legalAuthenticator = CDAGeneratorHelper.CreateLegalAuthenticator(consumerEnteredHealthSummary.CDAContext.LegalAuthenticator);

            //SETUP the patient
            patients.Add(CDAGeneratorHelper.CreateSubjectOfCare(consumerEnteredHealthSummary.SCSContext.SubjectOfCare));
            clinicalDocument.recordTarget = patients.ToArray();

            //SETUP the author
            authors.Add(CDAGeneratorHelper.CreateAuthor(consumerEnteredHealthSummary.SCSContext.Author, consumerEnteredHealthSummary.SCSContext.SubjectOfCare.Participant.UniqueIdentifier));
            clinicalDocument.author = authors.ToArray();

            //SETUP the Custodian
            clinicalDocument.custodian = CDAGeneratorHelper.CreateCustodian(consumerEnteredHealthSummary.CDAContext.Custodian);

            //XML BODY FILE
            components.Add
                (
                    CDAGeneratorHelper.CreateStructuredBodyFileComponent(consumerEnteredHealthSummary.SCSContent.StructuredBodyFiles, NarrativeGenerator)
                );

            components.Add(CDAGeneratorHelper.CreateComponent(consumerEnteredHealthSummary.SCSContent.AllergiesAndAdverseReactions, consumerEnteredHealthSummary.SCSContent.CustomNarrativeAllergiesAndAdverseReactions ,NarrativeGenerator));

            components.Add(CDAGeneratorHelper.CreateComponent(consumerEnteredHealthSummary.SCSContent.Medications, consumerEnteredHealthSummary.SCSContent.CustomNarrativeMedications ,NarrativeGenerator));

            //SETUP administrative observations component
            if (((consumerEnteredHealthSummary.ShowAdministrativeObservations.HasValue && consumerEnteredHealthSummary.ShowAdministrativeObservations.Value) ||
                  !consumerEnteredHealthSummary.ShowAdministrativeObservations.HasValue))
                components.Add
                    (
                        CDAGeneratorHelper.CreateAdministrativeObservations
                            (
                                consumerEnteredHealthSummary.SCSContext.SubjectOfCare,
                                consumerEnteredHealthSummary.SCSContent.CustomNarrativeAdministrativeObservations,
                                clinicalDocument.recordTarget[0].patientRole.id[0].root,
                                NarrativeGenerator 
                            )
                    );

            //Generate and return the E-Referral.
            return CDAGeneratorHelper.CreateXml(clinicalDocument, authors, legalAuthenticator, authenticators, recipients, participants, components, nonXmlBody, consumerEnteredHealthSummary.IncludeLogo, CDADocumentExtensionVersion.V3);
        }

        /// <summary>
        /// Generates a Consumer Entered Notes CDA (XML) document from the ConsumerEnteredNotes model
        /// </summary>
        /// <param name="consumerEnteredNotes">The ConsumerEnteredNotes object</param>
        /// <returns>XmlDocument (CDA - ConsumerEnteredNotes)</returns>
        public static XmlDocument GenerateConsumerEnteredNotes(ConsumerEnteredNotes consumerEnteredNotes)
        {
            var vb = new ValidationBuilder();

            if (vb.ArgumentRequiredCheck("consumerEnteredNotes", consumerEnteredNotes))
            {
                consumerEnteredNotes.Validate("consumerEnteredNotes", vb.Messages);

                LogoSetupAndValidation(consumerEnteredNotes.LogoPath, consumerEnteredNotes.IncludeLogo, vb);
            }

            if (vb.Messages.Any())
            {
                var ve = new ValidationException(vb.Messages);
                var messageString = ve.GetMessagesString();

                throw new ValidationException(vb.Messages);
            }

            var authors = new List<POCD_MT000040Author>();
            var recipients = new List<POCD_MT000040InformationRecipient>();
            var participants = new List<POCD_MT000040Participant1>();
            var components = new List<POCD_MT000040Component3>();
            var patients = new List<POCD_MT000040RecordTarget>();
            var authenticators = new List<POCD_MT000040Authenticator>();
            POCD_MT000040NonXMLBody nonXmlBody = null;

            //SETUP the clinical document object
            var clinicalDocument = CDAGeneratorHelper.CreateDocument
                (
                    consumerEnteredNotes.DocumentCreationTime,
                    CDADocumentType.ConsumerEnteredNotes,
                    consumerEnteredNotes.CDAContext.DocumentId,
                    consumerEnteredNotes.CDAContext.SetId,
                    consumerEnteredNotes.CDAContext.Version,
                    consumerEnteredNotes.DocumentStatus
                );

            //SETUP the Legal Authenticator
            var legalAuthenticator = CDAGeneratorHelper.CreateLegalAuthenticator(consumerEnteredNotes.CDAContext.LegalAuthenticator);

            //SETUP the patient
            patients.Add(CDAGeneratorHelper.CreateSubjectOfCare(consumerEnteredNotes.SCSContext.SubjectOfCare));
            clinicalDocument.recordTarget = patients.ToArray();

            //SETUP the author
            authors.Add(CDAGeneratorHelper.CreateAuthor(consumerEnteredNotes.SCSContext.Author, consumerEnteredNotes.SCSContext.SubjectOfCare.Participant.UniqueIdentifier));
            clinicalDocument.author = authors.ToArray();

            //SETUP the Custodian
            clinicalDocument.custodian = CDAGeneratorHelper.CreateCustodian(consumerEnteredNotes.CDAContext.Custodian);

            //XML BODY FILE
            components.Add
                (
                    CDAGeneratorHelper.CreateStructuredBodyFileComponent(consumerEnteredNotes.SCSContent.StructuredBodyFiles, NarrativeGenerator)
                );

            // Build content
            if (consumerEnteredNotes.SCSContent != null && (!consumerEnteredNotes.SCSContent.Title.IsNullOrEmptyWhitespace() || !consumerEnteredNotes.SCSContent.Description.IsNullOrEmptyWhitespace()))
            components.Add(new POCD_MT000040Component3
            {
                section = new POCD_MT000040Section
                {
                    code = CDAGeneratorHelper.CreateCodedWithExtensionElement("102.15513", CodingSystem.NCTIS, null, "Consumer Entered Note", null, null),
                    title = new ST { Text = new [] { consumerEnteredNotes.SCSContent.Title } },
                    text = consumerEnteredNotes.SCSContent.CustomNarrativeConsumerEnteredNote ?? new StrucDocText { Text = new [] { consumerEnteredNotes.SCSContent.Description }}
                }
            });

            //SETUP administrative observations component
            if (((consumerEnteredNotes.ShowAdministrativeObservations.HasValue && consumerEnteredNotes.ShowAdministrativeObservations.Value) ||
                  !consumerEnteredNotes.ShowAdministrativeObservations.HasValue))
                components.Add
                    (
                        CDAGeneratorHelper.CreateAdministrativeObservations
                            (
                                consumerEnteredNotes.SCSContext.SubjectOfCare,
                                consumerEnteredNotes.SCSContent.CustomNarrativeAdministrativeObservations,
                                clinicalDocument.recordTarget[0].patientRole.id[0].root,
                                NarrativeGenerator 
                            )
                    );

            //Generate and return the E-Referral.
            return CDAGeneratorHelper.CreateXml(clinicalDocument, authors, legalAuthenticator, authenticators, recipients, participants, components, nonXmlBody, consumerEnteredNotes.IncludeLogo, CDADocumentExtensionVersion.V3);
        }

        /// <summary>
        /// Generates an Advance Care Directive Custodian Record CDA (XML) document from the ACD Custodian Record model
        /// </summary>
        /// <param name="acdCustodianRecord">The Advance Care Directive Custodian Record object</param>
        /// <returns>XmlDocument (CDA - AcdCustodianRecord)</returns>
        public static XmlDocument GenerateAcdCustodianRecord(AcdCustodianRecord acdCustodianRecord)
        {
            var vb = new ValidationBuilder();

            if (vb.ArgumentRequiredCheck("acdCustodianRecord", acdCustodianRecord))
            {
                acdCustodianRecord.Validate("acdCustodianRecord", vb.Messages);

                LogoSetupAndValidation(acdCustodianRecord.LogoPath, acdCustodianRecord.IncludeLogo, vb);
            }

            if (vb.Messages.Any())
            {
                var ve = new ValidationException(vb.Messages);
                var messageString = ve.GetMessagesString();

                throw new ValidationException(vb.Messages);
            }

            var authors = new List<POCD_MT000040Author>();
            var recipients = new List<POCD_MT000040InformationRecipient>();
            var participants = new List<POCD_MT000040Participant1>();
            var components = new List<POCD_MT000040Component3>();
            var patients = new List<POCD_MT000040RecordTarget>();
            var authenticators = new List<POCD_MT000040Authenticator>();
            POCD_MT000040NonXMLBody nonXmlBody = null;

            //SETUP the clinical document object
            var clinicalDocument = CDAGeneratorHelper.CreateDocument
                (
                    acdCustodianRecord.DocumentCreationTime,
                    CDADocumentType.AdvanceCareDirectiveCustodianRecord,
                    acdCustodianRecord.CDAContext.DocumentId,
                    acdCustodianRecord.CDAContext.SetId,
                    acdCustodianRecord.CDAContext.Version,
                    acdCustodianRecord.DocumentStatus
                );

            //SETUP the Legal Authenticator
            var legalAuthenticator = CDAGeneratorHelper.CreateLegalAuthenticator(acdCustodianRecord.CDAContext.LegalAuthenticator);

            //SETUP the patient
            patients.Add(CDAGeneratorHelper.CreateSubjectOfCare(acdCustodianRecord.SCSContext.SubjectOfCare));
            clinicalDocument.recordTarget = patients.ToArray();

            //SETUP the author
            authors.Add(CDAGeneratorHelper.CreateAuthor(acdCustodianRecord.SCSContext.Author));
            clinicalDocument.author = authors.ToArray();

            //SETUP the Custodian
            clinicalDocument.custodian = CDAGeneratorHelper.CreateCustodian(acdCustodianRecord.CDAContext.Custodian);

            //XML BODY FILE
            components.Add
                (
                    CDAGeneratorHelper.CreateStructuredBodyFileComponent(acdCustodianRecord.SCSContent.StructuredBodyFiles, NarrativeGenerator)
                );
  
            // Set up ACD custodian records
            components.Add(CDAGeneratorHelper.CreateComponent(acdCustodianRecord.SCSContent.AcdCustodians, acdCustodianRecord.SCSContent.CustomNarrativeACDCustodianEntries ,NarrativeGenerator));

            //SETUP administrative observations component
            if (((acdCustodianRecord.ShowAdministrativeObservations.HasValue && acdCustodianRecord.ShowAdministrativeObservations.Value) ||
                  !acdCustodianRecord.ShowAdministrativeObservations.HasValue))
            components.Add
                    (
                        CDAGeneratorHelper.CreateAdministrativeObservations
                            (
                                acdCustodianRecord.SCSContext.SubjectOfCare,
                                acdCustodianRecord.SCSContent.CustomNarrativeAdministrativeObservations,
                                clinicalDocument.recordTarget[0].patientRole.id[0].root,
                                NarrativeGenerator 
                            )
                    );

            //Generate and return the E-Referral.
            return CDAGeneratorHelper.CreateXml(clinicalDocument, authors, legalAuthenticator, authenticators, recipients, participants, components, nonXmlBody, acdCustodianRecord.IncludeLogo, CDADocumentExtensionVersion.V3);
        }

        /// <summary>
        /// Generates an E-Referral CDA (XML) document from the e-referral model
        /// </summary>
        /// <param name="eReferral">EReferral</param>
        /// <returns>XmlDocument (CDA - EReferral)</returns>
        public static XmlDocument GenerateEReferral(EReferral eReferral)
        {
            var vb = new ValidationBuilder();

            if (vb.ArgumentRequiredCheck("ereferral", eReferral))
            {
                eReferral.Validate("ereferral", vb.Messages);

                LogoSetupAndValidation(eReferral.LogoPath, eReferral.IncludeLogo, vb);
            }

            if (vb.Messages.Any())
            {
                var ve = new ValidationException(vb.Messages);
                var messageString = ve.GetMessagesString();

                throw new ValidationException(vb.Messages);
            }

            var authors = new List<POCD_MT000040Author>();
            var recipients = new List<POCD_MT000040InformationRecipient>();
            var participants = new List<POCD_MT000040Participant1>();
            var components = new List<POCD_MT000040Component3>();
            var patients = new List<POCD_MT000040RecordTarget>();
            var authenticators = new List<POCD_MT000040Authenticator>();
            POCD_MT000040NonXMLBody nonXmlBody = null;

            //SETUP the clinical document object
            var clinicalDocument = CDAGeneratorHelper.CreateDocument
                (
                    eReferral.DocumentCreationTime,
                    CDADocumentType.EReferral,
                    eReferral.CDAContext.DocumentId,
                    eReferral.CDAContext.SetId,
                    eReferral.CDAContext.Version, 
                    eReferral.DocumentStatus
                );

            //SETUP the Legal Authenticator
            var legalAuthenticator = CDAGeneratorHelper.CreateLegalAuthenticator(eReferral.CDAContext.LegalAuthenticator);

            //SETUP the patient
            patients.Add(CDAGeneratorHelper.CreateSubjectOfCare(eReferral.SCSContext.SubjectOfCare));
            clinicalDocument.recordTarget = patients.ToArray();
            
            //SETUP the author
            authors.Add(CDAGeneratorHelper.CreateAuthor(eReferral.SCSContext.Author));
            clinicalDocument.author = authors.ToArray();

            // SETUP the patient nominated contacts
            if (eReferral.SCSContext.PatientNominatedContacts != null && eReferral.SCSContext.PatientNominatedContacts.Any())
            {
                 participants.AddRange(eReferral.SCSContext.PatientNominatedContacts.Select(nominatedContact => CDAGeneratorHelper.CreateParticipant(nominatedContact)));
            }

            //SETUP the Custodian
            clinicalDocument.custodian = CDAGeneratorHelper.CreateCustodian(eReferral.CDAContext.Custodian);

            //SETUP the recipients   
            if (eReferral.CDAContext.InformationRecipients != null && eReferral.CDAContext.InformationRecipients.Any())
            {
                recipients.AddRange(eReferral.CDAContext.InformationRecipients.Select(recipient => CDAGeneratorHelper.CreateInformationRecipient(recipient)));
            }

            //SETUP the participants    
            participants.Add(CDAGeneratorHelper.CreateParticipant(eReferral.SCSContent.Referee));

            // SETUP UsualGP's
            participants.Add(CDAGeneratorHelper.CreateParticipant(eReferral.SCSContent.UsualGP));

            //XML BODY FILE
            components.Add
                (
                    CDAGeneratorHelper.CreateStructuredBodyFileComponent(eReferral.SCSContent.StructuredBodyFiles, NarrativeGenerator)
                );

            //SETUP referral reason
            components.Add
                (
                    CDAGeneratorHelper.CreateComponentForReferralReason
                        (
                            eReferral.SCSContent.ReferralDateTime,
                            eReferral.SCSContent.ValidityDuration,
                            eReferral.SCSContent.ReferralReason,
                            eReferral.SCSContent.CustomNarrativeReferralDetail,
                            NarrativeGenerator
                        )
                );

            //SETUP the components (e.g. the body)  
            //setup the medications
            components.Add(CDAGeneratorHelper.CreateComponent(eReferral.SCSContent.Medications, NarrativeGenerator));

            //setup the medical history
            components.Add(CDAGeneratorHelper.CreateComponent(eReferral.SCSContent.MedicalHistory, NarrativeGenerator));

            //setup adverse substance reactions
            components.Add(CDAGeneratorHelper.CreateComponent((SCSModel.Common.AdverseReactions)eReferral.SCSContent.AdverseReactions, NarrativeGenerator, "103.16302.2.2.2"));

            //setup diagnostic investigations
            components.Add(CDAGeneratorHelper.CreateComponent(eReferral.SCSContent.DiagnosticInvestigations, CDADocumentType.EReferral, NarrativeGenerator));

            //SETUP administrative observations component
            if (((eReferral.ShowAdministrativeObservations.HasValue && eReferral.ShowAdministrativeObservations.Value) ||
                  !eReferral.ShowAdministrativeObservations.HasValue))
                components.Add
                    (
                        CDAGeneratorHelper.CreateAdministrativeObservations
                            (
                                eReferral.SCSContext.SubjectOfCare,
                                eReferral.SCSContent.CustomNarrativeAdministrativeObservations,
                                clinicalDocument.recordTarget[0].patientRole.id[0].root,
                                NarrativeGenerator 
                            )
                    );

            //Generate and return the E-Referral.
            return CDAGeneratorHelper.CreateXml(clinicalDocument, authors, legalAuthenticator, authenticators, recipients, participants, components, nonXmlBody, eReferral.IncludeLogo, CDADocumentExtensionVersion.V3);
        }

        /// <summary>
        /// Generates a Shared Health Summary CDA (XML) document from the shared health summary model
        /// </summary>
        /// <param name="sharedHealthSummary">SharedHealthSummary</param>
        /// <returns>XmlDocument (CDA - Shared Health Summary)</returns>
        public static XmlDocument GenerateSharedHealthSummary(SharedHealthSummary sharedHealthSummary)
        {
            var vb = new ValidationBuilder();

            if (vb.ArgumentRequiredCheck("consolidatedView", sharedHealthSummary))
            {
                sharedHealthSummary.Validate("consolidatedView", vb.Messages);

                LogoSetupAndValidation(sharedHealthSummary.LogoPath, sharedHealthSummary.IncludeLogo, vb);
            }

            if (vb.Messages.Any())
            {
                var ve = new ValidationException(vb.Messages);
                var messageString = ve.GetMessagesString();

                throw new ValidationException(vb.Messages);
            }

            var authors = new List<POCD_MT000040Author>();
            var recipients = new List<POCD_MT000040InformationRecipient>();
            var components = new List<POCD_MT000040Component3>();
            var patients = new List<POCD_MT000040RecordTarget>();
            var authenticators = new List<POCD_MT000040Authenticator>();
            POCD_MT000040NonXMLBody nonXmlBody = null;

            //SETUP the clinical document object
            var clinicalDocument = CDAGeneratorHelper.CreateDocument
                (
                    sharedHealthSummary.DocumentCreationTime,
                    CDADocumentType.SharedHeathSummary,
                    sharedHealthSummary.CDAContext.DocumentId,
                    sharedHealthSummary.CDAContext.SetId,
                    sharedHealthSummary.CDAContext.Version,
                    sharedHealthSummary.DocumentStatus
                );
            
            //SETUP the Legal Authenticator
            var legalAuthenticator = CDAGeneratorHelper.CreateLegalAuthenticator(sharedHealthSummary.CDAContext.LegalAuthenticator);

            //SETUP the patient
            patients.Add(CDAGeneratorHelper.CreateSubjectOfCare(sharedHealthSummary.SCSContext.SubjectOfCare));
            clinicalDocument.recordTarget = patients.ToArray();

            //SETUP the author
            authors.Add(CDAGeneratorHelper.CreateAuthor(sharedHealthSummary.SCSContext.Author));
            clinicalDocument.author = authors.ToArray();

            //SETUP the Custodian
            clinicalDocument.custodian = CDAGeneratorHelper.CreateCustodian(sharedHealthSummary.CDAContext.Custodian);

            //XML BODY FILE
            components.Add
                (
                    CDAGeneratorHelper.CreateStructuredBodyFileComponent(sharedHealthSummary.SCSContent.StructuredBodyFiles, NarrativeGenerator)
                );

            components.Add(CDAGeneratorHelper.CreateComponent((Nehta.VendorLibrary.CDA.SCSModel.Common.AdverseReactions)sharedHealthSummary.SCSContent.AdverseReactions, NarrativeGenerator, "103.16302.120.1.1"));
            components.Add(CDAGeneratorHelper.CreateComponent(sharedHealthSummary.SCSContent.Medications, NarrativeGenerator));
            components.Add(CDAGeneratorHelper.CreateComponent(sharedHealthSummary.SCSContent.MedicalHistory, NarrativeGenerator));
            components.Add(CDAGeneratorHelper.CreateComponent(sharedHealthSummary.SCSContent.Imunisations, NarrativeGenerator));

            //SETUP administrative observations component
            if (((sharedHealthSummary.ShowAdministrativeObservations.HasValue && sharedHealthSummary.ShowAdministrativeObservations.Value) ||
                  !sharedHealthSummary.ShowAdministrativeObservations.HasValue))
            components.Add
                    (
                        CDAGeneratorHelper.CreateAdministrativeObservations
                            (
                                sharedHealthSummary.SCSContext.SubjectOfCare,
                                sharedHealthSummary.SCSContent.CustomNarrativeAdministrativeObservations,
                                clinicalDocument.recordTarget[0].patientRole.id[0].root,
                                NarrativeGenerator 
                            )
                    );

            //Generate and return the SHS.
            return CDAGeneratorHelper.CreateXml(clinicalDocument, authors, legalAuthenticator, authenticators, recipients, null, components, nonXmlBody, sharedHealthSummary.IncludeLogo, CDADocumentExtensionVersion.V3);
        }

        /// <summary>
        /// Generates a Specialist SpecialistLetter CDA (XML) document from the specialistLetter model
        /// </summary>
        /// <param name="specialistLetter">SpecialistLetter</param>
        /// <returns>XmlDocument (CDA - Specialist SpecialistLetter)</returns>
        public static XmlDocument GenerateSpecialistLetter(SpecialistLetter specialistLetter)
        {
            var vb = new ValidationBuilder();

            if (vb.ArgumentRequiredCheck("specialistLetter", specialistLetter))
            {
                specialistLetter.Validate("specialistLetter", vb.Messages);

                LogoSetupAndValidation(specialistLetter.LogoPath, specialistLetter.IncludeLogo, vb);
            }

            if (vb.Messages.Any())
            {
                throw new ValidationException(vb.Messages);
            }

            var authors = new List<POCD_MT000040Author>();
            var recipients = new List<POCD_MT000040InformationRecipient>();
            var components = new List<POCD_MT000040Component3>();
            var patients = new List<POCD_MT000040RecordTarget>();
            var participants = new List<POCD_MT000040Participant1>();
            var authenticators = new List<POCD_MT000040Authenticator>();
            POCD_MT000040NonXMLBody nonXmlBody = null;

            //SETUP the clinical document object
            var clinicalDocument = CDAGeneratorHelper.CreateDocument
                (
                    specialistLetter.DocumentCreationTime ,
                    CDADocumentType.SpecialistLetter,
                    specialistLetter.CDAContext.DocumentId,
                    specialistLetter.CDAContext.SetId,
                    specialistLetter.CDAContext.Version,
                    specialistLetter.DocumentStatus
                );

            //SETUP the Legal Authenticator
            var legalAuthenticator = CDAGeneratorHelper.CreateLegalAuthenticator(specialistLetter.CDAContext.LegalAuthenticator);

            //SETUP the patient
            patients.Add(CDAGeneratorHelper.CreateSubjectOfCare(specialistLetter.SCSContext.SubjectOfCare));
            clinicalDocument.recordTarget = patients.ToArray();

            //SETUP the author
            authors.Add(CDAGeneratorHelper.CreateAuthor(specialistLetter.SCSContext.Author));
            clinicalDocument.author = authors.ToArray();

            //SETUP the Custodian
            clinicalDocument.custodian = CDAGeneratorHelper.CreateCustodian(specialistLetter.CDAContext.Custodian);

            //SETUP the participants    
            participants.Add(CDAGeneratorHelper.CreateParticipant(specialistLetter.SCSContext.Referrer));

            // SETUP the UsualGP
            participants.Add(CDAGeneratorHelper.CreateParticipant(specialistLetter.SCSContext.UsualGP));

            //SETUP encompassing encounter
            clinicalDocument.componentOf = CDAGeneratorHelper.CreateComponentOf(specialistLetter.SCSContext.DateTimeSubjectSeen);

            //SETUP the recipients   
            if (specialistLetter.CDAContext.InformationRecipients != null)
            {
                foreach (var recipient in specialistLetter.CDAContext.InformationRecipients)
                {
                    recipients.Add(CDAGeneratorHelper.CreateInformationRecipient(recipient));
                }
            }

            //XML BODY FILE
            components.Add
                (
                    CDAGeneratorHelper.CreateStructuredBodyFileComponent(specialistLetter.SCSContent.StructuredBodyFiles, NarrativeGenerator)
                );

            //SETUP the components (e.g. the body)  
            //setup the response details
            components.Add(CDAGeneratorHelper.CreateComponent(specialistLetter.SCSContent.ResponseDetails, NarrativeGenerator));

            //setup the recommendations
            components.Add(CDAGeneratorHelper.CreateComponent(specialistLetter.SCSContent.Recommendations, NarrativeGenerator));

            //setup the medications
            components.Add(CDAGeneratorHelper.CreateComponent(specialistLetter.SCSContent.Medications, NarrativeGenerator));

            //setup diagnostic investigations
            components.Add(CDAGeneratorHelper.CreateComponent(specialistLetter.SCSContent.DiagnosticInvestigations,CDADocumentType.SpecialistLetter, NarrativeGenerator));

            //setup adverse reactions
            components.Add(CDAGeneratorHelper.CreateComponent((SCSModel.Common.AdverseReactions)specialistLetter.SCSContent.AdverseReactions, NarrativeGenerator, null));

            //SETUP administrative observations component
            if (((specialistLetter.ShowAdministrativeObservations.HasValue && specialistLetter.ShowAdministrativeObservations.Value) ||
                  !specialistLetter.ShowAdministrativeObservations.HasValue))
            components.Add
                    (
                        CDAGeneratorHelper.CreateAdministrativeObservations
                            (
                                specialistLetter.SCSContext.SubjectOfCare,
                                specialistLetter.SCSContent.CustomNarrativeAdministrativeObservations,
                                clinicalDocument.recordTarget[0].patientRole.id[0].root,
                                NarrativeGenerator
                            )
                    );

            //Generate and return the Specialist SpecialistLetter
            return CDAGeneratorHelper.CreateXml(clinicalDocument, authors, legalAuthenticator, authenticators, recipients, participants, components, nonXmlBody, specialistLetter.IncludeLogo, CDADocumentExtensionVersion.V3);
        }

        /// <summary>
        /// Generates a Specialist SpecialistLetter CDA (XML) document from the eDischargeSummary model
        /// </summary>
        /// <param name="eDischargeSummary">EDischargeSummary</param>
        /// <returns>XmlDocument (CDA - Specialist SpecialistLetter)</returns>
        public static XmlDocument GenerateEDischargeSummary(EDischargeSummary eDischargeSummary)
        {
            var vb = new ValidationBuilder();

            if (vb.ArgumentRequiredCheck("eDischargeSummary", eDischargeSummary))
            {
                eDischargeSummary.Validate("eDischargeSummary", vb.Messages);

                LogoSetupAndValidation(eDischargeSummary.LogoPath, eDischargeSummary.IncludeLogo, vb);
            }

            if (vb.Messages.Any())
            {
                var ve = new ValidationException(vb.Messages);
                var messageString = ve.GetMessagesString();

                throw new ValidationException(vb.Messages);
            }

            var authors = new List<POCD_MT000040Author>();
            var recipients = new List<POCD_MT000040InformationRecipient>();
            var components = new List<POCD_MT000040Component3>();
            var patients = new List<POCD_MT000040RecordTarget>();
            var authenticators = new List<POCD_MT000040Authenticator>();
            var encounterParticipant = new List<POCD_MT000040EncounterParticipant>();
            POCD_MT000040NonXMLBody nonXmlBody = null;

            //SETUP the clinical document object
            var clinicalDocument = CDAGeneratorHelper.CreateDocument
                (
                    eDischargeSummary.DocumentCreationTime,
                    CDADocumentType.DischargeSummary,
                    eDischargeSummary.CDAContext.DocumentId,
                    eDischargeSummary.CDAContext.SetId,
                    eDischargeSummary.CDAContext.Version,
                    eDischargeSummary.DocumentStatus
                );

            //SETUP the Legal Authenticator
            var legalAuthenticator = CDAGeneratorHelper.CreateLegalAuthenticator(eDischargeSummary.CDAContext.LegalAuthenticator);

            //SETUP the patient
            patients.Add(CDAGeneratorHelper.CreateSubjectOfCare(eDischargeSummary.SCSContext.SubjectOfCare));
            clinicalDocument.recordTarget = patients.ToArray();

            //SETUP the author
            authors.Add(CDAGeneratorHelper.CreateAuthor(eDischargeSummary.SCSContext.Author));
            clinicalDocument.author = authors.ToArray();

            //SETUP the Custodian
            clinicalDocument.custodian = CDAGeneratorHelper.CreateCustodian(eDischargeSummary.CDAContext.Custodian);

            //SETUP encompassingEncounter for an Encounter
            if (eDischargeSummary.SCSContent.Event != null)
                clinicalDocument.componentOf = CDAGeneratorHelper.CreateComponentOf(eDischargeSummary.SCSContent.Event.Encounter);
            else
            {
                if (eDischargeSummary.SCSContext.Facility != null)
                {
                    clinicalDocument.componentOf = new POCD_MT000040Component1();
                    clinicalDocument.componentOf.encompassingEncounter = new POCD_MT000040EncompassingEncounter();
                }
            }

            clinicalDocument.componentOf.encompassingEncounter.location = CDAGeneratorHelper.CreateLocation(eDischargeSummary.SCSContext.Facility);
            
            //SETUP the Responsible Health Professional
            if (eDischargeSummary.SCSContent.Event != null)
                if (eDischargeSummary.SCSContent.Event.Encounter != null)
                    encounterParticipant.Add(CDAGeneratorHelper.CreateEncounterParticipant(eDischargeSummary.SCSContent.Event.Encounter.ResponsibleHealthProfessional));
            clinicalDocument.componentOf.encompassingEncounter.encounterParticipant = encounterParticipant.ToArray();

            var participants = CDAGeneratorHelper.CreateParticipantsDischargeSummary
                (
                    eDischargeSummary.SCSContent.Event != null
                        ? eDischargeSummary.SCSContent.Event.Encounter.LocationOfDischarge
                        : null,
                        eDischargeSummary.SCSContent.HealthProfile != null ?  eDischargeSummary.SCSContent.HealthProfile.NominatedPrimaryHealthCareProviders : null,
                        eDischargeSummary.SCSContent.Event != null ? eDischargeSummary.SCSContent.Event.Encounter.OtherParticipants : null
                );

            //SETUP the recipients   
            if (eDischargeSummary.CDAContext.InformationRecipients != null)
            {
                foreach (var recipient in eDischargeSummary.CDAContext.InformationRecipients)
                    recipients.Add(CDAGeneratorHelper.CreateInformationRecipient(recipient));
            }

            //XML BODY FILE
            components.Add
                (
                    CDAGeneratorHelper.CreateStructuredBodyFileComponent(eDischargeSummary.SCSContent.StructuredBodyFiles, NarrativeGenerator)
                );

            //Setup the Event
            components.Add(CDAGeneratorHelper.CreateComponent(eDischargeSummary.SCSContent.Event, NarrativeGenerator));

            //Setup the Medications 
            components.Add(CDAGeneratorHelper.CreateComponent(eDischargeSummary.SCSContent.Medications, NarrativeGenerator));

            //Setup the Health Profile 
            components.Add(CDAGeneratorHelper.CreateComponent(eDischargeSummary.SCSContent.HealthProfile, NarrativeGenerator));

            //Setup the Plan
            components.Add(CDAGeneratorHelper.CreateComponent(eDischargeSummary.SCSContent.Plan, NarrativeGenerator));


            //SETUP administrative observations component
            if (((eDischargeSummary.ShowAdministrativeObservations.HasValue && eDischargeSummary.ShowAdministrativeObservations.Value) ||
                  !eDischargeSummary.ShowAdministrativeObservations.HasValue))
                components.Add
                    (
                        CDAGeneratorHelper.CreateAdministrativeObservationsForDischargeSummary
                            (
                                eDischargeSummary.SCSContext.SubjectOfCare,
                                eDischargeSummary.SCSContent.CustomNarrativeAdministrativeObservations,
                                clinicalDocument.recordTarget[0].patientRole.id[0].root,
                                eDischargeSummary.SCSContent.Event != null && eDischargeSummary.SCSContent.Event.Encounter != null ? eDischargeSummary.SCSContent.Event.Encounter.Specialty : null,
                                NarrativeGenerator 
                            )
                    );

            //Generate and return the Specialist SpecialistLetter
            return CDAGeneratorHelper.CreateXml(clinicalDocument, authors, legalAuthenticator, authenticators, recipients, participants, components, nonXmlBody, eDischargeSummary.IncludeLogo, CDADocumentExtensionVersion.V3);
        }

        /// <summary>
        /// Generates a ConsolidatedView CDA (XML) document from the Consolidated View model
        /// </summary>
        /// <param name="consolidatedView">SharedHealthSummary</param>
        /// <returns>XmlDocument (CDA - Shared Health Summary)</returns>
        public static XmlDocument GenerateConsolidatedView(ConsolidatedView consolidatedView)
        {
            var vb = new ValidationBuilder();

            if (vb.ArgumentRequiredCheck("consolidatedView", consolidatedView))
            {
                consolidatedView.Validate("consolidatedView", vb.Messages);

                LogoSetupAndValidation(consolidatedView.LogoPath, consolidatedView.IncludeLogo, vb);
            }

            if (vb.Messages.Any())
            {
                var ve = new ValidationException(vb.Messages);
                var messageString = ve.GetMessagesString();

                throw new ValidationException(vb.Messages);
            }

            var authors = new List<POCD_MT000040Author>();
            var recipients = new List<POCD_MT000040InformationRecipient>();
            var components = new List<POCD_MT000040Component3>();
            var patients = new List<POCD_MT000040RecordTarget>();
            var authenticators = new List<POCD_MT000040Authenticator>();
            POCD_MT000040NonXMLBody nonXmlBody = null;

            //SETUP the clinical document object
            var clinicalDocument = CDAGeneratorHelper.CreateDocument
                (
                    consolidatedView.DocumentCreationTime,
                    CDADocumentType.ConsolidatedView,
                    consolidatedView.CDAContext.DocumentId,
                    consolidatedView.CDAContext.SetId,
                    consolidatedView.CDAContext.Version,
                    consolidatedView.DocumentStatus
                );
            

            //SETUP the patient
            patients.Add(CDAGeneratorHelper.CreateSubjectOfCare(consolidatedView.SCSContext.SubjectOfCare));
            clinicalDocument.recordTarget = patients.ToArray();

            //SETUP the author
            authors.Add(CDAGeneratorHelper.CreateAuthor(consolidatedView.SCSContext.Author));
            clinicalDocument.author = authors.ToArray();

            //SETUP the Custodian
            clinicalDocument.custodian = CDAGeneratorHelper.CreateCustodian(consolidatedView.CDAContext.Custodian);

            components.Add(CDAGeneratorHelper.CreateComponent(new List<IDocument> { consolidatedView.SCSContent.SharedHealthSummaryDocumentProvenance }, consolidatedView.SCSContent.CustomNarrativeSharedHealthSummaryDocumentProvenance, DocumentSections.SharedHealthSummary, DocumentProvenance.SharedHealthSummaryDocumentProvenance, NarrativeGenerator));
            components.Add(CDAGeneratorHelper.CreateComponent(consolidatedView.SCSContent.NewDocumentProvenance, consolidatedView.SCSContent.CustomNarrativeNewDocumentProvenance, DocumentSections.NewDocument, DocumentProvenance.NewDocumentProvenance, NarrativeGenerator));

            // The following three items are the same as SHS only they have a different component - section - title
            components.Add(CDAGeneratorHelper.UpdateComponentTitle(CDAGeneratorHelper.CreateComponent((SCSModel.Common.AdverseReactions)consolidatedView.SCSContent.SharedHealthSummaryAdverseReactions, NarrativeGenerator, "103.16302.120.1.1"), "Allergies and Adverse Reactions"));
            components.Add(CDAGeneratorHelper.UpdateComponentTitle(CDAGeneratorHelper.CreateComponent(consolidatedView.SCSContent.SharedHealthSummaryMedicationInstructions, NarrativeGenerator), "Medicines"));
            components.Add(CDAGeneratorHelper.UpdateComponentTitle(CDAGeneratorHelper.CreateComponent(consolidatedView.SCSContent.SharedHealthSummaryMedicalHistory, NarrativeGenerator), "Current and Past Medical History"));
            
            // The title is the same as the SHS
            components.Add(CDAGeneratorHelper.CreateComponent(consolidatedView.SCSContent.SharedHealthSummaryImunisations, NarrativeGenerator));

            components.Add(CDAGeneratorHelper.CreateComponent(consolidatedView.SCSContent.MedicareDocumentProvenance, consolidatedView.SCSContent.CustomNarrativeMedicareDocumentProvenance ,DocumentSections.Medicare, DocumentProvenance.MedicareDocumentProvenance, NarrativeGenerator));
            components.Add(CDAGeneratorHelper.CreateComponent(consolidatedView.SCSContent.RecentDocumentProvenance, consolidatedView.SCSContent.CustomNarrativeRecentDocumentProvenance, DocumentSections.RecentDocument, DocumentProvenance.RecentDocumentProvenance, NarrativeGenerator));
            components.Add(CDAGeneratorHelper.CreateComponent(new List<IDocument> { consolidatedView.SCSContent.AdvanceCareDirectiveCustodianDocumentProvenance },consolidatedView.SCSContent.CustomNarrativeAdvanceCareDirectiveCustodianDocumentProvenance, DocumentSections.AdvanceCareDirective, DocumentProvenance.AdvanceCareDirectiveCustodianDocumentProvenance, NarrativeGenerator));
            components.Add(CDAGeneratorHelper.CreateComponent(consolidatedView.SCSContent.RecentDiagnosticTestResultDocumentProvenance,consolidatedView.SCSContent.CustomNarrativeRecentDiagnosticTestResultDocumentProvenance, DocumentSections.RecentDiagnosticTestResult, DocumentProvenance.RecentDiagnosticTestResultDocumentProvenance, NarrativeGenerator));
            components.Add(CDAGeneratorHelper.CreateComponent(consolidatedView.SCSContent.ConsumerEnteredDocumentProvenance, consolidatedView.SCSContent.CustomNarrativeConsumerEnteredDocumentProvenance, DocumentSections.ConsumerEntered, DocumentProvenance.ConsumerEnteredDocumentProvenance, NarrativeGenerator));

            //SETUP administrative observations component
            if (((consolidatedView.ShowAdministrativeObservations.HasValue && consolidatedView.ShowAdministrativeObservations.Value) ||
                  !consolidatedView.ShowAdministrativeObservations.HasValue))
            components.Add
                (
                    CDAGeneratorHelper.CreateAdministrativeObservations
                        (
                            consolidatedView.SCSContext.SubjectOfCare,
                            consolidatedView.SCSContent.CustomNarrativeAdministrativeObservations,
                            clinicalDocument.recordTarget[0].patientRole.id[0].root,
                            NarrativeGenerator 
                        )
                );

            //Generate and return the SHS.
            return CDAGeneratorHelper.CreateXml(clinicalDocument, authors, null, authenticators, recipients, null, components, nonXmlBody, consolidatedView.IncludeLogo, CDADocumentExtensionVersion.V3);
        }

        /// <summary>
        /// Generates a MedicareInformationView CDA (XML) document from the Medicare View model
        /// </summary>
        /// <param name="medicareInformationView">MedicareInformationView</param>
        /// <returns>XmlDocument (CDA - Shared Health Summary)</returns>
        public static XmlDocument GenerateMedicareInformationView(MedicareInformationView medicareInformationView)
        {
          var vb = new ValidationBuilder();

          if (vb.ArgumentRequiredCheck("MedicareInformationView", medicareInformationView))
          {
              medicareInformationView.Validate("MedicareInformationView", vb.Messages);

              LogoSetupAndValidation(medicareInformationView.LogoPath, medicareInformationView.IncludeLogo, vb);
          }

          if (vb.Messages.Any())
          {
            var ve = new ValidationException(vb.Messages);
            var messageString = ve.GetMessagesString();

            throw new ValidationException(vb.Messages);
          }

          var authors = new List<POCD_MT000040Author>();
          var recipients = new List<POCD_MT000040InformationRecipient>();
          var components = new List<POCD_MT000040Component3>();
          var patients = new List<POCD_MT000040RecordTarget>();
          var authenticators = new List<POCD_MT000040Authenticator>();
          POCD_MT000040NonXMLBody nonXmlBody = null;

          //SETUP the clinical document object
          var clinicalDocument = CDAGeneratorHelper.CreateDocument
              (
                  medicareInformationView.DocumentCreationTime,
                  CDADocumentType.MedicareInformationView,
                  medicareInformationView.CDAContext.DocumentId,
                  medicareInformationView.CDAContext.SetId,
                  medicareInformationView.CDAContext.Version,
                  medicareInformationView.DocumentStatus
              );

          //SETUP the patient
          patients.Add(CDAGeneratorHelper.CreateSubjectOfCare(medicareInformationView.SCSContext.SubjectOfCare));
          clinicalDocument.recordTarget = patients.ToArray();

          //SETUP the author
          authors.Add(CDAGeneratorHelper.CreateAuthor(medicareInformationView.SCSContext.Author));
          clinicalDocument.author = authors.ToArray();

          //SETUP the Custodian
          clinicalDocument.custodian = CDAGeneratorHelper.CreateCustodian(medicareInformationView.CDAContext.Custodian);

          // Medicare View Exclusion Statement
          components.Add(CDAGeneratorHelper.CreateComponent(medicareInformationView.SCSContent.MedicareInformationViewExclusionStatement, NarrativeGenerator));

          // Medicare DVA Funded Services 
          components.Add(CDAGeneratorHelper.CreateComponent(medicareInformationView.SCSContent.MedicareDvaFundedServicesHistory, NarrativeGenerator));

          // Pharmaceutical Benefit Items 
          components.Add(CDAGeneratorHelper.CreateComponent(medicareInformationView.SCSContent.PharmaceuticalBenefitsHistory, NarrativeGenerator));

          // Australian Childhood Immunisation Register Component 
          components.Add(CDAGeneratorHelper.CreateComponent(medicareInformationView.SCSContent.AustralianChildhoodImmunisationRegisterHistory, NarrativeGenerator));

          // Australian OrganDonor Register Component 
          components.Add(CDAGeneratorHelper.CreateComponent(medicareInformationView.SCSContent.AustralianOrganDonorRegisterDecisionInformation, NarrativeGenerator));

          //SETUP administrative observations component
          if (((medicareInformationView.ShowAdministrativeObservations.HasValue && medicareInformationView.ShowAdministrativeObservations.Value) ||
                !medicareInformationView.ShowAdministrativeObservations.HasValue))
          components.Add
              (
                  CDAGeneratorHelper.CreateAdministrativeObservations
                      (
                          medicareInformationView.SCSContext.SubjectOfCare,
                          medicareInformationView.SCSContent.CustomNarrativeAdministrativeObservations,
                          clinicalDocument.recordTarget[0].patientRole.id[0].root,
                          NarrativeGenerator 
                      )
              );

          //Generate and return the SHS.
          return CDAGeneratorHelper.CreateXml(clinicalDocument, authors, null, authenticators, recipients, null, components, nonXmlBody, medicareInformationView.IncludeLogo, CDADocumentExtensionVersion.V3);
        }

        /// <summary>
        /// Generates a PrescriptionRecord CDA (XML) document from the Prescription Record model
        /// </summary>
        /// <param name="prescriptionRecord">A PrescriptionRecord</param>
        /// <returns>XmlDocument (CDA - Prescription Record)</returns>
        public static XmlDocument GeneratePrescriptionRecord(PrescriptionRecord prescriptionRecord)
        {
          var vb = new ValidationBuilder();

          if (vb.ArgumentRequiredCheck("PrescriptionRecord", prescriptionRecord))
          {
              prescriptionRecord.Validate("PrescriptionRecord", vb.Messages);

              LogoSetupAndValidation(prescriptionRecord.LogoPath, prescriptionRecord.IncludeLogo, vb);
          }

          if (vb.Messages.Any())
          {
            var ve = new ValidationException(vb.Messages);
            var messageString = ve.GetMessagesString();

            throw new ValidationException(vb.Messages);
          }

          var authors = new List<POCD_MT000040Author>();
          var recipients = new List<POCD_MT000040InformationRecipient>();
          var components = new List<POCD_MT000040Component3>();
          var patients = new List<POCD_MT000040RecordTarget>();
          var authenticators = new List<POCD_MT000040Authenticator>();
          POCD_MT000040NonXMLBody nonXmlBody = null;

          //SETUP the clinical document object
          var clinicalDocument = CDAGeneratorHelper.CreateDocument
              (
                  prescriptionRecord.DocumentCreationTime,
                  CDADocumentType.PrescriptionRecord,
                  prescriptionRecord.CDAContext.DocumentId,
                  prescriptionRecord.CDAContext.SetId,
                  prescriptionRecord.CDAContext.Version,
                  prescriptionRecord.DocumentStatus
              );

          // Setup the Parent Document
          if (prescriptionRecord.CDAContext.ParentDocuments != null && prescriptionRecord.CDAContext.ParentDocuments.Any())
          clinicalDocument.relatedDocument = CDAGeneratorHelper.CreateRelatedDocument
            (
              prescriptionRecord.CDAContext.ParentDocuments
            ).ToArray();

          //SETUP the patient
          patients.Add(CDAGeneratorHelper.CreateSubjectOfCare(prescriptionRecord.SCSContext.SubjectOfCare));
          clinicalDocument.recordTarget = patients.ToArray();

          //SETUP the author
          authors.Add(CDAGeneratorHelper.CreateAuthor(prescriptionRecord.SCSContext.Prescriber));
          clinicalDocument.author = authors.ToArray();

          //SETUP encompassing encounter
          clinicalDocument.componentOf = CDAGeneratorHelper.CreateComponentOf(prescriptionRecord.SCSContext.PrescriberOrganisation);

          //SETUP the Legal Authenticator
          POCD_MT000040LegalAuthenticator legalAuthenticator = null;
          if (prescriptionRecord.CDAContext.LegalAuthenticator != null)
          {
            legalAuthenticator = CDAGeneratorHelper.CreateLegalAuthenticator(prescriptionRecord.CDAContext.LegalAuthenticator);
          }

          //SETUP the Custodian
          clinicalDocument.custodian = CDAGeneratorHelper.CreateCustodian(prescriptionRecord.CDAContext.Custodian);

          // ETP Narrative for AdministrativeObservations
          StrucDocText prescriptionNarrative = NarrativeGenerator.CreateNarrative(prescriptionRecord.SCSContext.SubjectOfCare, clinicalDocument.recordTarget[0].patientRole.id[0].root, false);

          // Setup Prescription Item
          components.Add(CDAGeneratorHelper.CreateComponent(prescriptionRecord.SCSContent.PrescriptionItem, prescriptionRecord.SCSContext.Prescriber, prescriptionRecord.SCSContext.SubjectOfCare, NarrativeGenerator));


          //SETUP administrative observations component
          if (((prescriptionRecord.ShowAdministrativeObservations.HasValue && prescriptionRecord.ShowAdministrativeObservations.Value) ||
                !prescriptionRecord.ShowAdministrativeObservations.HasValue))
          components.Add
              (
                  CDAGeneratorHelper.CreateAdministrativeObservations
                      (
                          prescriptionRecord.SCSContext.SubjectOfCare,
                          prescriptionRecord.SCSContent.CustomNarrativeAdministrativeObservations ?? prescriptionNarrative,
                          clinicalDocument.recordTarget[0].patientRole.id[0].root,
                          NarrativeGenerator 
                      )
              );

          //Generate and return the SHS.
          return CDAGeneratorHelper.CreateXml(clinicalDocument, authors, legalAuthenticator, authenticators, recipients, null, components, nonXmlBody, prescriptionRecord.IncludeLogo, CDADocumentExtensionVersion.V3);
        }

        /// <summary>
        /// Generates a DispenseRecord CDA (XML) document from the Dispense Record model
        /// </summary>
        /// <param name="dispenseRecord">A DispenseRecord</param>
        /// <returns>XmlDocument (CDA - Dispense Record)</returns>
        public static XmlDocument GenerateDispenseRecord(DispenseRecord dispenseRecord)
        {
          var vb = new ValidationBuilder();

          if (vb.ArgumentRequiredCheck("DispenseRecord", dispenseRecord))
          {
            dispenseRecord.Validate("DispenseRecord", vb.Messages);

            LogoSetupAndValidation(dispenseRecord.LogoPath, dispenseRecord.IncludeLogo, vb);
          }

          if (vb.Messages.Any())
          {
            var ve = new ValidationException(vb.Messages);
            var messageString = ve.GetMessagesString();

            throw new ValidationException(vb.Messages);
          }

          var authors = new List<POCD_MT000040Author>();
          var recipients = new List<POCD_MT000040InformationRecipient>();
          var components = new List<POCD_MT000040Component3>();
          var patients = new List<POCD_MT000040RecordTarget>();
          var authenticators = new List<POCD_MT000040Authenticator>();
          POCD_MT000040NonXMLBody nonXmlBody = null;

          //SETUP the clinical document object
          var clinicalDocument = CDAGeneratorHelper.CreateDocument
              (
                  dispenseRecord.DocumentCreationTime,
                  CDADocumentType.DispenseRecord,
                  dispenseRecord.CDAContext.DocumentId,
                  dispenseRecord.CDAContext.SetId,
                  dispenseRecord.CDAContext.Version,
                  dispenseRecord.DocumentStatus
              );

          // Setup the Parent Document
          if (dispenseRecord.CDAContext.ParentDocuments != null && dispenseRecord.CDAContext.ParentDocuments.Any())
          clinicalDocument.relatedDocument = CDAGeneratorHelper.CreateRelatedDocument
            (
              dispenseRecord.CDAContext.ParentDocuments
            ).ToArray();

          //SETUP the patient
          patients.Add(CDAGeneratorHelper.CreateSubjectOfCare(dispenseRecord.SCSContext.SubjectOfCare));
          clinicalDocument.recordTarget = patients.ToArray();

          //SETUP the author
          authors.Add(CDAGeneratorHelper.CreateAuthor(dispenseRecord.SCSContext.Dispenser));
          clinicalDocument.author = authors.ToArray();

          //SETUP encompassing encounter
          clinicalDocument.componentOf = CDAGeneratorHelper.CreateComponentOf(dispenseRecord.SCSContext.DispenserOrganisation);

          //SETUP the Legal Authenticator
          POCD_MT000040LegalAuthenticator legalAuthenticator = null;
          if (dispenseRecord.CDAContext.LegalAuthenticator != null)
          {
            legalAuthenticator = CDAGeneratorHelper.CreateLegalAuthenticator(dispenseRecord.CDAContext.LegalAuthenticator);
          }

          //SETUP the Custodian
          clinicalDocument.custodian = CDAGeneratorHelper.CreateCustodian(dispenseRecord.CDAContext.Custodian);

          // Setup DispenseItem Item
          components.Add(CDAGeneratorHelper.CreateComponent(dispenseRecord.SCSContent.DispenseItem, dispenseRecord.SCSContext.Dispenser, dispenseRecord.SCSContext.DispenserOrganisation,dispenseRecord.SCSContext.SubjectOfCare, NarrativeGenerator));

          // ETP Narrative for AdministrativeObservations
          StrucDocText dispenseNarrative = NarrativeGenerator.CreateNarrative(dispenseRecord.SCSContext.SubjectOfCare, clinicalDocument.recordTarget[0].patientRole.id[0].root, false);

          //SETUP administrative observations component
          if (((dispenseRecord.ShowAdministrativeObservations.HasValue && dispenseRecord.ShowAdministrativeObservations.Value) ||
                !dispenseRecord.ShowAdministrativeObservations.HasValue))
          components.Add
              (
                  CDAGeneratorHelper.CreateAdministrativeObservations
                      (
                          dispenseRecord.SCSContext.SubjectOfCare,
                          dispenseRecord.SCSContent.CustomNarrativeAdministrativeObservations ?? dispenseNarrative,
                          clinicalDocument.recordTarget[0].patientRole.id[0].root,
                          NarrativeGenerator 
                      )
              );

          //Generate and return the SHS.
          return CDAGeneratorHelper.CreateXml(clinicalDocument, authors, legalAuthenticator, authenticators, recipients, null, components, nonXmlBody, dispenseRecord.IncludeLogo, CDADocumentExtensionVersion.V3);
        }
        #endregion

        #region Setup and Validation

        /// <summary>
        /// Verifies that the logo path location is a valid path and is included in the bin directory
        /// </summary>
        /// <returns>XmlDocument (CDA - EventSummary)</returns>
        public static void LogoSetupAndValidation(string logoPath, bool includeLogo, ValidationBuilder vb)
        {
          if (includeLogo)
          {
            if (!logoPath.IsNullOrEmptyWhitespace())
            {
              if (File.Exists(logoPath))
              {
                File.Copy(logoPath, "Logo.png", true);
              }
              else
              {
                vb.AddValidationMessage(vb.PathName, string.Empty, string.Format("The path '{0}' does not contain an image", logoPath));
              }
            }

            if (!File.Exists("Logo.png"))
            {
              vb.AddValidationMessage(vb.PathName, string.Empty, "Logo.png needs to be included in the output directory if 'IncludeLogo' is true");
            }
          }
        }
        #endregion
    }
}
