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

using JetBrains.Annotations;

using Nehta.VendorLibrary.CDA.Common;
using Nehta.VendorLibrary.CDA.Common.Enums;
using Nehta.VendorLibrary.CDA.Generator.Enums;
using Nehta.VendorLibrary.CDA.SCSModel;
using Nehta.VendorLibrary.CDA.SCSModel.Common.Entities;
using Nehta.VendorLibrary.Common;
using Nehta.VendorLibrary.CDA.SCSModel.DischargeSummary.Interfaces;
using CDA.Generator.Common.SCSModel.ConsolidatedView.Entities;

namespace Nehta.VendorLibrary.CDA.Generator
{
    /// <summary>
    /// This is the first version of the NEHTA narrative generator. 
    /// 
    /// It implements the INarrativeGenerator and is used with the CDAGenerator to build the narrative
    /// for each CDA Section.
    /// </summary>
    public class CDANarrativeGenerator : INarrativeGenerator
    {
        #region Constants
        private const String DELIMITER = "<CR>";
        private const String DELIMITERBREAK = "<BR>";
        #endregion

        /// <summary>
        /// This method creates the narrative for the subject of care
        /// </summary>
        /// <param name="subjectOfCareParticipation">subjectOfCareParticipation</param>
        /// <param name="patientId">patientId</param>
        /// <param name="showEntitlements">Show the entitlements for the subjectOfCare</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(IParticipationSubjectOfCare subjectOfCareParticipation, String patientId, Boolean showEntitlements)
        {
            var strucDocTableList = new List<StrucDocTable>();
            var narrative = new List<List<String>>();

            if (subjectOfCareParticipation != null && subjectOfCareParticipation.Participant != null && subjectOfCareParticipation.Participant.Person != null)
            {
                var person = subjectOfCareParticipation.Participant.Person;

                if (
                        person.DateOfBirthCalculatedFromAge.HasValue ||
                        person.DateOfBirthAccuracyIndicator != null ||
                        person.Age.HasValue ||
                        person.AgeAccuracyIndicator != null ||
                        person.BirthPlurality.HasValue ||
                        person.DateOfDeathAccuracyIndicator != null ||
                        person.MothersOriginalFamilyName != null ||
                        person.SourceOfDeathNotification != null ||
                        (showEntitlements && subjectOfCareParticipation.Participant.Entitlements != null && subjectOfCareParticipation.Participant.Entitlements.Any())
                    )
                    {
                      var columnHeaders = new List<string> { "Field", "ResultValue" };

                    //Date of Birth calculated from age
                    if (person.DateOfBirthCalculatedFromAge.HasValue)
                    narrative.Add
                    (
                        CreateNarrativeEntry("Date of Birth is Calculated From Age", (person.DateOfBirthCalculatedFromAge))
                    );

                    //Date of Birth accuracy indicatory
                    if (person.DateOfBirthAccuracyIndicator  != null)
                    narrative.Add
                    (
                        CreateNarrativeEntry("Date of Birth Accuracy Indicator", person.DateOfBirthAccuracyIndicator)
                    );

                    //Age Accuracy Indicator
                    if (person.AgeAccuracyIndicator.HasValue)
                    narrative.Add
                    (
                        CreateNarrativeEntry("Age Accuracy Indicator", person.AgeAccuracyIndicator)
                    );
                   
                    //Birth Plurality
                    if (person.BirthPlurality.HasValue)
                    narrative.Add                   
                    (
                       CreateNarrativeEntry("Birth Plurality", person.BirthPlurality, null)
                    );

                    //Age
                    if (person.Age.HasValue)
                    narrative.Add
                    (
                       CreateNarrativeEntry("Age", person.Age, person.AgeUnitOfMeasure.HasValue ? person.AgeUnitOfMeasure.Value.GetAttributeValue<NameAttribute, String>(x => x.Comment) : AgeUnitOfMeasure.Year.GetAttributeValue<NameAttribute, String>(x => x.Comment))
                    );

                    //Date of Death accuracy indicatory
                    if (person.DateOfDeathAccuracyIndicator != null)
                    narrative.Add
                    (
                       CreateNarrativeEntry("Date of Death Accuracy Indicator", person.DateOfDeathAccuracyIndicator)
                    );

                    // Source Of Death Notification
                    if (person.SourceOfDeathNotification.HasValue)
                        narrative.Add
                        (
                           CreateNarrativeEntry("Source Of Death Notification", person.SourceOfDeathNotification.GetAttributeValue<NameAttribute, String>(x => x.Name))
                        );

                    // Source Of Death Notification
                    if (person.MothersOriginalFamilyName != null)
                        narrative.Add
                            (  
                                CreateNarrativeEntry("Mothers Original Family Name", BuildPersonNames(new List<IPersonName> { person.MothersOriginalFamilyName }))
                            );

                    // Entitilements
                    if (showEntitlements)
                    {
                        if (subjectOfCareParticipation.Participant.Entitlements != null && subjectOfCareParticipation.Participant.Entitlements.Any())
                        {
                            foreach (var entitlement in subjectOfCareParticipation.Participant.Entitlements)
                            {
                                CodableText codeableTextEntry = null;

                                if (entitlement.Type != EntitlementType.Undefined)
                                {
                                    codeableTextEntry = new CodableText
                                    {
                                        Code = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Code),
                                        DisplayName = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                        OriginalText = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                        CodeSystem = CodingSystem.NCTISEntitlementTypeValues
                                    };
                                }

                                narrative.Add
                                    (
                                        CreateNarrativeEntry(entitlement, codeableTextEntry)
                                    );
                            }
                        }
                    }

                    strucDocTableList.Add
                        (
                            PopulateTable
                                (
                                    "DEMOGRAPHIC DATA",
                                    null,
                                    columnHeaders.ToArray(),
                                    null,
                                    narrative
                                )
                        );
                }
            }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.Text = new [] 
                {
                    "This section contains no entries."
                };
            }

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the adverse subject reactions section
        /// </summary>
        /// <param name="allergiesAndAdverseReactions">allergiesAndAdverseReactions</param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(List<Reaction> allergiesAndAdverseReactions)
        {
            var strucDocTableList = new List<StrucDocTable>();
            var narrative = new List<List<String>>();

            if (allergiesAndAdverseReactions != null && allergiesAndAdverseReactions.Any())
            {
                    foreach (var reaction in allergiesAndAdverseReactions)
                    {
                        var manfestationDesc = String.Empty;

                        if (reaction.ReactionEvent != null)
                            if (reaction.ReactionEvent.Manifestations != null)
                            {
                                foreach (var manifestation in reaction.ReactionEvent.Manifestations)
                                {
                                    manfestationDesc += manifestation.NarrativeText + DELIMITER;
                                }
                            }

                        narrative.Add(
                            new List<string>
                                {
                                    reaction.SubstanceOrAgent != null
                                        ? reaction.SubstanceOrAgent.NarrativeText
                                        : String.Empty,
                                    manfestationDesc
                                }
                            );
                    }

                    strucDocTableList.Add
                        (
                        PopulateTable
                            (
                            "Adverse Reactions",
                            null,
                            new[]
                                {
                                    "Substance/Agent",
                                    "Manifestation"
                                },
                            new string[0],
                            narrative
                            )
                        );
            }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the adverse subject reactions section
        /// </summary>
        /// <param name="adverseSubstanceReactions">allergiesAndAdverseReactions</param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(IAdverseReactions adverseSubstanceReactions)
        {
            var strucDocTableList = new List<StrucDocTable>();
            var narrative = new List<List<String>>();
            var narrativeParagraph = new List<StrucDocParagraph>();

            if (adverseSubstanceReactions != null)
            {
                // Adverse Substance Reaction
                if (adverseSubstanceReactions.AdverseSubstanceReaction != null)
                {
                    foreach (var adverserReaction in adverseSubstanceReactions.AdverseSubstanceReaction)
                    {
                        var manfestationDesc = String.Empty;

                        if (adverserReaction.ReactionEvent != null)
                            if (adverserReaction.ReactionEvent.Manifestations != null)
                            {
                                foreach (var manifestation in adverserReaction.ReactionEvent.Manifestations)
                                {
                                    manfestationDesc += manifestation.NarrativeText + DELIMITER;
                                }
                            }


                        narrative.Add(
                            new List<string>
                                {
                                    adverserReaction.SubstanceOrAgent != null ? adverserReaction.SubstanceOrAgent.NarrativeText : String.Empty,
                                    manfestationDesc
                                }
                            );
                    }

                    strucDocTableList.Add
                        (
                        PopulateTable
                            (
                            null,
                            null,
                            new[]
                                {
                                    "Substance/Agent",
                                    "Manifestation"
                                },
                            new string[0],
                            narrative
                            )
                        );
                }

               // Exclusion statement
              if (adverseSubstanceReactions.ExclusionStatement != null)
              {
                  narrativeParagraph.Add(CreateExclusionStatementNarrative("Exclusion Statement", adverseSubstanceReactions.ExclusionStatement));
              }

            }
        
            var strucDocText = new StrucDocText();

            // Table
            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            // Narrative Paragraph
            if (narrativeParagraph.Any())
            {
              strucDocText.paragraph = narrativeParagraph.ToArray();
            } 

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the medications section
        /// </summary>
        /// <param name="medications"></param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(List<IMedication> medications)
        {
            var narrative = new List<List<String>>();
            var strucDocTableList = new List<StrucDocTable>();

            var narativeHeader = new List<string>
                {
                    "Medication",
                    "Directions",
                    "Clinical Indication"
                };

            if (medications != null && medications.Any())
            {
                    narrative = new List<List<String>>();

                    foreach (var medication in medications)
                    {
                        //medicine_list + clinical Indication
                        if (medication.Medicine != null)
                        {
                            var medicationList = new List<String>
                                                 {
                                                    medication.Medicine.NarrativeText,
                                                    !medication.Directions.IsNullOrEmptyWhitespace() ? medication.Directions : medication.DirectionsNullFlavour.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                                    medication.ClinicalIndication
                                                 };

                            // Dynamical add comment is it is not null
                            if (!medication.Comment.IsNullOrEmptyWhitespace())
                            {
                                medicationList.Add(medication.Comment);

                                if (narativeHeader.Contains("Comment") == false)
                                {
                                    narativeHeader.Add("Comment");
                                }
                            }

                            //medicine_list + clinical Indication
                            narrative.Add(medicationList);
                        }
                    }

                    // Close empty cells
                    foreach (var narrativeEntry in narrative.Where(narrativeEntry => narativeHeader.Contains("Comment") && narrativeEntry.Count == 3))
                    {
                        narrativeEntry.Add(string.Empty);
                    }

                    strucDocTableList.Add
                    (
                        PopulateTable
                        (
                            "Medications",
                            null,
                            narativeHeader.ToArray(),
                            new string[0],
                            narrative
                        )
                    );
            }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the medications section
        /// </summary>
        /// <param name="reviewedMedications"></param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(IMedications reviewedMedications)
        {
            var narrative = new List<List<string>>();
            var strucDocTableList = new List<StrucDocTable>();
            var narrativeParagraph = new List<StrucDocParagraph>();

            if (reviewedMedications != null)
            {
                if (reviewedMedications.Medications != null)
                {
                    narrative = new List<List<String>>();

                    var narativeHeader = new List<string>()
                                             {
                                                 "Medication",
                                                 "Directions",
                                                 "Clinical Indication"
                                             };


                    foreach (var medication in reviewedMedications.Medications)
                    {

                        //medicine_list + clinical Indication
                        if (medication.Medicine != null)
                        {
                            var medicationList = new List<String>
                                                     {
                                                         medication.Medicine.NarrativeText,
                                                         !medication.Directions.IsNullOrEmptyWhitespace() ? medication.Directions : medication.DirectionsNullFlavour.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                                         medication.ClinicalIndication
                                                     };

                            // Dynamical add comment is it is not null
                            if (!medication.Comment.IsNullOrEmptyWhitespace())
                            {
                                medicationList.Add(medication.Comment);

                                if (narativeHeader.Contains("Comment") == false)
                                {
                                    narativeHeader.Add("Comment");
                                }
                            }

                            //medicine_list + clinical Indication
                            narrative.Add(medicationList);
                        }
                    }

                    // Close empty cells
                    foreach (var narrativeEntry in narrative.Where(narrativeEntry => narativeHeader.Contains("Comment") && narrativeEntry.Count == 3))
                    {
                        narrativeEntry.Add(string.Empty);
                    }

                    strucDocTableList.Add
                    (
                        PopulateTable
                        (
                            null,
                            null,
                            narativeHeader.ToArray(),
                            null,
                            narrative
                        )
                    );
                }

                // Exclusions
                if (reviewedMedications.ExclusionStatement != null)
                {
                  narrativeParagraph.Add(CreateExclusionStatementNarrative("Exclusion Statement", reviewedMedications.ExclusionStatement));
                }
            }

            var strucDocText = new StrucDocText();

            // Structured Tables
            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            // Narrative Paragraph
            if (narrativeParagraph.Any())
            {
              strucDocText.paragraph = narrativeParagraph.ToArray();
            } 

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the medications section
        /// </summary>
        /// <param name="medications">medications</param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(IMedicationsEReferral medications)
        {
            List<List<String>> narrative;
            var strucDocTableList = new List<StrucDocTable>();
            var narrativeParagraph = new List<StrucDocParagraph>();

            if (medications != null)
            {
                if (medications.MedicationsList != null)
                {
                    narrative = new List<List<String>>();

                    foreach (var medication in medications.MedicationsList)
                    {
                        if (medication != null)
                        {
                            // Medications
                            narrative.Add(
                                            new List<string>
                                            {
                                                medication.Medicine != null ?  medication.Medicine.NarrativeText : String.Empty,
                                                !medication.Directions.IsNullOrEmptyWhitespace() ? medication.Directions : medication.DirectionsNullFlavour.GetAttributeValue<NameAttribute, String>(x => x.Name)
                                            }
                                          );
                        }
                       
                    }

                    strucDocTableList.Add
                    (
                        PopulateTable
                        (
                            "Medications",
                            null,
                            new[]
                                {
                                    "Medication",
                                    "Directions"
                                },
                            new string[0],
                            narrative
                        )
                    );
                }

                // Exclusion statement
                if (medications.ExclusionStatement != null)
                {
                    narrativeParagraph.Add(CreateExclusionStatementNarrative("Exclusion Statement", medications.ExclusionStatement));
                }

            }
            var strucDocText = new StrucDocText();

            // Structured Tables
            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            // Narrative Paragraph
            if (narrativeParagraph.Any())
            {
              strucDocText.paragraph = narrativeParagraph.ToArray();
            } 

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the medications section
        /// </summary>
        /// <param name="medications">IMedicationsSpecialistLetter</param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(IMedicationsSpecialistLetter medications)
        {
            List<List<String>> narrative;
            var strucDocTableList = new List<StrucDocTable>();
            var narrativeParagraph = new List<StrucDocParagraph>();

            if (medications != null)
            {
                if (medications.MedicationsList != null)
                {
                    var narativeHeader = new List<string>()
                                             {
                                                 "Medication",
                                                 "Directions",
                                                 "Clinical Indication",
                                                 "Change Type",
                                                 "Change or Recommendation?",
                                                 "Change Description",
                                                 "Change Reason"
                                             };

                    narrative = new List<List<String>>();

                    foreach (var medication in medications.MedicationsList)
                    {
                        var medicationList = new List<String>
                                              {
                                                  medication.Medicine != null ? medication.Medicine.NarrativeText : String.Empty,
                                                  !medication.Directions.IsNullOrEmptyWhitespace() ? medication.Directions : medication.DirectionsNullFlavour.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                                  medication.ClinicalIndication ?? String.Empty,
                                                  medication.ChangeType.HasValue ? medication.ChangeType.GetAttributeValue<NameAttribute, String>(x => x.Name) : medication.ChangeTypeNullFlavour.GetAttributeValue<NameAttribute, String>(x => x.Name),                               
                                                  medication.RecommendationOrChange.HasValue ? medication.RecommendationOrChange.GetAttributeValue<NameAttribute, String>(x => x.Name) : medication.RecommendationOrChangeNullFlavour.GetAttributeValue<NameAttribute, String>(x => x.Name),                                    
                                                  medication.ChangeDescription ?? String.Empty,
                                                  medication.ChangeReason ?? String.Empty
                                              };

                        // Dynamical add comment is it is not null
                        if (!medication.Comment.IsNullOrEmptyWhitespace())
                        {
                            medicationList.Add(medication.Comment);

                            if (narativeHeader.Contains("Comment") == false)
                            {
                                narativeHeader.Add("Comment");
                            }
                        } 

                        //medicine_list + clinical Indication
                        narrative.Add(medicationList);
                    }

                    // Close empty cells
                    foreach (var narrativeEntry in narrative.Where(narrativeEntry => narativeHeader.Contains("Comment") && narrativeEntry.Count == 7))
                    {
                        narrativeEntry.Add(string.Empty);
                    }

                    strucDocTableList.Add
                    (
                        PopulateTable
                        (
                            "Reviewed Medications - Medications",
                            null,
                            narativeHeader.ToArray(),
                            new string[0],
                            narrative
                        )
                    );
                }

                // Exclusions
                if (medications.ExclusionStatement != null)
                {
                    narrativeParagraph.Add(CreateExclusionStatementNarrative("Exclusion Statement", medications.ExclusionStatement));
                }
            }

            var strucDocText = new StrucDocText();

            // Structured Tables
            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            // Narrative Paragraph
            if (narrativeParagraph.Any())
            {
              strucDocText.paragraph = narrativeParagraph.ToArray();
            } 

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the medical history section
        /// </summary>
        /// <param name="medicalHistory">medicalHistory</param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(IMedicalHistory medicalHistory)
        {

            var strucDocTableList = new List<StrucDocTable>();
            var narrativeParagraph = new List<StrucDocParagraph>();

            if (medicalHistory != null)
            {
                List<List<String>> narrative;

                // PROCEDURES
                if (medicalHistory.Procedures != null && medicalHistory.Procedures.Any())
                {
                    strucDocTableList.AddRange
                        (
                            CreateNarrativeEntry(medicalHistory.Procedures, false)
                        );
                }

                // PROCEDURE EXCLUSIONS
                if (medicalHistory.ProceduresExclusionStatement != null)
                {
                  narrativeParagraph.Add(CreateExclusionStatementNarrative("Procedures - Exclusion Statement", medicalHistory.ProceduresExclusionStatement));
                }

                //PROBLEM / DIAGNOSIS
                if (medicalHistory.ProblemDiagnosis != null && medicalHistory.ProblemDiagnosis.Any())
                {
                    strucDocTableList.AddRange
                        (
                            CreateNarrativeEntry(medicalHistory.ProblemDiagnosis, false)
                        );
                }

                // PROBLEM DIAGNOSIS EXCLUSIONS
                if (medicalHistory.ProblemDiagnosisExclusionStatement != null)
                {
                   narrativeParagraph.Add(CreateExclusionStatementNarrative("Problem Diagnosis - Exclusion Statement", medicalHistory.ProblemDiagnosisExclusionStatement));
                }

                //OTHER MEDICAL HISTORY
                if (medicalHistory.MedicalHistoryItems != null && medicalHistory.MedicalHistoryItems.Any())
                {
                    strucDocTableList.AddRange
                        (
                            CreateNarrativeEntry(medicalHistory.MedicalHistoryItems)
                        );
                }
            }

            var strucDocText = new StrucDocText();

            // Structured Tables
            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            // Narrative Paragraph
            if (narrativeParagraph.Any())
            {
              strucDocText.paragraph = narrativeParagraph.ToArray();
            } 

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the medical history section
        /// </summary>
        /// <param name="medicalHistory">medicalHistory</param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(IMedicalHistoryWithoutExclusions medicalHistory)
        {
            var strucDocTableList = new List<StrucDocTable>();

            if (medicalHistory != null)
            {
                // PROCEDURES
                if (medicalHistory.Procedures != null && medicalHistory.Procedures.Any())
                {
                    strucDocTableList.AddRange
                        (
                            CreateNarrativeEntry(medicalHistory.Procedures, false)
                        );
                }

                //PROBLEM / DIAGNOSIS
                if (medicalHistory.ProblemDiagnosis != null && medicalHistory.ProblemDiagnosis.Any())
                {
                    strucDocTableList.AddRange
                        (
                            CreateNarrativeEntry(medicalHistory.ProblemDiagnosis, false)
                        );
                }

                //OTHER MEDICAL HISTORY
                if (medicalHistory.MedicalHistoryItems != null && medicalHistory.MedicalHistoryItems.Any())
                {
                    strucDocTableList.AddRange
                        (
                            CreateNarrativeEntry(medicalHistory.MedicalHistoryItems)
                        );
                }

            }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.Text = new string[] { "This section contains no entries."};
            }

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the reviewed immunisations section
        /// </summary>
        /// <param name="immunisations">reviewedImmunisations</param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(Immunisations immunisations)
        {
            var strucDocTableList = new List<StrucDocTable>();
            var narrativeParagraph = new List<StrucDocParagraph>();

            if (immunisations != null)
            {

                //ADMINISTERED IMMUNISATION
                if (immunisations.AdministeredImmunisation != null && immunisations.AdministeredImmunisation.Any())
                {
                    strucDocTableList.AddRange
                        (
                                CreateNarrativeEntry(immunisations.AdministeredImmunisation)
                        );

                }

                //EXCLUSION STATEMENT
                if (immunisations.ExclusionStatement != null)
                {
                  narrativeParagraph.Add(CreateExclusionStatementNarrative("Exclusion Statement", immunisations.ExclusionStatement));
                }
            }

            var strucDocText = new StrucDocText();

            // Structured Tables
            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            // Narrative Paragraph
            if (narrativeParagraph.Any())
            {
              strucDocText.paragraph = narrativeParagraph.ToArray();
            } 

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the response details section
        /// </summary>
        /// <param name="responseDetails">IResponseDetails</param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(IResponseDetails responseDetails)
        {
            var narrative = new List<String>();
            var responseNarrative = new List<String>();

            var strucDocTableList = new List<StrucDocTable>();

            if (responseDetails != null)
            {
                var narrativeFound = false;
                
                // ResponseDetails
                if (responseDetails.Procedures != null && responseDetails.Procedures.Any())
                {
                    narrative.Add(CreateNarrativeEntry(responseDetails.Procedures));
                    narrativeFound = true;
                }

                else
                {
                    narrative.Add(String.Empty);
                }

                //Diagnoses 
                if(responseDetails.Diagnoses != null)
                {
                    narrative.Add(CreateNarrativeEntry(responseDetails.Diagnoses));
                    narrativeFound = true;
                }
                else
                {
                    narrative.Add(String.Empty);
                }

              //Other Diagnoses 
                if (responseDetails.OtherDiagnosisEntries != null && responseDetails.OtherDiagnosisEntries.Any())
                {
                   narrative.Add(CreateNarrativeEntry(responseDetails.OtherDiagnosisEntries));
                   narrativeFound = true;
                }
                else
                {
                    narrative.Add(String.Empty);
                }

              responseNarrative.Add
                         (
                         !responseDetails.ResponseNarrative.IsNullOrEmptyWhitespace() ? responseDetails.ResponseNarrative : String.Empty
                         );

                strucDocTableList.Add
                           (
                               PopulateTable
                                   (
                                       "Response Narrative",
                                       null,
                                       null,
                                       null,
                                       new List<List<String>> { responseNarrative }
                                   )
                           );


                if (narrativeFound)
                strucDocTableList.Add
                           (
                               PopulateTable
                                   (
                                       "Response Details",
                                       null,
                                       new[] { "Procedures", "Diagnoses ", "Other Diagnoses " },
                                       null,
                                       new List<List<String>> { narrative }
                                   )
                           );
            }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the recommendations section
        /// </summary>
        /// <param name="recommendations">IRecommendations</param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(IRecommendations recommendations)
        {
            List<List<String>> narrative;
            var strucDocTableList = new List<StrucDocTable>();
            var narrativeParagraph = new List<StrucDocParagraph>();

            if (recommendations != null)
            {
                if (recommendations.Recommendation != null && recommendations.Recommendation.Any())
                {
                    narrative = new List<List<String>>();
                    var narrativeEntry = new List<String>();

                    recommendations.Recommendation.ForEach
                        (                            
                            recommendation =>
                                {
                                narrativeEntry = new List<String>();
                                narrativeEntry.Add(CreateDuration(recommendation.TimeFrame));
                                narrativeEntry.Add(recommendation.Narrative);

                                if (recommendation.Addressee != null
                                    && recommendation.Addressee.Participant != null)
                                {
                                    if (recommendation.Addressee.Participant.Person != null)
                                        narrativeEntry.Add(BuildPersonNames(recommendation.Addressee.Participant.Person.PersonNames));
                                    else
                                        narrativeEntry.Add(string.Empty);

                                    narrativeEntry.Add(CreateAddress(recommendation.Addressee.Participant.Addresses, recommendation.Addressee.Participant.ElectronicCommunicationDetails));

                                    //if (recommendation.Addressee.Participant.Person != null && recommendation.Addressee.Participant.Person.Organisation != null)
                                    //{

                                    //    if (recommendation.Addressee.Participant.Person.Organisation.Occupation != null)
                                    //        narrativeEntry.Add(recommendation.Addressee.Participant.Person.Organisation.Occupation.GetAttributeValue<NameAttribute, string>(x => x.Name));
                                    //    else
                                    //        narrativeEntry.Add(string.Empty);

                                    //    if (recommendation.Addressee.Participant.Person.Organisation.PositionInOrganisation != null)
                                    //        narrativeEntry.Add(CreateNarrativeEntry(recommendation.Addressee.Participant.Person.Organisation.PositionInOrganisation));
                                    //    else
                                    //        narrativeEntry.Add(string.Empty);

                                    //    if (recommendation.Addressee.Participant.Person.Organisation.EmploymentType != null)
                                    //        narrativeEntry.Add(CreateNarrativeEntry(recommendation.Addressee.Participant.Person.Organisation.EmploymentType));
                                    //    else
                                    //        narrativeEntry.Add(string.Empty);
                                    //}
                                    //else
                                    //{
                                    //    narrativeEntry.Add(string.Empty);
                                    //    narrativeEntry.Add(string.Empty);
                                    //    narrativeEntry.Add(string.Empty);
                                    //}
                                }
                                narrative.Add(narrativeEntry);
                            }
                        );

                    
                    
                    strucDocTableList.Add
                        (
                            PopulateTable
                                (
                                    "Recommendations",
                                    null,
                                    new[] { "Time frame", "Recommendation", "Addressee", "Address / Contact" /*,"Occupation","Position In Organisation","Employment Type" */},
                                    new String[] { },
                                    narrative
                                )
                        );
                }

                // Exclusions
                if (recommendations.ExclusionStatement != null)
                {
                  narrativeParagraph.Add(CreateExclusionStatementNarrative("Exclusion Statement", recommendations.ExclusionStatement));
                }
            }

            var strucDocText = new StrucDocText();

            // Structured Tables
            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            // Narrative Paragraph
            if (narrativeParagraph.Any())
            {
              strucDocText.paragraph = narrativeParagraph.ToArray();
            } 

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the other Test Result section
        /// </summary>
        /// <param name="otherTestResult">OtherTestResult</param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(OtherTestResult otherTestResult)
        {
            var strucDocText = new StrucDocText();
            var narrative = new List<List<Object>>();
            var strucDocTableList = new List<StrucDocTable>();
            var renderMultiMediaList = new List<StrucDocRenderMultiMedia>();

            if (otherTestResult != null)
            {
              // Report Date
              if (otherTestResult.ReportDate != null)
                narrative.Add
                  (
                    new List<Object>
                      {
                        "Report Date",
                        otherTestResult.ReportDate.NarrativeText()
                      }
                  );

              // Report Name
              if (otherTestResult.ReportName != null)
                narrative.Add
                  (
                    new List<Object>
                      {
                        "Report Name",
                        otherTestResult.ReportName.NarrativeText
                      }
                  );

              // Report Status 
              if (otherTestResult.ReportStatus != null && otherTestResult.ReportStatus != ResultStatus.Undefined)
                narrative.Add
                  (
                    new List<Object>
                      {
                        "Report Status",
                        otherTestResult.ReportStatus.GetAttributeValue<NameAttribute, string>(x => x.Name)
                      }
                  );

              // Report Content ExternalData
              if (otherTestResult.ReportContent != null && otherTestResult.ReportContent.ExternalData != null)
                narrative.Add
                  (
                    new List<Object>
                      {
                        "Report Content",
                        CreateEncapsulatedData(otherTestResult.ReportContent.ExternalData, ref renderMultiMediaList)   
                      }
                  );

              // Report Content Text
              if (otherTestResult.ReportContent != null && !otherTestResult.ReportContent.Text.IsNullOrEmptyWhitespace())
                narrative.Add
                  (
                    new List<Object>
                      {
                        "Report Content",
                        otherTestResult.ReportContent.Text
                      }
                  );

              strucDocTableList.Add
                (
                  PopulateTable
                    (
                      null,
                      null,
                      null,
                      null,
                      narrative
                    )
                );

              strucDocText.table = strucDocTableList.ToArray();
            }

          return strucDocText;

        }

        /// <summary>
        /// This method creates the narrative for the diagnostic investigations section
        /// </summary>
        /// <param name="diagnosticInvestigations">IDiagnosticInvestigations</param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(IDiagnosticInvestigations diagnosticInvestigations)
        {
            var strucDocTableList = new List<StrucDocTable>();

            if (diagnosticInvestigations != null)
            {
                //This doesn't do anything as this section contains sub sections that render the narrative.
            }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            return strucDocText;
        }


        /// <summary>
        /// This method creates the narrative for the pathology test result section
        /// </summary>
        /// <param name="pathologyTestResult">pathologyTestResult</param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(PathologyTestResult pathologyTestResult)
        {
            var strucDocText = new StrucDocText();
            var narrative = new List<List<Object>>();
            var strucDocTableList = new List<StrucDocTable>();
            var renderMultiMediaList = new List<StrucDocRenderMultiMedia>();

            // Simple narrative
            if (!pathologyTestResult.xPreNarrative.IsNullOrEmptyWhitespace())
            {
                //PathologyTestResult TestResultName 
                if (pathologyTestResult.TestResultName != null)
                    narrative.Add
                    (
                        new List<Object>
                            {
                                "Pathology Test Result Name",
                                pathologyTestResult.TestResultName.NarrativeText
                            }
                    );

                //Overall Test Result Status 
                if (pathologyTestResult.OverallTestResultStatus.HasValue && pathologyTestResult.OverallTestResultStatus.Value != ResultStatus.Undefined)
                    narrative.Add
                    (
                        new List<Object>
                            {
                                "Overall Test Result Status",
                                pathologyTestResult.OverallTestResultStatus.Value.GetAttributeValue<NameAttribute, string>(x => x.Name)
                            }
                    );

               //Narrative 
                if (pathologyTestResult.OverallTestResultStatus.HasValue && pathologyTestResult.OverallTestResultStatus.Value != ResultStatus.Undefined)
                    narrative.Add
                    (
                        new List<Object>
                            {
                                "Test Result Date Time",
                                pathologyTestResult.TestResultDateTime.NarrativeText()
                            }
                    );


                strucDocTableList.Add
                   (
                        PopulateTable
                            (
                               null,
                               null,
                               null,
                               null,
                               narrative
                            )
                   );

                strucDocTableList.Add(poulateTablexPreNarrative(pathologyTestResult.xPreNarrative));                

                strucDocText.table = strucDocTableList.ToArray();

                return strucDocText;
            } 

            // Complex Narrative
            if (pathologyTestResult != null)
            {
                if (pathologyTestResult.PathologyTestSpecimenDetail != null)
                {
                    strucDocTableList.AddRange
                        (
                            CreateNarrativeEntry(pathologyTestResult.PathologyTestSpecimenDetail, "Pathology Test Specimen Detail", ref narrative, ref renderMultiMediaList)
                        );
                }

                if (pathologyTestResult.PathologyTestResultGroup != null)
                {
                    List<List<Object>> pathologyTestResultsList;

                    //Create Organizer and relationships, these are nested within the observation entry below
                    foreach (var testResultGroup in pathologyTestResult.PathologyTestResultGroup)
                    {
                        pathologyTestResultsList = new List<List<Object>>();

                        if (testResultGroup.ResultGroupSpecimenDetail != null)
                        {
                            var specimenDetail = CreateNarrativeEntry(new List<SpecimenDetail> { testResultGroup.ResultGroupSpecimenDetail }, "Result Group Specimen Detail", ref narrative, ref renderMultiMediaList);

                            if (specimenDetail != null)
                            {
                                strucDocTableList.Add(specimenDetail.FirstOrDefault());
                            }
                        }

                        if (testResultGroup.Results != null)
                        {
                            foreach (var pathologyTestResults in testResultGroup.Results)
                            {
                                var resultValueReferenceRangeDetails = String.Empty;
                                var pathologyTestResultsComments = String.Empty;

                                if (pathologyTestResults.ResultValueReferenceRangeDetails != null)
                                {
                                    foreach (var resultValueReferenceRange in pathologyTestResults.ResultValueReferenceRangeDetails)
                                    {
                                        resultValueReferenceRangeDetails += resultValueReferenceRange.ResultValueReferenceRangeMeaning.NarrativeText + DELIMITER + resultValueReferenceRange.Range.NarrativeText;
                                    }
                                }

                                if (pathologyTestResults.Comments != null)
                                {
                                    pathologyTestResultsComments = pathologyTestResults.Comments.Aggregate(pathologyTestResultsComments, (current, comment) => current + (comment + DELIMITER));
                                }

                                //Narrative 
                                pathologyTestResultsList.Add
                                    (
                                        new List<Object>
                                        {
                                            testResultGroup.ResultGroupName.NarrativeText.IsNullOrEmptyWhitespace() ? String.Empty : testResultGroup.ResultGroupName.NarrativeText,
                                            pathologyTestResults.ResultName == null ? String.Empty : pathologyTestResults.ResultName.NarrativeText,
                                            pathologyTestResults.ResultValue == null  ? String.Empty : (pathologyTestResults.ResultValue.ValueAsCodableText == null  ? String.Empty : pathologyTestResults.ResultValue.ValueAsCodableText.NarrativeText + DELIMITER) + (pathologyTestResults.ResultValue.ValueAsQuantity == null  ? String.Empty : pathologyTestResults.ResultValue.ValueAsQuantity.NarrativeText + DELIMITER) + (pathologyTestResults.ResultValue.ValueAsQuantityRange == null  ? String.Empty : pathologyTestResults.ResultValue.ValueAsQuantityRange.NarrativeText + DELIMITER),    
                                            pathologyTestResults.ResultValueStatus.HasValue ? pathologyTestResults.ResultValueStatus.Value.GetAttributeValue<NameAttribute, string>(x => x.Name) : String.Empty,
                                            resultValueReferenceRangeDetails,
                                            pathologyTestResultsComments,
                                            pathologyTestResults.ReferenceRangeGuidance.IsNullOrEmptyWhitespace() ? String.Empty : pathologyTestResults.ReferenceRangeGuidance,
                                            pathologyTestResults.ResultStatus.HasValue ? pathologyTestResults.ResultStatus.Value.GetAttributeValue<NameAttribute, string>(x => x.Name) : String.Empty 
                                        }
                                    );
                            }
                        }

                        strucDocTableList.Add
                           (
                                PopulateTable
                                    (
                                       String.Format("Test Result Group"),
                                       null,
                                       new[] { "Group Name", "Result Name", "Result Value", "Result Value Status", "Result Value Reference Range Details", "Result Comment", "Reference Range Guidance", "Result Status" },
                                       null,
                                       pathologyTestResultsList
                                    )
                           );
                    }
                }


                var pathologicalDiagnosis = String.Empty;
                if (pathologyTestResult.PathologicalDiagnosis != null)
                {
                    foreach (var diagnosis in pathologyTestResult.PathologicalDiagnosis)
                    {
                        pathologicalDiagnosis += diagnosis.NarrativeText + DELIMITER;
                    }
                }

                var testRequestDetailsList = new List<List<Object>>();

                if (pathologyTestResult.TestRequestDetails != null)
                {
                    foreach (var requestDetails in pathologyTestResult.TestRequestDetails)
                    {
                        var testRequestDetails = String.Empty;
                        if (requestDetails.TestsRequested != null)
                        {
                            foreach (var testsRequested in requestDetails.TestsRequested)
                            {
                                testRequestDetails += testsRequested.NarrativeText + DELIMITER;
                            }
                        }

                        testRequestDetailsList.Add
                        (
                           new List<Object>
                           {
                                requestDetails.LaboratoryTestResultIdentifier != null ? requestDetails.LaboratoryTestResultIdentifier.NarrativeText : String.Empty,
                                testRequestDetails
                           }
                        );
                    }

                    strucDocTableList.Insert
                        (
                            0,
                            (
                                PopulateTable
                                    (
                                        "Test Request Details",
                                        null,
                                        new[] { "Laboratory Test Result Identifier", "Test Requested Name(s)" },
                                        null,
                                        testRequestDetailsList
                                    )
                            )
                        );
                }

                if (narrative.Any())
                {
                    strucDocTableList.Add
                    (
                        PopulateTable
                            (
                                "Anatomical Site(s)", 
                                String.Empty,
                                new[] { /*"Specimen Identifier",*/ "Description", "Location", "Side", "Image / File" },
                                null,
                                narrative
                            )
                    );
                }

                narrative = new List<List<Object>>
                                        {
                                            new List<Object>
                                            {
                                                pathologyTestResult.TestResultDateTime != null ? pathologyTestResult.TestResultDateTime.NarrativeText() :  String.Empty,
                                                pathologyTestResult.TestResultName != null ? pathologyTestResult.TestResultName.NarrativeText : String.Empty,
                                                pathologyTestResult.DiagnosticService.HasValue ? pathologyTestResult.DiagnosticService.Value.GetAttributeValue<NameAttribute, String>(x => x.Name) : String.Empty,
                                                pathologyTestResult.OverallTestResultStatus.HasValue ? pathologyTestResult.OverallTestResultStatus.Value.GetAttributeValue<NameAttribute, String>(x => x.Name) : String.Empty,
                                                pathologyTestResult.ClinicalInformationProvided.IsNullOrEmptyWhitespace() ? String.Empty : pathologyTestResult.ClinicalInformationProvided,
                                                pathologyTestResult.PathologicalDiagnosis != null && pathologyTestResult.PathologicalDiagnosis.Any() ? pathologicalDiagnosis : String.Empty,
                                                pathologyTestResult.Conclusion.IsNullOrEmptyWhitespace() ? String.Empty : pathologyTestResult.Conclusion,
                                                pathologyTestResult.Comment.IsNullOrEmptyWhitespace() ? String.Empty : pathologyTestResult.Comment,
                                                pathologyTestResult.TestResultRepresentation != null ? CreateEncapsulatedData(pathologyTestResult.TestResultRepresentation, ref renderMultiMediaList) : null
                                            }
                                        };

                strucDocTableList.Insert
                    (
                        0,
                        (
                            PopulateTable
                                (
                                    "Pathology Test Result(s)",
                                    null,
                                    new[] { "Test Result DateTime", "Test Result Name", "Diagnostic Service", "Overall Test Result Status", "Clinical Information Provided", "Pathological Diagnosis", "Pathology Test Conclusion", "Test Comment", "Image / File" },
                                    null,
                                    narrative
                                )
                        )
                    );
            }

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.Any() ? strucDocTableList.ToArray() : null;
            }

            if (renderMultiMediaList.Any())
            {
                strucDocText.renderMultiMedia = renderMultiMediaList.ToArray();
            }

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the imaging examination result section
        /// </summary>
        /// <param name="imagingExaminationResult">IImagingExaminationResultEReferral</param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(IImagingExaminationResult imagingExaminationResult)
        {
            List<List<Object>> narrative;
            var strucDocTableList = new List<StrucDocTable>();
            var renderMultiMediaList = new List<StrucDocRenderMultiMedia>();

            if (imagingExaminationResult != null)
            {

                //Anatomical location image
                if (imagingExaminationResult.AnatomicalSite != null && imagingExaminationResult.AnatomicalSite.Any())
                {
                    narrative = new List<List<Object>>();

                    foreach (var anatomicalSite in imagingExaminationResult.AnatomicalSite)
                    {
                        //populate the narrative for each anatomical site
                        if (
                                !anatomicalSite.Description.IsNullOrEmptyWhitespace() ||
                                anatomicalSite.AnatomicalLocation != null
                            )
                            {
                            narrative.Add(
                                            new List<Object>
                                              {
                                                  anatomicalSite.Description, 
                                                  anatomicalSite.AnatomicalLocation != null && anatomicalSite.AnatomicalLocation.NameOfLocation != null ? anatomicalSite.AnatomicalLocation.NameOfLocation.NarrativeText : String.Empty, 
                                                  anatomicalSite.AnatomicalLocation != null && anatomicalSite.AnatomicalLocation.Side != null ? anatomicalSite.AnatomicalLocation.Side.NarrativeText : String.Empty, 
                                                  anatomicalSite.Images != null ? CreateEncapsulatedData(anatomicalSite.Images, ref renderMultiMediaList) : null
                                              }
                                         );
                       }
                    }

                    if (narrative.Any())
                    {
                        strucDocTableList.Add
                        (
                            PopulateTable
                                (
                                    "Anatomical Site(s)",
                                    null,
                                    new[] { "Description", "Location", "Side", "Image / File" },
                                    null,
                                    narrative
                                )
                        );
                    }
                }

                //Imaging examination name, modality, status, addational infromation provided and findings
                narrative = new List<List<Object>>();

                //Imaging Examination Result Name 
                if (imagingExaminationResult.ResultDateTime != null)
                {
                  narrative.Add
                        (
                             new List<Object> { "Imaging Examination Result Date Time", imagingExaminationResult.ResultDateTime.NarrativeText() }
                        );
                }

                //Imaging Examination Result Name 
                if (imagingExaminationResult.ExaminationResultName != null)
                {
                  narrative.Add
                        (
                             new List<Object> { "Result name", imagingExaminationResult.ExaminationResultName.NarrativeText }
                        );
                }

                //Imaging examination result modality
                if (imagingExaminationResult.Modality != null)
                  narrative.Add
                    (
                           new List<Object> { "Modality", imagingExaminationResult.Modality.NarrativeText }
                    );

                //Imaging examination result status
                if (imagingExaminationResult.ExaminationResultStatus != null)
                  narrative.Add
                    (
                          new List<Object> { "Result Status", imagingExaminationResult.ExaminationResultStatus.Value.GetAttributeValue<NameAttribute, string>(x => x.Name) }
                    );

                //Clinical information provided
                if (!imagingExaminationResult.ClinicalInformationProvided.IsNullOrEmptyWhitespace())
                  narrative.Add
                    (
                         new List<Object> { "Clinical Information", imagingExaminationResult.ClinicalInformationProvided }
                    );

                //Findings
                if (!imagingExaminationResult.Findings.IsNullOrEmptyWhitespace())
                  narrative.Add
                    (
                          new List<Object> {  "Findings", imagingExaminationResult.Findings }
                    );

                //Result representation
                if (!imagingExaminationResult.ExaminationResultRepresentation.IsNullOrEmptyWhitespace())
                  narrative.Add
                    (
                          new List<Object> { "Result Representation", imagingExaminationResult.ExaminationResultRepresentation }
                    );

                strucDocTableList.Add
                    (
                        PopulateTable
                            (
                                "Imaging Examination Result Details",
                                null,
                                new [] { "Field", "ResultValue" }, 
                                null,
                                narrative
                            )
                    );

                //Examination result group
                if (imagingExaminationResult.ResultGroup != null && imagingExaminationResult.ResultGroup.Any())
                {
                    strucDocTableList.AddRange
                        (
                            CreateNarrativeEntry(imagingExaminationResult.ResultGroup, ref renderMultiMediaList)
                        );
                }

                //Examination request details
                if (imagingExaminationResult.ExaminationRequestDetails != null)
                {
                    strucDocTableList.AddRange
                        (
                            CreateNarrativeEntry(imagingExaminationResult.ExaminationRequestDetails, ref renderMultiMediaList)
                        );
                }
            }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            if (renderMultiMediaList.Any())
            {
                strucDocText.renderMultiMedia = renderMultiMediaList.ToArray();
            }

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the reason for referral section; or any section that takes in a 
        /// narrative and a date time along with a duration.
        /// </summary>
        /// <param name="dateTime">dateTime</param>
        /// <param name="duration">duration</param>
        /// <param name="narrative">narrative</param>
        /// <param name="heading">heading</param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(ISO8601DateTime dateTime, CdaInterval duration, string narrative, String heading)
        {
            var narrativeText = new List<List<String>>();
            var strucDocTableList = new List<StrucDocTable>();
            var tableHeading = String.Empty;
            var strucDocText = new StrucDocText();
            var date = String.Empty;

            if (narrative != null && !narrative.IsNullOrEmptyWhitespace())
            {
                var durationAsString = String.Empty;
                var columHeaders = new List<String>();

                if (dateTime != null)
                {
                    columHeaders.Add("Date");
                    tableHeading = "Date ";

                    date = dateTime.NarrativeText();
                }

                if (duration != null)
                {
                    columHeaders.Add("Duration");

                    tableHeading +=  tableHeading == String.Empty ? "Duration" : "and Duration";

                    durationAsString = CreateDuration(duration);
                }

                var narrativeEntry = new List<String>();

                if(!date.IsNullOrEmptyWhitespace())
                {
                    narrativeEntry.Add(date);
                }

                if(!durationAsString.IsNullOrEmptyWhitespace())
                {
                    narrativeEntry.Add(durationAsString);
                }                     

                narrativeText.Add(narrativeEntry);

                strucDocTableList.Add
                    (
                        PopulateTable
                            (
                                tableHeading,
                                null,
                                columHeaders.ToArray(),
                                null,
                                narrativeText
                              )
                            );

                strucDocTableList.Add
                    (
                        PopulateTable
                            (
                                null,
                                null,
                                new [] { "Reason for Referral" }, 
                                null,
                                new List<List<String>> { new List<string> { narrative } }
                              )
                            );

                strucDocText.table = strucDocTableList.ToArray();
            }

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the XML Body File
        /// </summary>
        /// <param name="externalData">externalData</param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(ExternalData externalData)
        {
            var strucDocText = new StrucDocText();
            var renderMultiMediaList = new List<StrucDocRenderMultiMedia>();

            if(externalData != null)
            {
                if (!renderMultiMediaList.Select(multiMediaItem => multiMediaItem.referencedObject).Contains(externalData.ID))
                {
                    renderMultiMediaList.Add
                                 (
                                   externalData.ConvertToStrucDocRenderMultiMedia()
                                 );
                }

                strucDocText.renderMultiMedia = renderMultiMediaList.ToArray();
            }

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the XML Body File
        /// </summary>
        /// <param name="externalDataList">externalData</param>
        /// <returns>StrucDocText</returns>
        [NotNull]
        public StrucDocText CreateNarrative(List<ExternalData> externalDataList)
        {
            var strucDocText = new StrucDocText();
            var renderMultiMediaList = new List<StrucDocRenderMultiMedia>();

            if (
                    externalDataList != null &&
                    externalDataList.Any()
                )
            {
                externalDataList.ForEach
                    (
                        externalData =>
                            {
                                if (!renderMultiMediaList.Select(multiMediaItem => multiMediaItem.referencedObject).Contains(externalData.ID))
                                {
                                    renderMultiMediaList.Add
                                    (
                                        externalData.ConvertToStrucDocRenderMultiMedia()
                                    );
                                }
                            }
                    );

                strucDocText.renderMultiMedia = renderMultiMediaList.ToArray();
            }

            return strucDocText;
        }

        #region Private Create Narative Entry methods

        [NotNull]
        private static IEnumerable<StrucDocTable> CreateNarrativeEntry(ICollection<IImagingExaminationRequest> examinationRequests, ref List<StrucDocRenderMultiMedia> renderMultiMediaList)
        {
            var narrative = new List<List<String>>();
            var strucDocTableList = new List<StrucDocTable>();

            if (examinationRequests != null && examinationRequests.Any())
            {

                foreach (var imageExaminationRequest in examinationRequests)
                {
                    //Narrative text
                    var examinationRequestedName = String.Empty;
                    if (imageExaminationRequest.ExaminationRequestedName != null)
                        imageExaminationRequest.ExaminationRequestedName.ForEach
                            (
                            name => examinationRequestedName += examinationRequestedName.EndsWith(DELIMITER) ? name : !examinationRequestedName.IsNullOrEmptyWhitespace() ? DELIMITER + name : name
                            );

                    //DICOM study ID
                    var studyIdentifier = String.Empty;
                    if (imageExaminationRequest.StudyIdentifier != null)
                    {
                        studyIdentifier = "DICOM Study ID: " + imageExaminationRequest.StudyIdentifier.NarrativeText;
                    }

                    //Report ID
                    var reportIdentifier = String.Empty;
                    if (imageExaminationRequest.ReportIdentifier != null)
                    {
                        reportIdentifier = "Report ID: " + imageExaminationRequest.ReportIdentifier.NarrativeText;
                    }

                    //Image Details
                    var imageDetailSeriesIdentifier = String.Empty;
                    var imageDetailSubjectPosition = String.Empty;
                    var imageDateTime = String.Empty;

                    var imageLink = String.Empty;

                    if (imageExaminationRequest.ImageDetails != null && imageExaminationRequest.ImageDetails.Any())
                    {
                        foreach (var imageDetail in imageExaminationRequest.ImageDetails)
                        {
                            imageDetailSeriesIdentifier += imageDetail.SeriesIdentifier != null ? "DICOM Series ID: " + imageDetail.SeriesIdentifier.NarrativeText : String.Empty;

                            imageDetailSubjectPosition += !imageDetail.SubjectPosition.IsNullOrEmptyWhitespace() ?
                                                           imageDetailSubjectPosition.EndsWith(DELIMITER) ?
                                                           imageDetail.SubjectPosition :!imageDetailSubjectPosition.IsNullOrEmptyWhitespace() ?
                                                           DELIMITER + imageDetail.SubjectPosition : imageDetail.SubjectPosition : String.Empty;

                            if (imageDetail.Image != null)
                            {
                                if (imageDateTime.IsNullOrEmptyWhitespace())
                                {
                                    imageDateTime += imageDetail.DateTime.NarrativeText();
                                }
                                else
                                {
                                    if (!imageDateTime.EndsWith(DELIMITER))
                                    {
                                        imageDateTime += DELIMITER;
                                    }

                                    imageDateTime += imageDetail.DateTime.NarrativeText() + DELIMITER;
                                }
                            }
                        }
                    }


                    //Build a list of image links to alongside the table.
                    var narrativeDisplayList = new List<StrucDocRenderMultiMedia>();
                    if (imageExaminationRequest.ImageDetails != null)
                    {
                        foreach (var imageDetails in imageExaminationRequest.ImageDetails)
                        {
                            narrativeDisplayList.AddRange(CreateEncapsulatedData(imageDetails.Image, ref renderMultiMediaList));
                        }
                    }

                    var narrative2 = new List<List<Object>>
                                                  {
                                                      new List<Object>
                                                          {
                                                              imageDateTime,
                                                              examinationRequestedName,
                                                              studyIdentifier + DELIMITER + reportIdentifier +
                                                              DELIMITER + imageDetailSeriesIdentifier,
                                                              imageDetailSubjectPosition,
                                                              narrativeDisplayList ?? null
                                                          },

                                                  };


                    //DICOM Study ID", "Report ID", "DICOM Series ID
                    strucDocTableList.Add
                        (
                            PopulateTable
                                (
                                    "Examination Request(s) - Image Details",
                                    "",
                                    new[] { "Image Date", "Requested Examination Name", "Identifiers", "Subject Position", "Image / File" },
                                    new[] { "" },
                                    narrative2
                                )
                        );
                }
            }

            return strucDocTableList;
        }

        [NotNull]
        private static IEnumerable<StrucDocTable> CreateNarrativeEntry(ICollection<IImagingResultGroup> resultGroups, ref List<StrucDocRenderMultiMedia> renderMultiMediaList)
        {
            List<List<String>> narrative = null;
            var strucDocTableList = new List<StrucDocTable>();

            if (resultGroups != null && resultGroups.Any())
            {
                foreach (var resultGroup in resultGroups)
                {
                    narrative = new List<List<string>>();

                    foreach (var result in resultGroup.Results)
                    {
                        var resultValueReferenceRangeDetails = String.Empty;
                        var testResultsComments = String.Empty;

                        if (result.ResultValueReferenceRangeDetails != null)
                        {
                            foreach (var resultValueReferenceRange in result.ResultValueReferenceRangeDetails)
                            {
                                resultValueReferenceRangeDetails += resultValueReferenceRange.ResultValueReferenceRangeMeaning.NarrativeText + DELIMITER + resultValueReferenceRange.Range.NarrativeText;
                            }
                        }

                        if (result.Comments != null)
                        {
                            foreach (var comment in result.Comments)
                            {
                                testResultsComments += comment + DELIMITER;
                            }
                        }

                        narrative.Add
                            (
                                new List<String>
                                {
                                    resultGroup.ResultGroupName.NarrativeText.IsNullOrEmptyWhitespace() ? String.Empty : resultGroup.ResultGroupName.NarrativeText,
                                    result.ResultName == null ? String.Empty : result.ResultName.NarrativeText,
                                    result.ResultValue == null  ? String.Empty : (result.ResultValue.ValueAsCodableText == null  ? String.Empty : result.ResultValue.ValueAsCodableText.NarrativeText + DELIMITER) + (result.ResultValue.ValueAsQuantity == null  ? String.Empty : result.ResultValue.ValueAsQuantity.NarrativeText + DELIMITER) + (result.ResultValue.ValueAsQuantityRange == null  ? String.Empty : result.ResultValue.ValueAsQuantityRange.NarrativeText + DELIMITER),    
                                    result.ResultValueStatus.HasValue ? result.ResultValueStatus.Value.GetAttributeValue<NameAttribute, string>(x => x.Name) : String.Empty,
                                    resultValueReferenceRangeDetails,
                                    testResultsComments,
                                }
                            );
                    }

                    //Build the table for this result group
                    strucDocTableList.Add
                    (
                         PopulateTable
                             (
                                "Result Group(s)",
                                null,
                                new[] { "Result Group", "Result Name", "Result Value", "Result Value - Status", "Result Value - Range", "Result Comment" },
                                null,
                                narrative
                             )
                    );


                    if (resultGroup.AnatomicalSite != null)
                        strucDocTableList.Add(CreateAnatomicalSites(new List<AnatomicalSite> { resultGroup.AnatomicalSite }, ref renderMultiMediaList));

                }
            }

            return strucDocTableList;
        }

        [NotNull]
        private static IEnumerable<StrucDocTable> CreateNarrativeEntry(ICollection<IImmunisation> immunisations)
        {
            var narrative = new List<List<String>>();
            var strucDocTableList = new List<StrucDocTable>();

            if (immunisations != null && immunisations.Any())
            {

                foreach (var imunisation in immunisations)
                {
                        narrative.Add(
                            new List<String>
                                {
                                    imunisation.DateTime != null ? imunisation.DateTime.NarrativeText() : String.Empty,
                                    imunisation.Medicine != null ? imunisation.Medicine.NarrativeText : String.Empty,
                                    imunisation.SequenceNumber.HasValue ? imunisation.SequenceNumber.Value.ToString(CultureInfo.InvariantCulture) : String.Empty
                                });
                }
            }

            if (narrative.Any())
            {
                strucDocTableList.Add
                    (
                        PopulateTable
                        (
                            "Administered Immunisations",
                            null,
                            new[] { "Date Time", "Medicine", "Vaccine Sequence Number" },
                            new string[] { },
                            narrative
                        )
                    );
            }

            return strucDocTableList;
        }

        [NotNull]
        private static IEnumerable<StrucDocTable> CreateNarrativeEntry(IEnumerable<SpecimenDetail> specimenDetails, String narrativeTitle, ref List<List<Object>> anatomicalSiteNarrative, ref List<StrucDocRenderMultiMedia> renderMultiMediaList)
        {
          var narrative = new List<List<Object>>();
          var strucDocTableList = new List<StrucDocTable>();

          if (specimenDetails != null)
          {
            foreach (var specimenDetail in specimenDetails)
            {
              var physicalDetailsOutput = string.Empty;

              var narrativeDisplayList = new List<StrucDocRenderMultiMedia>();
              if (specimenDetail.PhysicalDetails != null)
              {
                foreach (var physicalDetails in specimenDetail.PhysicalDetails)
                {
                  if (physicalDetails != null)
                  {
                    if (physicalDetails.Volume != null)
                    {
                      physicalDetailsOutput = physicalDetailsOutput + physicalDetails.Volume.Value + physicalDetails.Volume.Units + DELIMITER;
                    }
                    else
                    {
                      physicalDetailsOutput += physicalDetails.Weight.Value + physicalDetails.Weight.Units + DELIMITER;
                    }

                    narrativeDisplayList.AddRange(CreateEncapsulatedData(physicalDetails.Image, ref renderMultiMediaList));
                  }
                }
              }

              if (specimenDetail.AnatomicalSite != null)
              {
                var anatomicalImage = string.Empty;
                foreach (var anatomicalSite in specimenDetail.AnatomicalSite)
                {
                  //populate the narrative for each anatomical site
                  if (!anatomicalSite.Description.IsNullOrEmptyWhitespace() || anatomicalSite.AnatomicalLocation != null)
                  {
                    anatomicalSiteNarrative.Add(
                        new List<Object>
                                        {
                                            specimenDetail.SpecimenIdentifier == null ? string.Empty : specimenDetail.SpecimenIdentifier.NarrativeText,
                                            anatomicalSite.Description,
                                            anatomicalSite.AnatomicalLocation != null && anatomicalSite.AnatomicalLocation.NameOfLocation != null
                                                ? anatomicalSite.AnatomicalLocation.NameOfLocation.NarrativeText
                                                : String.Empty,
                                            anatomicalSite.AnatomicalLocation != null && anatomicalSite.AnatomicalLocation.Side != null
                                                ? anatomicalSite.AnatomicalLocation.Side.NarrativeText
                                                : String.Empty,
                                           anatomicalSite.Images != null && anatomicalSite.Images.Count > 0 ? CreateEncapsulatedData(anatomicalSite.Images, ref renderMultiMediaList) : null
                                        }
                        );
                  }
                }
              }

              narrative.Add
                  (
                  new List<Object>
                            {
                                specimenDetail.ReceivedDateTime == null 
                                    ? String.Empty 
                                    : specimenDetail.ReceivedDateTime.NarrativeText(),
                                specimenDetail.SpecimenIdentifier == null ? string.Empty : specimenDetail.SpecimenIdentifier.NarrativeText,
                                specimenDetail.ParentSpecimenIdentifier == null ? string.Empty : specimenDetail.ParentSpecimenIdentifier.NarrativeText,
                                specimenDetail.ContainerIdentifier == null ? string.Empty : specimenDetail.ContainerIdentifier.NarrativeText,
                                specimenDetail.SpecimenTissueType == null
                                    ? String.Empty
                                    : specimenDetail.SpecimenTissueType.NarrativeText.IsNullOrEmptyWhitespace()
                                          ? String.Empty
                                          : specimenDetail.SpecimenTissueType.NarrativeText,
                                specimenDetail.SpecimenDescription.IsNullOrEmptyWhitespace()
                                    ? String.Empty
                                    : specimenDetail.SpecimenDescription,
                                physicalDetailsOutput ?? String.Empty,
                                specimenDetail.SamplingPreconditions == null
                                    ? String.Empty
                                    : specimenDetail.SamplingPreconditions.NarrativeText.IsNullOrEmptyWhitespace()
                                          ? String.Empty
                                          : specimenDetail.SamplingPreconditions.NarrativeText,
                                specimenDetail.CollectionDateTime == null
                                    ? String.Empty
                                    : specimenDetail.CollectionDateTime.NarrativeText(),
                                specimenDetail.CollectionProcedure == null
                                    ? String.Empty
                                    : specimenDetail.CollectionProcedure.NarrativeText,
                                specimenDetail.CollectionSetting.IsNullOrEmptyWhitespace()
                                    ? String.Empty
                                    : specimenDetail.CollectionSetting,
                                narrativeDisplayList ?? null
                            }
                  );
            }

            strucDocTableList.Add(
                PopulateTable
                    (
                        narrativeTitle,
                        null,
                        new[]
                                {
                                    "Received DateTime", "Identifier", "Parent Identifier", "Container", "Tissue Type",
                                    "Physical Description", "Physical Details", "Sampling Preconditions", "Collection Date",
                                    "Collection Procedure", "Collection Setting", "Image / File"
                                },
                        new[] { String.Empty },
                        narrative
                    )
                );
          }
          return strucDocTableList;
        }


        [NotNull]
        private static IEnumerable<StrucDocTable> CreateNarrativeEntry(ICollection<IProblemDiagnosis> problemDiagnosisList, Boolean reviewedProblemDiagnosis)
        {
            var narrative = new List<List<String>>();
            var strucDocTableList = new List<StrucDocTable>();

            if (problemDiagnosisList != null && problemDiagnosisList.Any())
            {
                foreach (var diagnosis in problemDiagnosisList)
                {
                    if (diagnosis != null)
                    {
                        //Problem / Diagnosis Narrative
                        narrative.Add
                                (
                                    CreateNarrativeEntry
                                    (
                                        diagnosis.DateOfOnset,
                                        diagnosis.DateOfResolutionRemission,
                                        diagnosis.ProblemDiagnosisIdentification != null ? diagnosis.ProblemDiagnosisIdentification.NarrativeText : String.Empty,
                                        diagnosis.Comment
                                    )
                                );
                    }
                }
            }

            if (narrative.Any())
            {
                strucDocTableList.Add
                    (
                       PopulateTable
                           (
                           reviewedProblemDiagnosis ? "Reviewed Medical History - Problem / Diagnosis" : "Medical History - Problem / Diagnosis",
                               null,
                               new[] { "Onset Date / Time", "Resolution Date / Time", "Problem / Diagnosis", "Comments" },
                               new string[] { },
                               narrative
                           )
                    );
            }

            return strucDocTableList;
        }


        [NotNull]
        private static IEnumerable<StrucDocTable> CreateNarrativeEntry(ICollection<Procedure> procedureList, Boolean reviewedProcedure)
        {
            var narrative = new List<List<String>>();
            var strucDocTableList = new List<StrucDocTable>();

            if (procedureList != null && procedureList.Any())
            {
                foreach (var procedure in procedureList)
                {
                    narrative.Add
                        (
                        CreateNarrativeEntry(procedure.Start, procedure.ProcedureName != null ? procedure.ProcedureName.NarrativeText : String.Empty, procedure.Comment)
                        );
                }

                strucDocTableList.Add
                (
                    PopulateTable
                        (
                            reviewedProcedure ? "Reviewed Medical History - Procedures" : "Medical History - Procedures",
                            null,
                            new[] { "Date Time", "Procedure", "Comments" },
                            new string[] { },
                            narrative
                        )
                );
            }

            return strucDocTableList;
        }

        [NotNull]
        private static IEnumerable<StrucDocTable> CreateNarrativeEntry(ICollection<IMedicalHistoryItem> medicalHistoryItems, string narrativeCaption)
        {
            // Add MedicalHistoryItem
            var narrative = new List<List<String>>();
            var strucDocTableList = new List<StrucDocTable>();
            if (medicalHistoryItems != null)
                foreach (var medicalHistoryItem in medicalHistoryItems)
                {

                    narrative.Add(
                        new List<String>
                                {
                                  CreateDuration(medicalHistoryItem.DateTimeInterval),
                                  medicalHistoryItem.ItemDescription ?? String.Empty,
                                  medicalHistoryItem.ItemComment ?? String.Empty,                              
                                }
                        );
                }

            if (narrative.Any())
                strucDocTableList.Add
                (
                    PopulateTable
                    (
                        narrativeCaption,
                        null,
                        new[] { "Date Time Interval", "Item Description", "Item Comment" },
                        new string[] { },
                        narrative
                    )
                );

            return strucDocTableList;
        }

        [NotNull]
        private static IEnumerable<StrucDocTable> CreateNarrativeEntry(ICollection<IMedicalHistoryItem> medicalHistoryItems)
        {
            return CreateNarrativeEntry(medicalHistoryItems, "Medical History Item");
        }        

        [NotNull]
        private static List<String> CreateNarrativeEntry(String heading, Boolean? value)
        {
            return new List<String>
                       {
                           !heading.IsNullOrEmptyWhitespace() ? heading: "Undefined",  value.HasValue ? value.Value.ToString(CultureInfo.InvariantCulture) : "Undefined"
                       };
        }

        [NotNull]
        private static List<String> CreateNarrativeEntry(String heading, String value)
        {
            return new List<String>
                       {
                           !heading.IsNullOrEmptyWhitespace() ? heading: "Undefined", !value.IsNullOrEmptyWhitespace() ? value: "Undefined"
                       };
        }

        [NotNull]
        private static List<String> CreateNarrativeEntry(String heading, IEnumerable<Nehta.VendorLibrary.CDA.SCSModel.Common.Entitlement> entitlements)
        {
            // Entitilements
            String entitlementsString = null;

            if (entitlements != null)
            {
                if (entitlements.Count() > 0)
                {
                    foreach (var entitlement in entitlements)
                    {
                        if (entitlement != null && entitlement.Type != EntitlementType.Undefined)
                        {
                            entitlementsString += (entitlement.Id != null ? entitlement.Id.NarrativeText : String.Empty);

                            if (entitlements.Count() > 1) entitlementsString += DELIMITER;
                        }
                    }
                }
            }

            return new List<String>
                       {
                          heading, entitlementsString
                       };
        }

        [NotNull]
        private static String CreateEntitlement(IEnumerable<Nehta.VendorLibrary.CDA.SCSModel.Common.Entitlement> entitlements)
        {
            // Entitilements
            String entitlementsString = String.Empty;

            if (entitlements != null)
            {
                if (entitlements.Any())
                {
                    foreach (var entitlement in entitlements)
                    {
                        if (entitlement != null && entitlement.Type != EntitlementType.Undefined)
                        {
                            entitlementsString += (entitlement.Id != null ? entitlement.Id.NarrativeText : String.Empty);

                            if (entitlements.Count() > 1) entitlementsString += DELIMITER;
                        }
                    }
                }
            }
            return entitlementsString;
        }
        private static List<String> CreateNarrativeEntry(String heading, DateAccuracyIndicator dateAccuracyIndicator)
        {
            var narrative = new List<String>();

            if(dateAccuracyIndicator != null)
            {
                narrative.Add(!heading.IsNullOrEmptyWhitespace() ? heading : "Undefined");
                narrative.Add((dateAccuracyIndicator.ConvertToEnum()).GetAttributeValue<NameAttribute, String>(x => x.Code));
            }

            return narrative;
        }

        [NotNull]
        private static List<String> CreateNarrativeEntry(String heading, int? value, string unit)
        {
            return new List<String>
                       {
                            !heading.IsNullOrEmptyWhitespace() ? heading: "Undefined",
                            string.Format
                                    (
                                      "{0}{1}", 
                                       value.HasValue ? value.Value.ToString(CultureInfo.InvariantCulture) : "Undefined",
                                       !unit.IsNullOrEmptyWhitespace() ? unit : string.Empty 
                                    )
                       };
        }

        [NotNull]
        private static List<String> CreateNarrativeEntry(SCSModel.Common.Entitlement entitlement, ICodableText codableText)
        {
            return new List<String>
                       {
                           codableText != null ? codableText.NarrativeText : "Undefined Entitlement",
                           entitlement.Id != null ? entitlement.Id.NarrativeText : String.Empty
                       };
        }

        [NotNull]
        private static List<String> CreateNarrativeEntry(Statement statement)
        {
            return new List<string>
                       {
                           statement.Value != null  ? statement.Value.GetAttributeValue<NameAttribute, string>(x => x.Name): String.Empty
                       };
        }

        [NotNull]
        private static List<String> CreateNarrativeEntry(String heading, ISO8601DateTime dateTime)
        {
            return new List<string>
                       {
                           heading,
                           dateTime != null
                               ? dateTime.NarrativeText()
                               : String.Empty
                       };
        }

        [NotNull]
        private static List<Object> CreateNarrativeEntry(ISO8601DateTime dateTime)
        {
            return new List<Object>
                       {
                           dateTime != null
                               ? dateTime.NarrativeText()
                               : String.Empty
                       };
        }

        [NotNull]
        private static List<String> CreateNarrativeEntry(ISO8601DateTime dateTime, String heading, String value)
        {
            return new List<string>
                       {
                           dateTime != null
                               ? dateTime.NarrativeText()
                               : String.Empty,
                            heading,
                            !value.IsNullOrEmptyWhitespace() 
                                ? value
                                : String.Empty
                       };
        }


        [NotNull]
        private static List<String> CreateNarrativeEntry(ISO8601DateTime dateTime, ISO8601DateTime dateTime2, String value, String value2)
        {
            return new List<string>
                       {
                           dateTime != null
                               ? dateTime.NarrativeText()
                               : String.Empty,
                           dateTime2 != null
                               ? dateTime2.NarrativeText()
                               : String.Empty,
                           !value.IsNullOrEmptyWhitespace() ? value : String.Empty,
                           !value2.IsNullOrEmptyWhitespace() ? value2 : String.Empty,
                       };
        }

        [NotNull]
        private static String CreateNarrativeEntry(List<IProcedureName> procedures)
        {
            var narrative = String.Empty;

            if (procedures != null && procedures.Any())
            {
                procedures.ForEach
                    (
                        procedure =>
                        {
                            narrative +=
                               procedure != null && procedure.ProcedureName != null
                                   ? procedure.ProcedureName.NarrativeText + DELIMITER
                                   : String.Empty;
                        }
                    );
            }

            return narrative;
        }

        [NotNull]
        private static String CreateNarrativeEntry(List<ICodableText> codableTextList)
        {
            var narrative = String.Empty;

            if (codableTextList != null && codableTextList.Any())
            {
                codableTextList.ForEach
                    (
                        codableText =>
                        {
                            narrative += codableText != null
                               ? codableText.NarrativeText + DELIMITER
                               : String.Empty;
                        }
                    );

            }

            return narrative;
        }

        [NotNull]
        private static String CreateNarrativeEntry(List<string> textList)
        {
            var narrative = String.Empty;

            if (textList != null && textList.Any())
            {
                textList.ForEach(a => narrative += a.IsNullOrEmptyWhitespace() ? string.Empty : a + DELIMITER);

            }

            return narrative;
        }

        private static String CreateNarrativeEntry(ICodableText codableTextList)
        {
            var narrative = String.Empty;

            if (codableTextList != null)
            {
                narrative += codableTextList.NarrativeText;
            }

            return narrative;
        }

        /// <summary>
        /// Creates a narative for IDischargeSummaryProblemDiagnosis
        /// </summary>
        /// <param name="problemDiagnosesThisVisit">A list of IDischargeSummaryProblemDiagnosis</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(SCSModel.DischargeSummary.ProblemDiagnosesThisVisit problemDiagnosesThisVisit)
        {
            var strucDocTableList = new List<StrucDocTable>();
            var narrativeParagraph = new List<StrucDocParagraph>();

            // Add any problem diagnosis entries
            if (problemDiagnosesThisVisit.ProblemDiagnosis != null && problemDiagnosesThisVisit.ProblemDiagnosis.Any()) 
            {
                strucDocTableList.AddRange(CreateProblemDiagnosisNarrative(problemDiagnosesThisVisit.ProblemDiagnosis));
            }

            // Add any exclusion statements
            if (problemDiagnosesThisVisit.ExclusionStatement != null)
            {
              narrativeParagraph.Add(CreateExclusionStatementNarrative("Exclusion Statment", problemDiagnosesThisVisit.ExclusionStatement));
            }

            var strucDocText = new StrucDocText();

            // Structured Tables
            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            // Narrative Paragraph
            if (narrativeParagraph.Any())
            {
              strucDocText.paragraph = narrativeParagraph.ToArray();
            } 

            return strucDocText;
        }

        /// <summary>
        /// Creates a IDocumentWithHealthEventEnded narrative.
        /// </summary>
        /// <returns>List of tables for use with a StrucDocText</returns>
        public StrucDocText CreateNarrative(List<Document> documents)
        {
          StrucDocText strucDocText = null;
          var showAuthorInHeader = false;
          var showAuthorAddressInHeader = false;
          var showDateTimeHealthEventEndedInHeader = false;

          if (documents != null && documents.Count() > 0)
          {
            var strucDocTableList = new List<StrucDocTable>();

            var narrative = new List<List<object>>();

            // Add any problem diagnosis entries
            foreach (var document in documents)
            {
              strucDocTableList = new List<StrucDocTable>();

              if (document != null && document.Link != null && document.Link.TemplateId != null)
              {
                // Add Date Time Authored
                var narrativeTable = new List<object>
                              {
                                document.DateTimeAuthored != null ? document.DateTimeAuthored.NarrativeText() : null
                              };

                if (document.DateTimeHealthEventEnded != null)
                {
                   showDateTimeHealthEventEndedInHeader = true;
                   narrativeTable.AddRange(
                      new List<object>
                        {
                          document.DateTimeHealthEventEnded.NarrativeText(),
                        });
                }

                narrativeTable.AddRange(
                               new List<object>{
                                new StrucDocLinkHtml { 
                                                          Text  = new [] { document.Link.TemplateId.GetAttributeValue<NameAttribute, string>(x => x.Title)}, 
                                                          href = string.Format("pcehr:{0}/{1}{2}",
                                                                               document.Link.RepositoryIdentifier,
                                                                               document.Link.DocumentIdentifier, 
                                                                               document.Link.DocumentIdentifierExtension.IsNullOrEmptyWhitespace() ? string.Empty : ":" + document.Link.DocumentIdentifierExtension)
                                                     }
                               });

                if (document.Author != null && document.Author.Participant != null)
                {
                  showAuthorInHeader = true;

                  var personOrganisation = document.Author.Participant.Person != null && document.Author.Participant.Person.PersonNames != null ? BuildPersonNames(document.Author.Participant.Person.PersonNames) : null;
                  if (document.Author.Participant.Person != null && document.Author.Participant.Person.Organisation != null && !document.Author.Participant.Person.Organisation.Name.IsNullOrEmptyWhitespace())
                  {
                    personOrganisation = string.Format("{0}{1}({2})", personOrganisation, DELIMITERBREAK, document.Author.Participant.Person.Organisation.Name);
                  }

                  narrativeTable.AddRange(
                               new List<object>
                                          {
                                            personOrganisation
                                          });

                  if (document.Author.Participant.Addresses != null || document.Author.Participant.ElectronicCommunicationDetails != null)
                  {
                    showAuthorAddressInHeader = true;
                    narrativeTable.AddRange(
                               new List<object>
                                          {
                                            CreateAddress(document.Author.Participant.Addresses, document.Author.Participant.ElectronicCommunicationDetails)
                                          });
                  }


                }

                narrative.Add(narrativeTable);
              }
            }

            var header = new List<string> { "Date Time Authored", "Health Event Ended", "Document", "Author / Organisation", "Address / Contact" };
            // Remove author to Table Header
            if (!showAuthorInHeader) header.Remove("Author / Organisation");

            // Remove author address to Table Header
            if (!showAuthorAddressInHeader) header.Remove("Address / Contact");
            
            // Remove author to Table Header
            if (!showDateTimeHealthEventEndedInHeader) header.Remove("Health Event Ended");
            
            strucDocTableList.Add
              (
                PopulateTable
                  (
                    null,
                    null,
                    header.ToArray(),
                    null,
                    narrative
                  )
              );


            strucDocText = new StrucDocText { table = strucDocTableList.ToArray() };
          }
          else
          {
            strucDocText = new StrucDocText { paragraph = new[] { new StrucDocParagraph { Text = new[] { "Not Known (Insufficient Information Available)" } } } };
          }

          return strucDocText;
        }

        /// <summary>
        /// Creates a IDocumentWithHealthEventEnded narrative.
        /// </summary>
        /// <returns>List of tables for use with a StrucDocText</returns>
        public StrucDocText CreateNarrative(List<IDocumentWithHealthEventEnded> documents)
        {
            var documentList = new List<Document>();
            if (documents != null)
            {
              // Add any problem diagnosis entries
              documentList.AddRange(documents.Select(document => document as Document));
            }
            return CreateNarrative(documentList);
        }

        /// <summary>
        /// Creates a IDocument narrative.
        /// </summary>
        /// <returns>List of tables for use with a StrucDocText</returns>
        public StrucDocText CreateNarrative(List<IDocument> documents)
        {
            var documentList = new List<Document>();
            if (documents != null)
            {
              // Add any problem diagnosis entries
              documentList.AddRange(documents.Select(document => document as Document));
            }
            return CreateNarrative(documentList);
        }

        /// <summary>
        /// Creates the problem diagnosis narrative.
        /// </summary>
        /// <param name="problemDiagnosis">List of problem diagnosis</param>
        /// <returns>List of tables for use with a StrucDocText</returns>
        private static IList<StrucDocTable> CreateProblemDiagnosisNarrative(IList<IDischargeSummaryProblemDiagnosis> problemDiagnosis)
        {
            List<List<String>> narrative;
            var strucDocTableList = new List<StrucDocTable>();

            if (problemDiagnosis != null && problemDiagnosis.Any())
            {
                narrative = new List<List<String>>();

                foreach (var problemDiagnoses in problemDiagnosis)
                {
                    // Medications
                    narrative.Add(
                        new List<string>
                          {
                              problemDiagnoses.ProblemDiagnosisType == null ? String.Empty : problemDiagnoses.ProblemDiagnosisType.NarrativeText,
                              problemDiagnoses.ProblemDiagnosisDescription == null ? String.Empty : problemDiagnoses.ProblemDiagnosisDescription.NarrativeText,
                          }
                    );
                }

                strucDocTableList.Add
                (
                    PopulateTable
                    (
                        "Problems/Diagnoses", null, new[]
                        {
                            "Type",
                            "Description"
                        },
                        new string[0],
                        narrative
                    )
                );
            }

            return strucDocTableList;
        }

        /// <summary>
        /// Create a Narrative for Administrative Observations.
        /// </summary>
        /// <param name="subjectOfCareParticipation">IParticipationSubjectOfCare</param>
        /// <param name="patientId">String</param>
        /// <param name="specialties">A list of ICodableText</param>
        /// <returns></returns>
        public StrucDocText CreateNarrative(IParticipationSubjectOfCare subjectOfCareParticipation, String patientId, List<ICodableText> specialties)
        {
            var strucDocTableList = new List<StrucDocTable>();
            var strucDocTextList = new List<StrucDocText> { CreateNarrative(subjectOfCareParticipation, patientId, true) };

            foreach (var strucDoc in strucDocTextList)
            {
                if (strucDoc != null && strucDoc.table !=  null)
                strucDocTableList.AddRange(strucDoc.table);
            }

            var strucDocText = new StrucDocText();

            // Don't show Specialties for now
            var narrative = new List<List<String>>();
            if (specialties != null)
            {
                foreach (var specialty in specialties)
                {
                    narrative.Add
                    (
                        new List<String> { specialty.NarrativeText }
                    );
                }
            }

            if (narrative.Count != 0)
            {
                strucDocTableList.Add
                (
                    PopulateTable
                        (
                            "Specialties",
                            null,
                            null,
                            null,
                            narrative
                        )
                );
            }

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.Text = new string[] { "This section contains no entries." };
            }

            return strucDocText;
        }

        /// <summary>
        /// CLINICAL INTERVENTIONS THIS VISIT
        /// </summary>
        /// <param name="clinicalIntervention">ClinicalIntervention</param>
        /// <returns></returns>
        public StrucDocText CreateNarrative(SCSModel.DischargeSummary.ClinicalIntervention clinicalIntervention)
        {
            List<List<String>> narrative;
            var strucDocTableList = new List<StrucDocTable>();

            if (clinicalIntervention != null)
            {
                narrative = new List<List<String>>();

                if (clinicalIntervention.Description != null)
                    foreach (var description in clinicalIntervention.Description)
                    {
                        // CLINICAL INTERVENTIONS THIS VISIT
                        narrative.Add(
                            new List<string>
                                {
                                    description.NarrativeText
                                }
                            );
                    }

                strucDocTableList.Add
                (
                    PopulateTable
                    (
                        null,
                        null,
                        new[] { "Clinical Intervention Description" },
                        new string[0],
                        narrative
                    )
                );
            }
            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.Text = new string[] { "This section contains no entries." };
            }

            return strucDocText;
        }

        /// <summary>
        /// CLINICAL SYNOPSIS
        /// </summary>
        /// <param name="clinicalSynopsis"></param>
        /// <returns></returns>
        public StrucDocText CreateNarrative(Nehta.VendorLibrary.CDA.SCSModel.DischargeSummary.ClinicalSynopsis clinicalSynopsis)
        {
            List<List<String>> narrative;
            var strucDocTableList = new List<StrucDocTable>();

            if (clinicalSynopsis != null)
            {
                narrative = new List<List<String>>();

                // CLINICAL SYNOPSIS
                narrative.Add(
                                new List<string>
                                      {
                                          clinicalSynopsis.Description
                                      }
                             );

                strucDocTableList.Add
                (
                    PopulateTable
                    (
                        "Clinical Synopsis",
                        null,
                        new[] { "Description" },
                        new string[0],
                        narrative
                    )
                );
            }
            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.Text = new string[] { "This section contains no entries." };
            }

            return strucDocText;
        }

        /// <summary>
        /// Current Medications On Discharge
        /// </summary>
        /// <param name="currentMedication">CurrentMedications</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(Nehta.VendorLibrary.CDA.SCSModel.DischargeSummary.CurrentMedications currentMedication)
        {
            List<StrucDocTable> strucDocTableList = new List<StrucDocTable>();
            var narrativeParagraph = new List<StrucDocParagraph>();

            // Add the current medications
            if (currentMedication.TherapeuticGoods != null && currentMedication.TherapeuticGoods.Any())
            {
                strucDocTableList.AddRange(CreateCurrentMedicationsNarrative(currentMedication.TherapeuticGoods));
            }

            // Add the exclusion statements
            if (currentMedication.ExclusionStatement != null)
            {
              narrativeParagraph.Add(CreateExclusionStatementNarrative("Exclusion Statement", currentMedication.ExclusionStatement));
            }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any()) // Structured Tables
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else if (narrativeParagraph.Any()) // Narrative Paragraph
            {
                strucDocText.paragraph = narrativeParagraph.ToArray();
            } 
            else
            {
                strucDocText.Text = new [] { "This section contains no entries." };
            }

            return strucDocText;
        }

        /// <summary>
        /// Creates the current medication narrative.
        /// </summary>
        /// <param name="therapeuticGoods">List of current medications.</param>
        /// <returns>List of tables for inclusion in the narrative.</returns>
        private static IList<StrucDocTable> CreateCurrentMedicationsNarrative(IList<ITherapeuticGood> therapeuticGoods)
        {

            List<List<String>> narrative;
            var strucDocTableList = new List<StrucDocTable>();

            if (therapeuticGoods != null)
            {

              narrative = new List<List<String>>();

              var narativeHeader = new List<String>() 
                        { 
                            "Item Status",
                            "Item Description",
                            "Duration", 
                            "Reason for Medication",
                            "Unit of Use Quantity Dispensed",
                            "Dose Instructions",
                            "Change made",
                            "Reason for change"
                        };


                foreach (ITherapeuticGood therapeuticGood in therapeuticGoods)
                {
                    if (therapeuticGood != null && therapeuticGood.MedicationHistory != null)
                    {
                        // Current Medications On Discharge
                        var medicationList = new List<String>
                                      {
                                        therapeuticGood.MedicationHistory.ItemStatus == null ? String.Empty : therapeuticGood.MedicationHistory.ItemStatus.NarrativeText,
                                        therapeuticGood.TherapeuticGoodIdentification  == null ? String.Empty : therapeuticGood.TherapeuticGoodIdentification.NarrativeText,
                                        therapeuticGood.MedicationHistory.MedicationDuration == null ? String.Empty : CreateIntervalText(therapeuticGood.MedicationHistory.MedicationDuration),
                                        therapeuticGood.ReasonForTherapeuticGood == null ? String.Empty : therapeuticGood.ReasonForTherapeuticGood,
                                        therapeuticGood.UnitOfUseQuantityDispensed.IsNullOrEmptyWhitespace() ? String.Empty : therapeuticGood.UnitOfUseQuantityDispensed,
                                        therapeuticGood.DoseInstruction == null ? String.Empty : therapeuticGood.DoseInstruction,
                                        therapeuticGood.MedicationHistory.ChangesMade == null ? String.Empty : therapeuticGood.MedicationHistory.ChangesMade.NarrativeText,
                                        therapeuticGood.MedicationHistory.ReasonForChange == null ? String.Empty : therapeuticGood.MedicationHistory.ReasonForChange

                                      };

                        // Dynamical add comment is it is not null
                        if (!therapeuticGood.AdditionalComments.IsNullOrEmptyWhitespace())
                        {
                            medicationList.Add(therapeuticGood.AdditionalComments);

                            if (narativeHeader.Contains("Additional Comments") == false)
                            {
                                narativeHeader.Add("Additional Comments");
                            }
                        }

                        //medicine_list + clinical Indication
                        narrative.Add(medicationList);

                        // Close empty cells
                        foreach (var narrativeEntry in narrative.Where(narrativeEntry => narativeHeader.Contains("Additional Comments") && narrativeEntry.Count == 8))
                        {
                            narrativeEntry.Add(string.Empty);
                        }

                    }
                }

                strucDocTableList.Add
                (
                    PopulateTable
                    (
                        "Current Medications On Discharge",
                        null,
                        narativeHeader.ToArray(),
                        new string[0],
                        narrative
                    )
                );

            }

            return strucDocTableList;
        }

        /// <summary>
        /// Creates the narrative text.
        /// </summary>
        /// <param name="interval">Interval.</param>
        /// <returns>Interval.</returns>
        private static string CreateIntervalText(CdaInterval interval)
        {
            if (interval == null)
            {
                return string.Empty;
            }

            return CdaIntervalFormatter.Format(interval);
        }

        /// <summary>
        /// Ceased Medications On Discharge
        /// </summary>
        /// <param name="ceasedMedications">CeasedMedications</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(Nehta.VendorLibrary.CDA.SCSModel.DischargeSummary.CeasedMedications ceasedMedications)
        {
            List<StrucDocTable> strucDocTableList = new List<StrucDocTable>();
            var narrativeParagraph = new List<StrucDocParagraph>();

            // Add the ceased medications
            if (ceasedMedications.TherapeuticGoods != null && ceasedMedications.TherapeuticGoods.Any())
            {
                strucDocTableList.AddRange(CreatedCeasedMedicationsNarrative(ceasedMedications.TherapeuticGoods));
            }

            // Add the exclusion statements
            if (ceasedMedications.ExclusionStatement != null)
            {
                narrativeParagraph.Add(CreateExclusionStatementNarrative("Exclusion Statement", ceasedMedications.ExclusionStatement));
            }

            var strucDocText = new StrucDocText();

            // Structured Tables
            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            // Narrative Paragraph
            else if (narrativeParagraph.Any())
            {
              strucDocText.paragraph = narrativeParagraph.ToArray();
            } 

            else
            {
                strucDocText.Text = new [] { "This section contains no entries." };
            }

            return strucDocText;
        }

        /// <summary>
        /// Creates the ceased medication narrative.
        /// </summary>
        /// <param name="therapeuticGoodCeaseds">List of ceased medications.</param>
        /// <returns>List of tables for inclusion in the narrative.</returns>
        private IList<StrucDocTable> CreatedCeasedMedicationsNarrative(IList<ITherapeuticGoodCeased> therapeuticGoodCeaseds)
        {
            var headerList = new List<String>() 
            { 
                "Item Status", 
                "Item Description", 
                "Change Made", 
                "Reason for Change" 
            };


            var strucDocTableList = new List<StrucDocTable>();

            if (therapeuticGoodCeaseds != null && therapeuticGoodCeaseds.Any())
            {
                var narrative = new List<List<String>>(); 

                foreach (ITherapeuticGoodCeased therapeuticGood in therapeuticGoodCeaseds)
                {
                    if (therapeuticGood != null && therapeuticGood.MedicationHistory != null)
                    {
                        // Ceased Medications On Discharge
                        narrative.Add(
                                        new List<string>
                                      {
                                          therapeuticGood.MedicationHistory.ItemStatus == null ? String.Empty : therapeuticGood.MedicationHistory.ItemStatus.NarrativeText,
                                          therapeuticGood.TherapeuticGoodIdentification  == null ? String.Empty : therapeuticGood.TherapeuticGoodIdentification.NarrativeText,
                                          therapeuticGood.MedicationHistory.ChangesMade == null ? String.Empty :therapeuticGood.MedicationHistory.ChangesMade.NarrativeText,
                                          therapeuticGood.MedicationHistory.ReasonForChange
                                      }
                                     );
                    }
                }

                strucDocTableList.Add
                (
                    PopulateTable
                    (
                        "Ceased Medications",
                        null,
                        headerList.ToArray(),
                        new string[0],
                        narrative
                    )
                );
            }

            return strucDocTableList;
        }

        /// <summary>
        /// Creates the narrative section for adverse reactions.
        /// </summary>
        /// <param name="adverseReactions">Adverse reactions</param>
        /// <returns></returns>
        public StrucDocText CreateNarrative(SCSModel.DischargeSummary.AdverseReactions adverseReactions)
        {
            List<StrucDocTable> strucDocTableList = new List<StrucDocTable>();
            var narrativeParagraph = new List<StrucDocParagraph>();

            if (adverseReactions.Reactions != null && adverseReactions.Reactions.Any())
            {
                strucDocTableList.AddRange(CreateAdverseReactionsNarrative(adverseReactions.Reactions));
            }

            if (adverseReactions.ExclusionStatement != null)
            {
              narrativeParagraph.Add(CreateExclusionStatementNarrative("Exclusion Statment", adverseReactions.ExclusionStatement));
            }

            var strucDocText = new StrucDocText();

            // Structured Tables
            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            // Narrative Paragraph
            if (narrativeParagraph.Any())
            {
              strucDocText.paragraph = narrativeParagraph.ToArray();
            } 

            return strucDocText;
        }

        /// <summary>
        /// Create narrative for IAdverseReactionDischargeSummary
        /// </summary>
        /// <param name="adverseReactions">A list of IAdverseReactionDischargeSummary's</param>
        /// <returns>StrucDocText</returns>
        public IList<StrucDocTable> CreateAdverseReactionsNarrative(ICollection<IAdverseReactionDischargeSummary> adverseReactions)
        {
            List<List<String>> narrative;
            var strucDocTableList = new List<StrucDocTable>();

            if (adverseReactions != null &&  adverseReactions.Any())
            {
                narrative = new List<List<String>>();

                foreach (var adverseReaction in adverseReactions)
                {
                    var reactionDescriptions = String.Empty;

                    if (adverseReaction.ReactionDescriptions != null)
                    {
                        adverseReaction.ReactionDescriptions.ForEach
                            (
                                reaction => { 
                                                reactionDescriptions += 
                                                    reaction == null ?
                                                        String.Empty : 
                                                        reaction.NarrativeText + DELIMITER; 
                                            }
                            );
                    }

                    narrative.Add(
                                  new List<string>
                                  {
                                     adverseReaction.AgentDescription == null ? String.Empty :adverseReaction.AgentDescription.NarrativeText,
                                     adverseReaction.AdverseReactionType == null ? String.Empty : adverseReaction.AdverseReactionType.NarrativeText,
                                     reactionDescriptions
                                  }
               );
                }

                strucDocTableList.Add
                (
                    PopulateTable
                    (
                        "Allergies/Adverse Reactions",
                        null,
                        new[] { "Agent Description", "Reaction Type", "Reaction Description(s)" },
                        new string[0],
                        narrative
                    )
                );
            }

            return strucDocTableList;
        }

        /// <summary>
        /// Create Narrative for Alerts
        /// </summary>
        /// <param name="alerts">A list of Alerts</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(ICollection<Nehta.VendorLibrary.CDA.SCSModel.DischargeSummary.Alert> alerts)
        {
            List<List<String>> narrative;
            var strucDocTableList = new List<StrucDocTable>();

            if (alerts != null && alerts.Any())
            {
                narrative = new List<List<String>>();

                foreach (var alert in alerts)
                {
                    narrative.Add(
                                      new List<string>
                                      {
                                         alert.AlertType == null ? String.Empty : alert.AlertType.NarrativeText,
                                         alert.AlertDescription == null ? String.Empty : alert.AlertDescription.NarrativeText
                                      }
                                 );
               }

                strucDocTableList.Add
                (
                    PopulateTable
                    (
                        "Alerts",
                        null,
                        new[] { "Type", "Description" },
                        new string[0],
                        narrative
                    )
                );
            }
            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.Text = new string[] { "This section contains no entries." };
            }

            return strucDocText;
        }

        /// <summary>
        /// IParticipationAcdCustodian
        /// </summary>
        /// <param name="participations">IParticipationAcdCustodian</param>
        /// <returns></returns>
        public StrucDocText CreateNarrative(IList<IParticipationAcdCustodian> participations)
        {
            List<List<String>> narrative;
            var headerList = new List<String>()
            { 
                "Date", 
                "Date Of Birth",  
                "Gender",  
                "Person Name", 
                "Organisation", 
                "Address / Contact" 
            };

            var strucDocTableList = new List<StrucDocTable>();

            if (participations != null && participations.Any())
            {
                narrative = new List<List<String>>();

                foreach (var participation in participations)
                {
                    var durationAsString = string.Empty;
                    if (participation.ParticipationPeriod != null)
                    {
                        durationAsString = CreateDuration(participation.ParticipationPeriod);
                    }

                    // Get organisation name
                    String organisationName = null;
                    if (participation.Participant != null)
                    {
                        if (participation.Participant.Organisation != null)
                            if (!participation.Participant.Organisation.Name.IsNullOrEmptyWhitespace())
                                organisationName = participation.Participant.Organisation.Name;

                        if (organisationName.IsNullOrEmptyWhitespace())
                            if (participation.Participant.Person != null)
                                if (participation.Participant.Person.Organisation != null)
                                    if (!participation.Participant.Person.Organisation.Name.IsNullOrEmptyWhitespace())
                                        organisationName =participation.Participant.Person.Organisation.Name;
                    }

                    narrative.Add(
                            new List<string>
                                {
                                    durationAsString,
                                    participation != null && participation.Participant != null && participation.Participant.Person != null && participation.Participant.Person.DateOfBirth != null ? participation.Participant.Person.DateOfBirth.NarrativeText() : String.Empty,
                                    participation != null && participation.Participant != null && participation.Participant.Person != null && participation.Participant.Person.Gender != null ? participation.Participant.Person.Gender.Value.GetAttributeValue<NameAttribute, String>(x => x.Name) : String.Empty,
                                    participation != null &&
                                    participation.Participant != null &&
                                    participation.Participant.Person != null
                                        ? BuildPersonNames(
                                              participation.Participant.Person.PersonNames)
                                        : String.Empty,
                                    (organisationName.IsNullOrEmptyWhitespace() ? string.Empty : organisationName),
                                    participation != null && participation.Participant != null && participation.Participant.Addresses != null ? CreateAddress(participation.Participant.Addresses.Cast<IAddress>(), participation.Participant.ElectronicCommunicationDetails) : string.Empty,
                                    }
                                );

                }

                if (narrative.Any())
                    strucDocTableList.Add
                    (
                        PopulateTable
                        (
                            "ACD Custodian",
                            null,
                            headerList.ToArray(),
                            new string[0],
                            narrative
                        )
                    );
            }
            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.Text = new string[] { "This section contains no entries." };
            }

            return strucDocText;
        }

        /// <summary>
        /// ArrangedServices
        /// </summary>
        /// <param name="arrangedServices">ArrangedServices</param>
        /// <returns></returns>
        public StrucDocText CreateNarrative(ICollection<Nehta.VendorLibrary.CDA.SCSModel.DischargeSummary.ArrangedServices> arrangedServices)
        {
            List<List<String>> narrative, narrativeDescription;

            var strucDocTableList = new List<StrucDocTable>();

            if (arrangedServices != null && arrangedServices.Any())
            {
              int i = 0;
                foreach (var arrangedService in arrangedServices)
                {
                   i++;
                    narrative = new List<List<String>>();
                    narrativeDescription = new List<List<String>>();

                    var durationAsString = string.Empty;
                    if (arrangedService.ServiceCommencementWindow != null)
                    {
                        durationAsString = CreateDuration(arrangedService.ServiceCommencementWindow);
                    }

                    // Get organisation name
                    String organisationName = null;
                    if (arrangedService.ServiceProvider != null)
                    {
                        if (arrangedService.ServiceProvider.Participant != null)
                        {
                            if (arrangedService.ServiceProvider.Participant.Organisation != null)
                                if (!arrangedService.ServiceProvider.Participant.Organisation.Name.IsNullOrEmptyWhitespace())
                                    organisationName = arrangedService.ServiceProvider.Participant.Organisation.Name;

                            if (organisationName.IsNullOrEmptyWhitespace())
                                if (arrangedService.ServiceProvider.Participant.Person != null)
                                    if (arrangedService.ServiceProvider.Participant.Person.Organisation != null)
                                      if (!arrangedService.ServiceProvider.Participant.Person.Organisation.Name.IsNullOrEmptyWhitespace())
                                                  organisationName = arrangedService.ServiceProvider.Participant.Person.Organisation.Name;
                        }
                    }

                    // Address / Contact
                    if (arrangedService.Status != EventTypes.Undefined)
                      narrative.Add
                      (
                          CreateNarrativeEntry("Status", arrangedService.Status.GetAttributeValue<NameAttribute, String>(x => x.Name))
                      );

                    // Service Commencement Window
                    if (!durationAsString.IsNullOrEmptyWhitespace())
                      narrative.Add
                      (
                          CreateNarrativeEntry("Service Commencement Window", durationAsString)
                      );

                    // Provider Person Name
                    if (arrangedService.ServiceProvider != null && arrangedService.ServiceProvider.Participant != null && arrangedService.ServiceProvider.Participant.Person != null)
                      narrative.Add
                      (
                          CreateNarrativeEntry("Provider Person Name", BuildPersonNames(arrangedService.ServiceProvider.Participant.Person.PersonNames))
                      );

                    // Provider Organisation
                    if (!organisationName.IsNullOrEmptyWhitespace())
                      narrative.Add
                      (
                          CreateNarrativeEntry("Provider Organisation", organisationName)
                      );

                    // Address / Contact
                    if (arrangedService.ServiceProvider != null)
                      narrative.Add
                      (
                          CreateNarrativeEntry("Address / Contact", CreateAddress(arrangedService.ServiceProvider.Participant.Addresses, arrangedService.ServiceProvider.Participant != null ? arrangedService.ServiceProvider.Participant.ElectronicCommunicationDetails : null))
                      );

                    if (arrangedService.ArrangedServiceDescription != null)
                      narrativeDescription.Add
                      (
                            new List<string>
                                {
                                     arrangedService.ArrangedServiceDescription.NarrativeText
                                }
                      );
                      
                    strucDocTableList.Add
                        (
                          PopulateTable
                          (
                              string.Format("Arranged Service {0}", i.ToString(CultureInfo.InvariantCulture)),
                              null,
                              null,
                              new string[0],
                              narrative
                          )
                        );

                    if (arrangedService.ArrangedServiceDescription != null)
                    strucDocTableList.Add
                        (
                          PopulateTable
                          (
                              "Description",
                              null,
                              null,
                              new string[0],
                              narrativeDescription
                          )
                        );
                    }

            }
            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.Text = new string[] { "This section contains no entries." };
            }

            return strucDocText;
        }

        /// <summary>
        /// Create the Recommendations Information Provided Narrative
        /// </summary>
        /// <param name="recommendationsInformationProvided">RecommendationsInformationProvided</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(SCSModel.DischargeSummary.RecommendationsInformationProvided recommendationsInformationProvided)
        {
            List<List<String>> narrative;
            List<List<String>> narrativeNote;

            var strucDocTableList = new List<StrucDocTable>();

            if (recommendationsInformationProvided != null && recommendationsInformationProvided.RecommendationsProvided != null && recommendationsInformationProvided.RecommendationsProvided.Any())
            {
                // NOTE : RECOMMENDATION RECIPIENT is mandatory 

              int i = 0;
              foreach (var recommendationsProvided in recommendationsInformationProvided.RecommendationsProvided)
                {
                  narrative = new List<List<String>>();
                  narrativeNote = new List<List<String>>();
                  i++;

                    var organisationName = String.Empty;
                    if (recommendationsProvided != null && recommendationsProvided.RecommendationRecipient != null)
                    {
                        if (recommendationsProvided.RecommendationRecipient.Participant != null)
                        {
                            if (recommendationsProvided.RecommendationRecipient.Participant.Organisation != null)
                                if (!recommendationsProvided.RecommendationRecipient.Participant.Organisation.Name.IsNullOrEmptyWhitespace())
                                    organisationName = recommendationsProvided.RecommendationRecipient.Participant.Organisation.Name;

                            if (organisationName.IsNullOrEmptyWhitespace())
                                if (recommendationsProvided.RecommendationRecipient.Participant.Person != null)
                                    if (recommendationsProvided.RecommendationRecipient.Participant.Person.Organisation != null)
                                        if (!recommendationsProvided.RecommendationRecipient.Participant.Person.Organisation.Name.IsNullOrEmptyWhitespace())
                                            organisationName = recommendationsProvided.RecommendationRecipient.Participant.Person.Organisation.Name;
                        }


                        // RecommendationsProvided RecommendationRecipient
                        if (recommendationsProvided.RecommendationRecipient.Participant != null && recommendationsProvided.RecommendationRecipient.Participant.Person != null)
                          narrative.Add
                          (
                              CreateNarrativeEntry("Recipient Person Name", BuildPersonNames(recommendationsProvided.RecommendationRecipient.Participant.Person.PersonNames))
                          );


                        // Recipient Organisation
                        if (!organisationName.IsNullOrEmptyWhitespace())
                          narrative.Add
                          (
                              CreateNarrativeEntry("Recipient Organisation", organisationName)
                          );

                        // Recipient Organisation
                        if (recommendationsProvided.RecommendationRecipient.Participant != null)
                          narrative.Add
                          (
                              CreateNarrativeEntry("Address / Contact", 
                              CreateAddress(recommendationsProvided.RecommendationRecipient.Participant.Addresses, recommendationsProvided.RecommendationRecipient.Participant.ElectronicCommunicationDetails))
                          );

                        // Recommendation Note
                        if (!recommendationsProvided.RecommendationNote.IsNullOrEmptyWhitespace())
                          narrativeNote.Add
                          (
                            new List<string>
                                {
                                     recommendationsProvided.RecommendationNote
                                }
                          );

                      strucDocTableList.Add
                      (
                          PopulateTable
                          (
                              string.Format("Recommendation {0}", i.ToString(CultureInfo.InvariantCulture)),
                              null,
                              null,
                              new string[0],
                              narrative
                          )
                      );


                      strucDocTableList.Add
                      (
                          PopulateTable
                          (
                              "Note",
                              null,
                              null,
                              new string[0],
                              narrativeNote
                          )
                      );

                    }
                }
            }

            // INFORMATION PROVIDED TO PATIENT AND/OR FAMILY
            if (recommendationsInformationProvided != null)
                if (recommendationsInformationProvided.InformationProvided != null && !recommendationsInformationProvided.InformationProvided.InformationProvidedToRelevantParties.IsNullOrEmptyWhitespace())
                {
                    narrative = new List<List<String>>();

                    narrative.Add(
                        new List<string>
                            {
                                recommendationsInformationProvided.InformationProvided.InformationProvidedToRelevantParties
                            }
                        );

                    strucDocTableList.Add
                        (
                            PopulateTable
                                (
                                    "Information Provided",
                                    null,
                                    null,
                                    new string[0],
                                    narrative
                                )
                        );
                }


            var strucDocText = new StrucDocText();
            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.Text = new [] { "This section contains no entries." };
            }

            return strucDocText;
        }

        /// <summary>
        /// Build the person Name
        /// </summary>
        /// <param name="personNames">The Person</param>
        /// <returns>A fommated person name</returns>
        private static String BuildPersonNames(List<IPersonName> personNames)
        {
            if (personNames == null) return string.Empty;

            var nameString = String.Empty;

            for (int x = 0; x < personNames.Count; x++)
            {
                var pn = personNames[x];

                nameString +=
                    pn.Titles != null && pn.Titles.Any() ?
                    pn.Titles.First() + " " :
                    String.Empty;

                nameString +=
                    pn.NameSuffix != null && pn.NameSuffix.Any() ?
                    pn.NameSuffix.First() + " " :
                    String.Empty;

                if (pn.GivenNames != null)
                {
                    nameString += pn.GivenNames.FirstOrDefault();
                }

                if (!pn.FamilyName.IsNullOrEmptyWhitespace())
                {
                  nameString += nameString.IsNullOrEmptyWhitespace() ? pn.FamilyName : " " + pn.FamilyName;
                }

                if (x < personNames.Count - 1)
                    nameString += DELIMITER;
            }

            return nameString;
        }

        /// <summary>
        /// This method creates the narrative for the imaging examination result section
        /// </summary>
        /// <param name="imagingExaminationResult">IImagingExaminationResultDischargeSummary</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(IImagingExaminationResultDischargeSummary imagingExaminationResult)
        {
            List<List<Object>> narrative;
            var strucDocTableList = new List<StrucDocTable>();
            var renderMultiMediaList = new List<StrucDocRenderMultiMedia>();

            if (imagingExaminationResult != null)
            {

                if (imagingExaminationResult.AnatomicalSite != null)
                     strucDocTableList.Add(CreateAnatomicalSites(imagingExaminationResult.AnatomicalSite, ref renderMultiMediaList));

                //Imaging examination name, modality, status, addational infromation provided and findings
                narrative = new List<List<Object>>();

                //Imaging Examination Result Name 
                if (imagingExaminationResult.ResultDateTime != null)
                {
                  narrative.Add
                        (
                             new List<Object> { "Imaging Examination Result Date Time", imagingExaminationResult.ResultDateTime.NarrativeText() }
                        );
                }

                //Imaging Examination Result Name 
                if (imagingExaminationResult.ExaminationResultName != null)
                {
                  narrative.Add
                        (
                             new List<Object> { "Result name", imagingExaminationResult.ExaminationResultName.NarrativeText }
                        );
                }

                //Imaging examination result modality
                if (imagingExaminationResult.Modality != null)
                  narrative.Add
                    (
                           new List<Object> { "Modality", imagingExaminationResult.Modality.NarrativeText }
                    );

                //Imaging examination result status
                if (imagingExaminationResult.ExaminationResultStatus != null)
                  narrative.Add
                    (
                          new List<Object> { "Result Status", imagingExaminationResult.ExaminationResultStatus.Value.GetAttributeValue<NameAttribute, string>(x => x.Name) }
                    );

                //Clinical information provided
                if (!imagingExaminationResult.ClinicalInformationProvided.IsNullOrEmptyWhitespace())
                  narrative.Add
                    (
                         new List<Object> { "Clinical Information", imagingExaminationResult.ClinicalInformationProvided }
                    );

                //Findings
                if (!imagingExaminationResult.Findings.IsNullOrEmptyWhitespace())
                  narrative.Add
                    (
                          new List<Object> { "Findings", imagingExaminationResult.Findings }
                    );

                //Result representation
                if (!imagingExaminationResult.ExaminationResultRepresentation.IsNullOrEmptyWhitespace())
                  narrative.Add
                    (
                          new List<Object> { "Result Representation", imagingExaminationResult.ExaminationResultRepresentation }
                    );

                strucDocTableList.Add
                    (
                        PopulateTable
                            (
                                "Imaging Examination Result Details",
                                null,
                                new[] { "Field", "ResultValue" },
                                null,
                                narrative
                            )
                    );


                //Examination result group
                if (imagingExaminationResult.ResultGroup != null && imagingExaminationResult.ResultGroup.Any())
                {
                    strucDocTableList.AddRange
                        (
                            CreateNarrativeEntry(imagingExaminationResult.ResultGroup, ref renderMultiMediaList)
                        );
                }



                //Examination request details
                if (imagingExaminationResult.ExaminationRequestDetails != null)
                {
                    strucDocTableList.AddRange
                        (
                            CreateNarrativeEntry(imagingExaminationResult.ExaminationRequestDetails, ref renderMultiMediaList)
                        );
                }
            }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.Text = new string[] { "This section contains no entries." };
            }

            if (renderMultiMediaList.Any())
            {
                strucDocText.renderMultiMedia = renderMultiMediaList.ToArray();
            }

            return strucDocText;
        }

        public static StrucDocTable CreateAnatomicalSites(List<AnatomicalSite> anatomicalSites, ref List<StrucDocRenderMultiMedia> renderMultiMediaList)
        {
            var structDocTable = new StrucDocTable();

            //Anatomical location image
            if (anatomicalSites.Any())
            {
                var narrative = new List<List<Object>>();

                foreach (var anatomicalSite in anatomicalSites)
                {

                    //populate the narrative for each anatomical site
                    if (
                            !anatomicalSite.Description.IsNullOrEmptyWhitespace() && anatomicalSite.AnatomicalLocation != null
                        )
                    {

                        narrative.Add(
                                        new List<Object>
                                              {
                                                  anatomicalSite.Description, 
                                                  anatomicalSite.AnatomicalLocation.NameOfLocation != null ? anatomicalSite.AnatomicalLocation.NameOfLocation.NarrativeText : String.Empty, 
                                                  anatomicalSite.AnatomicalLocation.Side != null ? anatomicalSite.AnatomicalLocation.Side.NarrativeText : String.Empty ,
                                                  anatomicalSite.Images != null ? CreateEncapsulatedData(anatomicalSite.Images, ref renderMultiMediaList) : null
                                              }
                                     );
                    }
                }

                if (narrative.Any())
                {
                    structDocTable =  PopulateTable
                        (
                            "Anatomical Site(s)",
                            null,
                            new[] {"Description", "Location", "Side", "Image / File"},
                            new[] {""},
                            narrative
                        );
                }
            }

            return structDocTable;
        }


        /// <summary>
        /// This method creates the narrative for the diagnostic investigations section
        /// </summary>
        /// <param name="diagnosticInvestigations">IDiagnosticInvestigationsDischargeSummary</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(Nehta.VendorLibrary.CDA.SCSModel.DischargeSummary.IDiagnosticInvestigationsDischargeSummary diagnosticInvestigations)
        {
            var narrative = new List<List<String>>();
            var strucDocTableList = new List<StrucDocTable>();

            if (diagnosticInvestigations != null)
            {
                //This doesn't do anything as this section contains sub sections that render the narrative.
            }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            return strucDocText;
        }


        /// <summary>
        /// Create Address for Narative
        /// </summary>
        /// <param name="addresses">A List of addresses</param>
        /// <returns>A formated Address</returns>
        private static String CreateAddress(IEnumerable<IAddress> addresses, IEnumerable<ElectronicCommunicationDetail> electronicCommunicationDetails)
        {
            var stringReturn = String.Empty;

            if (addresses != null && addresses.Count() > 0)
            {
                foreach (var address in addresses)
                {
                    if (address != null)
                    {
                        stringReturn += CreateAddress(address);
                    }

                    stringReturn += DELIMITERBREAK;
                }
            }

            if (electronicCommunicationDetails != null && electronicCommunicationDetails.Count() > 0)
            {
                foreach (var electronicCommunicationDetail in electronicCommunicationDetails)
                {
                    if (electronicCommunicationDetail != null)
                    {
                        stringReturn += electronicCommunicationDetail.Narrative + DELIMITERBREAK;
                    }
                }
            }

            return stringReturn;
        }

        /// <summary>
        /// Create Address for Narative
        /// </summary>
        /// <param name="address">An address</param>
        /// <returns>A formated Address</returns>
        private static String CreateAddress(IAddress address)
        {
            var stringReturn = String.Empty;

            if (address != null)
            {
                stringReturn = address.AddressPurpose.GetAttributeValue<NameAttribute, String>(x => x.Name) + ": ";

                if (address.AustralianAddress != null)
                {
                    if (address.AustralianAddress.UnstructuredAddressLines != null)
                    {
                        foreach (var unstructuredAddressLines in address.AustralianAddress.UnstructuredAddressLines)
                        {
                            stringReturn += unstructuredAddressLines;
                        }
                    }

                    if (address.AustralianAddress.StreetNumber != null)
                    {
                        stringReturn += (!stringReturn.IsNullOrEmptyWhitespace() ? ", " : String.Empty) +
                                        address.AustralianAddress.StreetNumber.Value.ToString(CultureInfo.InvariantCulture);
                    }

                    if (!address.AustralianAddress.StreetName.IsNullOrEmptyWhitespace())
                    {
                        stringReturn += (!stringReturn.IsNullOrEmptyWhitespace() ? ", " : String.Empty) +
                                        address.AustralianAddress.StreetName;
                    }

                    if (!address.AustralianAddress.SuburbTownLocality.IsNullOrEmptyWhitespace())
                    {
                        stringReturn += (!stringReturn.IsNullOrEmptyWhitespace() ? ", " : String.Empty) +
                                        address.AustralianAddress.SuburbTownLocality;
                    }

                    if (!address.AustralianAddress.PostCode.IsNullOrEmptyWhitespace())
                    {
                        stringReturn += (!stringReturn.IsNullOrEmptyWhitespace() ? ", " : String.Empty) +
                                        address.AustralianAddress.PostCode;
                    }
                }
                else if (address.InternationalAddress != null)
                {

                    if (address.InternationalAddress.AddressLine != null)
                        foreach (var internationalAddressLine in address.InternationalAddress.AddressLine)
                        {
                            stringReturn += internationalAddressLine;
                        }


                    if (!address.InternationalAddress.StateProvince.IsNullOrEmptyWhitespace())
                    {
                        stringReturn += (!stringReturn.IsNullOrEmptyWhitespace() ? ", " : String.Empty) +
                                        address.InternationalAddress.StateProvince;
                    }

                    if (!address.InternationalAddress.PostCode.IsNullOrEmptyWhitespace())
                    {
                        stringReturn += (!stringReturn.IsNullOrEmptyWhitespace() ? ", " : String.Empty) +
                                        address.InternationalAddress.PostCode;
                    }

                    if (address.InternationalAddress.Country != Country.Undefined)
                    {
                        stringReturn += (!stringReturn.IsNullOrEmptyWhitespace() ? ", " : String.Empty) +
                                        address.InternationalAddress.Country.GetAttributeValue<NameAttribute, String>(x => x.Name);
                    }
                }
            }

            return stringReturn;
        }


        /// <summary>
        /// Converts a duration to a string for the narrative.
        /// </summary>
        /// <param name="duration"></param>
        /// <returns></returns>
        private static String CreateDuration(CdaInterval duration)
        {
            if (duration == null)
            {
                return string.Empty;
            }

            return CdaIntervalFormatter.Format(duration);
        }

        /// <summary>
        /// Generates the Prescription Item for the narrative
        /// </summary>
        /// <param name="item">IEPrescriptionItem</param>
        /// <param name="prescriber">IParticipationPrescriber</param>
        /// <param name="subjectOfCare">IParticipationSubjectOfCare</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(PrescriptionItem item, IParticipationPrescriber prescriber, IParticipationSubjectOfCare subjectOfCare)
        {
            var strucDocTableList = new List<StrucDocTable>();
            var narrative = new List<List<String>>();
            var narrativeSubjectOfCareEntitlements = new List<List<String>>();
            var entitlementsColumnHeaders = new List<string> { "Entitlement Type", "Validity Duration", "Entitlement Number" };
            var narrativePrescriberEntitlements = new List<List<String>>();


            if (item != null)
            {
                    var columnHeaders = new List<string> { "Field", "ResultValue" };

                    //Therapeutic Good Identification
                    if (item.TherapeuticGoodId != null)
                      narrative.Add
                         (
                             CreateNarrativeEntry("Therapeutic Good Identification", item.TherapeuticGoodId.NarrativeText)
                         );

                    //Therapeutic Good Generic Name
                    if (item.TherapeuticGoodGenericName != null)
                      narrative.Add
                         (
                             CreateNarrativeEntry("Therapeutic Good Generic Name (Additional Therapeutic Good Detail)", item.TherapeuticGoodGenericName)
                         );

                    //Therapeutic Good Strength
                    if (item.TherapeuticGoodStrength != null)
                      narrative.Add
                         (
                             CreateNarrativeEntry("Therapeutic Good Strength (Additional Therapeutic Good Detail)", item.TherapeuticGoodStrength)
                         );

                    //DateTime Prescription Written
                    if (prescriber.PrescriptionWritten != null)
                      narrative.Add
                          (
                              CreateNarrativeEntry("Date and Time Prescription Written", prescriber.PrescriptionWritten)
                          );

                    //DateTime Prescription Expires
                    if (item.DateTimePrescriptionExpires != null)
                      narrative.Add
                          (
                              CreateNarrativeEntry("Date and Time Prescription Expires", item.DateTimePrescriptionExpires)
                          );

                    //Formula
                    if (!item.Formula.IsNullOrEmptyWhitespace())
                      narrative.Add
                        (
                            CreateNarrativeEntry("Formula", item.Formula)
                        );

                    //Formula
                    if (item.Form != null)
                      narrative.Add
                        (
                            CreateNarrativeEntry("Form", item.Form.NarrativeText)
                        );

                    //Directions
                    if (!item.Directions.IsNullOrEmptyWhitespace())
                      narrative.Add
                         (
                             CreateNarrativeEntry("Directions", item.Directions)
                         );


                    //Clinical Indication
                    if (item.ClinicalIndication != null)
                      narrative.Add
                         (
                             CreateNarrativeEntry("Clinical Indication", item.ClinicalIndication)
                         );

                    //Route
                    if (item.Route != null)
                      narrative.Add
                         (
                             CreateNarrativeEntry("Route", item.Route.NarrativeText)
                         );


                    //Quantity Description
                    if (item.DispensingInformation != null && !item.DispensingInformation.QuantityDescription.IsNullOrEmptyWhitespace())
                      narrative.Add
                         (
                             CreateNarrativeEntry("Quantity Description", item.DispensingInformation.QuantityDescription)
                         );

                    //Maximum Number of Repeats
                    if (item.DispensingInformation != null && item.DispensingInformation.MaximumNumberOfRepeats != null)
                      narrative.Add
                         (
                             CreateNarrativeEntry("Maximum Number of Repeats (Number of Repeats)", item.DispensingInformation.MaximumNumberOfRepeats, null)
                         );

                    // Minimum Interval Between Repeats
                    if (item.DispensingInformation != null && item.DispensingInformation.MinimumIntervalBetweenRepeats != null)
                      narrative.Add
                         (
                             CreateNarrativeEntry("Minimum Interval Between Repeats", CreateIntervalText(item.DispensingInformation.MinimumIntervalBetweenRepeats))
                         );

                    // PBS Manufacturer Code
                    if (item.PBSManufacturerCode != null)
                      narrative.Add
                         (
                             CreateNarrativeEntry("PBS Manufacturer Code (Administrative Manufacturer Code)", item.PBSManufacturerCode.NarrativeText)
                         );

                    // Brand Substitution Permitted
                    if (item.BrandSubstitutionPermitted != null)
                      narrative.Add
                         (
                             CreateNarrativeEntry("Brand Substitution Permitted", item.BrandSubstitutionPermitted)
                         );

                    // Comment
                    if (!item.Comment.IsNullOrEmptyWhitespace())
                      narrative.Add
                         (
                             CreateNarrativeEntry("Comment", item.Comment)
                         );


                    //Prescription Item Identifier
                    if (item.PrescriptionItemIdentifier != null)
                      narrative.Add
                          (
                              CreateNarrativeEntry("Prescription Item Identifier", item.PrescriptionItemIdentifier.NarrativeText)
                          );


                    // Entitilements Subject Of Care
                    if (subjectOfCare.Participant.Entitlements != null && subjectOfCare.Participant.Entitlements.Any())
                    {
                        foreach (var entitlement in subjectOfCare.Participant.Entitlements)
                        {
                            CodableText codeableTextEntry = null;

                            if (entitlement.Type != EntitlementType.Undefined)
                            {
                                codeableTextEntry = new CodableText
                                {
                                    Code = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Code),
                                    DisplayName = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                    OriginalText = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                    CodeSystem = CodingSystem.NCTISEntitlementTypeValues
                                };
                            }

                            narrativeSubjectOfCareEntitlements.Add
                                (
                                    new List<String>
                                     {
                                         codeableTextEntry != null ? codeableTextEntry.NarrativeText : "Undefined Entitlement",
                                         entitlement.ValidityDuration == null ? string.Empty : CreateIntervalText(entitlement.ValidityDuration),  
                                         entitlement.Id != null ? entitlement.Id.NarrativeText : String.Empty
                                     }
                                );
                        }
                    }

                    // Entitilements Prescriber
                    if (prescriber.Participant.Person.Entitlements != null && prescriber.Participant.Person.Entitlements.Any())
                    {
                        foreach (var entitlement in prescriber.Participant.Person.Entitlements)
                        {
                            CodableText codeableTextEntry = null;

                            if (entitlement.Type != EntitlementType.Undefined)
                            {
                                codeableTextEntry = new CodableText
                                {
                                    Code = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Code),
                                    DisplayName = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                    OriginalText = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                    CodeSystem = CodingSystem.NCTISEntitlementTypeValues
                                };
                            }

                            narrativePrescriberEntitlements.Add
                                (
                                    new List<String>
                                     {
                                         codeableTextEntry != null ? codeableTextEntry.NarrativeText : "Undefined Entitlement",
                                         entitlement.ValidityDuration == null ? string.Empty : CreateIntervalText(entitlement.ValidityDuration),  
                                         entitlement.Id != null ? entitlement.Id.NarrativeText : String.Empty
                                     }
                                );
                        }
                    }

                    strucDocTableList.AddRange
                        (
                           new List<StrucDocTable>
                           {
                                PopulateTable
                                        (
                                            null,
                                            null,
                                            columnHeaders.ToArray(),
                                            null,
                                            narrative
                                        ),
                                narrativeSubjectOfCareEntitlements.Any() ?  PopulateTable
                                        (
                                            "Subject Of Care Entitlement",
                                            null,
                                            entitlementsColumnHeaders.ToArray(),
                                            null,
                                            narrativeSubjectOfCareEntitlements
                                        ) : null,
                                narrativePrescriberEntitlements.Any() ?  PopulateTable
                                        (
                                            "Prescriber Entitlement",
                                            null,
                                            entitlementsColumnHeaders.ToArray(),
                                            null,
                                            narrativePrescriberEntitlements
                                        ) : null,

                           }
                        );
                }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            return strucDocText;
        }

        public StrucDocText CreateNarrative(DispenseItem item, IParticipationDispenser dispenser, IParticipationDispenserOrganisation dispenserOrganisation, IParticipationSubjectOfCare subjectOfCare)
        {
          var strucDocTableList = new List<StrucDocTable>();
          var narrative = new List<List<String>>();
          var narrativeSubjectOfCareEntitlements = new List<List<String>>();
          var entitlementsColumnHeaders = new List<string> { "Entitlement Type", "Validity Duration", "Entitlement Number" };
          var narrativePrescriberEntitlements = new List<List<String>>();


          if (item != null)
          {
            var columnHeaders = new List<string> { "Field", "ResultValue" };

            //Therapeutic Good Identification
            if (item.TherapeuticGoodId != null)
              narrative.Add
                 (
                     CreateNarrativeEntry("Therapeutic Good Identification", item.TherapeuticGoodId.NarrativeText)
                 );

            //Therapeutic Good Strength
            if (!item.TherapeuticGoodStrength.IsNullOrEmptyWhitespace())
              narrative.Add
                 (
                     CreateNarrativeEntry("Therapeutic Good Strength", item.TherapeuticGoodStrength)
                 );

            //Therapeutic Good Generic Name
            if (!item.TherapeuticGoodGenericName.IsNullOrEmptyWhitespace())
              narrative.Add
                 (
                     CreateNarrativeEntry("Therapeutic Good Generic Name", item.TherapeuticGoodGenericName)
                 );

            //Additional Dispensed Item Description
            if (!item.AdditionalDispensedItemDescription.IsNullOrEmptyWhitespace())
              narrative.Add
                 (
                     CreateNarrativeEntry("Additional Dispensed Item Description", item.AdditionalDispensedItemDescription)
                 );

            //Label Instruction
            if (!item.LabelInstruction.IsNullOrEmptyWhitespace())
              narrative.Add
                 (
                     CreateNarrativeEntry("Label Instruction", item.LabelInstruction)
                 );

            //Formula
            if (!item.Formula.IsNullOrEmptyWhitespace())
              narrative.Add
                (
                    CreateNarrativeEntry("Formula", item.Formula)
                );

            //Form
            if (item.Form != null)
              narrative.Add
                (
                    CreateNarrativeEntry("Form", item.Form.NarrativeText)
                );


            //Quantity Description
            if (!item.QuantityDescription.IsNullOrEmptyWhitespace())
              narrative.Add
                (
                    CreateNarrativeEntry("Quantity Description", item.QuantityDescription)
                );


            //Comment
            if (!item.Comment.IsNullOrEmptyWhitespace())
              narrative.Add
                (
                    CreateNarrativeEntry("Comment", item.Comment)
                );

            // Brand Substitution Occurred
            if (item.BrandSubstitutionOccurred != null)
              narrative.Add
                 (
                     CreateNarrativeEntry("Brand Substitution Occurred", item.BrandSubstitutionOccurred)
                 );

            //Number of this Dispense
            if (item.NumberOfThisDispense.HasValue)
              narrative.Add
                (
                    CreateNarrativeEntry("Number of this Dispense", item.NumberOfThisDispense.Value.ToString(CultureInfo.InvariantCulture))
                );

    
            //Maximum Number of Repeats
            if (item.MaximumNumberOfRepeats != null)
              narrative.Add
                 (
                     CreateNarrativeEntry("Maximum Number of Repeats", item.MaximumNumberOfRepeats, null)
                 );

            // PBS Manufacturer Code
            if (item.PBSManufacturerCode != null)
              narrative.Add
                 (
                     CreateNarrativeEntry("PBS Manufacturer Code", item.PBSManufacturerCode.NarrativeText)
                 );


            // Unique Pharmacy Prescription Number
            if (!item.UniquePharmacyPrescriptionNumber.IsNullOrEmptyWhitespace())
              narrative.Add
                 (
                     CreateNarrativeEntry("Unique Pharmacy Prescription Number", item.UniquePharmacyPrescriptionNumber)
                 );

            //Prescription Item Identifier
            if (item.PrescriptionItemIdentifier != null)
              narrative.Add
                  (
                      CreateNarrativeEntry("Prescription Item Identifier", item.PrescriptionItemIdentifier.NarrativeText)
                  );

            //DateTime Of Dispense Event
            if (item.DateTimeOfDispenseEvent != null)
              narrative.Add
                  (
                      CreateNarrativeEntry("DateTime of Dispense Event", item.DateTimeOfDispenseEvent)
                  );

            //DateTime Of Dispense Event
            if (item.DispenseItemIdentifier != null)
              narrative.Add
                  (
                      CreateNarrativeEntry("Dispense Item Identifier", item.DispenseItemIdentifier.NarrativeText)
                  );

            // Entitilements Subject Of Care
            if (subjectOfCare.Participant != null && subjectOfCare.Participant.Entitlements != null && subjectOfCare.Participant.Entitlements.Any())
            {
              foreach (var entitlement in subjectOfCare.Participant.Entitlements)
              {
                CodableText codeableTextEntry = null;

                if (entitlement.Type != EntitlementType.Undefined)
                {
                  codeableTextEntry = new CodableText
                  {
                    Code = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Code),
                    DisplayName = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Name),
                    OriginalText = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Name),
                    CodeSystem = CodingSystem.NCTISEntitlementTypeValues
                  };
                }

                narrativeSubjectOfCareEntitlements.Add
                    (
                        new List<String>
                                     {
                                         codeableTextEntry != null ? codeableTextEntry.NarrativeText : "Undefined Entitlement",
                                         entitlement.ValidityDuration == null ? string.Empty : CreateIntervalText(entitlement.ValidityDuration),  
                                         entitlement.Id != null ? entitlement.Id.NarrativeText : String.Empty
                                     }
                    );
              }
            }

            // Entitilements Prescriber
            if (dispenserOrganisation.Participant.Entitlements != null && dispenserOrganisation.Participant.Entitlements.Any())
            {
              foreach (var entitlement in dispenserOrganisation.Participant.Entitlements)
              {
                CodableText codeableTextEntry = null;

                if (entitlement.Type != EntitlementType.Undefined)
                {
                  codeableTextEntry = new CodableText
                  {
                    Code = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Code),
                    DisplayName = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Name),
                    OriginalText = entitlement.Type.GetAttributeValue<NameAttribute, String>(x => x.Name),
                    CodeSystem = CodingSystem.NCTISEntitlementTypeValues
                  };
                }

                narrativePrescriberEntitlements.Add
                    (
                        new List<String>
                                     {
                                         codeableTextEntry != null ? codeableTextEntry.NarrativeText : "Undefined Entitlement",
                                         entitlement.ValidityDuration == null ? string.Empty : CreateIntervalText(entitlement.ValidityDuration),  
                                         entitlement.Id != null ? entitlement.Id.NarrativeText : String.Empty
                                     }
                    );
              }
            }

            strucDocTableList.AddRange
                (
                   new List<StrucDocTable>
                           {
                                PopulateTable
                                        (
                                            null,
                                            null,
                                            columnHeaders.ToArray(),
                                            null,
                                            narrative
                                        ),
                                narrativeSubjectOfCareEntitlements.Any() ?  PopulateTable
                                        (
                                            "Subject Of Care Entitlement",
                                            null,
                                            entitlementsColumnHeaders.ToArray(),
                                            null,
                                            narrativeSubjectOfCareEntitlements
                                        ) : null,
                                narrativePrescriberEntitlements.Any() ?  PopulateTable
                                        (
                                            "Dispensing Organisation Entitlement",
                                            null,
                                            entitlementsColumnHeaders.ToArray(),
                                            null,
                                            narrativePrescriberEntitlements
                                        ) : null,

                           }
                );
          }

          var strucDocText = new StrucDocText();

          if (strucDocTableList.Any())
          {
            strucDocText.table = strucDocTableList.ToArray();
          }

          return strucDocText;
        }

        /// <summary>
        /// Generates the Prescription Item for the IObservationWeightHeight
        /// </summary>
        /// <param name="observation">IObservationWeightHeight</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(IObservationWeightHeight observation)
        {
            var strucDocTableList = new List<StrucDocTable>();
            var narrative = new List<List<String>>();

            if (observation != null)
            {
                var columnHeaders = new List<string> {"Date", "Name", "Value"};

                // BodyWeight
                if (observation.BodyWeight != null)
                {
                    // Weight
                    if (observation.BodyWeight.Weight != null)
                        narrative.Add
                            (
                            new List<String>
                                {
                                    observation.BodyWeight.BodyWeightObservationTime != null
                                        ? observation.BodyWeight.BodyWeightObservationTime.NarrativeText()
                                        : String.Empty,
                                    "Body Weight",
                                    observation.BodyWeight.Weight.Value + " " +
                                    observation.BodyWeight.UnitOfMeasure
                                }
                            );
                }

                // Weight
                if (observation.BodyHeight != null)
                {
                    narrative.Add
                        (
                            new List<String>
                                    {
                                        observation.BodyHeight.BodyHeightObservationTime != null 
                                            ? observation.BodyHeight.BodyHeightObservationTime.NarrativeText()
                                            : String.Empty,
                                        "Body Hight",
                                        observation.BodyHeight.Height + " " +
                                        observation.BodyHeight.UnitOfMeasure != null ? observation.BodyHeight.UnitOfMeasure : String.Empty
                                    }
                        );
                }

                    // Add body Height Narrative
                    strucDocTableList.Add
                        (
                            PopulateTable
                                (
                                    null,
                                    null,
                                    columnHeaders.ToArray(),
                                    null,
                                    narrative
                                )
                        );
                }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for Event Details
        /// </summary>
        /// <param name="eventDetails">EventDetails</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(EventDetails eventDetails) 
        {
            var strucDocTableList = new List<StrucDocTable>();
            var narrative = new List<List<String>>();

            if (eventDetails.ClinicalSynopsisDescription != null)
            {
                var columnHeaders = new List<string> { "Clinical Synopsis Description" };

                        narrative.Add
                            (
                                new List<String>
                                    {
                                        CreateNarrativeEntry(eventDetails.ClinicalSynopsisDescription) 
                                    }
                            );


                    // Add body Height Narrative
                    strucDocTableList.Add
                        (
                            PopulateTable
                                (
                                    null,
                                    null,
                                    columnHeaders.ToArray(),
                                    null,
                                    narrative
                                )
                        );
            }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the medication items
        /// </summary>
        /// <param name="medicationItems">A list of medicationItems</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(IEnumerable<IMedicationItem> medicationItems)
        {
            var narrative = new List<List<String>>();
            var strucDocTableList = new List<StrucDocTable>();

            if (medicationItems != null)
            {
                if (medicationItems.Count() > 0)
                {
                    var narativeHeader = new List<string>()
                                             {
                                                 "Medication",
                                                 "Directions",
                                                 "Clinical Indication",
                                                 "Change Type",
                                                 "Change or Recommendation?",
                                                 "Change Description",
                                                 "Change Reason"
                                             };

                    narrative = new List<List<String>>();

                    foreach (var medication in medicationItems)
                    {

                        //medicine_list + clinical Indication
                        var medicationList = new List<String>
                          {
                              medication.Medicine != null ? medication.Medicine.NarrativeText : String.Empty,
                              !medication.Directions.IsNullOrEmptyWhitespace() ? medication.Directions : medication.DirectionsNullFlavour.GetAttributeValue<NameAttribute, String>(x => x.Name),
                              medication.ClinicalIndication ?? String.Empty,
                              medication.ChangeType.HasValue ? medication.ChangeType.GetAttributeValue<NameAttribute, String>(x => x.Name) : medication.ChangeTypeNullFlavour.GetAttributeValue<NameAttribute, String>(x => x.Name),                               
                              medication.RecommendationOrChange.HasValue ? medication.RecommendationOrChange.GetAttributeValue<NameAttribute, String>(x => x.Name) : medication.RecommendationOrChangeNullFlavour.GetAttributeValue<NameAttribute, String>(x => x.Name),                                    
                              medication.ChangeDescription ?? String.Empty,
                              medication.ChangeReason ?? String.Empty
                          };

                        // Dynamical add comment is it is not null
                        if (!medication.Comment.IsNullOrEmptyWhitespace())
                        {
                            medicationList.Add(medication.Comment);

                            if (narativeHeader.Contains("Comment") == false)
                            {
                                narativeHeader.Add("Comment");
                            }
                        } 

                        narrative.Add(medicationList);
                    }

                    // Close empty cells
                    foreach (var narrativeEntry in narrative.Where(narrativeEntry => narativeHeader.Contains("Comment") && narrativeEntry.Count == 7))
                    {
                        narrativeEntry.Add(string.Empty);
                    }

                    strucDocTableList.Add
                    (
                        PopulateTable
                        (
                            "Reviewed Medications - Medications",
                            null,
                            narativeHeader.ToArray(),
                            new string[0],
                            narrative
                        )
                    );
                }
            }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.Text = new string[] { "This section contains no entries." };
            }

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for Diagnoses Intervention
        /// </summary>
        /// <param name="diagnosesIntervention">A diagnoses Intervention item</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(DiagnosesIntervention diagnosesIntervention)
        {
            var narrative = new List<List<String>>();
            var strucDocTableList = new List<StrucDocTable>();

            if (diagnosesIntervention != null)
            {
                narrative = new List<List<String>>();

                // Add Problem Diagnosis for Diagnoses Intervention
                if (diagnosesIntervention.ProblemDiagnosis != null)
                    foreach (var problemDiagnosis in diagnosesIntervention.ProblemDiagnosis)
                    {
                        narrative.Add(
                            new List<String>
                                {
                                    problemDiagnosis.ProblemDiagnosisIdentification != null ? problemDiagnosis.ProblemDiagnosisIdentification.NarrativeText : String.Empty,
                                    problemDiagnosis.DateOfResolutionRemission != null ?  problemDiagnosis.DateOfResolutionRemission.NarrativeText() : String.Empty,
                                    problemDiagnosis.DateOfOnset != null ? problemDiagnosis.DateOfOnset.NarrativeText() : String.Empty,
                                    problemDiagnosis.Comment.IsNullOrEmptyWhitespace()  ? String.Empty : problemDiagnosis.Comment

                                }
                            );
                    }

                if (narrative.Any())
                strucDocTableList.Add
                (
                    PopulateTable
                    (
                        "Problem/Diagnosis",
                        null,
                        new[]
                            {
                                "Identification", 
                                "Date Of Resolution Remission",                         
                                "Date of Onset",
                                "Comment"
                            },
                        new string[0],
                        narrative
                    )
                );

                // Add procedure for Diagnoses Intervention
                narrative = new List<List<String>>();
                if (diagnosesIntervention.Procedures != null)
                    foreach (var procedure in diagnosesIntervention.Procedures)
                    {
                        narrative.Add(
                            new List<String>
                                {
                                    procedure.ProcedureName != null ? procedure.ProcedureName.NarrativeText : String.Empty,
                                    procedure.Start != null ? procedure.Start.NarrativeText() : String.Empty,
                                    procedure.Comment.IsNullOrEmptyWhitespace() ? String.Empty : procedure.Comment
                                }
                            );
                    }

                if (narrative.Any())
                strucDocTableList.Add
                (
                    PopulateTable
                    (
                        "Procedure",
                        null,
                        new[]
                            {
                                "Name", 
                                "Start",                         
                                "Comment"
                            },
                        new string[0],
                        narrative
                    )
                );

                //OTHER MEDICAL HISTORY
                if (diagnosesIntervention.MedicalHistoryItem != null && diagnosesIntervention.MedicalHistoryItem.Any())
                {
                    strucDocTableList.AddRange
                        (
                            CreateNarrativeEntry(diagnosesIntervention.MedicalHistoryItem)
                        );
                }
            }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.Text = new [] { "This section contains no entries." };
            }

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for Immunisations
        /// </summary>
        /// <param name="immunisations">A list of Immunisation items</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(IEnumerable<IImmunisation> immunisations)
        {
            var narrative = new List<List<String>>();
            var strucDocTableList = new List<StrucDocTable>();

            if (immunisations != null && immunisations.Count() > 0)
            {

                foreach (var imunisation in immunisations)
                {
                    narrative.Add(
                        new List<String>
                                {
                                    imunisation.DateTime != null ? imunisation.DateTime.NarrativeText() : String.Empty,
                                    imunisation.Medicine != null ? imunisation.Medicine.NarrativeText : String.Empty,
                                    imunisation.SequenceNumber.HasValue ? imunisation.SequenceNumber.Value.ToString(CultureInfo.InvariantCulture) : String.Empty
                                });
                }
            }

            if (narrative.Any())
            {
                strucDocTableList.Add
                    (
                        PopulateTable
                        (
                            "Immunisations - Administered Immunisations",
                            null,
                            new[] { "Date Time", "Medicine", "Vaccine Sequence Number" },
                            new string[] { },
                            narrative
                        )
                    );
            }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.Text = new string[] { "This section contains no entries." };
            }

            return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for Requested Services
        /// </summary>
        /// <param name="requestedService">A list of Requested Services</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(RequestedService requestedService)
        {
            List<List<String>> narrative = new List<List<String>>();

            var strucDocTableList = new List<StrucDocTable>();
 
            if (requestedService != null)
            {
                    // Get organisation name
                    String organisationName = null;
                    if (requestedService.ServiceProvider != null)
                        if (requestedService.ServiceProvider.Participant != null)
                        {
                            if (requestedService.ServiceProvider.Participant.Organisation != null)
                                if (!requestedService.ServiceProvider.Participant.Organisation.Name.IsNullOrEmptyWhitespace())
                                    organisationName = requestedService.ServiceProvider.Participant.Organisation.Name;

                            if (organisationName.IsNullOrEmptyWhitespace())
                                if (requestedService.ServiceProvider.Participant.Person != null)
                                    if (requestedService.ServiceProvider.Participant.Person.Organisation != null)
                                        if (!requestedService.ServiceProvider.Participant.Person.Organisation.Name.IsNullOrEmptyWhitespace())
                                            organisationName = requestedService.ServiceProvider.Participant.Person.Organisation.Name;
                        }

                    String personName = null;
                    // Provider Person Name
                    if (requestedService.ServiceProvider != null && requestedService.ServiceProvider.Participant != null && requestedService.ServiceProvider.Participant.Person != null)
                            personName = BuildPersonNames(requestedService.ServiceProvider.Participant.Person.PersonNames);

                    // Requested Service Description
                    if (requestedService.RequestedServiceDescription != null)
                        narrative.Add
                        (
                            CreateNarrativeEntry("Requested Service Description", requestedService.RequestedServiceDescription.NarrativeText)
                        );

                    // Service Requested DateTime
                    if (requestedService.RequestedServiceDateTime != null)
                        narrative.Add
                        (
                            CreateNarrativeEntry("Service Requested DateTime", requestedService.RequestedServiceDateTime.NarrativeText())
                        );

                    // DateTime Service Scheduled or Service Commencement Window
                    if (requestedService.ServiceScheduled != null || requestedService.ServiceCommencementWindow != null)
                        narrative.Add
                        (
                            CreateNarrativeEntry("Service Scheduled", GetServiceScheduledOrServiceCommencementWindow(requestedService))
                        );

                    // Provider Organisation
                    if (!organisationName.IsNullOrEmptyWhitespace())
                        narrative.Add
                        (
                            CreateNarrativeEntry("Provider Organisation", organisationName)
                        );


                    // Provider Person Name
                    if (!personName.IsNullOrEmptyWhitespace())
                        narrative.Add
                        (
                            CreateNarrativeEntry("Provider Person Name", personName)
                        );

                   // Provider Person Name
                    if ((requestedService.ServiceProvider != null && requestedService.ServiceProvider.Participant.Addresses != null && requestedService.ServiceProvider.Participant.Addresses.Any()) || requestedService.ServiceProvider != null && requestedService.ServiceProvider.Participant.ElectronicCommunicationDetails != null)
                        narrative.Add
                        (
                            CreateNarrativeEntry("Address / Contact", CreateAddress(requestedService.ServiceProvider.Participant.Addresses, requestedService.ServiceProvider.Participant.ElectronicCommunicationDetails))
                        );

                    //// Contact
                    //if (requestedService.ServiceProvider != null && requestedService.ServiceProvider.Participant.ElectronicCommunicationDetails != null && requestedService.ServiceProvider.Participant.ElectronicCommunicationDetails.Any())
                    //    narrative.Add
                    //    (
                    //        CreateNarrativeEntry("Contact", CreateCommunicationDetails(requestedService.ServiceProvider.Participant.ElectronicCommunicationDetails))
                    //    );

                   //  Booking Status
                    if (requestedService.ServiceBookingStatus != EventTypes.Undefined)
                        narrative.Add
                        (
                            CreateNarrativeEntry( "Booking Status", requestedService.ServiceBookingStatus.GetAttributeValue<NameAttribute, String>(x => x.Name))
                        );

                    // Provider Person Name
                    if (!requestedService.SubjectOfCareInstructionDescription.IsNullOrEmptyWhitespace())
                        narrative.Add
                        (
                            CreateNarrativeEntry("Subject of Care Instruction Description", requestedService.SubjectOfCareInstructionDescription)
                        );
                }

            strucDocTableList.Add
            (
                PopulateTable
                    (
                        String.Empty,
                        null,
                        null,
                        new string[0],
                        narrative
                    )
            );

            var strucDocText = new StrucDocText();


            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.Text = new [] {"This section contains no entries."};
            }

            return strucDocText;
        }


        #region Medicare View

        #endregion

        /// <summary>
        /// Gets the service scheduled field or the service commencement window field.
        /// </summary>
        /// <param name="requestedService">Requested service.</param>
        /// <returns></returns>
        private string GetServiceScheduledOrServiceCommencementWindow(RequestedService requestedService)
        {
            if (requestedService.ServiceScheduled != null)
            {
                return requestedService.ServiceScheduled.NarrativeText();
            }
            
            if (requestedService.ServiceCommencementWindow != null)
            {
                return CreateDuration(requestedService.ServiceCommencementWindow);
            }

            return string.Empty;
        }

        private StrucDocParagraph CreateExclusionStatementNarrative(string caption, Statement statements)
        {
          return CreateExclusionStatementNarrative(caption, new List<Statement> { statements });
        }

        private StrucDocParagraph CreateExclusionStatementNarrative(string caption, List<Statement> statements)
        {
            // HEADER
          string exclusionStatements = string.Empty;

          if (statements.Count > 1)
          {
              foreach (var statment in statements)
              {
                exclusionStatements += ", ";
                exclusionStatements += statment.Value.GetAttributeValue<NameAttribute, string>(x => x.Name);
              }
          } 
            else
          {
             exclusionStatements = statements.First().Value.GetAttributeValue<NameAttribute, string>(x => x.Name);
          }

          return new StrucDocParagraph {Text = new[] {string.Format("{0} - {1}", caption, exclusionStatements)}};
        }

        private StrucDocParagraph CreateExclusionStatementNarrative(string caption, string statements)
        {
          return CreateExclusionStatementNarrative(caption, new List<string> { statements });
        }

        private StrucDocParagraph CreateExclusionStatementNarrative(string caption, List<string> statements)
        {
          // HEADER
          string exclusionStatements = string.Empty;

          if (statements.Count > 1)
          {
            foreach (var statment in statements)
            {
              exclusionStatements += ", ";
              exclusionStatements += statment;
            }
          }
          else
          {
            exclusionStatements = statements.First();
          }

          return new StrucDocParagraph { Text = new[] { string.Format("{0} - {1}", caption, exclusionStatements) } };
        }

  
        private static StrucDocTable PopulateTable(string caption, string summary, string[] columnHeaders, string[] rowHeadData, string[][] rowData)
        {
            var strucDocTable = new StrucDocTable();

            if (!caption.IsNullOrEmptyWhitespace())
            {
                strucDocTable.caption = new StrucDocCaption
                {
                    Text = new[] { caption }
                };
            }

            if (!summary.IsNullOrEmptyWhitespace())
            {
                strucDocTable.summary = summary;
            }

            // HEADER
            if (columnHeaders != null && columnHeaders.Length > 0)
            {
                strucDocTable.thead = new StrucDocThead
                {
                    tr = new StrucDocTr[1]
                };
                strucDocTable.thead.tr[0] = new StrucDocTr
                {
                    th = new StrucDocTh[columnHeaders.Length]
                };

                for (var i = 0; i < columnHeaders.Length; i++)
                {
                    strucDocTable.thead.tr[0].th[i] = new StrucDocTh
                    {
                        Text = new[] { columnHeaders[i] }
                    };
                }
            }

            //BODY
            if (rowData != null && rowData.Length > 0)
            {
                strucDocTable.tbody = new StrucDocTbody[1];
                strucDocTable.tbody[0] = new StrucDocTbody
                {
                    tr = new StrucDocTr[rowData.Length]
                };

                for (var i = 0; i < rowData.Length; i++)
                {
                    strucDocTable.tbody[0].tr[i] = new StrucDocTr();

                    strucDocTable.tbody[0].tr[i].td = new StrucDocTd[rowData[i].Length];  // FOR EACH COLUMN on a ROW
                    for (var j = 0; j < rowData[i].Length; j++)
                    {
                        strucDocTable.tbody[0].tr[i].td[j] = new StrucDocTd();
                        // CHECK FOR DELIMITER CHARS
                        if
                            (
                                rowData[i][j] != null && (rowData[i][j].Contains(DELIMITER) || rowData[i][j].Contains(DELIMITERBREAK))
                                
                            )
                           {

                            // CHECK FOR DELIMITER CHAR FOR LIST
                            if (rowData[i][j] != null && (rowData[i][j].Contains(DELIMITER)))
                            {
                                var dataSets = CalculateNumberOfDelimiters(rowData[i][j], DELIMITER);
                                var data = rowData[i][j];
                                //For Lists for the Cell rather than 
                                strucDocTable.tbody[0].tr[i].td[j].list = new StrucDocList[1];
                                strucDocTable.tbody[0].tr[i].td[j].list[0] = new StrucDocList
                                {
                                    item = new StrucDocItem[dataSets]
                                };
                                for (var k = 0; k < dataSets; k++)
                                {
                                    strucDocTable.tbody[0].tr[i].td[j].list[0].item[k] = new StrucDocItem
                                    {
                                        Text = new[]
                                    {
                                         data.Contains(DELIMITER) ? !data.StartsWith(DELIMITER) ? 
                                                data.Substring(0,data.IndexOf(DELIMITER)) :
                                                data.Substring(DELIMITER.Length).Contains((DELIMITER)) ?
                                                data.Substring(DELIMITER.Length, data.Substring(DELIMITER.Length).IndexOf(DELIMITER)) : data.Substring(DELIMITER.Length) : data
                                    }
                                    };

                                    data = data.Contains(DELIMITER) ?
                                             data.StartsWith(DELIMITER) ?
                                             data.Substring(DELIMITER.Length).Contains(DELIMITER) ?
                                             data.Substring(data.Substring(DELIMITER.Length).IndexOf(DELIMITER) + DELIMITER.Length) :
                                             String.Empty : data.Substring(data.IndexOf(DELIMITER)) : String.Empty;

                                }
                            }

                            // CHECK FOR DELIMITER CHAR FOR LIST
                            if (rowData[i][j] != null && (rowData[i][j].Contains(DELIMITERBREAK)))
                            {
                                var dataSets = CalculateNumberOfDelimiters(rowData[i][j], DELIMITERBREAK);
                                var data = rowData[i][j];
                                //For Lists for the Cell rather than 
                                var listBreaks = new List<string>();

                                for (var k = 0; k < dataSets; k++)
                                {
                                    listBreaks.Add(
                                                    data.Contains(DELIMITERBREAK) ? !data.StartsWith(DELIMITERBREAK) ?
                                                    data.Substring(0, data.IndexOf(DELIMITERBREAK)) :
                                                    data.Substring(DELIMITERBREAK.Length).Contains((DELIMITERBREAK)) ?
                                                    data.Substring(DELIMITERBREAK.Length, data.Substring(DELIMITERBREAK.Length).IndexOf(DELIMITERBREAK)) :
                                                    data.Substring(DELIMITERBREAK.Length) : data
                                                    );

                                    data = data.Contains(DELIMITERBREAK) ?
                                             data.StartsWith(DELIMITERBREAK) ?
                                             data.Substring(DELIMITERBREAK.Length).Contains(DELIMITERBREAK) ?
                                             data.Substring(data.Substring(DELIMITERBREAK.Length).IndexOf(DELIMITERBREAK) + DELIMITERBREAK.Length) :
                                             String.Empty : data.Substring(data.IndexOf(DELIMITERBREAK)) : String.Empty;
                                }

                                var strucDocList = new List<StrucDocContent>();
                                var firstTimeThrough = true;
                                foreach (var line in listBreaks)
                                {
                                    if (firstTimeThrough)
                                    {
                                        strucDocList.Add(new StrucDocContent {Text = new string[] {line}});
                                        firstTimeThrough = false;
                                    } 
                                    else 
                                    {
                                        strucDocList.Add(new StrucDocContent { Text = new string[] { line }, br = new string[] { string.Empty } });
                                    }

                                }
                                strucDocTable.tbody[0].tr[i].td[j].content = strucDocList.ToArray();
                            }
                        }
                        else
                        {
                            //No DELIMITERS 
                            strucDocTable.tbody[0].tr[i].td[j].Text = new[] { rowData[i][j] };
                        }
                    }
                }
            }

            return strucDocTable;
        }

        private static StrucDocTable PopulateTable(string caption, string summary, string[] columnHeaders, string[] rowHeadData, IList<List<string>> rowData)
        {
            var rowDataAsArray = new string[rowData.Count][];

            for (var i = 0; i < rowData.Count; i++)
            {
                if (rowData[i] != null)
                {
                    rowDataAsArray[i] = rowData[i].ToArray();
                }
            }

            return PopulateTable(caption, summary, columnHeaders, rowHeadData, rowDataAsArray);
        }

        private static StrucDocTable PopulateTable(string caption, string summary, string[] columnHeaders, string[] rowHeadData, List<List<object>> rowData)
        {
            var strucDocTable = new StrucDocTable();

            if (!caption.IsNullOrEmptyWhitespace())
            {
                strucDocTable.caption = new StrucDocCaption
                {
                    Text = new[] { caption }
                };
            }

            if (!summary.IsNullOrEmptyWhitespace())
            {
                strucDocTable.summary = summary;
            }

            // HEADER
            if (columnHeaders != null && columnHeaders.Length > 0)
            {
                strucDocTable.thead = new StrucDocThead
                {
                    tr = new StrucDocTr[1]
                };
                strucDocTable.thead.tr[0] = new StrucDocTr
                {
                    th = new StrucDocTh[columnHeaders.Length]
                };

                for (var i = 0; i < columnHeaders.Length; i++)
                {
                    strucDocTable.thead.tr[0].th[i] = new StrucDocTh
                    {
                        Text = new[] { columnHeaders[i] }
                    };
                }
            }

            //BODY
            if (rowData != null && rowData.Any())
            {
                strucDocTable.tbody = new StrucDocTbody[1];
                strucDocTable.tbody[0] = new StrucDocTbody
                {
                    tr = new StrucDocTr[rowData.Count()]
                };

                for (var rowCounter = 0; rowCounter < rowData.Count; rowCounter++)
                {
                    strucDocTable.tbody[0].tr[rowCounter] = new StrucDocTr();

                    strucDocTable.tbody[0].tr[rowCounter].td = new StrucDocTd[rowData[rowCounter].Count]; // FOR EACH COLUMN on a ROW

                    for (var cellCounter = 0; cellCounter < rowData[rowCounter].Count; cellCounter++)
                    {
                        strucDocTable.tbody[0].tr[rowCounter].td[cellCounter] = new StrucDocTd();

                        // CHECK FOR DELIMITER CHARS
                        if (
                                rowData[rowCounter][cellCounter] != null &&
                                rowData[rowCounter][cellCounter] is String &&
                                (((string)rowData[rowCounter][cellCounter]).Contains(DELIMITER) || ((string)rowData[rowCounter][cellCounter]).Contains(DELIMITERBREAK)) 
                            )
                        {
                            // CHECK FOR DELIMITER CHAR FOR LIST
                            if (((string)rowData[rowCounter][cellCounter]).Contains(DELIMITER))
                            {
                                var rowDataAsString = (rowData[rowCounter][cellCounter] as String);

                                // Get number of data sets
                                var dataSets = CalculateNumberOfDelimiters(rowDataAsString, DELIMITER);

                                //For Lists for the Cell rather than 
                                strucDocTable.tbody[0].tr[rowCounter].td[cellCounter].list = new StrucDocList[]
                                {
                                    new StrucDocList
                                        {
                                            item = new StrucDocItem[dataSets]
                                        }
                                };

                                for (var k = 0; k < dataSets; k++)
                                {
                                    strucDocTable.tbody[0].tr[rowCounter].td[cellCounter].list[0].item[k] = new StrucDocItem
                                    {
                                        Text = rowDataAsString == null ? null : new[]
                                             {
                                                     rowDataAsString.Contains(DELIMITER) ?
                                                     !rowDataAsString.StartsWith(DELIMITER) ? 
                                                      rowDataAsString.Substring(0,rowDataAsString.IndexOf(DELIMITER)) :
                                                      rowDataAsString.Substring(DELIMITER.Length).Contains((DELIMITER)) ?
                                                      rowDataAsString.Substring(DELIMITER.Length, rowDataAsString.Substring(DELIMITER.Length).IndexOf(DELIMITER)) :
                                                      rowDataAsString.Substring(DELIMITER.Length) :rowDataAsString
                                             }
                                    };

                                    //reduce the rowDataAsString variable to it only contains the remaining delimited items.
                                    rowDataAsString = rowDataAsString == null ? String.Empty : rowDataAsString.Contains(DELIMITER) ?
                                             rowDataAsString.StartsWith(DELIMITER) ?
                                             rowDataAsString.Substring(DELIMITER.Length).Contains(DELIMITER) ? rowDataAsString.Substring(rowDataAsString.Substring(DELIMITER.Length).IndexOf(DELIMITER) + DELIMITER.Length) :
                                             String.Empty : rowDataAsString.Substring(rowDataAsString.IndexOf(DELIMITER)) : String.Empty;
                                }
                            }


                            // CHECK FOR DELIMITER CHAR FOR LIST
                            if (((string)rowData[rowCounter][cellCounter]).Contains(DELIMITERBREAK))
                            {
                                var rowDataAsString = (rowData[rowCounter][cellCounter] as String);

                                // Get number of data sets
                                var dataSets = CalculateNumberOfDelimiters(rowDataAsString, DELIMITERBREAK);

                                //For Lists for the Cell rather than 
                                var listBreaks = new List<string>();

                                for (var k = 0; k < dataSets; k++)
                                {
                                    listBreaks.Add
                                             (
                                                     rowDataAsString.Contains(DELIMITERBREAK) ?
                                                     !rowDataAsString.StartsWith(DELIMITERBREAK) ? 
                                                      rowDataAsString.Substring(0,rowDataAsString.IndexOf(DELIMITERBREAK)) :
                                                      rowDataAsString.Substring(DELIMITERBREAK.Length).Contains((DELIMITERBREAK)) ?
                                                      rowDataAsString.Substring(DELIMITERBREAK.Length, rowDataAsString.Substring(DELIMITERBREAK.Length).IndexOf(DELIMITERBREAK)) :
                                                      rowDataAsString.Substring(DELIMITERBREAK.Length) :rowDataAsString
                                             );

                                    //reduce the rowDataAsString variable to it only contains the remaining delimited items.
                                    rowDataAsString = rowDataAsString == null ? String.Empty : rowDataAsString.Contains(DELIMITERBREAK) ?
                                             rowDataAsString.StartsWith(DELIMITERBREAK) ?
                                             rowDataAsString.Substring(DELIMITERBREAK.Length).Contains(DELIMITERBREAK) ? rowDataAsString.Substring(rowDataAsString.Substring(DELIMITERBREAK.Length).IndexOf(DELIMITERBREAK) + DELIMITERBREAK.Length) :
                                             String.Empty : rowDataAsString.Substring(rowDataAsString.IndexOf(DELIMITERBREAK)) : String.Empty;
                                }

                                var strucDocList = new List<StrucDocContent>();
                                var firstTimeThrough = true;
                                foreach (var line in listBreaks)
                                {
                                    if (firstTimeThrough)
                                    {
                                        strucDocList.Add(new StrucDocContent { Text = new string[] { line } });
                                        firstTimeThrough = false;
                                    }
                                    else
                                    {
                                        strucDocList.Add(new StrucDocContent { Text = new string[] { line }, br = new string[] { string.Empty } });
                                    }
                                }
                                strucDocTable.tbody[0].tr[rowCounter].td[cellCounter].content = strucDocList.ToArray();
                            }
                            
                        }
                        else
                        {
                             //No DELIMITERS
                            if (rowData[rowCounter][cellCounter] is String)
                            {
                                strucDocTable.tbody[0].tr[rowCounter].td[cellCounter].Text = new[] { rowData[rowCounter][cellCounter] as String };
                            }
                            
                            if(rowData[rowCounter][cellCounter] is StrucDocRenderMultiMedia)
                            {
                                strucDocTable.tbody[0].tr[rowCounter].td[cellCounter].renderMultiMedia = new[] { rowData[rowCounter][cellCounter] as StrucDocRenderMultiMedia };
                            }

                            if (rowData[rowCounter][cellCounter] is StrucDocLinkHtml)
                            {
                              strucDocTable.tbody[0].tr[rowCounter].td[cellCounter].content = new StrucDocContent[]
                                                                                                {
                                                                                                    new StrucDocContent{
                                                                                                    linkHtml = new StrucDocLinkHtml[]
                                                                                                                 {
                                                                                                                     rowData[rowCounter][cellCounter] as StrucDocLinkHtml 
                                                                                                                 } 
                                                                                                    }
                                                                                                };
                            }

                            if (rowData[rowCounter][cellCounter] != null && rowData[rowCounter][cellCounter] is List<StrucDocRenderMultiMedia>)
                            {
                                strucDocTable.tbody[0].tr[rowCounter].td[cellCounter].renderMultiMedia = ((List<StrucDocRenderMultiMedia>) rowData[rowCounter][cellCounter]).ToArray();
                            }
                        }
                    }

                    var collectionContainsMultiMedia = false;

                    rowData[rowCounter].ForEach(
                                                    innerItem =>
                                                    {
                                                        if(
                                                                !collectionContainsMultiMedia && 
                                                                    innerItem is StrucDocRenderMultiMedia ||
                                                                    innerItem is List<StrucDocRenderMultiMedia> 
                                                            )
                                                        {
                                                            collectionContainsMultiMedia = true;
                                                        }
                                                    }
                                                );

                    // CHECK FOR AN EMPTY IMAGE CELL
                    if (
                            rowData[rowCounter].Count > 1 &&
                            collectionContainsMultiMedia &&
                            (
                                strucDocTable.tbody[0].tr[rowCounter].td[rowData[rowCounter].Count -1].renderMultiMedia == null ||
                                strucDocTable.tbody[0].tr[rowCounter].td[rowData[rowCounter].Count -1].renderMultiMedia.Count() == 0
                            ) && strucDocTable.tbody[0].tr[rowCounter].td[rowData[rowCounter].Count -1].Text == null
                        )
                    {
                        strucDocTable.tbody[0].tr[rowCounter].td[rowData[rowCounter].Count -1].Text = new[] { "See above.." };
                    }
                    
                }
            }

            return strucDocTable;
        }

        private static StrucDocTable poulateTablexPreNarrative(string xPreNarrative)
        {
           return
                (
                    new StrucDocTable
                        {
                            tbody = new []
                                       {
                                          new StrucDocTbody
                                              {
                                                  tr = new []
                                                           {
                                                               new StrucDocTr
                                                               {
                                                                         td  = new []
                                                                                   {
                                                                                       new StrucDocTd
                                                                                           {
                                                                                                    paragraph = new []
                                                                                                                    {
                                                                                                                        new StrucDocParagraph
                                                                                                                            {
                                                                                                                                styleCode = "xPre",
                                                                                                                                Text = new [] { xPreNarrative },
                                                                                                                            }
                                                                                                                    }

                                                                                           }
                                                                                   }
                                                               }
                                                           }
                                              }
                                       }
                        }

                    );
        }

        private static Int32 CalculateNumberOfDelimiters(string search, string delimiter)
        {
            var ctr = 0;

            if (search.Contains(delimiter))
            {
                if (search.StartsWith(delimiter))
                {
                    //Remove the starting delimiter before performing any delimiter checking
                    //Note; the starting delimter is processed by the base case, where we are 
                    //      left with an empty string at the end of the delimiter processing.
                    search = search.Substring(search.IndexOf(delimiter) + delimiter.Length);
                }

                if (search.Contains(delimiter))
                {
                    do
                    {
                        search = search.Substring(search.IndexOf(delimiter) + delimiter.Length);
                        ctr++;
                    }
                    while 
                    (
                        search.IndexOf(delimiter) != -1
                    );
                }

                if (!search.IsNullOrEmptyWhitespace())
                {
                    //We have some more data, increment the delimiter count; thus ensuring that this
                    //data gets rendered within the populate table method.
                    ctr++;
                }
            }
            return ctr;
        }

        /// <summary>
        /// CreateEncapsulatedData
        /// </summary>
        /// <param name="encapsulatedData">The ExternalData item</param>
        /// <param name="sectionHeaderList">This item gets inserted into the section header </param>
        /// <returns>This item gets inserted into the narrative</returns>
        private static List<StrucDocRenderMultiMedia> CreateEncapsulatedData(ExternalData encapsulatedData, ref List<StrucDocRenderMultiMedia> sectionHeaderList)
        {
            return CreateEncapsulatedData((new List<ExternalData> { encapsulatedData }), ref sectionHeaderList);
        }

        /// <summary>
        /// CreateEncapsulatedData
        /// </summary>
        /// <param name="encapsulatedData">The ExternalData[] items</param>
        /// <param name="sectionHeaderList">This item gets inserted into the section header</param>
        /// <returns>This item gets inserted into the narrative</returns>
        private static List<StrucDocRenderMultiMedia> CreateEncapsulatedData(List<ExternalData> encapsulatedData, ref List<StrucDocRenderMultiMedia> sectionHeaderList)
        {
            var tableEntryRenderMultiMedia = new List<StrucDocRenderMultiMedia>();

            if (encapsulatedData != null)
            {
                foreach (var dataItem in encapsulatedData)
                {
                    if (dataItem != null)
                    {
                        if (dataItem.ExternalDataMediaType != MediaType.TXT && dataItem.ExternalDataMediaType != MediaType.PDF)
                        {
                            if (
                                !sectionHeaderList.Select(multiMediaItem => multiMediaItem.referencedObject).Contains(dataItem.ID))
                            {
                                sectionHeaderList.Add(dataItem.ConvertToStrucDocRenderMultiMedia());
                            }
                        }
                        else
                        {
                            tableEntryRenderMultiMedia.Add(dataItem.ConvertToStrucDocRenderMultiMedia());
                        }
                    } 
                }
            }
            return tableEntryRenderMultiMedia;
        }


        #region Medicare Information View 

        /// <summary>
        /// This method creates the narrative for the MedicareInformationViewExclusionStatement section
        /// </summary>
        /// <param name="australianChildhoodImmunisationRegisterEntries">australianChildhoodImmunisationRegisterEntries</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(AustralianChildhoodImmunisationRegisterEntries australianChildhoodImmunisationRegisterEntries)
        {
          var strucDocText = new StrucDocText();
          if (australianChildhoodImmunisationRegisterEntries != null)
          {
            strucDocText.Text = new[] { "Waiting for 'Medicare Information View CDA Rendering Specification', Version 1.0" };
          }

          return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the MedicareInformationViewExclusionStatement section
        /// </summary>
        /// <param name="medicareInformationViewExclusionStatement">medicareInformationViewExclusionStatement</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(MedicareInformationViewExclusionStatement medicareInformationViewExclusionStatement)
        {
          var strucDocText = new StrucDocText();
          if (medicareInformationViewExclusionStatement != null)
          {
            strucDocText.Text = new[] { medicareInformationViewExclusionStatement.GeneralStatement };
          }

          return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the Australian Childhood Immunisation Register Entry section
        /// </summary>
        /// <param name="australianChildhoodImmunisationRegisterEntry">AustralianChildhoodImmunisationRegisterEntry</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(AustralianChildhoodImmunisationRegisterEntry australianChildhoodImmunisationRegisterEntry)
        {
          var strucDocText = new StrucDocText();
          strucDocText.Text = new[] { "Waiting for 'Medicare Information View CDA Rendering Specification', Version 1.0" };
          return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the MedicareDVAFundedServices section
        /// </summary>
        /// <param name="medicareDVAFundedServices">MedicareDVAFundedServices</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(MedicareDVAFundedServices medicareDVAFundedServices)
        {
          var strucDocText = new StrucDocText();

          strucDocText.Text = new[] { "Waiting for 'Medicare Information View CDA Rendering Specification', Version 1.0" };
          return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the australianOrganDonorRegisterDetails section
        /// </summary>
        /// <param name="australianOrganDonorRegisterDetails">AustralianOrganDonorRegisterDetails</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(AustralianOrganDonorRegisterDetails australianOrganDonorRegisterDetails)
        {
          var strucDocText = new StrucDocText();

          strucDocText.Text = new[] { "Waiting for 'Medicare Information View CDA Rendering Specification', Version 1.0" };
          return strucDocText;
        }

        /// <summary>
        /// This method creates the narrative for the Pharmaceutical Benefit Items section
        /// </summary>
        /// <param name="pharmaceuticalBenefitItems">PharmaceuticalBenefitItems</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(PharmaceuticalBenefitItems pharmaceuticalBenefitItems)
        {
          var strucDocText = new StrucDocText();
          strucDocText.Text = new[] { "Waiting for 'Medicare Information View CDA Rendering Specification', Version 1.0" };
          return strucDocText;
        }

        #endregion
    }
        #endregion






}
    
