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

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

        public static string OutputFolderPath { get; set; }

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

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

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

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

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

        #endregion

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

            var consumerEnteredHealthSummary = PopulateConsumerEnteredHealthSummary(true);

            try
            {
                CDAGenerator.NarrativeGenerator = new CDANarrativeGenerator();

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

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

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

            return xmlDoc;
        }

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

            var consumerEnteredHealthSummary = PopulateConsumerEnteredHealthSummary(true);

            try
            {
                CDAGenerator.NarrativeGenerator = new CDANarrativeGenerator();

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

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

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

            return xmlDoc;
        }

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

            var consumerEnteredHealthSummary = PopulateConsumerEnteredHealthSummary(false);

            try
            {
                CDAGenerator.NarrativeGenerator = new CDANarrativeGenerator();

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

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

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

            return xmlDoc;
        }

        #region Populate Methods
        /// <summary>
        /// This method populates an consumerEnteredHealthSummary model with either the mandatory sections only, or both 
        /// the mandatory and optional sections
        /// </summary>
        /// <param name="mandatorySectionsOnly">mandatorySectionsOnly</param>
        /// <returns>ConsumerEnteredHealthSummary</returns>
        internal static ConsumerEnteredHealthSummary PopulateConsumerEnteredHealthSummary(Boolean mandatorySectionsOnly)
        {
            var consumerEnteredHealthSummary = ConsumerEnteredHealthSummary.CreateConsumerEnteredHealthSummary();

            // Include Logo
            consumerEnteredHealthSummary.IncludeLogo = true;

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

            #region Setup and populate the CDA context model

            // Setup and populate the CDA context model
            var cdaContext = ConsumerEnteredHealthSummary.CreateCDAContext();
            // Document Id
            cdaContext.DocumentId = BaseCDAModel.CreateIdentifier(BaseCDAModel.CreateGuid(), null);
            // Set Id  
            cdaContext.SetId = BaseCDAModel.CreateIdentifier(BaseCDAModel.CreateGuid(), null);
            // CDA Context Version
            cdaContext.Version = "1";

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

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

            consumerEnteredHealthSummary.CDAContext = cdaContext;
            #endregion

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

            consumerEnteredHealthSummary.SCSContext = ConsumerEnteredHealthSummary.CreateSCSContext();

            consumerEnteredHealthSummary.SCSContext.Author = ConsumerEnteredHealthSummary.CreateAuthor();
            PopulateAuthor(consumerEnteredHealthSummary.SCSContext.Author, mandatorySectionsOnly);

            consumerEnteredHealthSummary.SCSContext.SubjectOfCare = ConsumerEnteredHealthSummary.CreateSubjectOfCare();
            GenericObjectReuseSample.HydrateExtendedSubjectofCare(consumerEnteredHealthSummary.SCSContext.SubjectOfCare, mandatorySectionsOnly);

            #endregion

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

            // Allergies And Adverse Reactions
            consumerEnteredHealthSummary.SCSContent.AllergiesAndAdverseReactions = CreateAllergiesAndAdverseReactions(mandatorySectionsOnly);

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

            #endregion

            return consumerEnteredHealthSummary;
        }

        public static void PopulateAuthor(IParticipationConsumerAuthor author, bool mandatoryOnly)
        {
            var person = BaseCDAModel.CreatePerson();

            // Document Author > Role
            author.Role = BaseCDAModel.CreateRole(Occupation.MedicalOncologist);

            // Document Author > Participant
            author.Participant = ConsumerEnteredHealthSummary.CreateParticipantForAuthor();

            // Document Author > Participant > Entity Identifier
            person.Identifiers = new List<Identifier> { 
                BaseCDAModel.CreateHealthIdentifier(HealthIdentifierType.IHI, "8003605833337658") 
            };

            // Document Author > Participant > Per-son or Organisation or Device > Person > Person Name
            var name1 = BaseCDAModel.CreatePersonName();
            name1.FamilyName = "Doctor";

            var name2 = BaseCDAModel.CreatePersonName();
            name2.FamilyName = "Wong";

            person.PersonNames = new List<IPersonName>() { name1, name2 };
        
            if (!mandatoryOnly)
            {
                author.Participant.RelationshipToSubjectOfCare = BaseCDAModel.CreateRole(Occupation.MedicalOncologist);

                // Document Author > Participation Period
                author.AuthorParticipationPeriodOrDateTimeAuthored = new ISO8601DateTime(DateTime.Now);

                name1.GivenNames = new List<string> { "Good" };
                name1.Titles = new List<string> { "Doctor" };
                name1.NameUsages = new List<NameUsage> { NameUsage.Legal };

                name2.GivenNames = new List<string> { "Davey" };
                name2.Titles = new List<string> { "Brother" };
                name2.NameUsages = new List<NameUsage> { NameUsage.NewbornName };

                // Document Author > Participant > Address
                var address1 = BaseCDAModel.CreateAddress();
                address1.AddressPurpose = AddressPurpose.Residential;
                address1.AustralianAddress = BaseCDAModel.CreateAustralianAddress();

                var address2 = BaseCDAModel.CreateAddress();
                address2.AddressPurpose = AddressPurpose.TemporaryAccommodation;
                address2.AustralianAddress = BaseCDAModel.CreateAustralianAddress();

                var addressList = new List<IAddress> { address1, address2 };

                author.Participant.Addresses = addressList;

                address1.AustralianAddress.UnstructuredAddressLines = new List<string> { "1 Clinician Street" };
                address1.AustralianAddress.SuburbTownLocality = "Nehtaville";
                address1.AustralianAddress.State = AustralianState.QLD;
                address1.AustralianAddress.PostCode = "5555";
                address1.AustralianAddress.DeliveryPointId = 32568931;

                address2.AustralianAddress.UnstructuredAddressLines = new List<string> { "2 Clinician Street" };
                address2.AustralianAddress.SuburbTownLocality = "Nehtaville";
                address2.AustralianAddress.State = AustralianState.QLD;
                address2.AustralianAddress.PostCode = "5555";
                address2.AustralianAddress.DeliveryPointId = 32568931;

                // Document Author > Participant > Elec-tronic Communication Detail
                var coms1 = BaseCDAModel.CreateElectronicCommunicationDetail(
                    "0345754566",
                    ElectronicCommunicationMedium.Telephone,
                    ElectronicCommunicationUsage.WorkPlace);

                var coms2 = BaseCDAModel.CreateElectronicCommunicationDetail(
                    "authen@globalauthens.com",
                    ElectronicCommunicationMedium.Email,
                    ElectronicCommunicationUsage.WorkPlace);

                author.Participant.ElectronicCommunicationDetails = new List<ElectronicCommunicationDetail> { coms1, coms2 };
            }

            author.Participant.Person = person;      
        }

        private static List<Reaction> CreateAllergiesAndAdverseReactions(bool mandatoryOnly)
        {
            if (mandatoryOnly)
            {
                return null;
            }
            else
            {
                return new List<Reaction>()
                {
                    ConsumerEnteredHealthSummary.CreateAllergyAndAdverseReaction("agent 1", new List<string>() { "mani 1a", "mani 1b"}),
                    ConsumerEnteredHealthSummary.CreateAllergyAndAdverseReaction("agent 2", new List<string>() { "mani 2a", "mani 2b"})
                };
            }
        }

        private static List<IMedication>  CreateMedications(bool mandatoryOnly)
        {
            if (mandatoryOnly)
                return null;
            else
            {
                var list = new List<IMedication>()
                {
                    ConsumerEnteredHealthSummary.CreateMedication("medicine 1", "take 1", "indication 1", "comment 1"),
                    ConsumerEnteredHealthSummary.CreateMedication("medicine 2", "take 2", "indication 2", "comment 2")
                };

                return list;
            }
        }

        #endregion
    }
}
