/*
 * 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.Runtime.Serialization;
using CDA.Generator.Common.Common.Time.Enum;
using CDA.Generator.Common.SCSModel.Interfaces;
using CDA.Generator.Common.SCSModel.PhysicalMeasurements.Interfaces;
using JetBrains.Annotations;
using Nehta.VendorLibrary.CDA.Common;
using Nehta.VendorLibrary.CDA.Common.Enums;
using Nehta.VendorLibrary.CDA.SCSModel.DischargeSummary.Interfaces;
using Nehta.VendorLibrary.Common;

namespace Nehta.VendorLibrary.CDA.SCSModel.Common
{
    [Serializable]
    [DataContract]
    [KnownType(typeof(Person))]
    [KnownType(typeof(CodableText))]
    [KnownType(typeof(Participant))]
    [KnownType(typeof(DischargeSummary.Participation))]
    internal class Participation : IParticipation, IParticipationPatientNominatedContact, IParticipationAcdCustodian, 
        IParticipationSubjectOfCare, IParticipationDocumentAuthor, IParticipationCustodian, IParticipationLegalAuthenticator, 
        IParticipationInformationRecipient, IParticipationReferee, IParticipationUsualGP, IParticipationReferrer, IParticipationAddressee, 
        IParticipationServiceProvider, IParticipationPrescriberInstructionRecipient, IParticipationPrescriber, 
        IParticipationPrescriberOrganisation, IParticipationDispenser, IParticipationDispenserOrganisation,
        IParticipationConsumerAuthor, IParticipationServiceRequester, IParticipationInformationProvider, IParticipationInformationProviderHealthcareProvider,
        IParticipationInformationProviderNonHealthcareProvider, IParticipationAuthorNonHealthcareProvider, IParticipationAuthorHealthcareProvider, IParticipationHealthcareFacility
    {
        #region Properties

        [CanBeNull]
        [DataMember]
        public ICodableText Role { get; set; }
 
        [CanBeNull]
        [DataMember]
        public CdaInterval ParticipationPeriod { get; set; }

        [CanBeNull]
        [DataMember]
        public ISO8601DateTime DateTimeAuthored { get; set; }

        [CanBeNull]
        [DataMember]
        public ISO8601DateTime EffectiveTime { get; set; }

        [CanBeNull]
        [DataMember]
        public ISO8601DateTime AuthorParticipationPeriodOrDateTimeAuthored { get; set; }

        [CanBeNull]
        [DataMember]
        public RoleType RoleType { get; set; }

        [CanBeNull]
        [DataMember]
        ISubjectOfCare IParticipationSubjectOfCare.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IAuthorWithRelationship IParticipationConsumerAuthor.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IPrescriber IParticipationPrescriber.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IDispenser IParticipationDispenser.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IDispenserOrganisation IParticipationDispenserOrganisation.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IHealthcareFacility IParticipationHealthcareFacility.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IPrescriberOrganisation IParticipationPrescriberOrganisation.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IPrescriberInstructionRecipient IParticipationPrescriberInstructionRecipient.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IAuthor IParticipationDocumentAuthor.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IReferee IParticipationReferee.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IReferrer IParticipationReferrer.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IUsualGP IParticipationUsualGP.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IAddressee IParticipationAddressee.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IServiceProvider IParticipationServiceProvider.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IParticipant IParticipation.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        ILegalAuthenticator IParticipationLegalAuthenticator.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IInformationRecipient IParticipationInformationRecipient.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        ICustodian IParticipationCustodian.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IInformationProvider IParticipationInformationProvider.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IPatientNominatedContacts IParticipationPatientNominatedContact.Participant { get; set;  }

        [CanBeNull]
        [DataMember]
        IAcdCustodian IParticipationAcdCustodian.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IServiceRequester IParticipationServiceRequester.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IAuthorNonHealthcareProvider IParticipationAuthorNonHealthcareProvider.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        IAuthorHealthcareProvider IParticipationAuthorHealthcareProvider.Participant { get; set; }

        [CanBeNull]
        [DataMember]
        public IInformationProviderHealthcareProvider Participant { get; set; }


        #endregion

        #region Constructors
        internal Participation()
        {
        }
        #endregion

        #region Validation

        void IParticipationDocumentAuthor.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            if (vb.ArgumentRequiredCheck("Role", Role))
            {
                if (Role != null) Role.ValidateMandatory(vb.Path + "Role", vb.Messages);
            }

            // Get participant in this context
            var participant = ((IParticipationDocumentAuthor)this).Participant;

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }
        }

        void IParticipationDocumentAuthor.ValidateOptional(string path, bool nullableRole , List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            if (vb.ArgumentRequiredCheck("Role", Role))
            {
                if (Role != null && nullableRole)
                {
                    Role.Validate(vb.Path + "Role", vb.Messages);
                } 
                else
                {
                    Role.ValidateMandatory(vb.Path + "Role", vb.Messages);
                }
            }

            // Get participant in this context
            var participant = ((IParticipationDocumentAuthor)this).Participant;

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }
        }

        void IParticipationSubjectOfCare.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            // Get participant in this context
            var participant = ((IParticipationSubjectOfCare)this).Participant;

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null)
                {
                    vb.ArgumentRequiredCheck("Participant.Addresses", participant.Addresses);
                    participant.Validate(vb.Path + "Participant", vb.Messages);

                    // Move the Gender and Date Of Birth validation outside of the person object to cater for newer IG's where these elements are optional
                    var person =(IPersonSubjectOfCare)participant.Person;

                    if (person != null)
                    {
                        vb.ArgumentRequiredCheck("Gender", person.Gender);
                        vb.ArgumentRequiredCheck("DateOfBirth", person.DateOfBirth);
                    }
                }
            }
        }

        void IParticipationSubjectOfCare.ValidateATS(string path, List<ValidationMessage> messages)
        {
          var vb = new ValidationBuilder(path, messages);

          // Get participant in this context
          var participant = ((IParticipationSubjectOfCare)this).Participant;

          if (vb.ArgumentRequiredCheck("Participant", participant))
          {
            if (participant != null)
            {
              participant.Validate(vb.Path + "Participant", vb.Messages);
            }

            vb.RangeCheck("Must be only one participant.Addresses", participant.Addresses, 1, 1);

            if (vb.ArgumentRequiredCheck("participant.Person", participant.Person))
            {
              var person = participant.Person;

              if (person != null)
              {
                vb.ArgumentRequiredCheck("Gender", person.Gender);
                vb.ArgumentRequiredCheck("DateOfBirth", person.DateOfBirth);

                if (person.PersonNames != null)
                  vb.RangeCheck("Must be only one participant.Person.PersonName", participant.Person.PersonNames, 1, 1);

                if (person.DateOfDeath != null)
                  vb.AddValidationMessage(vb.PathName, null, "A Date Of Death can not be specified for EPrescription subjectOfCare");

                if (person.CountryOfBirth != Country.Undefined)
                  vb.AddValidationMessage(vb.PathName, null, "A Country Of Birth can not be specified for EPrescription subjectOfCare");

                if (person.StateOfBirth != AustralianState.Undefined)
                  vb.AddValidationMessage(vb.PathName, null, "A State Of Birth can not be specified for EPrescription subjectOfCare");
              }
            }
          }
        }

        void IParticipationSubjectOfCare.ValidateOptional(string path, bool optionalAddress, bool optionalGender, bool optionalDateOfBirth, List<ValidationMessage> messages)
        {
          var vb = new ValidationBuilder(path, messages);

          // Get participant in this context
          var participant = ((IParticipationSubjectOfCare)this).Participant;

          if (vb.ArgumentRequiredCheck("Participant", participant))
          {
            if (participant != null)
            {

              if (!optionalAddress)
                  vb.ArgumentRequiredCheck("Participant.Addresses", participant.Addresses);

              participant.Validate(vb.Path + "Participant", vb.Messages);
            }

            if (participant != null && participant.Person != null)
            {
              // Move the Gender and Date Of Birth validation outside of the person object to cater for newer IG's where these elements are optional
              var person = (IPersonSubjectOfCare)participant.Person;

                if (!optionalGender)
                vb.ArgumentRequiredCheck("Gender", person.Gender);

                if (!optionalDateOfBirth)
                vb.ArgumentRequiredCheck("DateOfBirth", person.DateOfBirth);
            }
          }
        }

        void IParticipationUsualGP.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            if (vb.ArgumentRequiredCheck("Role", Role))
            {
                if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
            }
            
            // Get participant in this context
            var participant = ((IParticipationUsualGP)this).Participant;

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }
        }

        void IParticipationReferee.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            if (vb.ArgumentRequiredCheck("Role", Role))
            {
                if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
            }
            
            // Get participant in this context
            var participant = ((IParticipationReferee)this).Participant;

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }
        }

        void IParticipationReferrer.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            if (vb.ArgumentRequiredCheck("Role", Role))
            {
                if (Role != null) Role.ValidateMandatory(vb.Path + "Role", vb.Messages);
            }

            // Get participant in this context
            var participant = ((IParticipationReferrer)this).Participant;

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }
        }

        void IParticipationAddressee.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            // Get participant in this context
            var participant = ((IParticipationAddressee)this).Participant;

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }

            if (vb.ArgumentRequiredCheck("Role", Role))
            {
                if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
            }
        }

        void IParticipationPrescriber.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            if (vb.ArgumentRequiredCheck("Role", Role))
            {
                if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
            }
  
            // Get participant in this context
            var participant = ((IParticipationPrescriber)this).Participant;

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null)
                {
                  participant.Validate(vb.Path + "Participant", vb.Messages);

                  if (participant.Person != null)
                  {
                     vb.ArgumentRequiredCheck("participant.Person.Occupation", participant.Person.Occupation);
                  }
                }
            }
        }

        void IParticipationDispenser.ValidateATS(string path, List<ValidationMessage> messages)
        {
          var vb = new ValidationBuilder(path, messages);

          vb.ArgumentRequiredCheck("DateTimeAuthored", DateTimeAuthored);

          if (vb.ArgumentRequiredCheck("Role", Role))
          {
            if (Role != null)
            {
              Role.Validate(vb.Path + "Role", vb.Messages);

              if (!(Role.Code == "2515" && Role.CodeSystemCode == "2.16.840.1.113883.13.62" && Role.DisplayName == "Pharmacists"))
                vb.AddValidationMessage(vb.Path + "Role", null, "The Dispenser Role should have a code '2515' and a CodeSystemCode = '2.16.840.1.113883.13.62' and a DisplayName = 'Pharmacists'");
            }
          }

          // Get participant in this context
          var participant = ((IParticipationDispenser)this).Participant;

          if (vb.ArgumentRequiredCheck("Participant", participant))
            if (participant != null) participant.ValidateATS(vb.Path + "Participant", vb.Messages);

        }

        void IParticipationPrescriber.ValidateATS(string path, List<ValidationMessage> messages)
        {
          var vb = new ValidationBuilder(path, messages);

          if (vb.ArgumentRequiredCheck("Role", Role))
          {
            if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
          }

          // Get participant in this context
          var participant = ((IParticipationPrescriber)this).Participant;

          if (vb.ArgumentRequiredCheck("Participant", participant))
          {
            if (participant != null)
            {
              participant.Validate(vb.Path + "Participant", vb.Messages);

              if (participant.Addresses != null)
                  vb.RangeCheck("IParticipationPrescriber.Addresses", participant.Addresses, 0, 1);

              if (vb.ArgumentRequiredCheck("IParticipationPrescriber.Person", participant.Person))
              {
                  vb.RangeCheck("ParticipationPrescriber.Person.Identifiers", participant.Person.Identifiers, 1, 1);
                  vb.RangeCheck("ParticipationPrescriber.Person.PersonNames", participant.Person.PersonNames, 1, 1);
              }
            }
          }

        }

        void IParticipationPrescriberOrganisation.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            // Get participant in this context
            var participant = ((IParticipationPrescriberOrganisation)this).Participant;

            if (vb.ArgumentRequiredCheck("Role", Role))
            {
                if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
            }

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }
        }

        void IParticipationPrescriberOrganisation.ValidateATS(string path, List<ValidationMessage> messages)
        {
          var vb = new ValidationBuilder(path, messages);

          // Get participant in this context
          var participant = ((IParticipationPrescriberOrganisation)this).Participant;

          if (vb.ArgumentRequiredCheck("Role", Role))
          {
            if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
          }

          if (vb.ArgumentRequiredCheck("Participant", participant))
          {
            if (participant != null)
            {
              participant.Validate(vb.Path + "Participant", vb.Messages);

              if (participant.Organisation != null)
              {
                 vb.RangeCheck("ParticipationPrescriberOrganisation.Organisation.Identifiers", participant.Organisation.Identifiers, 1, 1);
              }

              if (participant.Addresses != null)
              {
                 vb.RangeCheck("ParticipationPrescriberOrganisation.Addresses", participant.Addresses, 1, 1);
              }

              if (participant.ElectronicCommunicationDetails != null)
              {
                 vb.ArgumentRequiredCheck("ParticipationPrescriberOrganisation.ElectronicCommunicationDetails", participant.ElectronicCommunicationDetails);
              }
            }
          }
        }

        void IParticipationPatientNominatedContact.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            // Get participant in this context
            var participant = ((IParticipationPatientNominatedContact)this).Participant;

            if (vb.ArgumentRequiredCheck("Role", Role))
            {
                if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
            }

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }
        }

        void IParticipationAcdCustodian.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            // Get participant in this context
            var participant = ((IParticipationAcdCustodian)this).Participant;

            if (vb.ArgumentRequiredCheck("Role", Role))
            {
                if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
            }

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }
        }

        void IParticipationServiceProvider.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            if (vb.ArgumentRequiredCheck("Role", Role))
            {
                if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
            }

            // Get participant in this context
            var participant = ((IParticipationServiceProvider)this).Participant;

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }
        }

        void IParticipationServiceRequester.Validate(string path, List<ValidationMessage> messages)
        {
          var vb = new ValidationBuilder(path, messages);

          if (vb.ArgumentRequiredCheck("Role", Role))
          {
            if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
          }

          if (ParticipationPeriod != null)
          {
             ParticipationPeriod.Validate(vb.Path + "ParticipationPeriod", vb.Messages);
          }

          // Get participant in this context
          var participant = ((IParticipationServiceRequester)this).Participant;

          if (vb.ArgumentRequiredCheck("Participant", participant))
          {
            if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
          }
        }

        void IParticipationDispenser.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            // Get participant in this context
            var participant = ((IParticipationDispenser)this).Participant;

            if (vb.ArgumentRequiredCheck("Role", Role))
            {
              if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
            }

            vb.ArgumentRequiredCheck("DateTimeAuthored", DateTimeAuthored);

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }
        }

        void IParticipationDispenserOrganisation.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            // Get participant in this context
            var participant = ((IParticipationDispenserOrganisation)this).Participant;

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }
        }

        void IParticipationDispenserOrganisation.ValidateATS(string path, List<ValidationMessage> messages)
        {
          var vb = new ValidationBuilder(path, messages);

          // Get participant in this context
          var participant = ((IParticipationDispenserOrganisation)this).Participant;

          if (vb.ArgumentRequiredCheck("Participant", participant))
          {
            if (participant != null) participant.ValidateATS(vb.Path + "Participant", vb.Messages);
          }
        }

        void IParticipationPrescriberInstructionRecipient.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            // Get participant in this context
            var participant = ((IParticipationPrescriberInstructionRecipient)this).Participant;

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }
        }

        void IParticipationLegalAuthenticator.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);
            var participant = ((IParticipationLegalAuthenticator)this).Participant;

            if (Role != null)
            {
                if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
            }

            // Get participant in this context
            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }
        }

        void IParticipationLegalAuthenticator.ValidateATS(string path, List<ValidationMessage> messages)
        {
          var vb = new ValidationBuilder(path, messages);
          var participant = ((IParticipationLegalAuthenticator)this).Participant;

          if (Role != null)
          {
            if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
          }

          // Get participant in this context
          if (vb.ArgumentRequiredCheck("Participant", participant))
          {
            if (participant != null)
            {
              participant.Validate(vb.Path + "Participant", vb.Messages);

              if (vb.ArgumentRequiredCheck("IParticipationLegalAuthenticator.Person",participant.Person))
              {

                if (vb.ArgumentRequiredCheck("participant.Person.Identifiers", participant.Person.Identifiers))
                 vb.RangeCheck("IParticipationLegalAuthenticator.Person.Identifiers", participant.Person.Identifiers, 1, 1);

                 vb.ArgumentRequiredCheck("IParticipationLegalAuthenticator.Person.PersonNames", participant.Person.PersonNames);
              }

              if (vb.ArgumentRequiredCheck("IParticipationLegalAuthenticator.Organisation", participant.Organisation))
              {
                vb.ArgumentRequiredCheck("IParticipationLegalAuthenticator.Organisation.Identifiers", participant.Organisation.Identifiers);
              }
            }
          }
        }

        void IParticipationInformationRecipient.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            // Get participant in this context
            var participant = ((IParticipationInformationRecipient)this).Participant;

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }
        }

        void IParticipationCustodian.ValidateATS(string path, List<ValidationMessage> messages)
        {
          var vb = new ValidationBuilder(path, messages);

          // Get participant in this context
          var participant = ((IParticipationCustodian)this).Participant;

          if (vb.ArgumentRequiredCheck("Participant", participant))
          {
            if (participant != null)
            {
              participant.Validate(vb.Path + "Participant", vb.Messages);

              if (vb.ArgumentRequiredCheck("IParticipationCustodian.Organisation", participant.Organisation))
                if (vb.ArgumentRequiredCheck("IParticipationCustodian.Organisation.Identifiers", participant.Organisation.Identifiers))
                vb.RangeCheck("IParticipationCustodian.Organisation.Identifiers", participant.Organisation.Identifiers, 1, 1);
            }
          }
        }

        void IParticipationCustodian.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            // Get participant in this context
            var participant = ((IParticipationCustodian)this).Participant;

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }

        }

        void IParticipationConsumerAuthor.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            // Get participant in this context
            var participant = ((IParticipationConsumerAuthor)this).Participant;

            vb.ArgumentRequiredCheck("AuthorParticipationPeriodOrDateTimeAuthored", AuthorParticipationPeriodOrDateTimeAuthored);

            if (vb.ArgumentRequiredCheck("Role", Role))
            {
                if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
            }

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
            }
        }

        void IParticipationInformationProvider.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            // Get participant in this context
            var participation = ((IParticipationInformationProvider)this);

            if (participation.ParticipationPeriod != null) 
            {
               if (participation.ParticipationPeriod.Type != IntervalType.Low)
               {
                 vb.AddValidationMessage(vb.Path + ".ParticipationPeriod", null, "ParticipationPeriod must be instanticated using CdaInterval.CreateLow");
               }
            }

            if (vb.ArgumentRequiredCheck("Role", Role))
            {
                if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
            }

            if (vb.ArgumentRequiredCheck("Participant", participation.Participant))
            {
                participation.Participant.Validate(vb.Path + "Participant", vb.Messages);
            }
        }

        void IParticipationInformationProviderHealthcareProvider.Validate(string path, List<ValidationMessage> messages)
        {
          var vb = new ValidationBuilder(path, messages);

          // Get participant in this context
          var participation = ((IParticipationInformationProviderHealthcareProvider)this);

          if (participation.ParticipationPeriod != null)
          {
            if (participation.ParticipationPeriod.Type != IntervalType.Low)
            {
              vb.AddValidationMessage(vb.Path + ".ParticipationPeriod", null, "ParticipationPeriod must be instanticated using CdaInterval.CreateLow");
            }
          }

          if (vb.ArgumentRequiredCheck("Role", Role))
          {
            if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
          }

          if (vb.ArgumentRequiredCheck("Participant", participation.Participant))
          {
            if (participation.Participant != null) participation.Participant.Validate(vb.Path + "Participant", vb.Messages);
          }
        }

        void IParticipationInformationProviderNonHealthcareProvider.Validate(string path, List<ValidationMessage> messages)
        {
          var vb = new ValidationBuilder(path, messages);

          // Get participant in this context
          var participation = ((IParticipationInformationProviderNonHealthcareProvider)this);

          if (participation.ParticipationPeriod != null)
          {
            if (participation.ParticipationPeriod.Type != IntervalType.Low)
            {
              vb.AddValidationMessage(vb.Path + ".ParticipationPeriod", null, "ParticipationPeriod must be instanticated using CdaInterval.CreateLow");
            }
          }

          if (vb.ArgumentRequiredCheck("Role", Role))
          {
            Role.Validate(vb.Path + "Role", vb.Messages);

            if (Role.Code != "AGNT" || Role.CodeSystemName != "HL7RoleClass" || Role.CodeSystemCode != "2.16.840.1.113883.5.110" || Role.DisplayName !=  "agent")
            {
              vb.AddValidationMessage(vb.Path + ".Role", null, "Role must be of type @code='AGNT', @codeSystemName='HL7RoleClass', @codeSystem='2.16.840.1.113883.5.110', @displayName='agent'");
            }
          }

          if (vb.ArgumentRequiredCheck("Participant", participation.Participant))
          {
            if (participation.Participant != null) participation.Participant.Validate(vb.Path + "Participant", vb.Messages);
          }
        }

        void IParticipationAuthorNonHealthcareProvider.Validate(string path, List<ValidationMessage> messages)
        {
            var vb = new ValidationBuilder(path, messages);

            if (vb.ArgumentRequiredCheck("Role", Role))
            {
                if (Role != null)
                {
                    Role.ValidateMandatory(vb.Path + "Role", vb.Messages);
                }
            }

            // Get participant in this context
            var participant = ((IParticipationAuthorNonHealthcareProvider)this).Participant;

            vb.ArgumentRequiredCheck("AuthorParticipationPeriodOrDateTimeAuthored", AuthorParticipationPeriodOrDateTimeAuthored);

            if (vb.ArgumentRequiredCheck("Participant", participant))
            {
                if (participant != null)
                {
                    participant.Validate(vb.Path + "Participant", vb.Messages);
                }
            }
        }

        void IParticipationAuthorHealthcareProvider.Validate(string path, List<ValidationMessage> messages)
        {
          var vb = new ValidationBuilder(path, messages);

          if (vb.ArgumentRequiredCheck("Role", Role))
          {
            if (Role != null) Role.ValidateMandatory(vb.Path + "Role", vb.Messages);
          }

          // Get participant in this context
          var participant = ((IParticipationAuthorHealthcareProvider)this).Participant;

          vb.ArgumentRequiredCheck("AuthorParticipationPeriodOrDateTimeAuthored", AuthorParticipationPeriodOrDateTimeAuthored);

          if (vb.ArgumentRequiredCheck("Participant", participant))
          {
              if (participant != null) participant.Validate(vb.Path + "Participant", vb.Messages);
          }
        }

        void IParticipationHealthcareFacility.Validate(string path, bool mandatoryRole, bool mandatoryTwoElectronicCommunicationDetail, List<ValidationMessage> messages)
        {
          var vb = new ValidationBuilder(path, messages);

          if (mandatoryRole)
          if (vb.ArgumentRequiredCheck("Role", Role))
          {
            if (Role != null) Role.Validate(vb.Path + "Role", vb.Messages);
          }

          vb.ArgumentRequiredCheck("ParticipationPeriod", ParticipationPeriod);

          // Get participant in this context
          var participant = ((IParticipationHealthcareFacility)this).Participant;

          if (vb.ArgumentRequiredCheck("Participant", participant))
          {
            if (participant != null)
            {
                participant.Validate(vb.Path + "Participant", vb.Messages);

                if (mandatoryTwoElectronicCommunicationDetail)
               if (vb.ArgumentRequiredCheck("ElectronicCommunicationDetails", participant.ElectronicCommunicationDetails))
               {
                   var containsTelephone = false;
                   var containsFax= false;
                   foreach (var electronicCommunicationDetails in participant.ElectronicCommunicationDetails)
                   {
                       if (electronicCommunicationDetails.Medium == ElectronicCommunicationMedium.Telephone || electronicCommunicationDetails.Medium == ElectronicCommunicationMedium.Mobile) 
                           containsTelephone = true;
                       if (electronicCommunicationDetails.Medium == ElectronicCommunicationMedium.Fax) 
                           containsFax = true;
                   }

                   if (!(containsTelephone && containsFax))
                   {
                       vb.AddValidationMessage("Participant.ElectronicCommunicationDetails", null, "The value of at least one Electronic Communication Medium SHALL be 'Telephone' or 'Mobile telephone'. The value of at least one Electronic communication Medium SHALL be 'Facsimile' machine");
                   }

                   if (participant.ElectronicCommunicationDetails != null && participant.ElectronicCommunicationDetails.Count > 2)
                   {
                       vb.AddValidationMessage("Participant.ElectronicCommunicationDetails", null, "2..* ElectronicCommunicationDetails are required for this HEALTHCARE FACILIT ");
                   }
               }
            }
          }
        }
     

      #endregion

    }
}
