/*
 * 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 Nehta.HL7.CDA;
using Nehta.VendorLibrary.CDA.Generator.Enums;
using Nehta.VendorLibrary.CDA.SCSModel.Common.Entities;
using Nehta.VendorLibrary.Common;
using Nehta.VendorLibrary.CDA.Generator;
using Nehta.VendorLibrary.CDA.Common.Enums;
using Nehta.VendorLibrary.CDA.Common;
using Nehta.VendorLibrary.CDA.SCSModel;
using Nehta.VendorLibrary.CDA.SCSModel.Common;

namespace Nehta.VendorLibrary.CDA.Sample
{
    /// <summary>
    /// This project is intended to demonstrate how an EReferral CDA document can be created.
    /// 
    /// The project contains two samples, the first is designed to create a fully populated CDA document, including
    /// all of the optional sections and entries. The second sample only populates the mandatory sections and entries.
    /// 
    /// The CDA model is split into three distinct sections, each of which needs to be created via the 
    /// EReferral class, and then populated with data as appropriate. The three sections that need to be
    /// created and hydrated with data are:
    /// 
    ///     CDA Context (Clinical Document Architecture - Context)
    ///     SCS Context (Structured Document Template - Context)
    ///     SCS Content (Structured Document Template - Content)
    /// 
    /// The CDA Context typically contains information that is to be represented within the header of the document
    /// that is not encapsulated with the SCS context.
    /// E.g. Generic CDA sections or entries; for example custodian.
    /// 
    /// The SCS Context typically contains information that is to be represented within the header of the document
    /// and relates specifically to the type of document that is to be created.
    /// E.g. E-Referral specific CDA sections or entries; for example Subject of Care.
    /// 
    /// The SCS Content typically contains information that is to be represented with the body of the document.
    /// </summary>
    public class EReferralSample 
    {
        #region Properties

        public static string OutputFolderPath { get; set; }

        public static String OutputFileNameAndPath
        {
            get
            {
                return OutputFolderPath + @"\EReferral.xml";
            }
        }

        public static String ImageFileNameAndPath
        {
            get
            {
                return OutputFolderPath + @"\x-ray.jpg";
            }
        }

        public static String PitNameAndPath
        {
            get
            {
                return OutputFolderPath + @"\PIT.txt";
            }
        }

        public static String StructuredFileAttachment
        {
            get
            {
                return OutputFolderPath + @"\attachment.pdf";
            }
        }

        public static String ResultFileNameAndPath
        {
            get
            {
                return OutputFolderPath + @"\path1234.pdf";
            }
        }

        // Note: Place this in any string field and and this will insert a break
        private const String DELIMITERBREAK = "<BR>";
        
        #endregion

        /// <summary>
        /// This example populates only the mandatory Sections / Entries; as a result this sample omits all
        /// of the content within the body of the CDA document; as each of the sections within the body
        /// are optional.
        /// </summary>
        public XmlDocument PopulatedEReferralSample()
        {
            XmlDocument xmlDoc = null;

            var eReferral = PopulateEReferral(true);

            try
            {
                CDAGenerator.NarrativeGenerator = new CDANarrativeGenerator();

                //Pass the E-Referral model into the GenerateEReferral method 
                xmlDoc = CDAGenerator.GenerateEReferral(eReferral);

                xmlDoc.Save(OutputFileNameAndPath);
            }
            catch (ValidationException ex)
            {
                //Catch any validation exceptions
                var validationMessages = ex.GetMessagesString();

                //Handle any validation errors as appropriate.
                throw;
            }

            return xmlDoc;
        }

        /// <summary>
        /// This example populates only the mandatory Sections / Entries; as a result this sample omits all
        /// of the content within the body of the CDA document; as each of the sections within the body
        /// are optional.
        /// </summary>
        public XmlDocument PopulateEReferralSample_1A(string fileName)
        {
            XmlDocument xmlDoc = null;

           var document = PopulateEReferral(true);

            document.SCSContent = EReferral.CreateSCSContent();
            document.SCSContent.Referee = CreateReferee(true);

            document.IncludeLogo = false;

            var structuredBodyFileList = new List<ExternalData>();

            var structuredBodyFile = BaseCDAModel.CreateStructuredBodyFile();
            structuredBodyFile.Caption = "Structured Body File";
            structuredBodyFile.ExternalDataMediaType = MediaType.PDF;
            structuredBodyFile.Path = StructuredFileAttachment;
            structuredBodyFileList.Add(structuredBodyFile);

            document.SCSContent.StructuredBodyFiles = structuredBodyFileList;

            try
            {
                CDAGenerator.NarrativeGenerator = new CDANarrativeGenerator();

                //Pass the document model into the Generate method 
                xmlDoc = CDAGenerator.GenerateEReferral(document);

                using (var writer = XmlWriter.Create(OutputFolderPath + @"\" + fileName, new XmlWriterSettings() { Indent = true }))
                {
                    if (!fileName.IsNullOrEmptyWhitespace()) xmlDoc.Save(writer);
                }
            }
            catch (ValidationException ex)
            {
                //Catch any validation exceptions
                var validationMessages = ex.GetMessagesString();

                //Handle any validation errors as appropriate.
                throw;
            }

            return xmlDoc;
        }

        /// <summary>
        /// This sample populates only the mandatory Sections / Entries
        /// </summary>
        public XmlDocument MinPopulatedEReferralSample(string fileName)
        {
            XmlDocument xmlDoc = null;

            var eReferral = PopulateEReferral(true);

            try
            {
                CDAGenerator.NarrativeGenerator = new CDANarrativeGenerator();

                //Pass the E-Referral model into the GenerateEReferral method 
                xmlDoc = CDAGenerator.GenerateEReferral(eReferral);

                using (var writer = XmlWriter.Create(OutputFolderPath + @"\" + fileName, new XmlWriterSettings { Indent = true }))
                {
                    if (!fileName.IsNullOrEmptyWhitespace()) xmlDoc.Save(writer);
                }
            }
            catch (ValidationException ex)
            {
                //Catch any validation exceptions
                var validationMessages = ex.GetMessagesString();

                //Handle any validation errors as appropriate.
                throw;
            }

            return xmlDoc;
        }

        /// <summary>
        /// This sample populates both the mandatory and optional Sections / Entries; as a result this sample
        /// includes all of the sections within the body and each section includes at least one example for 
        /// each of its optional entries.
        /// </summary>
        public XmlDocument MaxPopulatedEReferralSample(string fileName)
        {
            XmlDocument xmlDoc = null;

            var eReferral = PopulateEReferral(false);

            try
            {
                CDAGenerator.NarrativeGenerator = new CDANarrativeGenerator();

                //Pass the E-Referral model into the GenerateEReferral method 
                xmlDoc = CDAGenerator.GenerateEReferral(eReferral);

                using (var writer = XmlWriter.Create(OutputFolderPath + @"\" + fileName, new XmlWriterSettings { Indent = true }))
                {
                    if (!fileName.IsNullOrEmptyWhitespace()) xmlDoc.Save(writer);
                }
            }
            catch (ValidationException ex)
            {
                //Catch any validation exceptions
                var validationMessages = ex.GetMessagesString();

                //Handle any validation errors as appropriate.
                throw;
            }

            return xmlDoc;
        }

        #region Populate Methods


        /// <summary>
        /// This method populates an eReferral model with either the mandatory sections only, or both 
        /// the mandatory and optional sections
        /// </summary>
        /// <param name="mandatorySectionsOnly">mandatorySectionsOnly</param>
        /// <returns>EReferral</returns>
        internal static EReferral PopulateEReferral(Boolean mandatorySectionsOnly)
        {
            var eReferral = EReferral.CreateEReferral();

            // Set Creation Time
            eReferral.DocumentCreationTime = new ISO8601DateTime(DateTime.Now);

            // Include Logo
            eReferral.IncludeLogo = true;

            #region Setup and populate the CDA context model

            // Setup and populate the CDA context model
            var cdaContext = EReferral.CreateCDAContext();
            // Document Id
            cdaContext.DocumentId = BaseCDAModel.CreateIdentifier(BaseCDAModel.CreateGuid(), null);

            // Set Id  
            cdaContext.SetId = BaseCDAModel.CreateIdentifier(BaseCDAModel.CreateGuid(), null);
            // CDA Context Version
            cdaContext.Version = "1";

            // Custodian
            cdaContext.Custodian = EReferral.CreateCustodian();
            GenericObjectReuseSample.HydrateCustodian(cdaContext.Custodian, mandatorySectionsOnly);

            // Legal authenticator
            if (!mandatorySectionsOnly)
            {
                cdaContext.LegalAuthenticator = EReferral.CreateLegalAuthenticator();
                GenericObjectReuseSample.HydrateAuthenticator(cdaContext.LegalAuthenticator, mandatorySectionsOnly);
            }

            // Create information recipient
            if (!mandatorySectionsOnly)
            {
                var recipient1 = EReferral.CreateInformationRecipient();
                var recipient2 = EReferral.CreateInformationRecipient();
                GenericObjectReuseSample.HydrateRecipient(recipient1, RecipientType.Primary, mandatorySectionsOnly);
                GenericObjectReuseSample.HydrateRecipient(recipient2, RecipientType.Secondary, mandatorySectionsOnly);
                cdaContext.InformationRecipients = new List<IParticipationInformationRecipient> { recipient1, recipient2 };
            }

            eReferral.CDAContext = cdaContext;
            #endregion

            #region Setup and Populate the SCS Context model
            // Setup and Populate the SCS Context model

            eReferral.SCSContext = EReferral.CreateSCSContext();

            eReferral.SCSContext.Author = EReferral.CreateAuthor();
            GenericObjectReuseSample.HydrateAuthor(eReferral.SCSContext.Author, mandatorySectionsOnly);

            eReferral.SCSContext.SubjectOfCare = EReferral.CreateSubjectOfCare();
            GenericObjectReuseSample.HydrateSubjectofCare(eReferral.SCSContext.SubjectOfCare, mandatorySectionsOnly);

            if (!mandatorySectionsOnly)
            {
              eReferral.SCSContext.PatientNominatedContacts = CreatePatientNominatedContacts(mandatorySectionsOnly);
            }

            #endregion

            #region Setup and populate the SCS Content model
            // Setup and populate the SCS Content model
            eReferral.SCSContent = EReferral.CreateSCSContent();

            // Referral detail
            eReferral.SCSContent.ReferralReason = "Referral reason";

            eReferral.SCSContent.ReferralDateTime = new ISO8601DateTime(DateTime.Now);
            eReferral.SCSContent.ValidityDuration = EReferral.CreateInterval("6", TimeUnitOfMeasure.Month);
            eReferral.SCSContent.Referee = CreateReferee(mandatorySectionsOnly);

            // Medications
            eReferral.SCSContent.Medications = CreateMedications(mandatorySectionsOnly);

            // Medical history
            eReferral.SCSContent.MedicalHistory = CreateMedicalHistory(mandatorySectionsOnly);

            // Adverse reactions
            eReferral.SCSContent.AdverseReactions = CreateAdverseReactions(mandatorySectionsOnly);

            if (!mandatorySectionsOnly)
            {
              eReferral.SCSContent.UsualGP = CreateUsualGPOrganisation(mandatorySectionsOnly);

                // Diagnostic Investigations
              eReferral.SCSContent.DiagnosticInvestigations = CreateDiagnosticInvestigations(mandatorySectionsOnly);
            }
            #endregion

            return eReferral;
        }

        /// <summary>
        /// Creates the patient nominated contacts section.
        /// </summary>
        /// <returns></returns>
        private static IList<IParticipationPatientNominatedContact> CreatePatientNominatedContacts(Boolean mandatorySectionsOnly)
        {
            IParticipationPatientNominatedContact contact1 = CreatePatientNominatedContactPerson(
                "UsualGP", "Person", "8003610000021101", "1 Clinician Street", "0345754566", mandatorySectionsOnly);

            IParticipationPatientNominatedContact contact2 = CreatePatientNominatedContactPerson(
                "John", "Doe", "8003610000021101", "2 Clinician Street", "0345754888", mandatorySectionsOnly);

            IParticipationPatientNominatedContact contact3 = CreatePatientNominatedContactOrganisation(
                "Some Hospital", "Ward 1F", "8003620000021100", "1 Test Street", "0345754811", mandatorySectionsOnly);

            return new[] { contact1, contact2, contact3 };
        }

        private static IParticipationPatientNominatedContact CreatePatientNominatedContactOrganisation(string name, string department, string id, string addressLine, string phone, Boolean mandatorySectionsOnly)
        {
            IParticipationPatientNominatedContact nominatedContact = EReferral.CreateParticipationPatientNominatedContact();

            nominatedContact.Participant = EReferral.CreatePatientNominatedContact();

            IOrganisation organisation = EReferral.CreateOrganisation();
            organisation.Department = department;
            organisation.Name = name;
            organisation.NameUsage = OrganisationNameUsage.EnterpriseName;
            organisation.Identifiers = new List<Identifier>
                                           {
                                               BaseCDAModel.CreateHealthIdentifier(HealthIdentifierType.HPIO, id)
                                           };

            nominatedContact.Participant.Organisation = organisation;

            // Address
            var address = EReferral.CreateAddress();
            address.AddressPurpose = AddressPurpose.Residential;
            address.AustralianAddress = EReferral.CreateAustralianAddress();
            address.AustralianAddress.UnstructuredAddressLines = new List<string> { addressLine };
            address.AustralianAddress.SuburbTownLocality = "Nehtaville";
            address.AustralianAddress.State = AustralianState.QLD;
            address.AustralianAddress.PostCode = "5555";
            address.AustralianAddress.DeliveryPointId = 32568931;

            nominatedContact.Participant.Addresses = new List<IAddress> {address};

            // Communication
            var electronicCommunicationDetail = EReferral.CreateElectronicCommunicationDetail
                (
                   phone,
                   ElectronicCommunicationMedium.Telephone,
                   new List<ElectronicCommunicationUsage> { ElectronicCommunicationUsage.WorkPlace, ElectronicCommunicationUsage.Home }
                );

            nominatedContact.Participant.ElectronicCommunicationDetails = new List<ElectronicCommunicationDetail> {electronicCommunicationDetail};

            if (!mandatorySectionsOnly)
            {
                nominatedContact.Role = EReferral.CreateRole(Occupation.GeneralMedicalPractitioner);
            } else
            {
                nominatedContact.Role = EReferral.CreateRole(NullFlavour.TemporarilyUnavailable);
            }

            return nominatedContact;
        }


      /// <summary>
      /// Creates a patient nominated contact.
      /// </summary>
      /// <param name="givenName">Given name</param>
      /// <param name="familyName">Family name</param>
      /// <param name="hpii">Hpii</param>
      /// <param name="addressLine">Address line</param>
      /// <param name="phone">Phone</param>
      /// <param name="mandatorySectionsOnly">Populates only mandatory sections only </param>
      /// <returns>IParticipationPatientNominatedContact</returns>
      private static IParticipationPatientNominatedContact CreatePatientNominatedContactPerson(string givenName, string familyName, string hpii, string addressLine, string phone, Boolean mandatorySectionsOnly)
        {
            IParticipationPatientNominatedContact nominatedContact = EReferral.CreateParticipationPatientNominatedContact();

            nominatedContact.Participant = EReferral.CreatePatientNominatedContact();

            // Name
            var personName = EReferral.CreatePersonName();
            personName.GivenNames = new List<string> { givenName };
            personName.FamilyName = familyName;
            personName.Titles = new List<string> { "Doctor" };
            personName.NameUsages = new List<NameUsage> { NameUsage.Legal };

            nominatedContact.Participant.Person = EReferral.CreatePersonPatientNominatedContacts();

            nominatedContact.Participant.Person.PersonNames = new List<IPersonName> { personName };

            // Address
            var address = EReferral.CreateAddress();
            address.AddressPurpose = AddressPurpose.Business;
            address.AustralianAddress = EReferral.CreateAustralianAddress();
            address.AustralianAddress.UnstructuredAddressLines = new List<string> { addressLine };
            address.AustralianAddress.SuburbTownLocality = "Nehtaville";
            address.AustralianAddress.State = AustralianState.QLD;
            address.AustralianAddress.PostCode = "5555";
            address.AustralianAddress.DeliveryPointId = 32568931;

            nominatedContact.Participant.Addresses = new List<IAddress> { address };

            // Communication
            var electronicCommunicationDetail = EReferral.CreateElectronicCommunicationDetail
                (
                   phone,
                   ElectronicCommunicationMedium.Telephone,
                   ElectronicCommunicationUsage.WorkPlace
                );

            nominatedContact.Participant.ElectronicCommunicationDetails = new List<ElectronicCommunicationDetail> 
                                { 
                                    electronicCommunicationDetail 
                                };

            // Identifiers
            nominatedContact.Participant.Person.Identifiers = new List<Identifier>
                                  {
                                      BaseCDAModel.CreateHealthIdentifier(HealthIdentifierType.HPII, hpii)
                                  };

            if (!mandatorySectionsOnly)
            {
                nominatedContact.Role = EReferral.CreateRole(Occupation.GeneralMedicalPractitioner);
            } else
            {
                nominatedContact.Role = EReferral.CreateRole(NullFlavour.PositiveInfinity);
            }

            return nominatedContact;
        }

        /// <summary>
        /// Creates and Hydrates a UsualGP
        /// 
        /// Note: the data used within this method is intended as a guide and should be replaced.
        /// </summary>
        /// <returns>>A Hydrated UsualGP object</returns>
        private static IParticipationUsualGP CreateUsualGPOrganisation(Boolean mandatorySectionsOnly)
        {
            IParticipationUsualGP usualGP = EReferral.CreateUsualGP();

            var participant = EReferral.CreateParticipantForUsualGP();

            var organisation = EReferral.CreateOrganisation();
            organisation.Name = "Bay hill hospital (UsualGP Organisation)";
            organisation.NameUsage = OrganisationNameUsage.LocallyUsedName;
            organisation.Department = "Department";

            organisation.Identifiers = new List<Identifier> { BaseCDAModel.CreateHealthIdentifier(HealthIdentifierType.HPIO, "8003620000020052") };
            participant.Organisation = organisation;

            var address = EReferral.CreateAddress();
            address.AddressPurpose = AddressPurpose.Business;
            address.AustralianAddress = EReferral.CreateAustralianAddress();
            address.AustralianAddress.UnstructuredAddressLines = new List<string> { "1 Clinician Street" };
            address.AustralianAddress.SuburbTownLocality = "Nehtaville";
            address.AustralianAddress.State = AustralianState.QLD;
            address.AustralianAddress.PostCode = "5555";
            address.AustralianAddress.DeliveryPointId = 32568931;

            var addressList = new List<IAddress>
                                {
                                    address
                                };
            participant.Addresses = addressList;

            var electronicCommunicationDetail = EReferral.CreateElectronicCommunicationDetail
                (
                   "0345754566",
                   ElectronicCommunicationMedium.Telephone,
                   ElectronicCommunicationUsage.WorkPlace
                );

            participant.ElectronicCommunicationDetails = new List<ElectronicCommunicationDetail> { electronicCommunicationDetail };

            if (!mandatorySectionsOnly)
            {
              usualGP.Role = BaseCDAModel.CreateRole(Occupation.GeneralMedicalPractitioner);
            } 
              else
            {
              usualGP.Role = BaseCDAModel.CreateRole(NullFlavour.PositiveInfinity);
            }

            usualGP.Participant = participant;

            return usualGP;
        }

        /// <summary>
        /// Creates and Hydrates a UsualGP
        /// 
        /// Note: the data used within this method is intended as a guide and should be replaced.
        /// </summary>
        /// <returns>>A Hydrated UsualGP object</returns>
        private static IParticipationUsualGP CreateUsualGPPerson(Boolean mandatorySectionsOnly)
        {
            var usualGP = EReferral.CreateUsualGP();

            var participant = EReferral.CreateParticipantForUsualGP();

            var personName = EReferral.CreatePersonName();
            personName.GivenNames = new List<string> { "UsualGP" };
            personName.FamilyName = "Person";
            personName.Titles = new List<string> { "Doctor" };
            personName.NameUsages = new List<NameUsage> { NameUsage.Legal };

            var person = EReferral.CreatePersonWithOrganisation();
            person.PersonNames = new List<IPersonName>();
            person.PersonNames.Add(personName);
            person.Identifiers = new List<Identifier> { BaseCDAModel.CreateHealthIdentifier(HealthIdentifierType.HPII, "8003610000021101") };

            participant.Person = person;

            var organisation = EReferral.CreateEmploymentOrganisation();
            organisation.Name = "Bay hill hospital";
            organisation.NameUsage = OrganisationNameUsage.LocallyUsedName;
            organisation.Identifiers = new List<Identifier> { BaseCDAModel.CreateHealthIdentifier(HealthIdentifierType.HPIO, "8003620000020052") };
            participant.Person.Organisation = organisation;

            var address = EReferral.CreateAddress();
            address.AddressPurpose = AddressPurpose.Business;
            address.AustralianAddress = EReferral.CreateAustralianAddress();
            address.AustralianAddress.UnstructuredAddressLines = new List<string> { "1 Clinician Street" };
            address.AustralianAddress.SuburbTownLocality = "Nehtaville";
            address.AustralianAddress.State = AustralianState.QLD;
            address.AustralianAddress.PostCode = "5555";
            address.AustralianAddress.DeliveryPointId = 32568931;

            var addressList = new List<IAddress>
                                {
                                    address
                                };
            participant.Addresses = addressList;

            var electronicCommunicationDetail = EReferral.CreateElectronicCommunicationDetail
                (
                   "0345754566",
                   ElectronicCommunicationMedium.Telephone,
                   ElectronicCommunicationUsage.WorkPlace
                );

            participant.ElectronicCommunicationDetails = new List<ElectronicCommunicationDetail> { electronicCommunicationDetail };

            if (!mandatorySectionsOnly)
            {
               usualGP.Role = BaseCDAModel.CreateRole(Occupation.GeneralMedicalPractitioner);
            } 
              else
            {
               usualGP.Role = BaseCDAModel.CreateRole(NullFlavour.Other);
            }

            usualGP.Participant = participant;

            return usualGP;
        }


        /// <summary>
        /// Creates and Hydrates an natomicalSite
        /// </summary>
        /// <returns>AnatomicalSite</returns>
        private static AnatomicalSite CreateAnatomicalSite(String description, String code, CodingSystem codingSystem, String name, String side, List<ExternalData> images)
        {
            var anatomicalSite = EReferral.CreateAnatomicalSite();
            anatomicalSite.Description = description;
            anatomicalSite.AnatomicalLocation = EReferral.CreateAnatomicalLocation();
            anatomicalSite.AnatomicalLocation.NameOfLocation = EReferral.CreateAnatomicLocationName(code, codingSystem, name, null);
            anatomicalSite.AnatomicalLocation.Side = EReferral.CreateAnatomicLocationSide("8006542", CodingSystem.SNOMED, side, null, null);
            anatomicalSite.Images = images;
            return anatomicalSite;
        }

        /// <summary>
        /// Creates and Hydrates a Reference Range
        /// </summary>
        /// <returns>ReferenceRange</returns>
        private static ResultValueReferenceRangeDetail CreateReferenceRange(String code, String name, String units, String high, String low)
        {
            var resultValueReferenceRangeDetail = EReferral.CreateResultValueReferenceRangeDetail();
            resultValueReferenceRangeDetail.Range = EReferral.CreateQuantityRange();
            resultValueReferenceRangeDetail.Range.High = high;
            resultValueReferenceRangeDetail.Range.Low = low;
            resultValueReferenceRangeDetail.Range.Units = units;
            resultValueReferenceRangeDetail.ResultValueReferenceRangeMeaning = EReferral.CreateResultValueReferenceRangeMeaning
                                                                                (
                                                                                    code,
                                                                                    CodingSystem.SNOMED,
                                                                                    name,
                                                                                    null,
                                                                                    null
                                                                                );

            return resultValueReferenceRangeDetail;
        }

        /// <summary>
        /// Creates and Hydrates a Physical Details
        /// </summary>
        /// <returns>PhysicalDetails</returns>
        private static PhysicalDetails CreatePhysicalDetails(String value, String units)
        {
            PhysicalDetails physicalDetails = null;

            if (!value.IsNullOrEmptyWhitespace() && !units.IsNullOrEmptyWhitespace())
            {
                physicalDetails = EReferral.CreatePhysicalDetails();

                physicalDetails.Volume = EReferral.CreateQuantity();
                physicalDetails.Volume.Value = value;
                physicalDetails.Volume.Units = units;
            }


            return physicalDetails;
        }

        /// <summary>
        /// Creates and Hydrates the Medications section for the E-Referral.
        /// 
        /// Note: the data used within this method is intended as a guide and should be replaced.
        /// </summary>
        /// <returns>A Hydrated Medications object</returns>
        private static IMedicationsEReferral CreateMedications(bool mandatorySectionsOnly)
        {
            var medications = EReferral.CreateMedications();

            if (!mandatorySectionsOnly)
            {
                var medicationList = new List<IMedicationInstruction>();

                var medication1 = EReferral.CreateMedication();
                medication1.Directions = "As directed by packaging.";

                medication1.Medicine = EReferral.CreateMedicine("23641011000036102", CodingSystem.AMT,"paracetamol 500 mg + codeine phosphate 30 mg tablet", null, null);
                medicationList.Add(medication1);

                var medication2 = EReferral.CreateMedication();
                medication2.DirectionsNullFlavour = NullFlavour.TemporarilyUnavailable;

                medication2.Medicine = EReferral.CreateMedicine("23641011000036102", CodingSystem.AMT,"paracetamol 500 mg + codeine phosphate 30 mg tablet", null, null);
                medicationList.Add(medication2);

                medications.MedicationsList = medicationList;
            } 
            else
            {
                medications.ExclusionStatement = EReferral.CreateExclusionStatement();
                medications.ExclusionStatement.Value = NCTISGlobalStatementValues.NoneKnown;
            }

            return medications;
        }

        /// <summary>
        /// Creates and Hydrates the medical history section for the E-Referral.
        /// 
        /// Note: the data used within this method is intended as a guide and should be replaced.
        /// </summary>
        /// <returns>A Hydrated MedicalHistory object</returns>
        private static IMedicalHistoryWithoutExclusions CreateMedicalHistory(bool mandatorySectionsOnly)
        {
            var medicalHistory = EReferral.CreateMedicalHistory();

            if (!mandatorySectionsOnly)
            {
                var procedureList = new List<Procedure>();

                var procedure = EReferral.CreateProcedure();
                procedure.Comment = "Procedure Comment goes here.";
                procedure.ProcedureName = EReferral.CreateProcedureName("397956004", CodingSystem.SNOMED, "hip replacement", null, null);
                procedure.Start = new ISO8601DateTime(DateTime.Now.AddDays(-12));
                procedureList.Add(procedure);

                var prodcedure2 = EReferral.CreateProcedure();
                prodcedure2.Comment = "Procedure Comment goes here.";
                prodcedure2.ProcedureName = EReferral.CreateProcedureName("397956004", CodingSystem.SNOMED, "Procedure Comment", null, null);
                prodcedure2.Start = new ISO8601DateTime(DateTime.Now.AddDays(-40));
                procedureList.Add(prodcedure2);

                var medicalHistoryItems = new List<IMedicalHistoryItem>();
                var medicalHistoryItem = EReferral.CreateMedicalHistoryItem();
                medicalHistoryItem.DateTimeInterval = BaseCDAModel.CreateInterval(
                    new ISO8601DateTime(DateTime.Now, ISO8601DateTime.Precision.Day),
                    new ISO8601DateTime(DateTime.Now.AddDays(200), ISO8601DateTime.Precision.Day));
                medicalHistoryItem.ItemDescription = "Medical history item goes here";
                medicalHistoryItem.ItemComment = "Medical history Comment goes here";
                medicalHistoryItems.Add(medicalHistoryItem);

                var diagnosisList = new List<IProblemDiagnosis>();
                var diagnois = EReferral.CreateProblemDiagnosis();
                diagnois.Comment = "Problem/Diagnosis Comment goes here.";
                diagnois.ProblemDiagnosisIdentification = EReferral.CreateProblemDiagnosisIdentification("116223007", CodingSystem.SNOMED, "Comorbidity", "");
                diagnois.DateOfOnset = new ISO8601DateTime(DateTime.Now);
                diagnois.DateOfResolutionRemission = new ISO8601DateTime(DateTime.Now, ISO8601DateTime.Precision.Day);
                diagnosisList.Add(diagnois);

                medicalHistory.MedicalHistoryItems = medicalHistoryItems;
                medicalHistory.Procedures = procedureList;
                medicalHistory.ProblemDiagnosis = diagnosisList;
            } 

            return medicalHistory;
        }

        /// <summary>
        /// Creates and Hydrates the adverse substance reactions section for E-Referral.
        /// 
        /// Note: the data used within this method is intended as a guide and should be replaced.
        /// </summary>
        /// <returns>A Hydrated ReviewedAdverseSubstanceReactions object</returns>
        private static IAdverseReactions CreateAdverseReactions(bool mandatorySectionsOnly)
        {
            var adverseReactions = EReferral.CreateAdverseSubstanceReactions();

            if (!mandatorySectionsOnly)
            {
                adverseReactions.AdverseSubstanceReaction = new List<Reaction>
                                                            {
                                                                CreateAdverseReaction("90580008", "Fish"),
                                                                CreateAdverseReaction("90580001", "Peanuts")
                                                            };
            } else
            {
                adverseReactions.ExclusionStatement = EReferral.CreateExclusionStatement();
                adverseReactions.ExclusionStatement.Value = NCTISGlobalStatementValues.NoneKnown;
            }

            return adverseReactions;
        }

        /// <summary>
        /// Creates an adverse reaction.
        /// </summary>
        /// <param name="code">Code for the adverse reaction.</param>
        /// <param name="name">Name of the adverse reaction.</param>
        /// <returns></returns>
        private static Reaction CreateAdverseReaction(string code, string name)
        {
            Reaction reaction = EReferral.CreateReaction();

            reaction.SubstanceOrAgent = EReferral.CreateSubstanceOrAgent
                (
                    code,
                    CodingSystem.SNOMED,
                    name,
                    name,
                    null
                );

            reaction.ReactionEvent = EReferral.CreateReactionEvent();
            reaction.ReactionEvent.Manifestations = new List<ICodableText>
            {
                EReferral.CreateManifestation
                (
                    "271807003",
                    CodingSystem.SNOMED,
                    name + " Skin Rash", // Add the name to make it unique when multiple reactions are created
                    null,
                    null
                ),
                EReferral.CreateManifestation
                (
                    "271807001",
                    CodingSystem.SNOMED,
                    name + " Red Sore", // Add the name to make it unique when multiple reactions are created
                    null,
                    null
                )
            };

            return reaction;
        }


        private static List<RequestedService> CreateRequestedService(Boolean mandatorySectionsOnly)
        {
            var requestedServiceList = new List<RequestedService>();

            // Create Service Provider for a Person
            var requestedServicePerson = EReferral.CreateRequestedService();

            requestedServicePerson.RequestedServiceDescription = EReferral.CreateRequestedServiceDescription("39818891000056100", CodingSystem.NCTIS, "Requested Service Description", null, null);
            requestedServicePerson.ServiceBookingStatus = EventTypes.Definition;
            // Create Duration
            requestedServicePerson.SubjectOfCareInstructionDescription = "Subject Of Care Instruction Description";
            requestedServicePerson.RequestedServiceDateTime = new ISO8601DateTime(DateTime.Now.AddDays(4));
            // Create Person
            requestedServicePerson.ServiceProvider = CreateServiceProviderPerson(mandatorySectionsOnly);

            // Add to list
            requestedServiceList.Add(requestedServicePerson);

            // Create Service Provider for a Organisation
            var requestedServiceOrganisation = EReferral.CreateRequestedService();
            requestedServiceOrganisation.RequestedServiceDescription = EReferral.CreateRequestedServiceDescription("39818891000056100", CodingSystem.NCTIS, "Requested Service Description", null, null);
            requestedServiceOrganisation.ServiceBookingStatus = EventTypes.Intent;
            requestedServiceOrganisation.ServiceScheduled = new ISO8601DateTime(DateTime.Now);

            requestedServiceOrganisation.SubjectOfCareInstructionDescription = "Subject Of Care Instruction Description";
            requestedServiceOrganisation.RequestedServiceDateTime = new ISO8601DateTime(DateTime.Now.AddDays(4));
            requestedServiceOrganisation.ServiceProvider = CreateServiceProviderOrganisation(mandatorySectionsOnly);

            // Add to list
            requestedServiceList.Add(requestedServiceOrganisation);

            return requestedServiceList;
        }

        /// <summary>
        /// Creates and Hydrates a Service Provider Person
        /// 
        /// Note: the data used within this method is intended as a guide and should be replaced.
        /// </summary>
        /// <returns>A Hydrated IParticipationHealthProfessional object</returns>
        private static IParticipationServiceProvider CreateServiceProviderPerson(Boolean mandatorySectionsOnly)
        {
            var serviceProvider = EReferral.CreateServiceProvider();

            var participant = EReferral.CreateParticipantForServiceProvider();
            serviceProvider.Participant = participant;

            var personName = BaseCDAModel.CreatePersonName();
            personName.FamilyName = "Dr Jane Anderson";
            personName.NameUsages = new List<NameUsage> { NameUsage.Legal };

            participant.Person = EReferral.CreatePersonForServiceProvider();
            participant.Person.Identifiers = new List<Identifier> { BaseCDAModel.CreateHealthIdentifier(HealthIdentifierType.HPII, "8003610000001145") };

            participant.Person.Organisation = EReferral.CreateEmploymentOrganisation();
            participant.Person.Organisation.Name = "Bay Hill Hospital (ServiceProviderPerson)";
            participant.Person.Organisation.NameUsage = OrganisationNameUsage.Other;
            participant.Person.Organisation.Identifiers = new List<Identifier> { BaseCDAModel.CreateHealthIdentifier(HealthIdentifierType.HPIO, "8003620000045562") }; 

            participant.Person.PersonNames = new List<IPersonName> { personName };

            var electronicCommunicationDetail = EReferral.CreateElectronicCommunicationDetail(
                "0345754566",
                ElectronicCommunicationMedium.Telephone,
                ElectronicCommunicationUsage.WorkPlace);

            var electronicCommunicationDetail2 = EReferral.CreateElectronicCommunicationDetail(
                "04355754566",
                ElectronicCommunicationMedium.Mobile,
                ElectronicCommunicationUsage.PrimaryHome);

            participant.ElectronicCommunicationDetails = new List<ElectronicCommunicationDetail> { electronicCommunicationDetail, electronicCommunicationDetail2 };

            var address = EReferral.CreateAddress();
            address.AddressPurpose = AddressPurpose.Business;
            address.AustralianAddress = EReferral.CreateAustralianAddress();
            address.AustralianAddress.UnstructuredAddressLines = new List<string> { "1 Clinician Street test" };
            address.AustralianAddress.SuburbTownLocality = "Nehtaville";
            address.AustralianAddress.State = AustralianState.QLD;
            address.AustralianAddress.PostCode = "5555";
            address.AustralianAddress.DeliveryPointId = 32568931;

            participant.Addresses = new List<IAddress>
            {
                address, address
            };

            if (!mandatorySectionsOnly)
            {
                serviceProvider.Role = BaseCDAModel.CreateRole(Occupation.GeneralMedicalPractitioner);
            }
             else
            {
                serviceProvider.Role = BaseCDAModel.CreateRole(NullFlavour.Other);
            }

            return serviceProvider;
        }

        /// <summary>
        /// Creates and Hydrates a Service Provider Organisation
        /// 
        /// Note: the data used within this method is intended as a guide and should be replaced.
        /// </summary>
        /// <returns>A Hydrated IParticipationHealthProfessional object</returns>
        private static IParticipationServiceProvider CreateServiceProviderOrganisation(Boolean mandatorySectionsOnly)
        {
            var serviceProvider = EReferral.CreateServiceProvider();

            serviceProvider.Participant = EReferral.CreateParticipantForServiceProvider();

            serviceProvider.Participant.Organisation = EReferral.CreateOrganisation();
            serviceProvider.Participant.Organisation.Name = "Bay Hill Hospital (ServiceProviderOrganisation)";
            serviceProvider.Participant.Organisation.NameUsage = OrganisationNameUsage.Other;
            serviceProvider.Participant.Organisation.Identifiers = new List<Identifier> { BaseCDAModel.CreateHealthIdentifier(HealthIdentifierType.HPIO, "8003620000045562") }; 

            var electronicCommunicationDetail = EReferral.CreateElectronicCommunicationDetail(
                "0345754566",
                ElectronicCommunicationMedium.Telephone,
                ElectronicCommunicationUsage.WorkPlace);

            serviceProvider.Participant.ElectronicCommunicationDetails = new List<ElectronicCommunicationDetail> { electronicCommunicationDetail };

            var address = EReferral.CreateAddress();
            address.AddressPurpose = AddressPurpose.Residential;
            address.AustralianAddress = EReferral.CreateAustralianAddress();
            address.AustralianAddress.UnstructuredAddressLines = new List<string> { "1 Clinician Street" };
            address.AustralianAddress.SuburbTownLocality = "Nehtaville";
            address.AustralianAddress.State = AustralianState.QLD;
            address.AustralianAddress.PostCode = "5555";
            address.AustralianAddress.DeliveryPointId = 32568931;

            serviceProvider.Participant.Addresses = new List<IAddress> 
            { 
                address 
            };

            if (!mandatorySectionsOnly)
            {
               serviceProvider.Role = BaseCDAModel.CreateRole(Occupation.GeneralMedicalPractitioner);
            } 
              else
            {
               serviceProvider.Role = BaseCDAModel.CreateRole(NullFlavour.Other);
            }


            return serviceProvider;
        }

        /// <summary>
        /// Creates and Hydrates a Service Provider Person
        /// 
        /// Note: the data used within this method is intended as a guide and should be replaced.
        /// </summary>
        /// <returns>A Hydrated IParticipationHealthProfessional object</returns>
        private static IParticipationReferee CreateReferee(bool mandatorySectionsOnly)
        {
            var referee = EReferral.CreateReferee();

            var participant = EReferral.CreateParticipantForReferee();
            referee.Participant = participant;

            var personName = BaseCDAModel.CreatePersonName();
            personName.FamilyName = "Dr Jane Anderson";
            personName.NameUsages = new List<NameUsage> { NameUsage.Legal };

            participant.Person = EReferral.CreatePersonForServiceProvider();
            participant.Person.Identifiers = new List<Identifier> { BaseCDAModel.CreateHealthIdentifier(HealthIdentifierType.HPII, "8003610000001145") };

            participant.Person.Organisation = EReferral.CreateEmploymentOrganisation();
            participant.Person.Organisation.Name = "Bay Hill Hospital (RefereePerson)";
            participant.Person.Organisation.NameUsage = OrganisationNameUsage.Other;
            participant.Person.Organisation.Identifiers = new List<Identifier> { BaseCDAModel.CreateHealthIdentifier(HealthIdentifierType.HPIO, "8003620000045562") };

            participant.Person.PersonNames = new List<IPersonName> { personName };

            var electronicCommunicationDetail = EReferral.CreateElectronicCommunicationDetail(
                "0345754566",
                ElectronicCommunicationMedium.Telephone,
                ElectronicCommunicationUsage.WorkPlace);

            participant.ElectronicCommunicationDetails = new List<ElectronicCommunicationDetail> { electronicCommunicationDetail };

            var address = EReferral.CreateAddress();
            address.AddressPurpose = AddressPurpose.Business;
            address.AustralianAddress = EReferral.CreateAustralianAddress();
            address.AustralianAddress.UnstructuredAddressLines = new List<string> { "1 Clinician Street" };
            address.AustralianAddress.SuburbTownLocality = "Nehtaville";
            address.AustralianAddress.State = AustralianState.QLD;
            address.AustralianAddress.PostCode = "5555";
            address.AustralianAddress.DeliveryPointId = 32568931;

            if (!mandatorySectionsOnly)
            {
               referee.Role = BaseCDAModel.CreateRole(Occupation.GeneralMedicalPractitioner);
            }
              else
            {
               referee.Role = BaseCDAModel.CreateRole(NullFlavour.AskedButUnknown);
            }

            participant.Addresses = new List<IAddress>
            {
                address
            };

            return referee;
        }

        /// <summary>
        /// Creates and Hydrates a Service Provider Organisation
        /// 
        /// Note: the data used within this method is intended as a guide and should be replaced.
        /// </summary>
        /// <returns>A Hydrated IParticipationHealthProfessional object</returns>
        private static IParticipationReferee CreateRefereeOrganisation(bool mandatorySectionsOnly)
        {
            var serviceProvider = EReferral.CreateReferee();

            serviceProvider.Participant = EReferral.CreateParticipantForReferee();

            serviceProvider.Participant.Organisation = EReferral.CreateOrganisation();
            serviceProvider.Participant.Organisation.Name = "Bay Hill Hospital (RefereeOrganisation)";
            serviceProvider.Participant.Organisation.NameUsage = OrganisationNameUsage.Other;
            serviceProvider.Participant.Organisation.Identifiers = new List<Identifier> { BaseCDAModel.CreateHealthIdentifier(HealthIdentifierType.HPIO, "8003620000045562") }; 

            var electronicCommunicationDetail = EReferral.CreateElectronicCommunicationDetail(
                "0345754566",
                ElectronicCommunicationMedium.Telephone,
                ElectronicCommunicationUsage.WorkPlace);

            serviceProvider.Participant.ElectronicCommunicationDetails = new List<ElectronicCommunicationDetail> { electronicCommunicationDetail };

            var address = EReferral.CreateAddress();
            address.AddressPurpose = AddressPurpose.Residential;
            address.AustralianAddress = EReferral.CreateAustralianAddress();
            address.AustralianAddress.UnstructuredAddressLines = new List<string> { "1 Clinician Street" };
            address.AustralianAddress.SuburbTownLocality = "Nehtaville";
            address.AustralianAddress.State = AustralianState.QLD;
            address.AustralianAddress.PostCode = "5555";
            address.AustralianAddress.DeliveryPointId = 32568931;

            if (!mandatorySectionsOnly)
            {
                serviceProvider.Role = BaseCDAModel.CreateRole(Occupation.GeneralMedicalPractitioner);
            } 
              else
            {
                serviceProvider.Role = BaseCDAModel.CreateRole(NullFlavour.NegativeInfinity);
            }

            serviceProvider.Participant.Addresses = new List<IAddress> 
            { 
                address 
            };

            return serviceProvider;
        }

        /// <summary>
        /// Creates and Hydrates the diagnostic investigations substance reactions section.
        /// 
        /// Note: the data used within this method is intended as a guide and should be replaced.
        /// </summary>
        /// <returns>A Hydrated DiagnosticInvestigations object</returns>
        private static IDiagnosticInvestigations CreateDiagnosticInvestigations(Boolean mandatoryOnly)
        {
            IDiagnosticInvestigations diagnosticInvestigations = EReferral.CreateDiagnosticInvestigations();

            diagnosticInvestigations.ImagingExaminationResult = new List<IImagingExaminationResult>
                                                                {
                                                                    CreateImagingResults("Leg Image"),
                                                                    CreateImagingResults("Head Image")
                                                                };

            // Pathology test results
            diagnosticInvestigations.PathologyTestResult = new List<PathologyTestResult> 
                                                           {
                                                                CreatePathologyResults("Chemisty studies (set)", PitNameAndPath),
                                                                CreatePathologyResults("Blood studies (set)")
                                                           };

            // Requested Service
            diagnosticInvestigations.RequestedService = CreateRequestedService(mandatoryOnly);

            // Other Test Result 
            diagnosticInvestigations.OtherTestResult = new List<OtherTestResult>
                                                       {
                                                              CreateOtherTestResultAttachment(),
                                                              CreateOtherTestResultText()
                                                       };

            return diagnosticInvestigations;
        }

        /// <summary>
        /// Creates and hydrates the 'Other Test Result' Attachment section.
        /// </summary>
        /// <returns>A hydrated 'OtherTestResult' object.</returns>
        private static OtherTestResult CreateOtherTestResultAttachment()
        {
          var otherTestResult = BaseCDAModel.CreateOtherTestResult();
          otherTestResult.ReportName = BaseCDAModel.CreateCodableText(null, null, null, "Report with Attachment", null);
          otherTestResult.ReportStatus = ResultStatus.Interim;

          // Report ExternalData
          ExternalData report = BaseCDAModel.CreateExternalData();
          report.ExternalDataMediaType = MediaType.PDF;
          report.Path = ResultFileNameAndPath;
          report.Caption = "Path File";

          otherTestResult.ReportContent = BaseCDAModel.CreateEncapsulatedData();
          otherTestResult.ReportContent.ExternalData = report;
          otherTestResult.ReportDate = new ISO8601DateTime(DateTime.Now.AddDays(-2));

          return otherTestResult;
        }

        /// <summary>
        /// Creates and hydrates the 'Other Test Result' text section.
        /// </summary>
        /// <returns>A hydrated 'OtherTestResult' object.</returns>
        private static OtherTestResult CreateOtherTestResultText()
        {
          var otherTestResult = BaseCDAModel.CreateOtherTestResult();
          otherTestResult.ReportName = BaseCDAModel.CreateCodableText(null, null, null, "Report with Text", null);
          otherTestResult.ReportStatus = ResultStatus.Interim;

          otherTestResult.ReportContent = BaseCDAModel.CreateEncapsulatedData();
          otherTestResult.ReportContent.Text = "Report Content Text";
          otherTestResult.ReportDate = new ISO8601DateTime(DateTime.Now.AddDays(-2));

          return otherTestResult;
        }

        /// <summary>
        /// Creates and Hydrates the Imaging Results section 
        /// </summary>
        /// <returns>A Hydrated IImagingExaminationResultDischargeSummary object</returns>
        private static IImagingExaminationResult CreateImagingResults(string name)
        {
            // Image 1
            ExternalData image1 = EReferral.CreateExternalData();
            image1.ExternalDataMediaType = MediaType.JPEG;
            image1.Path = ImageFileNameAndPath;
            image1.Caption = "X-Ray";

            // Image 2
            ExternalData image2 = EReferral.CreateExternalData();
            image2.ExternalDataMediaType = MediaType.JPEG;
            image2.Path = ImageFileNameAndPath;
            image2.Caption = "X-Ray - Left Femur";

            // Image 3
            ExternalData image3 = EReferral.CreateExternalData();
            image3.ExternalDataMediaType = MediaType.JPEG;
            image3.Path = ImageFileNameAndPath;
            image3.Caption = "X-Ray - Right Arm";

            // Anatomical site 1
            AnatomicalSite anatomicalSite1 = CreateAnatomicalSite(
                "Femur Length",
                "50496004",
                CodingSystem.SNOMED,
                "left Femur",
                "left",
                new List<ExternalData> { image1, image2 }
                );

            // Anatomical site 2
            AnatomicalSite anatomicalSite2 = CreateAnatomicalSite(
                "Arm Length",
                "50496005",
                CodingSystem.SNOMED,
                "right Arm",
                "right",
                new List<ExternalData> { image3 }
                );

            // Imaging results 1
            IImagingResult imagingResult1 = EReferral.CreateImagingResult();
            imagingResult1.Comments = new List<string> { "Femur measured during ultrasound scan.", "Legs measured during ultrasound scan." };
            imagingResult1.ResultName = EReferral.CreateResultName("16310003", CodingSystem.SNOMED, "ultrasound scan", null, null);
            imagingResult1.ResultValue = EReferral.CreateResultValue();
            imagingResult1.ResultValue.ValueAsCodableText = EReferral.CreateCodableText("765676767", CodingSystem.SNOMED, "ultrasound scan description", null, null);
            imagingResult1.ResultValueStatus = HL7ObservationInterpretationNormality.Normal;
            imagingResult1.ResultValueReferenceRangeDetails = new List<ResultValueReferenceRangeDetail>
                                                                  {
                                                                      CreateReferenceRange("86228006", "normal range", "ml", "17", "13"), 
                                                                      CreateReferenceRange("86228007", "high range", "ml", "50", "100")
                                                                  };

            // Imaging results 2
            IImagingResult imagingResult2 = EReferral.CreateImagingResult();
            imagingResult2.Comments = new List<string> { "Neck measured during ultrasound scan.", "Neck measured during ultrasound scan." };
            imagingResult2.ResultName = EReferral.CreateResultName("16310040", CodingSystem.SNOMED, "neck ultrasound scan", null, null);
            imagingResult2.ResultValue = EReferral.CreateResultValue();
            imagingResult2.ResultValue.ValueAsCodableText = EReferral.CreateCodableText("77777", CodingSystem.SNOMED, "x-ray description", null, null);
            imagingResult2.ResultValueStatus = HL7ObservationInterpretationNormality.Normal;
            imagingResult2.ResultValueReferenceRangeDetails = new List<ResultValueReferenceRangeDetail>
                                                                  {
                                                                      CreateReferenceRange("86228006", "normal range", "kg", "15", "18"), 
                                                                      CreateReferenceRange("86228007", "high range", "kg", "60", "110")
                                                                  };

            // Imaging results 3
            IImagingResult imagingResult3 = EReferral.CreateImagingResult();
            imagingResult3.Comments = new List<string> { "Waist measured during ultrasound scan.", "Waist measured during ultrasound scan." };
            imagingResult3.ResultName = EReferral.CreateResultName("16310042", CodingSystem.SNOMED, "waist ultrasound scan", null, null);
            imagingResult3.ResultValue = EReferral.CreateResultValue();
            imagingResult3.ResultValue.ValueAsCodableText = EReferral.CreateCodableText("765676767", CodingSystem.SNOMED, "ultrasound scan description", null, null);
            imagingResult3.ResultValueStatus = HL7ObservationInterpretationNormality.Normal;
            imagingResult3.ResultValueReferenceRangeDetails = new List<ResultValueReferenceRangeDetail>
                                                                  {
                                                                      CreateReferenceRange("86228006", "normal range", "ml", "15", "18"), 
                                                                      CreateReferenceRange("86228007", "high range", "ml", "60", "110")
                                                                  };


            // Image 4
            ExternalData image4 = EReferral.CreateExternalData();
            image4.ExternalDataMediaType = MediaType.JPEG;
            image4.Path = ImageFileNameAndPath;
            image4.Caption = "4 X-Ray";

            // Image details 1
            IImageDetails imageDetails1 = EReferral.CreateImageDetails();
            imageDetails1.DateTime = new ISO8601DateTime(DateTime.Now);
            imageDetails1.SubjectPosition = "Supine";
            imageDetails1.SeriesIdentifier = BaseCDAModel.CreateInstanceIdentifier("1.2.3.1.2.2654654654654564", "Series Identifier");
            imageDetails1.Image = image4;

            // Image 5
            ExternalData image5 = EReferral.CreateExternalData();
            image5.ExternalDataMediaType = MediaType.JPEG;
            image5.Path = ImageFileNameAndPath;
            image5.Caption = "5 X-Ray";

            // Image details 2
            IImageDetails imageDetails2 = EReferral.CreateImageDetails();
            imageDetails2.DateTime = new ISO8601DateTime(DateTime.Now);
            imageDetails2.SubjectPosition = "Sublime";
            imageDetails2.SeriesIdentifier = BaseCDAModel.CreateInstanceIdentifier("1.2.3.1.2.2654654654654564", "Series Identifier");
            imageDetails2.Image = image5;

            // Image 6
            ExternalData image6 = EReferral.CreateExternalData();
            image6.ExternalDataMediaType = MediaType.JPEG;
            image6.Path = ImageFileNameAndPath;
            image6.Caption = "6 X-Ray";

            // Image details 3
            IImageDetails imageDetails3 = EReferral.CreateImageDetails();
            imageDetails3.DateTime = new ISO8601DateTime(DateTime.Now);
            imageDetails3.SubjectPosition = "Head";
            imageDetails3.SeriesIdentifier = BaseCDAModel.CreateInstanceIdentifier("1.2.3.1.2.2654654654654564", "Series Identifier");
            imageDetails3.Image = image6;

            // Imaging result group 1
            IImagingResultGroup imagingResultGroup1 = EReferral.CreateImagingResultGroup();
            imagingResultGroup1.Results = new List<IImagingResult>
                                              {
                                                  imagingResult1 
                                              };

            imagingResultGroup1.AnatomicalSite = anatomicalSite1;
            imagingResultGroup1.ResultGroupName = BaseCDAModel.CreateResultGroupName
                (
                    "268445003",
                    CodingSystem.SNOMED,
                    "ultrasound scan - obstetric",
                    null,
                    null
                );

            // Imaging result group 2
            IImagingResultGroup imagingResultGroup2 = EReferral.CreateImagingResultGroup();
            imagingResultGroup2.Results = new List<IImagingResult>
                                              {
                                                  imagingResult3
                                              };
            imagingResultGroup2.AnatomicalSite = anatomicalSite2;
            imagingResultGroup2.ResultGroupName = BaseCDAModel.CreateResultGroupName
                (
                    "268445033",
                    CodingSystem.SNOMED,
                    "ultrasound scan - other",
                    null,
                    null
                );


            // Imaging examination result 1
            ImagingExaminationResult imagingExaminationResult = EReferral.CreateImagingExaminationResult();
            imagingExaminationResult.ClinicalInformationProvided = "Patient pregnant. Confirm dates. Estimate from LNMP 18 weeks.";
            imagingExaminationResult.ExaminationRequestDetails = new List<IImagingExaminationRequest>
                                                                     {
                                                                         CreateImagingExaminationRequest("A/U Obstetric - Dating", imageDetails1),
                                                                         CreateImagingExaminationRequest("A/U Skin - Stuff", new List<IImageDetails> { imageDetails2, imageDetails3 })
                                                                     };
            imagingExaminationResult.ExaminationResultName = EReferral.CreateExaminationResultName("1234", CodingSystem.METEOR, name, name, null);
            imagingExaminationResult.Findings = "Normal obstetric ultrasound with foetal biometry indicating getational age of 18W0D.";
            imagingExaminationResult.Modality = EReferral.CreateModality("16310003", CodingSystem.SNOMED, "ultrasound", null, null);
            imagingExaminationResult.ResultDateTime = new ISO8601DateTime(DateTime.Now.AddDays(-2));
            imagingExaminationResult.ExaminationResultStatus = ResultStatus.Final;
            imagingExaminationResult.ExaminationResultRepresentation = "ResultRepresentation";
            imagingExaminationResult.ResultGroup = new List<IImagingResultGroup>
                                                       {
                                                           imagingResultGroup1, imagingResultGroup2
                                                       };

            return imagingExaminationResult;
        }


        private static PathologyTestResult CreatePathologyResults(string name, string simpleNarrativePath)
        {
            // Pathology test result
            var pathologyTestResult = EReferral.CreatePathologyTestResult();

            if (!simpleNarrativePath.IsNullOrEmptyWhitespace()) pathologyTestResult.xPreNarrative = File.ReadAllText(simpleNarrativePath);

            pathologyTestResult.TestResultDateTime = new ISO8601DateTime(DateTime.Now.AddDays(-2));
            pathologyTestResult.OverallTestResultStatus = ResultStatus.Final;

            var specimenDetail = EReferral.CreateSpecimenDetail();
            specimenDetail.CollectionDateTime = new ISO8601DateTime(DateTime.Now.AddDays(-2));

            pathologyTestResult.PathologyTestSpecimenDetail = new List<SpecimenDetail> { specimenDetail };

            pathologyTestResult.TestResultName = EReferral.CreateCodableText("18719-5", CodingSystem.LOINC, name, null, null);

            return pathologyTestResult;
        }


        /// <summary>
        /// Creates and Hydrates the Pathology Results section 
        /// </summary>
        /// <returns>A Hydrated PathologyTestResult object</returns>
        private static PathologyTestResult CreatePathologyResults(string name)
        {
            // Image 1
            ExternalData image1 = EReferral.CreateExternalData();
            image1.ExternalDataMediaType = MediaType.JPEG;
            image1.Path = ImageFileNameAndPath;
            image1.Caption = "X-Ray";

            // Image 1
            ExternalData image2 = EReferral.CreateExternalData();
            image2.ExternalDataMediaType = MediaType.JPEG;
            image2.Path = ImageFileNameAndPath;
            image2.Caption = "X-Ray";

            // Report 1
            ExternalData report1 = EReferral.CreateExternalData();
            report1.ExternalDataMediaType = MediaType.PDF;
            report1.Path = ResultFileNameAndPath;
            report1.Caption = "Results";

            // Anatomical site 1
            AnatomicalSite anatomicalSite1 = CreateAnatomicalSite(
                "Femur Length",
                "50496004",
                CodingSystem.SNOMED,
                "left Femur",
                "left",
                new List<ExternalData> { image1 }
                );

            // Anatomical site 2
            AnatomicalSite anatomicalSite2 = CreateAnatomicalSite(
                "Cubital fossa",
                "50496076",
                CodingSystem.SNOMED,
                "right Femur",
                "right",
                null
                );

            // Anatomical site 3
            AnatomicalSite anatomicalSite3 = CreateAnatomicalSite(
                "Rotia vossa",
                "50496080",
                CodingSystem.SNOMED,
                "left Arm",
                "left",
                null
                );

            // Specimen detail 1
            SpecimenDetail specimenDetail1 = EReferral.CreateSpecimenDetail();
            specimenDetail1.AnatomicalSite = new List<AnatomicalSite>
                                                 {
                                                     anatomicalSite1
                                                 };
            specimenDetail1.CollectionDateTime = new ISO8601DateTime(DateTime.Now.AddDays(-22));
            specimenDetail1.CollectionProcedure = EReferral.CreateCollectionProcedure("82078001", CodingSystem.SNOMED, "blood draw", null, null);
            specimenDetail1.CollectionSetting = "Ward 1A";
            specimenDetail1.ContainerIdentifier = BaseCDAModel.CreateInstanceIdentifier("1.2.36.45364", "CNH45218964");
            specimenDetail1.ParentSpecimenIdentifier = BaseCDAModel.CreateInstanceIdentifier("1.2.36.45364", EReferral.CreateGuid());
            specimenDetail1.SpecimenDescription = "physicalDetails-Description";
            specimenDetail1.PhysicalDetails = new List<PhysicalDetails> {CreatePhysicalDetails("6", "ml")};
            specimenDetail1.ReceivedDateTime = new ISO8601DateTime(DateTime.Now);
            specimenDetail1.SamplingPreconditions = EReferral.CreateSamplingPreconditions("16985007", CodingSystem.SNOMED, "fasting", null, null);
            specimenDetail1.SpecimenIdentifier = BaseCDAModel.CreateInstanceIdentifier("1.2.36.45364", EReferral.CreateGuid());
            specimenDetail1.SpecimenTissueType = EReferral.CreateSpecimenTissueType("specimenDetail-SpecimenTissueType-someCode", CodingSystem.SNOMED, "DisplayName", null, null);

            // Specimen detail 2
            SpecimenDetail specimenDetail2 = EReferral.CreateSpecimenDetail();
            specimenDetail2.AnatomicalSite = new List<AnatomicalSite>
                                                 {
                                                     anatomicalSite2, anatomicalSite3
                                                 };
            specimenDetail2.CollectionDateTime = new ISO8601DateTime(DateTime.Now.AddDays(-12));
            specimenDetail2.CollectionProcedure = EReferral.CreateCollectionProcedure("82078002", CodingSystem.SNOMED, "Urine sample", null, null);
            specimenDetail2.CollectionSetting = "Ward 3B";
            specimenDetail2.ContainerIdentifier = BaseCDAModel.CreateInstanceIdentifier("1.2.36.45364", "AZH45218964");
            specimenDetail2.ParentSpecimenIdentifier = BaseCDAModel.CreateInstanceIdentifier("1.2.36.45364", EReferral.CreateGuid());
            specimenDetail2.SpecimenDescription = "Urine sample";
            specimenDetail2.PhysicalDetails = new List<PhysicalDetails> {CreatePhysicalDetails("20", "kg")};
            specimenDetail2.ReceivedDateTime = new ISO8601DateTime(DateTime.Now);
            specimenDetail2.SamplingPreconditions = EReferral.CreateSamplingPreconditions("16985007", CodingSystem.SNOMED, "fasting", null, null);
            specimenDetail2.SpecimenIdentifier = BaseCDAModel.CreateInstanceIdentifier("1.2.36.45364", EReferral.CreateGuid());

            // Specimen detail 3
            SpecimenDetail specimenDetail3 = EReferral.CreateSpecimenDetail();
            specimenDetail3.CollectionDateTime = new ISO8601DateTime(DateTime.Now.AddDays(-12));
            specimenDetail3.CollectionProcedure = EReferral.CreateCollectionProcedure("82078002", CodingSystem.SNOMED, "Urine sample", null, null);
            specimenDetail3.CollectionSetting = "Ward 3B";
            specimenDetail3.ContainerIdentifier = BaseCDAModel.CreateInstanceIdentifier("1.2.36.45364", "AZH45218964");
            specimenDetail3.ParentSpecimenIdentifier = BaseCDAModel.CreateInstanceIdentifier("1.2.36.45364", EReferral.CreateGuid());
            specimenDetail3.SpecimenDescription = "Urine sample";
            specimenDetail3.PhysicalDetails = new List<PhysicalDetails> {CreatePhysicalDetails("20", "kg")};
            specimenDetail3.ReceivedDateTime = new ISO8601DateTime(DateTime.Now);
            specimenDetail3.SamplingPreconditions = EReferral.CreateSamplingPreconditions("16985007", CodingSystem.SNOMED, "fasting", null, null);
            specimenDetail3.SpecimenIdentifier = BaseCDAModel.CreateInstanceIdentifier("1.2.36.45364", EReferral.CreateGuid());

            // Test result 1
            ITestResult testResult1 = EReferral.CreateTestResult();
            testResult1.Comments = new List<string> { "Sodium test result comments", "More comments", "Another comment" };
            testResult1.ReferenceRangeGuidance = "Reference range guidance comments for Sodium; eg. the quantity should be between the high and low values";
            testResult1.ResultName = EReferral.CreateResultName("2951-2", CodingSystem.SNOMED, "Sodium", null, null);
            testResult1.ResultStatus = ResultStatus.Interim;
            testResult1.ResultValue = EReferral.CreateResultValue();
            testResult1.ResultValue.ValueAsQuantity = EReferral.CreateQuantity();
            testResult1.ResultValue.ValueAsQuantity.Value = "12";
            testResult1.ResultValue.ValueAsQuantity.Units = "ml";
            testResult1.ResultValueStatus = HL7ObservationInterpretationNormality.Normal;
            testResult1.ResultValueReferenceRangeDetails = new List<ResultValueReferenceRangeDetail>
                                                               {
                                                                   CreateReferenceRange("86228007", "high range", "ml", "50", "100"), 
                                                                   CreateReferenceRange("86228008", "low range", "ml", "10", "20"), 
                                                               };

            // Test result 2
            ITestResult testResult2 = EReferral.CreateTestResult();
            testResult2.Comments = new List<string> { "Blood test result comments", "More comments", "Another comment" };
            testResult2.ReferenceRangeGuidance = "Reference range guidance comments for blood; eg. the quantity should be between the high and low values";
            testResult2.ResultName = EReferral.CreateResultName("2951-2", CodingSystem.SNOMED, "Blood", null, null);
            testResult2.ResultStatus = ResultStatus.Final;
            testResult2.ResultValue = EReferral.CreateResultValue();
            testResult2.ResultValue.ValueAsQuantity = EReferral.CreateQuantity();
            testResult2.ResultValue.ValueAsQuantity.Value = "5";
            testResult2.ResultValue.ValueAsQuantity.Units = "km";
            testResult2.ResultValueStatus = HL7ObservationInterpretationNormality.Normal;
            testResult2.ResultValueReferenceRangeDetails = new List<ResultValueReferenceRangeDetail>
                                                               {
                                                                   CreateReferenceRange("86228007", "high range", "ml", "50", "100"), 
                                                                   CreateReferenceRange("86228008", "low range", "ml", "10", "20"), 
                                                               };

            // Test result 3
            ITestResult testResult3 = EReferral.CreateTestResult();
            testResult3.Comments = new List<string> { "Heart test result comments", "More comments", "Another comment" };
            testResult3.ReferenceRangeGuidance = "Reference range guidance comments for heart; eg. the quantity should be between the high and low values";
            testResult3.ResultName = EReferral.CreateResultName("2951-2", CodingSystem.SNOMED, "Blood", null, null);
            testResult3.ResultStatus = ResultStatus.Final;
            testResult3.ResultValue = EReferral.CreateResultValue();
            testResult3.ResultValue.ValueAsQuantity = EReferral.CreateQuantity();
            testResult3.ResultValue.ValueAsQuantity.Value = "5";
            testResult3.ResultValue.ValueAsQuantity.Units = "km";
            testResult3.ResultValueStatus = HL7ObservationInterpretationNormality.Normal;
            testResult3.ResultValueReferenceRangeDetails = new List<ResultValueReferenceRangeDetail>
                                                               {
                                                                   CreateReferenceRange("86228007", "high range", "psi", "2", "150"), 
                                                                   CreateReferenceRange("86228008", "low range", "psi", "15", "200"), 
                                                               };


            // Test request 1
            ITestRequest testRequest1 = EReferral.CreateTestRequest();
            testRequest1.LaboratoryTestResultIdentifier = BaseCDAModel.CreateInstanceIdentifier(BaseCDAModel.CreateGuid(), "Laboratory Test Result Identifier");
            testRequest1.TestsRequested = new List<ICodableText>
                                              {
                                                  EReferral.CreateTestRequestName("275707000", CodingSystem.SNOMED, "blood serum tests"),
                                                  EReferral.CreateTestRequestName("275707001", CodingSystem.SNOMED, "blood pressure tests"),
                                              };

            // Test request 2
            ITestRequest testRequest2 = EReferral.CreateTestRequest();
            testRequest2.LaboratoryTestResultIdentifier = BaseCDAModel.CreateInstanceIdentifier(BaseCDAModel.CreateGuid(), "Laboratory Test Result Identifier");
            testRequest2.TestsRequested = new List<ICodableText>
                                              {
                                                  EReferral.CreateTestRequestName("275707005", CodingSystem.SNOMED, "heart serum tests"),
                                                  EReferral.CreateTestRequestName("275707006", CodingSystem.SNOMED, "heart pressure tests"),
                                              };

            // Test result group 1
            ITestResultGroup testResultGroup1 = EReferral.CreateTestResultGroup();
            testResultGroup1.Results = new List<ITestResult> { testResult1, testResult2 };
            testResultGroup1.ResultGroupSpecimenDetail = specimenDetail1;
            testResultGroup1.ResultGroupName = BaseCDAModel.CreateResultGroupName
                (
                    "18719-5",
                    CodingSystem.LOINC,
                    "Chemistry Studies (Set)",
                    null,
                    null
                );

            // Test result group 2
            ITestResultGroup testResultGroup2 = EReferral.CreateTestResultGroup();
            testResultGroup2.Results = new List<ITestResult> { testResult3 };
            testResultGroup2.ResultGroupSpecimenDetail = specimenDetail2;
            testResultGroup2.ResultGroupName = BaseCDAModel.CreateResultGroupName(NullFlavour.Masked);


            // Pathology test result
            PathologyTestResult pathologyTestResult = EReferral.CreatePathologyTestResult();
            pathologyTestResult.Comment = "testResultGroup-Comment";
            pathologyTestResult.Conclusion = "testResultGroup-Conclusion";
            pathologyTestResult.TestResultDateTime = new ISO8601DateTime(DateTime.Now.AddDays(-2));
            pathologyTestResult.PathologicalDiagnosis = new List<ICodableText>
                                                            {
                                                                EReferral.CreatePathologicalDiagnois("17621005", CodingSystem.SNOMED, "normal", null, null),
                                                                EReferral.CreatePathologicalDiagnois("17621002", CodingSystem.SNOMED, "abnormal", null, null)
                                                            };
            pathologyTestResult.OverallTestResultStatus = ResultStatus.Final;
            pathologyTestResult.ClinicalInformationProvided = "Hepatitus";
            pathologyTestResult.DiagnosticService = DiagnosticServiceSectionID.Chemistry;
            pathologyTestResult.TestRequestDetails = new List<ITestRequest>
                                                         {
                                                             testRequest1, testRequest2
                                                         };
            pathologyTestResult.PathologyTestSpecimenDetail = new List<SpecimenDetail> { specimenDetail3 };
            pathologyTestResult.TestResultName = EReferral.CreateCodableText("18719-5", CodingSystem.LOINC, name, null, null);
            pathologyTestResult.TestResultRepresentation = report1;
            pathologyTestResult.PathologyTestResultGroup = new List<ITestResultGroup>
                                                               {
                                                                   testResultGroup1, testResultGroup2
                                                               };

            return pathologyTestResult;
        }

        /// <summary>
        /// Creates and Hydrates a IImagingExaminationRequest object
        /// </summary>
        /// <param name="examinationRequestName">The ExaminationRequestName</param>
        /// <param name="imageDetails">List of ImageDetails</param>
        /// <returns>A Hydrated IImagingExaminationRequest object</returns>
        private static IImagingExaminationRequest CreateImagingExaminationRequest(String examinationRequestName, List<IImageDetails> imageDetails)
        {
            var imagingExaminationRequest = EventSummary.CreateImagingExaminationRequest();
            imagingExaminationRequest.ExaminationRequestedName = new List<String>
                                                                     {
                                                                         examinationRequestName, "another name"
                                                                     };

            if (imageDetails != null && imageDetails.Any())
            {
                int index = 0;
                foreach (IImageDetails imageDetail in imageDetails)
                {
                    imageDetail.ImageViewName = EventSummary.CreateImageViewName(null, null, null, index + 1 + " X-Ray - " + examinationRequestName, null);
                    imageDetail.Image.Caption = imageDetail.ImageViewName.OriginalText;
                    index++;
                }

                imagingExaminationRequest.ImageDetails = imageDetails;
            }

            imagingExaminationRequest.ReportIdentifier = BaseCDAModel.CreateInstanceIdentifier(BaseCDAModel.CreateGuid(), "3355552BHU-23.3");
            imagingExaminationRequest.StudyIdentifier = imagingExaminationRequest.StudyIdentifier = BaseCDAModel.CreateInstanceIdentifier(BaseCDAModel.CreateGuid(), "Accession Number Group: 0008  Element: 0050");

            return imagingExaminationRequest;
        }

        /// <summary>
        /// Creates and Hydrates a IImagingExaminationRequest object
        /// </summary>
        /// <param name="examinationRequestName">The ExaminationRequestName</param>
        /// <param name="imageDetails">The imageDetails</param>
        /// <returns>A Hydrated IImagingExaminationRequest object</returns>
        private static IImagingExaminationRequest CreateImagingExaminationRequest(String examinationRequestName, IImageDetails imageDetails)
        {
            return CreateImagingExaminationRequest(examinationRequestName, new List<IImageDetails> { imageDetails });
        }

        #endregion
    }
}
