/*
 * Copyright 2013 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.Globalization;
using System.Linq;
using System.Runtime.Serialization;
using System.Xml;
using CDA.Generator.Common.CDAModel.Entities;
using CDA.Generator.Common.Common.Time;
using CDA.Generator.Common.Common.Time.Enum;
using CDA.Generator.Common.SCSModel.ConsolidatedView.Entities;
using CDA.Generator.Common.SCSModel.Interfaces;
using CDA.Generator.Common.SCSModel.PhysicalMeasurements.Interfaces;
using JetBrains.Annotations;
using Nehta.HL7.CDA;
using Nehta.VendorLibrary.CDA.Common.Enums;
using Nehta.VendorLibrary.CDA.Generator.Enums;
using Nehta.VendorLibrary.CDA.Generator.Helper;
using Nehta.VendorLibrary.CDA.SCSModel;
using Nehta.VendorLibrary.CDA.SCSModel.Common;
using Nehta.VendorLibrary.CDA.SCSModel.Common.Entities;
using Nehta.VendorLibrary.CDA.SCSModel.DischargeSummary.Interfaces;
using Nehta.VendorLibrary.Common;
using Entitlement = Nehta.VendorLibrary.CDA.SCSModel.Common.Entitlement;
using IServiceProvider = Nehta.VendorLibrary.CDA.SCSModel.IServiceProvider;
using Participant = Nehta.VendorLibrary.CDA.SCSModel.Common.Participant;

namespace Nehta.VendorLibrary.CDA.Common
{
    /// <summary>
    /// This class encapsulates all the properties that are common between the various CDA documents
    /// </summary>
    [Serializable]
    [DataContract]
    public class BaseCDAModel
    {
        #region Constants
        private const String HEALTH_IDENTIFIER_QUALIFIER = "1.2.36.1.2001.1003.0.";
        private const String EXTERNAL_HEALTH_IDENTIFIER_QUALIFIER = "1.2.36.1.2001.1005.41.";

        #endregion

        #region Properties

        /// <summary>
        /// The status of this CDA document
        /// </summary>
        [CanBeNull]
        [DataMember]
        public ISO8601DateTime DocumentCreationTime { get; set; }

        /// <summary>
        /// The status of this CDA document
        /// </summary>
        [CanBeNull]
        [DataMember]
        public DocumentStatus DocumentStatus { get; set; }

        /// <summary>
        /// Indicates if the CDA document should include a logo
        /// </summary>
        [CanBeNull]
        [DataMember]
        public Boolean IncludeLogo { get; set; }

        /// <summary>
        /// This is optional field, this will copy the logo file to the output directory.
        /// If LogoPath is not populated and IncludeLogo is true the assumption is the user will 
        /// manually copy the image file to the output directory.
        /// </summary>
        [CanBeNull]
        [DataMember]
        public string LogoPath { get; set; }

        /// <summary>
        /// Show Administration Observations in the Narrative
        /// NOTE: This currently fails schematron V 3.0.4.0
        ///       This is a valid only for point to point usage
        /// </summary>
        [CanBeNull]
        [DataMember]
        public Boolean? ShowAdministrativeObservations { get; set; }
        #endregion

        #region static methods

        /// <summary>
        /// Creates a legal authenticator
        /// </summary>
        /// <returns>An Authenticator Object</returns>
        public static IParticipationLegalAuthenticator CreateLegalAuthenticator()
        {
            return new Participation();
        }

        /// <summary>
        /// Creates an authenticator
        /// </summary>
        /// <returns>An Authenticator Object</returns>
        public static IParticipationLegalAuthenticator CreateAuthenticator()
        {
            return new Participation();
        }

        /// <summary>
        /// Creates an information recipient
        /// </summary>
        /// <returns>Recipient</returns>
        public static IParticipationInformationRecipient CreateInformationRecipient()
        {
            return new Participation();
        }

        /// <summary>
        /// Creates a person that is constrained down to an IPersonName
        /// </summary>
        /// <returns>(IPersonName) person</returns>
        public static IPersonName CreatePersonName()
        {
            return new PersonName();
        }

        /// <summary>
        /// Creates a person constrained for a Person With Organisation
        /// </summary>
        /// <returns>(IPerson) Person With Organisation</returns>
        public static IPersonWithOrganisation CreatePersonWithOrganisation()
        {
            return new Person();
        }

        /// <summary>
        /// Creates a person constrained for a Person Consumer
        /// </summary>
        /// <returns>(IPerson) Person With Organisation</returns>
        public static IPersonConsumer CreatePersonConsumer()
        {
            return new Person();
        }

        /// <summary>
        /// Creates a person constrained for a IPersonWithRelationship
        /// </summary>
        /// <returns>(IPersonWithRelationship) Person With Relationship</returns>
        public static IPersonWithRelationship CreatePersonWithRelationship()
        {
            return new Person();
        }
        
        /// <summary>
        /// Creates a address that is constrained down to an IAddress
        /// </summary>
        /// <returns>(IAddress) address</returns>
        public static IAddress CreateAddress()
        {
            return new Address();
        }

        /// <summary>
        /// Creates an international address
        /// </summary>
        /// <returns>InternationalAddress</returns>
        public static InternationalAddress CreateInternationalAddress()
        {
            return new InternationalAddress();
        }

        /// <summary>
        /// Creates a recipient
        /// </summary>
        /// <returns>A Recipient Object</returns>
        public static IInformationRecipient CreateRecipient()
        {
            return new Participant();
        }

        /// <summary>
        /// Creates an ElectronicCommunicationDetail Object
        /// </summary>
        /// <param name="address">Address</param>
        /// <param name="medium">Medium; E.g. Email</param>
        /// <param name="usage">Usage; E.g. Home</param>
        /// <returns>An ElectronicCommunicationDetail Object</returns>
        public static ElectronicCommunicationDetail CreateElectronicCommunicationDetail(string address, ElectronicCommunicationMedium medium, ElectronicCommunicationUsage usage)
        {
            return new ElectronicCommunicationDetail
            {
                Address = address,
                Medium = medium,
                Usage = new List<ElectronicCommunicationUsage> { usage }
            };
        }

        /// <summary>
        /// Creates an ElectronicCommunicationDetail Object
        /// </summary>
        /// <param name="address">Address</param>
        /// <param name="medium">Medium; E.g. Email</param>
        /// <param name="usage">Usage; E.g. Home</param>
        /// <returns>An ElectronicCommunicationDetail Object</returns>
        public static ElectronicCommunicationDetail CreateElectronicCommunicationDetail(string address, ElectronicCommunicationMedium medium, List<ElectronicCommunicationUsage> usage)
        {
            return new ElectronicCommunicationDetail
            {
                Address = address,
                Medium = medium,
                Usage = usage
            };
        }

        /// <summary>
        /// Creates an ElectronicCommunicationDetail Object
        /// </summary>
        /// <returns>An ElectronicCommunicationDetail Object</returns>
        public static ElectronicCommunicationDetail CreateElectronicCommunicationDetail()
        {
            return new ElectronicCommunicationDetail();
        }

        /// <summary>
        /// Creates an Australian Address
        /// </summary>
        /// <returns>(AustralianAddress) Australian Address</returns>
        public static AustralianAddress CreateAustralianAddress()
        {
            return new AustralianAddress();
        }

        
        /// <summary>
        /// Creates a custodian
        /// </summary>
        /// <returns>(IParticipationCustodian) Custodian</returns>
        public static IParticipationCustodian CreateCustodian()
        {
            return new Participation();
        }

        /// <summary>
        /// Creates a custodian
        /// </summary>
        /// <returns>(Custodian) Custodian</returns>
        public static ICustodian CreateParticipantCustodian()
        {
            return new Participant();
        }

        /// <summary>
        /// Creates a participation constrained down to an IParticipationSubjectOfCare
        /// </summary>
        /// <returns>(IParticipationSubjectOfCare) Participation</returns>
        public static IParticipationSubjectOfCare CreateSubjectOfCare()
        {
            return new Participation();
        }

        /// <summary>
        /// Creates a participation constrained down to an IParticipationDocumentAuthor
        /// </summary>
        /// <returns>(IParticipationDocumentAuthor) Participation</returns>
        public static IParticipationDocumentAuthor CreateAuthor()
        {
            return new Participation();
        }

        /// <summary>
        /// Creates a participation constrained down to an ISubjectOfCare
        /// </summary>
        /// <returns>(ISubjectOfCare) Participation</returns>
        public static ISubjectOfCare CreateParticipantForSubjectOfCare()
        {
            return new Participant();
        }

        
        /// <summary>
        /// Creates a participation constrained down to an ISubjectOfCare
        /// </summary>
        /// <returns>(ISubjectOfCare) Participation</returns>
        public static ILegalAuthenticator CreateParticipantForLegalAuthenticator()
        {
            return new Participant();
        }

       /// <summary>
        /// Creates a person constrained down to an IPersonSubjectOfCare
        /// </summary>
        /// <returns>(IPersonSubjectOfCare) Person</returns>
        public static IPersonSubjectOfCare CreatePersonForSubjectOfCare()
        {
            return new Person();
        }

        /// <summary>
        /// Creates a person constrained down to an IPerson
        /// </summary>
        /// <returns>(IPerson) Person</returns>
        public static IPerson CreatePerson()
        {
            return new Person();
        }

        /// <summary>
        /// Creates a person constrained down to an IPerson
        /// </summary>
        /// <returns>(IPerson) Person</returns>
        public static IPersonPrescriber CreatePersonPrescriber()
        {
            return new Person();
        }


        /// <summary>
        /// Creates a person constrained down to an IInformationRecipient
        /// </summary>
        /// <returns>(IInformationRecipient) Participant</returns>
        public static  IInformationRecipient CreateParticipantForInformationRecipient()
        {
            return new Participant();
        }

        /// <summary>
        /// Create Participant for a IServiceRequester  
        /// </summary>
        /// <returns>(IServiceRequester) Participant</returns>
        public static IServiceRequester CreateParticipantForServiceRequester()
        {
          return new Participant();
        }

        /// <summary>
        /// Create Participation for a IParticipationServiceProvider
        /// </summary>
        /// <returns>(IParticipationServiceRequester) Participation</returns>
        public static IParticipationServiceRequester CreateServiceRequester()
        {
          return new Participation();
        }

        /// <summary>
        /// Create Participant for a ServiceProvider   
        /// </summary>
        /// <returns>(IServiceProvider) Participant</returns>
        public static IServiceProvider CreateParticipantForServiceProvider()
        {
          return new Participant();
        }

        /// <summary>
        /// Create Participation for a IParticipationServiceProvider
        /// </summary>
        /// <returns>(IParticipationServiceProvider) Participation</returns>
        public static IParticipationServiceProvider CreateServiceProvider()
        {
          return new Participation();
        }


        /// <summary>
        /// Creates a Participant constrained down to an IAuthorHealthcareProvider
        /// </summary>
        /// <returns>(IAuthorHealthcareProvider) Participant</returns>
        public static IAuthorHealthcareProvider CreateParticipantForAuthorHealthcareProvider()
        {
            return new Participant();
        }

        /// <summary>
        /// Creates a Participant constrained down to an IAuthorNonHealthcareProvider
        /// </summary>
        /// <returns>(IAuthorNonHealthcareProvider) Participant</returns>
        public static IAuthorNonHealthcareProvider CreateParticipantForAuthorNonHealthcareProvider()
        {
            return new Participant();
        }

        /// <summary>
        /// Creates a Participant constrained down to an IHealthcareFacility
        /// </summary>
        /// <returns>(Participant) IAuthorNonHealthcareProvider</returns>
        public static IHealthcareFacility CreateParticipantForHealthcareFacility()
        {
            return new Participant();
        }

        /// <summary>
        /// Creates a Participant constrained down to an IInformationProviderHealthcareProvider
        /// </summary>
        /// <returns>(Participant) IInformationProviderHealthcareProvider</returns>
        public static IInformationProviderHealthcareProvider CreateParticipantForInformationProviderHealthcareProvider()
        {
            return new Participant();
        }

        /// <summary>
        /// Creates a Participation constrained down to an IInformationProviderHealthcareProvider
        /// </summary>
        /// <returns>(Participation) IInformationProviderHealthcareProvider</returns>
        public static IParticipationAuthorHealthcareProvider CreateAuthorHealthcareProvider()
        {
            return new Participation();
        }

        /// <summary>
        /// Creates a Participation constrained down to an IParticipationAuthorNonHealthcareProvider
        /// </summary>
        /// <returns>(Participation) IParticipationAuthorNonHealthcareProvider</returns>
        public static IParticipationAuthorNonHealthcareProvider CreateAuthorNonHealthcareProvider()
        {
          return new Participation();
        }

        /// <summary>
        /// Creates a Person constrained down to an IPersonHealthcareProvider
        /// </summary>
        /// <returns>(Person) IPersonHealthcareProvider</returns>
        public static IPersonHealthcareProvider CreatePersonHealthcareProvider()
        {
            return new Person();
        }
        /// <summary>
        /// Creates a Person constrained down to an IPerson
        /// </summary>
        /// <returns>(Person) IPerson</returns>
        public static IPerson CreatePersonNonHealthcareProvider()
        {
            return new Person();
        }

        /// <summary>
        /// Creates a AuthorAuthoringDevice Participant
        /// </summary>
        /// <returns>AuthorAuthoringDevice</returns>
        public static AuthorAuthoringDevice CreateAuthorAuthoringDevice()
        {
            return new AuthorAuthoringDevice();
        }

        /// <summary>
        /// Creates an entitlement
        /// </summary>
        /// <returns>An Entitlement Object</returns>
        public static Entitlement CreateEntitlement()
        {
            return new Entitlement();
        }

        /// <summary>
        /// Create an MedicalRecordNumber object
        /// </summary>
        /// <param name="medicalRecordNumber">The Medical Record Number</param>
        /// <param name="root">The organisations HPIO</param>
        /// <param name="organisationName">The Organisatiosn Name</param>
        /// <returns>MRN</returns>
        public static Identifier CreateMedicalRecordNumber(String medicalRecordNumber, String root, String organisationName)
        {
            return  
            CreateIdentifier
            (
                    organisationName,
                    null,
                    medicalRecordNumber,
                    root,
                    CreateCodableText
                    (
                        "MR",
                        CodingSystem.HL7IdentifierType,
                        null,
                        null,
                        null
                    )
             );
        }

        /// <summary>
        /// Create a CreateMedicareNumber object
        /// </summary>
        /// <param name="medicalRecordNumber">MedicareNumberType</param>
        /// <param name="medicareNumber">medicalRecordNumber</param>
        /// <returns>MRN</returns>
        public static Identifier CreateMedicareNumber(MedicareNumberType medicalRecordNumber, String medicareNumber)
        {
            return 
            CreateIdentifier
            (
                    medicalRecordNumber.GetAttributeValue<NameAttribute, string>(x => x.Name),
                    null,
                    medicareNumber,
                    medicalRecordNumber.GetAttributeValue<NameAttribute, string>(x => x.Code),
                    CreateCodableText
                    (
                        "MC",
                        CodingSystem.HL7IdentifierType,
                        null,
                        null,
                        null
                     )
            );
        }


        /// <summary>
        /// Creates a DVA entitlement.
        /// </summary>
        /// <param name="dvaNumber">DVA number.</param>
        /// <param name="entitlementType">Entitlement type.</param>
        /// <param name="validityDuration">Entitlement validity duration.</param>
        /// <returns>Entitlement.</returns>
        public static Entitlement CreateDvaEntitlement(string dvaNumber, EntitlementType entitlementType, CdaInterval validityDuration)
        {
            Entitlement entitlement = new Entitlement();
            entitlement.Id = CreateDvaNumber(dvaNumber, entitlementType);
            entitlement.Type = entitlementType;
            entitlement.ValidityDuration = validityDuration;

            return entitlement;
        }

        /// <summary>
        /// Create a DVA entitlement with no validity duration.
        /// </summary>
        /// <param name="dvaNumber">DVA number.</param>
        /// <param name="entitlementType">Entitlement type.</param>
        /// <returns>Entitlement.</returns>
        public static Entitlement CreateDvaEntitlement(string dvaNumber, EntitlementType entitlementType)
        {
            return CreateDvaEntitlement(dvaNumber, entitlementType, null);
        }

        /// <summary>
        /// Create a DVA number object
        /// </summary>
        /// <param name="dvaNumber">DVA number</param>
        /// <param name="entitlementType">Entitlement type</param>
        /// <returns>DVA identifier</returns>
        public static Identifier CreateDvaNumber(string dvaNumber, EntitlementType entitlementType)
        {
            if (dvaNumber == null)
            {
                throw new ArgumentException("'dvaNumber' cannot be null");
            }

            if (!(entitlementType == EntitlementType.RepatriationHealthOrangeBenefits ||
                  entitlementType == EntitlementType.RepatriationHealthGoldBenefits || 
                  entitlementType == EntitlementType.RepatriationHealthWhiteBenefits))
            {
                throw new ArgumentException("Entitlement type must be either: RepatriationHealthOrangeBenefits, " +
                    "RepatriationHealthGoldBenefits or RepatriationHealthWhiteBenefits");                                
            }            

            return
            CreateIdentifier
            (
                    "Department of Veterans' Affairs",
                    null,
                    dvaNumber,
                    "2.16.840.1.113883.3.879.270091",
                    CreateCodableText
                    (
                        entitlementType.GetAttributeValue<NameAttribute, string>(x => x.Code),
                        CodingSystem.NCTISEntitlementTypeValues,
                        entitlementType.GetAttributeValue<NameAttribute, string>(x => x.Name),
                        null,
                        null
                     )
            );
        }

        /// <summary>
        /// Creates an identifier
        /// </summary>
        /// <param name="identifierType">An Identifier Type</param>
        /// <param name="value">A Quantity</param>
        /// <returns>An Identifier Object</returns>
        public static Identifier CreateHealthIdentifier(HealthIdentifierType identifierType, String value)
        {
            return new Identifier
            {
                AssigningAuthorityName = identifierType.GetAttributeValue<NameAttribute, String>(x => x.Code),
                AssigningGeographicArea = identifierType.GetAttributeValue<NameAttribute, String>(x => x.Name),
                Root = identifierType.GetAttributeValue<NameAttribute, String>(x => x.Extension) + value
            };
        }

        /// <summary>
        /// Creates an identifier
        /// </summary>
        /// <param name="assigningAuthorityName">Assigning Authority Name</param>
        /// <param name="assigningGeographicArea">Assigning Geographic Area</param>
        /// <param name="extension">extension</param>
        /// <param name="root">root</param>
        /// <param name="code">A Code</param>
        /// <returns>An Identifier Object</returns>
        public static Identifier CreateIdentifier(
            string assigningAuthorityName,
            HealthcareIdentifierGeographicArea? assigningGeographicArea, 
            string extension, 
            string root, 
            ICodableText code)
        {
            Identifier identifier = null;

            identifier = new Identifier
            {
                AssigningAuthorityName = assigningAuthorityName,
                AssigningGeographicArea = assigningGeographicArea.HasValue ? assigningGeographicArea.GetAttributeValue<NameAttribute, String>(x => x.Name) : null,
                Extension = extension,
                Root = root,
                Code = code
            };

          return identifier;
        }



        /// <summary>
        /// Allow the craetion of a Close The Gap Benefit Number
        /// 
        /// The value SHALL conform to the following format statement: 
        /// The format is "CTGnnX": - The first three characters are "CTG" 
        /// The fourth and fifth characters (nn) are a numeric value representing the incremental number of a CTG script written by a prescriber in a day (01 to 99). 
        /// The sixth character (X) is a validation character based on the PBS code validation. 
        /// PBS Code Validation: 
        /// 1. Link in a series the sequence number (nn) with the date of prescribing, in the format "ddmmyy" to create an 8 digit number "nnddmmyy". 
        /// 2. Divide the number by 19 and obtain the remainder. 
        /// 3. Determine the check digit using the table below, based on the remainder.
        /// 
        /// </summary>
        /// <param name="incrementalNumber">The fourth and fifth characters (nn) are a numeric value representing the incremental number of a CTG script written by a prescriber in a day (01 to 99</param>
        /// <param name="dateOfPrescribing">The the sequence number (nn) with the date of prescribing, in the format "ddmmyy" to create an 8 digit number "nnddmmyy"</param>
        /// <returns>Close The Gap Benefit Number</returns>
        public static string CreateCloseTheGapBenefitNumber(int incrementalNumber, ISO8601DateTime dateOfPrescribing)
        {
             string numberString = incrementalNumber.ToString(CultureInfo.InvariantCulture);

             if (incrementalNumber < 10) numberString = "0" + numberString;

             if (incrementalNumber > 99 || incrementalNumber < 0)
             {
               throw new ArgumentException("IncrementalNumber can not be greater than 99 or less then 0");
             }

             string sequenceNumber = numberString + dateOfPrescribing.DateTime.ToString("ddMMyyyy");

             var remainder = Convert.ToInt32(sequenceNumber) % 19;

             var checkCharacter = string.Empty;
             switch (remainder.ToString(CultureInfo.InvariantCulture))
             {
                 case "0":
                    checkCharacter = "B";
                    break;
                 case "1":
                    checkCharacter = "C";
                    break;
                 case "2":
                    checkCharacter = "D";
                    break;
                 case "3":
                    checkCharacter = "E";
                    break;
                 case "4":
                    checkCharacter = "F";
                    break;
                 case "5":
                    checkCharacter = "G";
                    break;
                 case "6":
                    checkCharacter = "H";
                    break;
                 case "7":
                    checkCharacter = "J";
                    break;
                 case "8":
                    checkCharacter = "K";
                    break;
                 case "9":
                    checkCharacter = "L";
                    break;
                 case "10":
                    checkCharacter = "M";
                    break;
                 case "11":
                    checkCharacter = "N";
                    break;
                 case "12":
                    checkCharacter = "P";
                    break;
                 case "13":
                    checkCharacter = "Q";
                    break;
                 case "14":
                    checkCharacter = "R";
                    break;
                 case "15":
                    checkCharacter = "T";
                    break;
                 case "16":
                    checkCharacter = "W";
                    break;
                 case "17":
                    checkCharacter = "X";
                    break;
                 case "18":
                    checkCharacter = "Y";
                    break;
             }

              // Note: Determine the check digit using the table below, based on the remainder.
              // This table does not exists in the current ATS document 
              // Untill this table is release the first remander digit will be used in this instance.

              return string.Format("CTG{0}{1}", numberString, checkCharacter);
        }

        /// <summary>
        /// Creates an Employee Number Identifier
        /// </summary>
        /// <param name="organisationName">Organisation Name</param>
        /// <param name="extension">extension</param>
        /// <param name="hpio">hpio</param>
        /// <returns>An Identifier Object</returns>
        public static Identifier CreateEmployeeNumberIdentifier(
            string organisationName,
            string extension,
            string hpio)
        {
          Identifier identifier = null;

          identifier = new Identifier
          {
            AssigningAuthorityName = organisationName,
            Extension = extension,
            Root = EXTERNAL_HEALTH_IDENTIFIER_QUALIFIER + hpio,
            Code = CreateCodableText("EI", CodingSystem.HL7IdentifierType, null, null, null)
          };

          return identifier;
        }

        /// <summary>
        /// Creates an identifier
        /// </summary>
        /// <param name="extension">extension</param>
        /// <param name="root">root</param>
        /// <returns>An Identifier Object</returns>
        public static Identifier CreateIdentifier(string root, string extension)
        {
          Identifier identifier = null;

          identifier = new Identifier
          {
              Extension = extension,
              Root = root,
          };

          return identifier;
        }

        /// <summary>
        /// Creates an instance identifier  
        /// </summary>
        /// <param name="root">A UUID or OID</param>
        /// <param name="extension">Unique identifier within the scope of the identifier root</param>
        /// <returns></returns>
        public static InstanceIdentifier CreateInstanceIdentifier(
            string root,
            string extension)
        {
            return new InstanceIdentifier()
                       {
                           Root = root,
                           Extension = extension
                       };
        }

        /// <summary>
        /// Creates a person constrained down to an IAuthor
        /// </summary>
        /// <returns>(IAuthor) Person</returns>
        public static IAuthor CreateParticipantForAuthor()
        {
            return new Participant();
        }

        /// <summary>
        /// Creates an organisation constrained down to an IOrganisation
        /// </summary>
        /// <returns>(IOrganisationDischargeSummary) Organisation</returns>
        public static IOrganisation CreateOrganisation()
        {
            return new Organisation();
        }

        /// <summary>
        /// Creates an employment organisation.
        /// </summary>
        /// <returns>Employment organisation.</returns>
        public static IEmploymentOrganisation CreateEmploymentOrganisation()
        {
            return new EmploymentOrganisation();
        }

        /// <summary>
        /// Creates an Organisation constrained down to an IOrganisationName
        /// </summary>
        /// <returns>(IOrganisationName) Organisation</returns>
        public static IOrganisationName CreateOrganisationName()
        {
            return new Organisation();
        }
        /// <summary>
        /// Creates a Encapsulated Data Item
        /// </summary>
        /// <returns>An EncapsulatedData</returns>
        public static EncapsulatedData CreateEncapsulatedData()
        {
          return new EncapsulatedData();
        }
        /// <summary>
        /// Creates a ExternalData Attachment
        /// </summary>
        /// <returns>An ExternalData</returns>
        public static ExternalData CreateExternalData()
        {
            return new ExternalData();
        }
        
        /// <summary>
        /// Creates a quantity
        /// </summary>
        /// <returns>A Quantity Object</returns>
        public static Quantity CreateQuantity()
        {
            return new Quantity();
        }

        /// <summary>
        /// Creates a quantity
        /// </summary>
        /// <returns>A Quantity Object</returns>
        public static Quantity CreateQuantity(string value, string units)
        {
          return new Quantity
          {
            Units = units,
            Value = value
          };
        }

        /// <summary>
        /// Creates a quantity
        /// </summary>
        /// <returns>A Quantity Object</returns>
        public static Quantity CreateQuantity(string value, UnitOfMeasure units)
        {
          return new Quantity
          {
            Units = units.GetAttributeValue<NameAttribute, String>(x => x.Code),
            Value = value
          };
        }


        /// <summary>
        /// Creates a FrequencyQuantity
        /// </summary>
        /// <returns>FrequencyQuantity</returns>
        public static FrequencyQuantity CreateFrequencyQuantity()
        {
          return new FrequencyQuantity();
        }

        /// <summary>
        /// Creates a quantity range
        /// </summary>
        /// <returns>QuantityRange</returns>
        public static QuantityRange CreateQuantityRange()
        {
            return new QuantityRange();
        }

        /// <summary>
        /// Creates a quantity range
        /// </summary>
        /// <returns>QuantityRange</returns>
        public static QuantityRange CreateQuantityRange(Double? high, Double? low, string units)
        {
          return new QuantityRange
          {
            High = high,
            Low = low,
            Units = units
          };
        }

        /// <summary>
        /// Creats a role
        /// </summary>
        /// <returns>CodableText</returns>
        public static ICodableText CreateRole()
        {
            return new CodableText();
        }
        /// <summary>
        /// Creats a role
        /// </summary>
        /// <returns>CodableText</returns>
        public static ICodableText CreateRole(String code, CodingSystem? codeSystem, String displayName, String originalText, List<ICodableTranslation> translations)
        {
            return CreateCodableText(code, codeSystem, displayName, originalText, translations);
        }

        /// <summary>
        /// Creates a participation Role
        /// </summary>
        /// <param name="code">role participation</param>
        /// <param name="codeSystem">The code system associated with the code</param>
        /// <param name="displayName">The display name associated with the code</param>
        /// <param name="originalText">Original text, usually applicable in the absence of a code and display name</param>
        /// <param name="translations">Any translations that are associated with this participation role</param>
        /// <returns>CodableText defining a participation role</returns>
        public static ICodableText CreateParticipationRole(String code, CodingSystem? codeSystem, String displayName, String originalText, List<ICodableTranslation> translations)
        {
            return CreateCodableText(code, codeSystem, displayName, originalText, translations);
        }
        
        /// <summary>
        /// Creates a codableText object that contains and defines a role
        /// </summary>
        /// <param name="code">A code</param>
        /// <param name="codeSystem">The code system associated with the code</param>
        /// <param name="displayName">The display name associated with the code</param>
        /// <param name="originalText">Original text, usually applicable in the absence of a code and display name</param>
        /// <returns>A codable text representing the role</returns>
        public static ICodableText CreateRole(String code, CodingSystem? codeSystem, String displayName, String originalText)
        {
            var codableText = new CodableText();

            if (codeSystem.HasValue)
            {
                codableText.DisplayName = displayName;
                codableText.Code = code;
                codableText.CodeSystemCode = codeSystem.Value.GetAttributeValue<NameAttribute, string>(a => a.Code);
                codableText.CodeSystemName = codeSystem.Value.GetAttributeValue<NameAttribute, string>(a => a.Name);
                codableText.CodeSystemVersion = codeSystem.Value.GetAttributeValue<NameAttribute, string>(a => a.Version);
            }

            if (!originalText.IsNullOrEmptyWhitespace())
                codableText.OriginalText = originalText;

            return codableText;
        }

        /// <summary>
        /// Creates a codableText object that contains and defines a role as defined by an occupation
        /// </summary>
        /// <param name="occupation">The occupation defining the role</param>
        /// <returns>A codable text representing the role</returns>
        public static ICodableText CreateRole(Occupation occupation)
        {
            return new CodableText
            {
                DisplayName = occupation != Occupation.Undefined ? occupation.GetAttributeValue<NameAttribute, String>(x => x.Name) : String.Empty,
                Code = occupation != Occupation.Undefined ? occupation.GetAttributeValue<NameAttribute, String>(x => x.Code) : String.Empty,
                CodeSystem = CodingSystem.ANZSCO
            };
        }

        /// <summary>
        /// Creates a codableText object that contains and defines a role as defined by a RoleCodeAndRoleClassCodes
        /// </summary>
        /// <param name="roleCodeAndRoleClassCodes">The occupation defining the role</param>
        /// <returns>A codable text representing the role</returns>
        public static ICodableText CreateRole(RoleCodeAndRoleClassCodes roleCodeAndRoleClassCodes)
        {
            return new CodableText
            {
                DisplayName =  roleCodeAndRoleClassCodes.GetAttributeValue<NameAttribute, String>(x => x.Name),
                Code = roleCodeAndRoleClassCodes.GetAttributeValue<NameAttribute, String>(x => x.Code) ,
                CodeSystemCode = ((CodingSystem)Enum.Parse(typeof(CodingSystem), roleCodeAndRoleClassCodes.GetAttributeValue<NameAttribute, string>(x => x.CodeSystem))).GetAttributeValue<NameAttribute, string>(x => x.Code),
                CodeSystemName = ((CodingSystem)Enum.Parse(typeof(CodingSystem), roleCodeAndRoleClassCodes.GetAttributeValue<NameAttribute, string>(x => x.CodeSystem))).GetAttributeValue<NameAttribute, string>(x => x.Name),
                CodeSystemVersion = ((CodingSystem)Enum.Parse(typeof(CodingSystem), roleCodeAndRoleClassCodes.GetAttributeValue<NameAttribute, string>(x => x.CodeSystem))).GetAttributeValue<NameAttribute, string>(x => x.Version),
            };
        }

        /// <summary>
        /// Creates a codableText object that contains and defines a role as a nullFlavor
        /// </summary>
        /// <param name="nullFlavor"></param>
        /// <returns>CodableText</returns>
        public static ICodableText CreateRole(NullFlavour nullFlavor)
        {
            var codableText = new CodableText();
            codableText.NullFlavour = nullFlavor;
            return codableText;
        }

      /// <summary>
      /// Creates a result group name
      /// </summary>
      /// <param name="code">result group name code</param>
      /// <param name="codeSystem">The code system associated with the code</param>
      /// <param name="displayName">The display name associated with the code</param>
      /// <param name="originalText">Original text, usually applicable in the absence of a code and display name</param>
      /// <param name="translations">Any translations that are associated with this result group name</param>
      /// <returns>CodableText defining a result group name</returns>
      public static ICodableText CreateResultGroupName(String code, CodingSystem? codeSystem, String displayName, String originalText, List<ICodableTranslation> translations)
      {
        return CreateCodableText(code, codeSystem, displayName, originalText, translations);
      }

      /// <summary>
      /// Creates a result group name
      /// </summary>
      /// <param name="nullFlavor">nullFlavor</param>
      /// <returns>CodableText defining a result group name</returns>
      public static ICodableText CreateResultGroupName(NullFlavour nullFlavor)
      {
        return CreateCodableText(nullFlavor);
      }

      /// <summary>
      /// Creates a codableText object
      /// </summary>
      /// <param name="originalText">Original text, usually applicable in the absence of a code and display name</param>
      /// <returns>CodableText</returns>
      public static ICodableText CreateCodableText(String originalText)
      {
          return CreateCodableText(null, null, null, originalText, null);
      }

        /// <summary>
        /// Creates a codableText object
        /// </summary>
        /// <param name="code">A code</param>
        /// <param name="codeSystem">The code system associated with the code</param>
        /// <param name="displayName">The display name associated with the code</param>
        /// <param name="originalText">Original text, usually applicable in the absence of a code and display name</param>
        /// <param name="translations">Any translations that are associated with this codable text</param>
        /// <returns>CodableText</returns>
        public static ICodableText CreateCodableText(String code, CodingSystem? codeSystem, String displayName, String originalText, List<ICodableTranslation> translations)
        {
            var codableText = new CodableText();

            if (codeSystem.HasValue)
            {
                codableText.DisplayName = displayName;
                codableText.Code = code;
                codableText.CodeSystemCode = codeSystem.Value.GetAttributeValue<NameAttribute, string>(a => a.Code);
                codableText.CodeSystemName = codeSystem.Value.GetAttributeValue<NameAttribute, string>(a => a.Name);
                codableText.CodeSystemVersion = codeSystem.Value.GetAttributeValue<NameAttribute, string>(a => a.Version);
            }

            if (!originalText.IsNullOrEmptyWhitespace())
                codableText.OriginalText = originalText;

            if (translations != null && translations.Any())
                codableText.Translations = translations;

            return codableText;
        }

        /// <summary>
        /// Creates a codableText object
        /// </summary>
        /// <param name="code">A code</param>
        /// <param name="codeSystemCode">The Code for the CodableText</param>
        /// <param name="codeSystemName">The CodeSystemName for the CodableText</param>
        /// <param name="codeSystemVersion">The CodeSystemVersion \ for the CodableText</param>
        /// <param name="displayName">The display name associated with the code</param>
        /// <param name="originalText">Original text, usually applicable in the absence of a code and display name</param>
        /// <param name="translations">Any translations that are associated with this codable text</param>
        /// <returns>CodableText</returns>
        public static ICodableText CreateCodableText(String code, string codeSystemCode, string codeSystemName, string codeSystemVersion,  String displayName, String originalText, List<ICodableTranslation> translations)
        {
          var codableText = new CodableText();

            codableText.DisplayName = displayName;
            codableText.Code = code;
            codableText.CodeSystemCode = codeSystemCode;
            codableText.CodeSystemName = codeSystemName;
            codableText.CodeSystemVersion = codeSystemVersion;

          if (!originalText.IsNullOrEmptyWhitespace())
            codableText.OriginalText = originalText;

          if (translations != null && translations.Any())
            codableText.Translations = translations;

          return codableText;
        }

        /// <summary>
        /// Creates a codable text nullable object
        /// </summary>
        /// <param name="nullFlavor"></param>
        /// <returns>CodableText</returns>
        public static ICodableText CreateCodableText(NullFlavour nullFlavor)
        {
           var codableText = new CodableText();
           codableText.NullFlavour = nullFlavor;
           return codableText;
        }

        /// <summary>
        /// Create a QuestionData 
        /// </summary>
        /// <typeparam name="T">An Enum</typeparam>
        /// <param name="defaultValue">Enum</param>
        /// <returns>A CodableText castesd from an Enum</returns>
        public static ICodableText CreateQuestionData<T>(T defaultValue) where T : struct, IConvertible
        {
            if (!typeof(T).IsEnum)
            {
                throw new ArgumentException("T must be an enumerated type which can be mapped to CodingSystem");
            }

            var enumeration = defaultValue as Enum;

            return new CodableText
            {
                DisplayName = enumeration.GetAttributeValue<NameAttribute, string>(x => x.Name),
                Code = enumeration.GetAttributeValue<NameAttribute, string>(x => x.Code),
                CodeSystemCode = ((CodingSystem)Enum.Parse(typeof(CodingSystem), enumeration.GetAttributeValue<NameAttribute, string>(x => x.CodeSystem))).GetAttributeValue<NameAttribute, string>(x => x.Code),
                CodeSystemName = ((CodingSystem)Enum.Parse(typeof(CodingSystem), enumeration.GetAttributeValue<NameAttribute, string>(x => x.CodeSystem))).GetAttributeValue<NameAttribute, string>(x => x.Name),
                CodeSystemVersion = ((CodingSystem)Enum.Parse(typeof(CodingSystem), enumeration.GetAttributeValue<NameAttribute, string>(x => x.CodeSystem))).GetAttributeValue<NameAttribute, string>(x => x.Version),
                OriginalText = enumeration.GetAttributeValue<NameAttribute, string>(x => x.Title)
            };
        }

        /// <summary>
        /// Creates a codable text object
        /// </summary>
        /// <param name="code">code</param>
        /// <param name="codeSystem">The code system associated with the code</param>
        /// <param name="displayName">The display name associated with the code</param>
        /// <param name="originalText">Original text, usually applicable in the absence of a code and display name</param>
        /// <returns>CodableText</returns>
        public static ICodableTranslation CreateCodableTranslation(String code, CodingSystem? codeSystem, String displayName, String originalText)
        {
            var codableText = new CodableText();

            if (codeSystem.HasValue)
            {
                codableText.DisplayName = displayName;
                codableText.Code = code;
                codableText.CodeSystemCode = codeSystem.Value.GetAttributeValue<NameAttribute, string>(a => a.Code);
                codableText.CodeSystemName = codeSystem.Value.GetAttributeValue<NameAttribute, string>(a => a.Name);
                codableText.CodeSystemVersion = codeSystem.Value.GetAttributeValue<NameAttribute, string>(a => a.Version);
            }

            if (!originalText.IsNullOrEmptyWhitespace())
                codableText.OriginalText = originalText;

            return codableText;
        }

        /// <summary>
        /// Creates an electronic communication detail
        /// </summary>
        /// <param name="address">Address, E.g.. Phone number, Email address etc</param>
        /// <param name="medium">Medium, E.g. Telephone</param>
        /// <param name="usage">Usage, E.g. Business</param>
        /// <returns>ElectronicCommunicationDetail</returns>
        public static ElectronicCommunicationDetail CreateElectronicCommunicationDetail(string address, ElectronicCommunicationMedium? medium, ElectronicCommunicationUsage? usage)
        {
            var electronicCommunicationDetail = new ElectronicCommunicationDetail
            {
                Address = address
            };

            if (medium.HasValue)
            {
                electronicCommunicationDetail.Medium = medium.Value;
            }

            if (usage.HasValue)
            {
                electronicCommunicationDetail.Usage = new List<ElectronicCommunicationUsage> {usage.Value};
            }

            return electronicCommunicationDetail;
        }

        /// <summary>
        /// Creates an electronic communication detail
        /// </summary>
        /// <param name="address">Address, E.g.. Phone number, Email address etc</param>
        /// <param name="medium">Medium, E.g. Telephone</param>
        /// <param name="usage">Usage, E.g. Business</param>
        /// <returns>ElectronicCommunicationDetail</returns>
        public static ElectronicCommunicationDetail CreateElectronicCommunicationDetail(string address, ElectronicCommunicationMedium? medium, List<ElectronicCommunicationUsage> usage)
        {
            var electronicCommunicationDetail = new ElectronicCommunicationDetail
            {
                Address = address
            };

            if (medium.HasValue)
            {
                electronicCommunicationDetail.Medium = medium.Value;
            }

            if (usage != null)
            {
                electronicCommunicationDetail.Usage = usage;
            }

            return electronicCommunicationDetail;
        }


        /// <summary>
        /// Create a valid Guid
        /// </summary>
        /// <returns></returns>
        public static string CreateGuid()
        {
            return
                (
                    new UniqueId().ToString().Replace("urn:uuid:", "")
                );
        }

        /// <summary>
        /// Creates an interval with a start and end date/time.
        /// </summary>
        /// <param name="start">Start date/time.</param>
        /// <param name="end">End date/time.</param>
        /// <returns>Interval.</returns>
        public static CdaInterval CreateInterval(ISO8601DateTime start, ISO8601DateTime end)
        {
          return CdaInterval.CreateLowHigh(start, end) as CdaInterval;
        }

        /// <summary>
        /// Creates an interval from a width.
        /// </summary>
        /// <param name="widthValue">Interval width.</param>
        /// <param name="unit">Unit.</param>
        /// <returns>Interval.</returns>
        public static CdaInterval CreateInterval(string widthValue, TimeUnitOfMeasure unit)
        {
          return CdaInterval.CreateWidth(widthValue, unit) as CdaInterval;
        }

        /// <summary>
        /// Creates an interval for a high value.
        /// </summary>
        /// <param name="high">Interval high.</param>
        /// <returns>Interval.</returns>
        public static CdaInterval CreateInterval(ISO8601DateTime high)
        {
          return CdaInterval.CreateHigh(high) as CdaInterval;
        }

        /// <summary>
        /// Creates a CreateStructuredBodyFile (External Data)
        /// </summary>
        /// <returns>ExternalData</returns>
        public static ExternalData CreateStructuredBodyFile()
        {
            return new ExternalData();
        }

        /// <summary>
        /// Creates and Hydrates a PhysicalDetails object
        /// </summary>
        /// <returns>An Empty PhysicalDetails object</returns>
        public static PhysicalDetails CreatePhysicalDetails()
        {
            return new PhysicalDetails();
        }

        /// <summary>
        /// Creates an Imaging Examination Request
        /// </summary>
        /// <returns>(IImagingExaminationRequest) Request</returns>
        public static IImagingExaminationRequest CreateImagingExaminationRequest()
        {
            return new Request();
        }

        /// <summary>
        /// Creates a pathology test result
        /// </summary>
        /// <returns>PathologyTestResult</returns>
        public static PathologyTestResult CreatePathologyTestResult()
        {
            return new PathologyTestResult();
        }

        /// <summary>
        /// Creates a specimen detail
        /// </summary>
        /// <returns>SpecimenDetail</returns>
        public static SpecimenDetail CreateSpecimenDetail()
        {
            return new SpecimenDetail();
        }

        /// <summary>
        /// Creates an anatomical site
        /// </summary>
        /// <returns>AnatomicalSite</returns>
        public static AnatomicalSite CreateAnatomicalSite()
        {
            return new AnatomicalSite();
        }

        /// <summary>
        /// Creates a Link Object
        /// </summary>
        /// <returns>Link</returns>
        public static Link CreateLink()
        {
          return new Link();
        }

        /// <summary>
        /// Creates and Hydrates a PhysicalDetails object
        /// </summary>
        /// <param name="value">The Quantity</param>
        /// <param name="units">The Unit</param>
        /// <param name="image">The ExternalData</param>
        /// <returns>A Hydrated PhysicalDetails object</returns>
        public static PhysicalDetails CreatePhysicalDetails(String value, String units, ExternalData image)
        {
            PhysicalDetails physicalDetails = null;

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

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

            if (image != null)
            {
                physicalDetails.Image = image;
            }

            return physicalDetails;
        }

      /// <summary>
      /// Creates a OtherTestResult
      /// </summary>
      /// <returns>OtherTestResult</returns>
      public static OtherTestResult CreateOtherTestResult()
      {
        return new OtherTestResult();
      }

      /// <summary>
      /// Creates a External Concept Identifier
      /// </summary>
      /// <returns>Identifier</returns>
      public static Identifier CreateExternalConceptIdentifier(ExternalConcepts externalConcepts, string extention)
      {
        return CreateIdentifier(
          CodingSystem.AustralianPBSManufacturerCode.GetAttributeValue<NameAttribute, String>(x => x.Name),
          null,
          extention,
          String.Format("{0}.{1}", CodingSystem.NCTISExternalConcepts.GetAttributeValue<NameAttribute, String>(x => x.Code), externalConcepts.GetAttributeValue<NameAttribute, String>(x => x.Code)),
          null
          );
      }

      #region ETP

      /// <summary>
      /// Creates a Prescriber
      /// </summary>
      /// <returns></returns>
      public static IParticipationPrescriber CreatePrescriber()
      {
        return new Participation();
      }

      /// <summary>
      /// Creates a participant for a prescriber
      /// </summary>
      /// <returns></returns>
      public static IPrescriber CreateParticipantForPrescriber()
      {
        return new Participant();
      }

      /// <summary>
      /// Creates a person
      /// </summary>
      /// <returns>(IPersonPrescriber) Person</returns>
      public static IPersonPrescriber CreatePersonForPrescriber()
      {
        return new Person();
      }

      /// <summary>
      /// Creates a Prescriber organisation
      /// </summary>
      /// <returns>(IParticipationPrescriberOrganisation) Participation</returns>
      public static IParticipationPrescriberOrganisation CreatePrescriberOrganisation()
      {
        return new Participation();
      }

      /// <summary>
      /// Creates a participant for a prescriber organisation
      /// </summary>
      /// <returns>(IPrescriberOrganisation) Participant</returns>
      public static IPrescriberOrganisation CreateParticipantForPrescriberOrganisation()
      {
        return new Participant();
      }

      /// <summary>
      /// Creates a dispenser
      /// </summary>
      /// <returns></returns>
      public static IParticipationDispenser CreateDispenser()
      {
        return new Participation
        {
           Role = CreateRole(Occupation.Pharmacists)
        };
      }

      /// <summary>
      /// Creates a participant for a dispenser
      /// </summary>
      /// <returns></returns>
      public static IDispenser CreateParticipantForDispenser()
      {
        return new Participant();
      }

      /// <summary>
      /// Creates a person
      /// </summary>
      /// <returns>(IPersonDispenser) Person</returns>
      public static IPersonDispenser CreatePersonForDispenser()
      {
        return new Person();
      }

      /// <summary>
      /// Creates a Dispenser organisation
      /// </summary>
      /// <returns>(IParticipationDispenserOrganisation) Participation</returns>
      public static IParticipationDispenserOrganisation CreateDispenserOrganisation()
      {
        return new Participation();
      }

      /// <summary>
      /// Creates a participant for a dispenser organisation
      /// </summary>
      /// <returns>(IDispenserOrganisation) Participant</returns>
      public static IDispenserOrganisation CreateParticipantForDispenserOrganisation()
      {
        return new Participant();
      }

      /// <summary>
      /// Creates a ParentDocument  
      /// </summary>
      /// <returns>ParentDocument</returns>
      public static ParentDocument CreateParentDocument()
      {
        return new ParentDocument();
      }

      /// <summary>
      /// Creates a Medicare View Exclusion Statement
      /// </summary>
      /// <returns>(IMedicareOverviewContext) Context</returns>
      public static ExclusionStatement CreateExclusionStatement()
      {
        return new ExclusionStatement();
      }

      /// <summary>
      /// Creates a Medicare View Exclusion Statement
      /// </summary>
      /// <returns>(IMedicareOverviewContext) Context</returns>
      public static ExclusionStatement CreateExclusionStatement(string sectionTitle, string generalStatement)
      {
        return CreateExclusionStatement(sectionTitle, generalStatement, null);
      }

      /// <summary>
      /// Creates a Medicare View Exclusion Statement
      /// </summary>
      /// <returns>(IMedicareOverviewContext) Context</returns>
      public static ExclusionStatement CreateExclusionStatement(string sectionTitle, string generalStatement, StrucDocText customNarrative)
      {
        return new ExclusionStatement
        {
          CustomNarrative = customNarrative,
          GeneralStatement = generalStatement,
          SectionTitle = sectionTitle
        };
      }

      /// <summary>
      /// Create a CreateTherapeuticGoodIdentification CodableText
      /// </summary>
      /// <param name="code">CreateTherapeuticGoodIdentification code</param>
      /// <param name="codeSystem">The code system associated with the code</param>
      /// <param name="displayName">The display name associated with the code</param>
      /// <param name="originalText">Original text, usually applicable in the absence of a code and display name</param>
      /// <param name="translations">Any translations that are associated with this procedure</param>
      /// <returns>CreateTherapeuticGoodIdentification </returns>
      public static ICodableText CreateTherapeuticGoodIdentification(String code, CodingSystem? codeSystem, String displayName, String originalText, List<ICodableTranslation> translations)
      {
        return CreateCodableText(code, codeSystem, displayName, originalText, translations);
      }

      /// <summary>
      /// Creates a PBSExtemporaneousIngredient
      /// </summary>
      /// <returns>PBSExtemporaneousIngredient</returns>
      public static PBSExtemporaneousIngredient CreatePBSExtemporaneousIngredient(ICodableText ingredientName, Quantity ingredientQuantity)
      {
        return new PBSExtemporaneousIngredient
        {
          IngredientName = ingredientName,
          IngredientQuantity = ingredientQuantity
        };
      }

      /// <summary>
      /// Creates a QuantityUnit
      /// </summary>
      /// <returns>QuantityUnit</returns>
      public static QuantityUnit CreateQuantityToDispense()
      {
        return new QuantityUnit();
      }

      /// <summary>
      /// Creates a QuantityUnit
      /// </summary>
      /// <returns>QuantityUnit</returns>
      public static QuantityUnit CreateQuantityToDispense(Quantity dose, string quantityDescription)
      {
        return CreateQuantityUnit(dose, quantityDescription);
      }

      /// <summary>
      /// Creates a QuantityUnit
      /// </summary>
      /// <returns>QuantityUnit</returns>
      public static QuantityUnit CreateQuantityToDispense(string value, ICodableText doseUnit, string quantityDescription)
      {
        return CreateQuantityUnit(value, doseUnit, quantityDescription);
      }

      /// <summary>
      /// Creates a QuantityUnit
      /// </summary>
      /// <returns>QuantityUnit</returns>
      public static QuantityUnit CreateStructuredDose()
      {
        return new QuantityUnit();
      }

      /// <summary>
      /// Creates a QuantityUnit
      /// </summary>
      /// <returns>QuantityUnit</returns>
      public static QuantityUnit CreateStructuredDose(Quantity dose, string quantityDescription)
      {
        return CreateQuantityUnit(dose, quantityDescription);
      }

      /// <summary>
      /// Creates a QuantityUnit
      /// </summary>
      /// <returns>QuantityUnit</returns>
      public static QuantityUnit CreateStructuredDose(string value, ICodableText doseUnit, string quantityDescription)
      {
        return CreateQuantityUnit(value, doseUnit, quantityDescription);
      }

      /// <summary>
      /// Creates a QuantityUnit
      /// </summary>
      /// <returns>QuantityUnit</returns>
      public static QuantityUnit CreateQuantityUnit()
      {
        return new QuantityUnit();
      }

      /// <summary>
      /// Creates a QuantityUnit
      /// </summary>
      /// <returns>QuantityUnit</returns>
      public static QuantityUnit CreateQuantityUnit(Quantity dose, string quantityDescription)
      {
        return new QuantityUnit
        {
          Quantity = dose,
          QuantityDescription = quantityDescription
        };
      }

      /// <summary>
      /// Creates a QuantityUnit
      /// </summary>
      /// <returns>QuantityUnit</returns>
      public static QuantityUnit CreateQuantityUnit(string value, ICodableText doseUnit, string quantityDescription)
      {
        return new QuantityUnit
        {
          Quantity = new Quantity { Value = value },
          Unit = doseUnit,
          QuantityDescription = quantityDescription
        };
      }

      /// <summary>
      /// Creates a Therapeutic Good ID
      /// </summary>
      /// <returns>(ICodableText) CodableText</returns>
      public static ICodableText CreateTherapeuticGoodIdentification()
      {
        return new CodableText();
      }

      /// <summary>
      /// Creates a medicine
      /// </summary>
      /// <param name="code">role medicine</param>
      /// <param name="codeSystem">The code system associated with the code</param>
      /// <param name="codeSystemVersion">The current CodeSystemVersion for the AMT SnomedCode</param>
      /// <param name="displayName">The display name associated with the code</param>
      /// <param name="originalText">Original text, usually applicable in the absence of a code and display name</param>
      /// <param name="translations">Any translations that are associated with this medicine</param>
      /// <returns>CodableText defining a medicine</returns>
      public static ICodableText CreateMedicine(String code, CodingSystem codeSystem, String codeSystemVersion, String displayName, String originalText, List<ICodableTranslation> translations)
      {
        return CreateCodableText(code,
                                 codeSystem.GetAttributeValue<NameAttribute, string>(a => a.Code),
                                 codeSystem.GetAttributeValue<NameAttribute, string>(a => a.Name),
                                 codeSystemVersion,
                                 displayName,
                                 originalText,
                                 translations);
      }

      /// <summary>
      /// Creates a Timing object
      /// </summary>
      /// <returns>Timing</returns>
      public static Timing CreateTiming()
      {
        return new Timing();
      }

      #endregion

      #region Time

      /// <summary>
      /// Creates am StructuredTiming
      /// </summary>
      /// <returns>StructuredTiming</returns>
      public static StructuredTiming CreateStructuredTiming()
      {
        return new StructuredTiming();
      }

      /// <summary>
      /// Creates a EventRelatedIntervalOfTime (EIVL_TS)
      /// </summary>
      /// <returns>EventRelatedIntervalOfTime</returns>
      public static EventRelatedIntervalOfTime CreateEventRelatedIntervalOfTime()
      {
        return new EventRelatedIntervalOfTime();
      }

      /// <summary>
      /// Creates a ParentheticSetExpressionOfTime (SXPR_TS)
      /// </summary>
      /// <returns>ParentheticSetExpressionOfTime</returns>
      public static ParentheticSetExpressionOfTime CreateParentheticSetExpressionOfTime()
      {
        return new ParentheticSetExpressionOfTime();
      }

      /// <summary>
      /// Creates a IPeriodicIntervalOfTime (PIVL_TS)
      /// </summary>
      /// <returns>IPeriodicIntervalOfTime</returns>
      public static PeriodicIntervalOfTime CreatePeriodicIntervalOfTime()
      {
        return new PeriodicIntervalOfTime();
      }

      /// <summary>
      /// Creats a SetComponentTS (SXCM_TS)
      /// </summary>
      /// <returns>SetComponentTS</returns>
      public static SetComponentTS CreateSetComponentTS()
      {
        return new SetComponentTS();
      }

      /// <summary>
      /// Creates a Frequency
      /// </summary>
      /// <returns>Frequency</returns>
      public static Frequency CreateFrequency()
      {
        return new Frequency();
      }

      /// <summary>
      /// Creates an CdaInterval with low.
      /// </summary>
      /// <param name="low">Low.</param>
      /// <returns>Interval</returns>
      public static CdaInterval CreateLow(ISO8601DateTime low)
      {
        return CdaInterval.CreateLow(low);
      }

      /// <summary>
      /// Creates an CdaInterval with low.
      /// </summary>
      /// <param name="low">Low.</param>
      /// <param name="value">value.</param>
      /// <param name="operatorType">operatorType.</param>
      /// <param name="nullFlavor">nullFlavor.</param>
      /// <returns>CdaInterval</returns>
      public static CdaInterval CreateLow(ISO8601DateTime low, int? value, OperationTypes? operatorType, NullFlavor? nullFlavor)
      {
        return CdaInterval.CreateLow(low, value, operatorType, nullFlavor);
      }

      /// <summary>
      /// Creates an CdaInterval with a width.
      /// </summary>
      /// <param name="width">Width.</param>
      /// <param name="unit">Unit.</param>
      /// <returns>CdaInterval</returns>
      public static CdaInterval CreateWidth(string width, TimeUnitOfMeasure unit)
      {
        return CdaInterval.CreateWidth(width, unit);
      }

      /// <summary>
      /// Creates an CdaInterval with a width.
      /// </summary>
      /// <param name="width">Width.</param>
      /// <param name="value">Quantity.</param>
      /// <param name="unit">Unit.</param>
      /// <param name="operatorType">operatorType.</param>
      /// <param name="nullFlavor">nullFlavor.</param> 
      /// <returns>CdaInterval</returns>
      public static CdaInterval CreateWidth(string width, TimeUnitOfMeasure unit, int? value, OperationTypes? operatorType, NullFlavor? nullFlavor)
      {
        return CdaInterval.CreateWidth(width, unit, value, operatorType, nullFlavor);
      }

      /// <summary>
      /// Creates an CdaInterval with high.
      /// </summary>
      /// <param name="high">High.</param>
      /// <returns>Interval</returns>
      public static CdaInterval CreateHigh(ISO8601DateTime high)
      {
        return CdaInterval.CreateHigh(high);
      }

      /// <summary>
      /// Creates an CdaInterval with high.
      /// </summary>
      /// <param name="value">value.</param>
      /// <param name="operatorType">operatorType.</param>
      /// <param name="nullFlavor">nullFlavor.</param>
      /// <param name="high">High.</param>
      /// <returns>CdaInterval</returns>
      public static CdaInterval CreateHigh(ISO8601DateTime high, int? value, OperationTypes? operatorType, NullFlavor? nullFlavor)
      {
        return CdaInterval.CreateHigh(high, value, operatorType, nullFlavor);
      }

      /// <summary>
      /// Creates an CdaInterval with center.
      /// </summary>
      /// <param name="center">Center.</param>
      /// <returns>Interval</returns>
      public static CdaInterval CreateCenter(ISO8601DateTime center)
      {
        return CdaInterval.CreateCenter(center);
      }

      /// <summary>
      /// Creates an CdaInterval with center.
      /// </summary>
      /// <param name="value">value.</param>
      /// <param name="operatorType">operatorType.</param>
      /// <param name="nullFlavor">nullFlavor.</param>
      /// <param name="center">Center.</param>
      /// <returns>CdaInterval</returns>
      public static CdaInterval CreateCenter(ISO8601DateTime center, int? value, OperationTypes? operatorType, NullFlavor? nullFlavor)
      {
        return CdaInterval.CreateCenter(center, value, operatorType, nullFlavor);
      }

      /// <summary>
      /// Creates an CdaInterval with high and low.
      /// </summary>
      /// <param name="low">Low.</param>
      /// <param name="high">High.</param>
      /// <returns>CdaInterval</returns>
      public static CdaInterval CreateLowHigh(ISO8601DateTime low, ISO8601DateTime high)
      {
        return CdaInterval.CreateLowHigh(low, high);
      }


      /// <summary>
      /// Creates an CdaInterval with high and low.
      /// </summary>
      /// <param name="low">Low.</param>
      /// <param name="high">High.</param>
      /// <param name="value">value.</param>
      /// <param name="operatorType">operatorType.</param>
      /// <param name="nullFlavor">nullFlavor.</param>
      /// <returns>CdaInterval</returns>
      public static CdaInterval CreateLowHigh(ISO8601DateTime low, ISO8601DateTime high, int? value, OperationTypes? operatorType, NullFlavor? nullFlavor)
      {
        return CdaInterval.CreateLowHigh(low, high, value, operatorType, nullFlavor);
      }

      /// <summary>
      /// Creates an CdaInterval with low and width.
      /// </summary>
      /// <param name="low">Low.</param>
      /// <param name="value">Quantity.</param>
      /// <param name="unit">Unit.</param>
      /// <returns>CdaInterval</returns>
      public static CdaInterval CreateLowWidth(ISO8601DateTime low, string value, TimeUnitOfMeasure unit)
      {
        return CdaInterval.CreateLowWidth(low, value, unit);
      }

      /// <summary>
      /// Creates an CdaInterval with low and width.
      /// </summary>
      /// <param name="low">Low.</param>
      /// <param name="width">Width.</param>
      /// <param name="unit">Unit.</param>
      /// <param name="value">value.</param>
      /// <param name="operatorType">operatorType.</param>
      /// <param name="nullFlavor">nullFlavor.</param>
      /// <returns>CdaInterval</returns>
      public static CdaInterval CreateLowWidth(ISO8601DateTime low, string width, TimeUnitOfMeasure unit, int? value, OperationTypes? operatorType, NullFlavor? nullFlavor)
      {
        return CdaInterval.CreateLowWidth(low, width, unit, value, operatorType, nullFlavor);
      }

      /// <summary>
      /// Creates an CdaInterval with high and width.
      /// </summary>
      /// <param name="high">High.</param>
      /// <param name="width">width.</param>
      /// <param name="unit">Unit.</param>
      /// <returns>CdaInterval</returns>
      public static CdaInterval CreateHighWidth(ISO8601DateTime high, string width, TimeUnitOfMeasure unit)
      {
        return CdaInterval.CreateHighWidth(high, width, unit);
      }

      /// <summary>
      /// Creates an CdaInterval with high and width.
      /// </summary>
      /// <param name="high">High.</param>
      /// <param name="width">Width.</param>
      /// <param name="unit">Unit.</param>
      /// <param name="value">value.</param>
      /// <param name="operatorType">operatorType.</param>
      /// <param name="nullFlavor">nullFlavor.</param>
      /// <returns>CdaInterval</returns>
      public static CdaInterval CreateHighWidth(ISO8601DateTime high, string width, TimeUnitOfMeasure unit, int? value, OperationTypes? operatorType, NullFlavor? nullFlavor)
      {
        return CdaInterval.CreateHighWidth(high, width, unit, value, operatorType, nullFlavor);
      }


      /// <summary>
      /// Creates an CdaInterval with center and width.
      /// </summary>
      /// <param name="center">Center.</param>
      /// <param name="value">Quantity.</param>
      /// <param name="unit">Unit.</param>
      /// <returns>CdaInterval</returns>
      public static CdaInterval CreateCenterWidth(ISO8601DateTime center, string value, TimeUnitOfMeasure unit)
      {
        return CdaInterval.CreateCenterWidth(center, value, unit);
      }

      /// <summary>
      /// Creates an CdaInterval with center and width.
      /// </summary>
      /// <param name="center">Center.</param>
      /// <param name="width">Width.</param>
      /// <param name="unit">Unit.</param>
      /// <param name="value">value.</param>
      /// <param name="operatorType">operatorType.</param>
      /// <param name="nullFlavor">nullFlavor.</param>
      /// <returns>CdaInterval</returns>
      public static CdaInterval CreateCenterWidth(ISO8601DateTime center, string width, TimeUnitOfMeasure unit, int? value, OperationTypes? operatorType, NullFlavor? nullFlavor)
      {
        return CdaInterval.CreateCenterWidth(center, width, unit, value, operatorType, nullFlavor);
      }

      #endregion

      #region Utilities

      /// <summary>
      /// Creates a OID
      /// </summary>
      /// <returns>Creates an OID</returns>
      public static string CreateOid()
      {
         return OIDHelper.UuidToOid(CreateGuid());
      }

      /// <summary>
      /// Converts a UUID to an OID
      /// </summary>
      /// <returns>Creates an OID</returns>
      public static string ConvertUuidToOid(string uuid)
      {
        return OIDHelper.UuidToOid(uuid);
      }

      /// <summary>
      /// Calculate an age based on the Birth Date
      /// </summary>
      /// <param name="birthdate"></param>
      /// <returns></returns>
      public static int CalculateAge(DateTime birthdate)
      {
        // get the difference in years
        int years = DateTime.Now.Year - birthdate.Year;
        // subtract another year if we're before the
        // birth day in the current year
        if (DateTime.Now.Month < birthdate.Month ||
            (DateTime.Now.Month == birthdate.Month && DateTime.Now.Day < birthdate.Day))
          years--;

        return years;
      }

      #endregion

      #endregion

        #region Constructors
        /// <summary>
        /// Default Constructor
        /// </summary>
        public BaseCDAModel()
        {
            ShowAdministrativeObservations = true;
        }
        #endregion
    }
}
