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

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
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(Nehta.VendorLibrary.CDA.SCSModel.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
    {
        #region Properties

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

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

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

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

        [CanBeNull]
        [DataMember]
        public ISO8601DateTime PrescriptionWritten { 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]
        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]
        IPatientNominatedContacts IParticipationPatientNominatedContact.Participant { get; set;  }

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

        [CanBeNull]
        [DataMember]
        IServiceRequester IParticipationServiceRequester.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 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);
                }
            }
        }

        void IParticipationSubjectOfCare.ValidateOptionalAddress(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);
          }
        }

        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);

            vb.ArgumentRequiredCheck("PrescriptionWritten", PrescriptionWritten);

            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);
            }
        }

        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 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("DateTimeAuthenticated", DateTimeAuthenticated);

            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 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 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.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;

            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);
            }
        }

        #endregion
    }
}
