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

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using CDA.Generator.Common.SCSModel.ATS.ETP.Entities;
using CDA.Generator.Common.SCSModel.CeHR.Entities;
using CDA.Generator.Common.SCSModel.ConsumerAchievements.Entities;
using CDA.Generator.Common.SCSModel.MedicareOverview.Entities;
using CDA.Generator.Common.SCSModel.PhysicalMeasurements.Interfaces;
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;
using CDA.Generator.Common.Common.Time;
using System.Collections;
using CDA.Generator.Common.SCSModel.ATS.ETP.Interfaces;

namespace Nehta.VendorLibrary.CDA.Generator
{
    /// <summary>
    /// This is the first version of the NEHTA narrative generator. 
    /// Exclus
    /// 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 SECTIONEMPTYTEXT = "This section contains no entries.";
        private const String DELIMITER = "<CR>";
        private const String DELIMITERBREAK = "<BR>";
        private const String DELIMITEREMAILSTART = "<MAIL>";
        private const String DELIMITEREMAILEND = "</MAIL>";
        #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>
      /// <param name="earliestDateForFiltering">Earliest Date For Filtering</param>
      /// <param name="latestDateForFiltering">Latest Date For Filtering</param>
      /// <returns>StrucDocText</returns>
      public StrucDocText CreateNarrative(IParticipationSubjectOfCare subjectOfCareParticipation, String patientId, Boolean showEntitlements, ISO8601DateTime earliestDateForFiltering, ISO8601DateTime latestDateForFiltering)
        {
            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 
                    )
                    {
                    var columnHeaders = new List<string> { "Field", "Value" };

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

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

                    // Latest Date For Filtering
                    if (latestDateForFiltering != null)
                      narrative.Add
                          (
                              CreateNarrativeEntry("DateTime Health Event Started", latestDateForFiltering)
                          );

                    // Earliest Date For Filtering
                    if (earliestDateForFiltering != null)
                      narrative.Add
                          (
                              CreateNarrativeEntry("DateTime Health Event Ended", earliestDateForFiltering)
                          );

  
                    strucDocTableList.Add
                        (
                            PopulateTable
                                (
                                    "Demographic Data",
                                    null,
                                    columnHeaders.ToArray(),
                                    null,
                                    narrative
                                )
                        );
                }
            }

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
               strucDocText.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
            }

            return strucDocText;
        }

        /// <summary>
        /// This method inserts text into a StrucDocParagraph
        /// </summary>
        /// <param name="text">The Text To be inserted into the Paragraph </param>
        /// <returns>StrucDocParagraph</returns>
        [NotNull]
        public StrucDocParagraph[] CreateParagraph(string text)
        {
          return new []
                {
                  new StrucDocParagraph
                    {
                      Text = new [] { text}
                    }   
                };
        }

        /// <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",
                                    "Manifestations"
                                },
                            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
                            (
                            "Adverse Reactions",
                            null,
                            new[]
                                {
                                    "Substance/Agent",
                                    "Manifestations"
                                },
                            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
                        (
                            "Medications",
                            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 Status",
                                                 "Change Description",
                                                 "Change Reason",
                                                 "Comment"
                                             };

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

                    foreach (var medication in medications.MedicationsList)
                    {
                      string changeStatus;
                      if (medication.ChangeTypeNullFlavour.HasValue) // because if there is no change status, the fact of whether this is a recommendation or change is irrelevant
                        changeStatus = "No change information";
                      else
                      {
                        changeStatus = medication.ChangeType != null ? medication.ChangeType.Value.GetAttributeValue<NameAttribute, String>(x => x.Name) : string.Empty;
                        // if there's no change, or recommendation or change value, we don't say anything about it
                        if (medication.ChangeType != null && (medication.ChangeType.Value != ChangeType.Unchanged && !medication.RecommendationOrChangeNullFlavour.HasValue))
                        {
                          if (medication.RecommendationOrChange.HasValue && medication.RecommendationOrChange.Value == RecomendationOrChange.TheChangeHasBeenMade)
                            changeStatus = changeStatus + " (done)";
                          else
                            changeStatus = "Recommendation: " + changeStatus + " (not done)";
                        }
                      }

                      var medicationList = new List<String>
                                              {
                                                  medication.Medicine != null ? medication.Medicine.NarrativeText : null,
                                                  !medication.Directions.IsNullOrEmptyWhitespace() ? medication.Directions : medication.DirectionsNullFlavour.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                                  medication.ClinicalIndication,
                                                  changeStatus,
                                                  !medication.ChangeDescription.IsNullOrEmptyWhitespace() ? medication.ChangeDescription : null,
                                                  !medication.ChangeReason.IsNullOrEmptyWhitespace() ? medication.ChangeReason : null,
                                                  !medication.Comment.IsNullOrEmptyWhitespace() ? medication.Comment : null
                                              };

                      narrative.Add(medicationList);
                    }

                    StripEmptyColoums(ref narativeHeader, ref narrative, new List<int> {3,4,5,6});

                    strucDocTableList.Add
                    (
                        PopulateTable
                        (
                            "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 strucDocItemList = new List<StrucDocItem>();
            StrucDocTable table = null;

            if (medicalHistory != null)
            {
                List<ProblemDiagnosis> problemDiagnosisList = null;
                if (medicalHistory.ProblemDiagnosis != null)
                {
                  problemDiagnosisList = medicalHistory.ProblemDiagnosis.ConvertAll(x => x as ProblemDiagnosis);
                }

                List<Procedure> proceduresList = null;
                if (medicalHistory.Procedures != null)
                {
                  proceduresList = medicalHistory.Procedures.ConvertAll(x => x as Procedure);
                }

                List<MedicalHistoryItem> medicalHistoryItemList = null;
                if (medicalHistory.MedicalHistoryItems != null)
                {
                  medicalHistoryItemList = medicalHistory.MedicalHistoryItems.ConvertAll(x => x as MedicalHistoryItem);
                }

                table = CreateNarrative(problemDiagnosisList, proceduresList, medicalHistoryItemList);

                // PROCEDURE EXCLUSIONS
                if (medicalHistory.ProceduresExclusionStatement != null)
                {
                  strucDocItemList.Add(CreateExclusionStrucDocItem("Procedures:", medicalHistory.ProceduresExclusionStatement));
                }

                // PROBLEM DIAGNOSIS EXCLUSIONS
                if (medicalHistory.ProblemDiagnosisExclusionStatement != null)
                {
                  strucDocItemList.Add(CreateExclusionStrucDocItem("Problem Diagnosis:", medicalHistory.ProblemDiagnosisExclusionStatement));
                }
            }

            var strucDocText = new StrucDocText();

            // Structured Tables
            if (table != null)
            {
              strucDocText.table = new [] {  table };
            }

            // Narrative Paragraph
            if (strucDocItemList.Any())
            {
              strucDocText.list = new [] { new StrucDocList { item = strucDocItemList.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>();

              StrucDocTable table = null;

              if (medicalHistory != null)
              {
                List<ProblemDiagnosis> problemDiagnosisList = null;
                if (medicalHistory.ProblemDiagnosis != null)
                {
                  problemDiagnosisList = medicalHistory.ProblemDiagnosis.ConvertAll(x => x as ProblemDiagnosis);
                }

                List<Procedure> proceduresList = null;
                if (medicalHistory.Procedures != null)
                {
                  proceduresList = medicalHistory.Procedures.ConvertAll(x => x as Procedure);
                }

                List<MedicalHistoryItem> medicalHistoryItemList = null;
                if (medicalHistory.MedicalHistoryItems != null)
                {
                  medicalHistoryItemList = medicalHistory.MedicalHistoryItems.ConvertAll(x => x as MedicalHistoryItem);
                }

                table = CreateNarrative(problemDiagnosisList, proceduresList, medicalHistoryItemList);

              }

            var strucDocText = new StrucDocText();

            if (table != null)
            {
              strucDocText.table = new [] { table };
            }
            else
            {
              strucDocText.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
            }

            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 strucDocItemList = new List<StrucDocItem>();

          if (responseDetails != null)
          {
            // ResponseDetails
            if (responseDetails.Procedures != null && responseDetails.Procedures.Any())
            {
               foreach(var procedure in responseDetails.Procedures)
               {
                 if (procedure.ProcedureName != null)
                   strucDocItemList.Add(new StrucDocItem { Text = new[] { string.Format("{0} {1}", procedure.ProcedureName.NarrativeText, "(procedure)") } });
               }
            }

            //Diagnoses 
            if (responseDetails.Diagnoses != null)
            {
              foreach (var diagnoses in responseDetails.Diagnoses)
              {
                if (diagnoses != null)
                  strucDocItemList.Add(new StrucDocItem { Text = new[] { string.Format("{0} {1}", diagnoses.NarrativeText, "(diagnoses)") } });
              }
            }

            //Other Diagnoses 
            if (responseDetails.OtherDiagnosisEntries != null && responseDetails.OtherDiagnosisEntries.Any())
            {
              foreach (var otherDiagnosisEntries in responseDetails.OtherDiagnosisEntries)
              {
                if (otherDiagnosisEntries != null)
                  strucDocItemList.Add(new StrucDocItem { Text = new[] { string.Format("{0} {1}", otherDiagnosisEntries, "(other entry)") } });
              }
            }
          }

          var responseNarrative = new List<String>();
          var strucDocTableList = new List<StrucDocTable>();
          responseNarrative.Add
                     (
                     !responseDetails.ResponseNarrative.IsNullOrEmptyWhitespace() ? responseDetails.ResponseNarrative : String.Empty
                     );

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


          var strucDocText = new StrucDocText();

          //if (responseDetails != null && responseDetails.ResponseNarrative != null)
          //{
          //  strucDocText.content = new []
          //                           {
          //                             new StrucDocContent
          //                               {
          //                                 Text  = new [] { responseDetails.ResponseNarrative  }
          //                               },
          //                             new StrucDocContent
          //                               {
          //                                 br = new [] { string.Empty }
          //                               },
          //                             new StrucDocContent
          //                               {
          //                                 br = new [] { string.Empty }
          //                               }
          //                           };
          //}

          if (strucDocItemList.Any())
          {
            strucDocText.list = new[] { new StrucDocList
                                          {
                                            caption = new StrucDocCaption {  Text = new [] { "Diagnoses" }},
                                            item =  strucDocItemList.ToArray()
                                          } 
                                      };
          }

          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(recommendation.Narrative);
                                narrativeEntry.Add(CreateDuration(recommendation.TimeFrame));

                               var addressee = string.Empty;

                                if (recommendation.Addressee != null
                                    && recommendation.Addressee.Participant != null)
                                {
                                  if (recommendation.Addressee.Participant.Person != null)
                                    addressee += BuildPersonNames(recommendation.Addressee.Participant.Person.PersonNames);
                                  else
                                  {
                                    if (recommendation.Addressee.Participant.Organisation != null)
                                      addressee += recommendation.Addressee.Participant.Organisation.Name;
                                  }

                                  if (recommendation.Addressee.Role != null)
                                  {
                                    addressee +=  string.Format(" ({0}) ", recommendation.Addressee.Role.NarrativeText);
                                  }

                                  addressee += CreateAddress(null, recommendation.Addressee.Participant.ElectronicCommunicationDetails);
                                }

                                narrativeEntry.Add(addressee);
                                narrative.Add(narrativeEntry);
                            }
                        );

                    
                    
                    strucDocTableList.Add
                        (
                            PopulateTable
                                (
                                    "Recommendations",
                                    null,
                                    new[] {  "Recommendation", "Time frame", "Addressee"},
                                    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>();
            var header = new[] { "Field", "Value" };

            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
                    (
                      "Other Test Result",
                      null,
                      header,
                      null,
                      narrative
                    )
                );

              strucDocText.table = strucDocTableList.ToArray();

              if (renderMultiMediaList.Any())
              {
                strucDocText.renderMultiMedia = renderMultiMediaList.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>();
            var header = new[] { "Field", "Value" };

            // 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
                            (
                               "Pathology Test Result",
                               null,
                               header,
                               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 
                                        }
                                    );
                            }
                        }

                        var headerListPathologyTestResultsList = new List<string>
                        {
                          "Group Name", "Result Name", "Result Value", "Status", " Reference Range Details",
                          "Result Comment", "Reference Range Guidance", "Result Status"
                        };

                        StripEmptyColoums(ref headerListPathologyTestResultsList, ref pathologyTestResultsList, null);

                        strucDocTableList.Add
                           (
                                PopulateTable
                                    (
                                       "Test Result Group",
                                       null,
                                       headerListPathologyTestResultsList.ToArray(),
                                       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
                           }
                        );
                    }

                    var headerListTestRequestDetails = new List<string>
                                 {
                                   "Laboratory Test Result Identifier", "Test Requested Name(s)"
                                 };

                    StripEmptyColoums(ref headerListTestRequestDetails, ref testRequestDetailsList, null);

                    strucDocTableList.Insert
                        (
                            0,
                            (
                                PopulateTable
                                    (
                                        "Test Request Details",
                                        null,
                                        headerListTestRequestDetails.ToArray(),
                                        null,
                                        testRequestDetailsList
                                    )
                            )
                        );
                }


                var headerListAnatomicalSite = new List<string>
                                 {
                                   "Identifier", "Description", "Location", "Side", "Image / File"
                                 };

                StripEmptyColoums(ref headerListAnatomicalSite, ref narrative, null);

                if (narrative.Any())
                {
                    strucDocTableList.Add
                    (
                        PopulateTable
                            (
                                "Anatomical Site(s)", 
                                null,
                                headerListAnatomicalSite.ToArray(),
                                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,
                                                CreateEncapsulatedData(pathologyTestResult.TestResultRepresentation, ref renderMultiMediaList)
                                            }
                                        };

              var headerList = new List<string>
                                 {
                                   "Result DateTime",
                                   "Result Name",
                                   "Diagnostic Service",
                                   "Overall Result Status",
                                   "Clinical Information",
                                   "Diagnosis",
                                   "Conclusion",
                                   "Comment",
                                   "Result Representation"
                                 };

                StripEmptyColoums(ref headerList, ref narrative, null);

                strucDocTableList.Insert
                    (
                        0,
                        (
                            PopulateTable
                                (
                                    "Pathology Test Result(s)",
                                    null,
                                    headerList.ToArray(),
                                    null,
                                    narrative
                                )
                        )
                    );
            }

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

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

            return strucDocText;
        }

        /// <summary>
        /// Creates EncapsulatedData for the narrative
        /// </summary>
        /// <param name="encapsulatedData">An EncapsulatedData</param>
        /// <param name="renderMultiMediaList">A list of StrucDocRenderMultiMedia</param>
        /// <returns></returns>
        public object CreateEncapsulatedData(EncapsulatedData encapsulatedData, ref List<StrucDocRenderMultiMedia> renderMultiMediaList)
        {
          object result = null;
          if (encapsulatedData != null && !encapsulatedData.Text.IsNullOrEmptyWhitespace())
          {
            result = encapsulatedData.Text;
          }
          else if (encapsulatedData != null && encapsulatedData.ExternalData != null)
          {
            result = CreateEncapsulatedData(encapsulatedData.ExternalData, ref renderMultiMediaList);
          }
          return result;
        }

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

            var headerList = new List<string>
                                 {
                                   "Description", "Location", "Side", "Image / File" 
                                 };

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

                    StripEmptyColoums(ref headerList, ref narrative, null);

                    if (narrative.Any())
                    {
                        strucDocTableList.Add
                        (
                            PopulateTable
                                (
                                    "Anatomical Site(s)",
                                    null,
                                    headerList.ToArray(),
                                    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", "Value" }, 
                                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
                        (
                            "Reason for Referral",
                            null,
                            null,
                            null,
                            new List<List<String>> { new List<string> { narrative } }
                          )
                        );

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

            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<Object>>();
            var strucDocTableList = new List<StrucDocTable>();

            var headerList = new List<string>
                               {
                                 "Requested Examination Name",
                                 "Image Date",
                                 "Identifiers",
                                 "Subject Position",
                                 "Image / File"
                               };

            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.
                  List<StrucDocRenderMultiMedia> narrativeDisplayList = null;
                    if (imageExaminationRequest.ImageDetails != null)
                    {
                        foreach (var imageDetails in imageExaminationRequest.ImageDetails)
                        {
                          if (imageDetails.Image != null)
                          {
                            if (narrativeDisplayList == null)
                                narrativeDisplayList = new List<StrucDocRenderMultiMedia>();

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

                  narrative.Add(new List<Object>
                                   {
                                     examinationRequestedName,
                                     imageDateTime,
                                     studyIdentifier + DELIMITER + reportIdentifier +
                                     DELIMITER + imageDetailSeriesIdentifier,
                                     imageDetailSubjectPosition,
                                     narrativeDisplayList
                                   });
                }

                StripEmptyColoums(ref headerList, ref narrative, null);

                //DICOM Study ID", "Report ID", "DICOM Series ID
                strucDocTableList.Add
                    (
                        PopulateTable
                            (
                                "Examination Request(s) - Image Details",
                                null,
                                headerList.ToArray(),
                                null,
                                narrative
                            )
                    );
            }

            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>();
            var headerList = new List<string> { "Result Group", "Name", "Value", "Status", "Range", "Comment" };

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

                    StripEmptyColoums(ref headerList, ref narrative, null);

                    //Build the table for this result group
                    strucDocTableList.Add
                    (
                         PopulateTable
                             (
                                "Result Group(s)",
                                null,
                                headerList.ToArray(),
                                null,
                                narrative
                             )
                    );


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

                }
            }

            return strucDocTableList;
        }

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

          var list = new List<KeyValuePair<DateTime, List<string>>>();

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

          list.Sort(Compare);
          narrative = list.Select(item => item.Value).ToList();

          var headerListImmunisations = new List<string>
                           {
                             "Vaccine", "Sequence Number", "Date" 
                           };

          StripEmptyColoums(ref headerListImmunisations, ref narrative, null);

          if (narrative.Any())
          {
            strucDocTableList.Add
                (
                    PopulateTable
                    (
                        "Immunisations - Administered Immunisations",
                        null,
                        headerListImmunisations.ToArray(),
                        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;

              List<StrucDocRenderMultiMedia> narrativeDisplayList = null;
              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;
                    }

                    if (physicalDetails.Image != null)
                    {
                      narrativeDisplayList = new List<StrucDocRenderMultiMedia>();
                      var encapsulatedData = CreateEncapsulatedData(physicalDetails.Image, ref renderMultiMediaList);
                      narrativeDisplayList.AddRange(encapsulatedData);
                    }

                  }
                }
              }

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

            var headerList = new List<string>
                               {
                                 "Received DateTime",
                                 "Identifier",
                                 "Parent Identifier",
                                 "Container",
                                 "Tissue Type",
                                 "Physical Description",
                                 "Physical Details",
                                 "Sampling Preconditions",
                                 "Collection Date",
                                 "Collection Procedure",
                                 "Collection Setting",
                                 "Image / File"
                               };

            StripEmptyColoums(ref headerList, ref narrative, null);

            strucDocTableList.Add(
                PopulateTable
                    (
                        narrativeTitle,
                        null,
                        headerList.ToArray(),
                        new[] { String.Empty },
                        narrative
                    )
                );
          }
          return strucDocTableList;
        }

        [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<String> CreateNarrativeEntry(String heading, int? value)
        {
          return new List<string>
                       {
                           heading,
                           value.HasValue ? value.Value.ToString(CultureInfo.InvariantCulture) : 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 strucDocList = new List<StrucDocList>();
            var narrativeParagraph = new List<StrucDocParagraph>();

            // Add any problem diagnosis entries
            if (problemDiagnosesThisVisit.ProblemDiagnosis != null && problemDiagnosesThisVisit.ProblemDiagnosis.Any()) 
            {
              strucDocList.Add(new StrucDocList { item = CreateProblemDiagnosisNarrative(problemDiagnosesThisVisit.ProblemDiagnosis).ToArray() });
            }

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

            var strucDocText = new StrucDocText();

            // Structured Tables
            if (strucDocList.Any())
            {
              strucDocText.list = strucDocList.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.Any())
          {
            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>{
                                    CreateLink(document.Link)
                               });

                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
                  (
                    "Documents",
                    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 List<StrucDocItem> CreateProblemDiagnosisNarrative(IList<IDischargeSummaryProblemDiagnosis> problemDiagnosis)
        {
          List<List<String>> narrative;
          var strucItemList = new List<StrucDocItem>();

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

                foreach (var problemDiagnoses in problemDiagnosis)
                {

                  strucItemList.Add(
                                    new StrucDocItem
                                    {
                                      Text = new[] 
                                                 {                                          
                                                   string.Format("{0} ({1})",problemDiagnoses.ProblemDiagnosisDescription == null ? String.Empty : problemDiagnoses.ProblemDiagnosisDescription.NarrativeText, problemDiagnoses.ProblemDiagnosisType == null ? String.Empty : problemDiagnoses.ProblemDiagnosisType.NarrativeText)
                                                 }
                                    }
                               );

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

          return strucItemList;
        }

        /// <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
                    (
                        "Clinical Intervention Description",
                        null,
                        new[] { "Value(s)" },
                        new string[0],
                        narrative
                    )
                );
            }
            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
              strucDocText.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
            }

            return strucDocText;
        }

        /// <summary>
        /// CLINICAL SYNOPSIS
        /// </summary>
        /// <param name="clinicalSynopsis"></param>
        /// <returns></returns>
        public StrucDocText CreateNarrative(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[] { "Clinical Synopsis" },
                        new string[0],
                        narrative
                    )
                );
            }
            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
            }

            return strucDocText;
        }

        /// <summary>
        /// Current Medications On Discharge
        /// </summary>
        /// <param name="currentMedication">CurrentMedications</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(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.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
            }

            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>
                        { 
                            "Medication",
                            "Directions",
                            "Dispensed",
                            "Clinical Indication",
                            "Duration",
                            "Change Status",
                            "Change Description",
                            "Change Reason",
                            "Comments"
                        };


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

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

                StripEmptyColoums(ref narativeHeader, ref narrative, new List<int> {5,6,7,8});

                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.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
            }

            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>() 
            { 
                "Medication", 
                "Change Made", 
                "Change Status", 
                "Change Reason" 
            };

            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.TherapeuticGoodIdentification  == null ? String.Empty : therapeuticGood.TherapeuticGoodIdentification.NarrativeText,
                                          therapeuticGood.MedicationHistory.ChangesMade == null ? String.Empty :therapeuticGood.MedicationHistory.ChangesMade.NarrativeText,
                                          therapeuticGood.MedicationHistory.ItemStatus == null ? String.Empty : therapeuticGood.MedicationHistory.ItemStatus.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)
        {
            var 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>>();

                var narativeHeader = new List<string>
                                             {
                                                 "Agent Description", 
                                                 "Reaction Description(s)",
                                                 "Reaction Type"
                                             };

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


                    var adverseReactionEntry = new List<string>
                                               {
                                                 adverseReaction.AgentDescription == null ? String.Empty : adverseReaction.AgentDescription.NarrativeText,
                                                 reactionDescriptions,
                                                 adverseReaction.AdverseReactionType != null ? adverseReaction.AdverseReactionType.NarrativeText : null
                                               };
     

                    narrative.Add(adverseReactionEntry);
                }

                StripEmptyColoums(ref narativeHeader, ref narrative, null);

                strucDocTableList.Add
                (
                    PopulateTable
                    (
                        "Allergies/Adverse Reactions",
                        null,
                        narativeHeader.ToArray(),
                        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<SCSModel.DischargeSummary.Alert> alerts)
        {
            List<List<String>> narrative;
            var strucItemList = new List<StrucDocItem>();

            if (alerts != null && alerts.Any())
            {
                foreach (var alert in alerts)
                {
                    strucItemList.Add(
                                      new StrucDocItem
                                        {
                                          Text = new [] 
                                                 {                                          
                                                   string.Format("{0} ({1})",alert.AlertDescription == null ? String.Empty : alert.AlertDescription.NarrativeText, alert.AlertType == null ? String.Empty : alert.AlertType.NarrativeText)
                                                 }
                                        }
                                 );
               }

            }
            var strucDocText = new StrucDocText();

            if (strucItemList.Any())
            {
              strucDocText.list = new[] {new StrucDocList {item = strucItemList.ToArray()}};
            }
            else
            {
               strucDocText.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
            }

            return strucDocText;
        }

      public StrucDocText CreateNarrative(AustralianChildhoodImmunisationRegisterEntry australianChildhoodImmunisationRegisterEntry)
      {
        throw new NotImplementedException();
      }

      /// <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.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
            }

            return strucDocText;
        }

        /// <summary>
        /// ArrangedServices
        /// </summary>
        /// <param name="arrangedServices">ArrangedServices</param>
        /// <returns></returns>
        public StrucDocText CreateNarrative(ICollection<SCSModel.DischargeSummary.ArrangedServices> arrangedServices)
        {
            var narrative = new List<List<String>>();

            var strucDocTableList = new List<StrucDocTable>();

            var headerList = new List<String>()
            { 
                "Description", 
                "Commencement", 
                "Status",
                "Name",
                "Details",
                "Phone",
                "Email"
            };

            if (arrangedServices != null && arrangedServices.Any())
            {
                foreach (var arrangedService in arrangedServices)
                {
                    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;
                        }
                    }

                    var arrangedServiceEntry = 
                            new List<string>
                                {
                                    arrangedService.ArrangedServiceDescription != null ? arrangedService.ArrangedServiceDescription.NarrativeText : null,
                                    durationAsString,
                                    arrangedService.Status != EventTypes.Undefined ? arrangedService.Status.GetAttributeValue<NameAttribute, String>(x => x.Name): null,
                                    arrangedService.ServiceProvider != null && arrangedService.ServiceProvider.Participant.Person != null && arrangedService.ServiceProvider.Participant.Person.PersonNames.Any() ? BuildPersonNames(arrangedService.ServiceProvider.Participant.Person.PersonNames) : null,
                                    !organisationName.IsNullOrEmptyWhitespace() ? organisationName : null,
                                    arrangedService.ServiceProvider != null && arrangedService.ServiceProvider.Participant != null && arrangedService.ServiceProvider.Participant.ElectronicCommunicationDetails != null ? CreatePhone(arrangedService.ServiceProvider.Participant.ElectronicCommunicationDetails) : null,
                                    arrangedService.ServiceProvider != null && arrangedService.ServiceProvider.Participant != null && arrangedService.ServiceProvider.Participant.ElectronicCommunicationDetails != null ? CreateEmail(arrangedService.ServiceProvider.Participant.ElectronicCommunicationDetails) : null
                             };


                     narrative.Add(arrangedServiceEntry);

                      }
                   }

                   StripEmptyColoums(ref headerList, ref narrative, null);

                    if (arrangedServices.Any())
                    strucDocTableList.Add
                        (
                          PopulateTable
                          (
                              "Arranged Service",
                              null,
                              headerList.ToArray(), 
                              null,
                              narrative
                          )
                        );

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
            }

            return strucDocText;
        }

        /// <summary>
        /// Strip Empty Coloums Remove empty coloum from a narrative List and the headerList
        /// </summary>
        /// <param name="headerList">A string List of headers</param>
        /// <param name="narrative">The narrative</param>
        /// <param name="optionalItems">A list of int's if these are included then only these positional can be removed</param>
        public static void StripEmptyColoums(ref List<String> headerList, ref List<List<Object>> narrative, List<int> optionalItems)
        {
          var tableCellRegister = new BitArray(headerList.Count, false);
          // Detect Empty Cells 
          // Remove Item from Header and remove cells from the table
          foreach (var narrativeEntry in narrative)
          {
            for (int i = 0; i < narrativeEntry.Count; i++)
            {
              if (TryConvertTo<string>(narrativeEntry[i]))
              {
                if (!((string) narrativeEntry[i]).IsNullOrEmptyWhitespace() && !tableCellRegister[i])
                {
                  tableCellRegister[i] = true;
                }
              } else
              {
                tableCellRegister[i] = true;
              }
            }
          }

          var found = false;
          for (int i = 0; i < tableCellRegister.Count; i++)
          {
            if (!tableCellRegister[i])
            {
              if (optionalItems == null || (optionalItems.Contains(i)))
              {

                foreach (var narrativeEntry in narrative)
                {
                  narrativeEntry.RemoveAt(i);
                }

                // Perform a Recursive call to ensure that the items in the list that are removed correspond to the correct Position Location
                headerList.RemoveAt(i);
                found = true;
                break;
              }
            }
          }

          // Perform a Recursive call to ensure that the items in the list that are 
          // removed correspond to the correct Position Location
          if (found)
            StripEmptyColoums(ref headerList, ref narrative, optionalItems);
        }

        public static Boolean TryConvertTo<T>(object input)
        {
          try
          {
            Convert.ChangeType(input, typeof(T));
            return true;
          }
          catch
          {
          }

          return false;
        }

        /// <summary>
        /// Strip Empty Coloums Remove empty coloum from a narrative List and the headerList
        /// </summary>
        /// <param name="headerList">A string List of headers</param>
        /// <param name="narrative">The narrative</param>
        /// <param name="optionalItems">A list of int's if these are included then only these positional can be removed</param>
        public static void StripEmptyColoums(ref List<String> headerList, ref List<List<String>> narrative, List<int> optionalItems)
        {
            var tableCellRegister = new BitArray(headerList.Count, false);
            // Detect Empty Cells 
            // Remove Item from Header and remove cells from the table
            foreach (var narrativeEntry in narrative)
            {
              for (int i = 0; i < narrativeEntry.Count; i++)
              {
                if (!narrativeEntry[i].IsNullOrEmptyWhitespace() && !tableCellRegister[i])
                {
                  tableCellRegister[i] = true;
                }
              }
            }

            var found = false;
            for (int i = 0; i < tableCellRegister.Count; i++)
            {
              if (!tableCellRegister[i])
              {
                  if (optionalItems == null || (optionalItems.Contains(i)))
                  {

                  foreach (var narrativeEntry in narrative)
                  {
                    narrativeEntry.RemoveAt(i);
                  }

                  // Perform a Recursive call to ensure that the items in the list that are removed correspond to the correct Position Location
                  headerList.RemoveAt(i);
                  found = true;  
                  break;
                }
              }
            }
      
            // Perform a Recursive call to ensure that the items in the list that are 
            // removed correspond to the correct Position Location
            if (found)
              StripEmptyColoums(ref headerList, ref narrative, optionalItems);
        }

        /// <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 = narrative = new List<List<String>>(); ;

            var headerList = new List<String>()
            { 
                "Description", 
                "Name",
                "Details",
                "Phone",
                "Email"
            };

            var strucDocTableList = new List<StrucDocTable>();

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

              foreach (var recommendationsProvided in recommendationsInformationProvided.RecommendationsProvided)
                {


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

                        narrative.Add(
                                new List<string>
                                {
                                    recommendationsProvided.RecommendationNote ?? null,
                                    recommendationsProvided.RecommendationRecipient.Participant.Person != null && recommendationsProvided.RecommendationRecipient.Participant.Person.PersonNames.Any() ? BuildPersonNames(recommendationsProvided.RecommendationRecipient.Participant.Person.PersonNames) : null,
                                    !organisationName.IsNullOrEmptyWhitespace() ? organisationName : null,
                                    recommendationsProvided.RecommendationRecipient != null && recommendationsProvided.RecommendationRecipient.Participant != null && recommendationsProvided.RecommendationRecipient.Participant.ElectronicCommunicationDetails != null ? CreatePhone(recommendationsProvided.RecommendationRecipient.Participant.ElectronicCommunicationDetails) : null,
                                    recommendationsProvided.RecommendationRecipient != null && recommendationsProvided.RecommendationRecipient.Participant != null && recommendationsProvided.RecommendationRecipient.Participant.ElectronicCommunicationDetails != null ? CreateEmail(recommendationsProvided.RecommendationRecipient.Participant.ElectronicCommunicationDetails) : null
                             }
                        );
                    }
                }

              StripEmptyColoums(ref headerList, ref narrative, null);

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

            // 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,
                                    new [] { "Value" }, 
                                    new string[0],
                                    narrative
                                )
                        );
                }


            var strucDocText = new StrucDocText();
            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
              strucDocText.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
            }

            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.ToUpper() : " " + pn.FamilyName.ToUpper();
                }

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

            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", "Value" },
                                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.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
            }

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

                var headerListAnatomicalSite = new List<string>
                                 {
                                   "Description", "Location", "Side", "Image / File"
                                 };

                StripEmptyColoums(ref headerListAnatomicalSite, ref narrative, null);

                if (narrative.Any())
                {
                    structDocTable =  PopulateTable
                        (
                            "Anatomical Site(s)",
                            null,
                            headerListAnatomicalSite.ToArray(),
                            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, IList<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.Any())
            {
                stringReturn += CreateElectronicCommunicationDetails(electronicCommunicationDetails);
            }

            return stringReturn;
        }

        /// <summary>
        /// Create Email for Narative
        /// </summary>
        /// <returns>A formated Address</returns>
        private static String CreateEmail(IList<ElectronicCommunicationDetail> electronicCommunicationDetails)
        {
            var emailList = new List<ElectronicCommunicationDetail>();
            foreach(var electronicCommunicationDetail in  electronicCommunicationDetails)
            {
              if (electronicCommunicationDetail != null && electronicCommunicationDetail.Medium == ElectronicCommunicationMedium.Email)
                {
                  emailList.Add(electronicCommunicationDetail);
                }
            }
            return CreateElectronicCommunicationDetails(emailList);
        }

        /// <summary>
        /// Create Phone for Narative
        /// </summary>
        /// <returns>A formated Address</returns>
        private static String CreatePhone(IList<ElectronicCommunicationDetail> electronicCommunicationDetails)
        {
          var emailList = new List<ElectronicCommunicationDetail>();
          foreach (var electronicCommunicationDetail in electronicCommunicationDetails)
          {
            if (electronicCommunicationDetail != null && (electronicCommunicationDetail.Medium == ElectronicCommunicationMedium.Mobile || electronicCommunicationDetail.Medium == ElectronicCommunicationMedium.Telephone))
            {
              emailList.Add(electronicCommunicationDetail);
            }
          }
          return CreateElectronicCommunicationDetails(emailList);
        }

      /// <summary>
        /// Create Address for Narative
        /// </summary>
        /// <returns>A formated Address</returns>
        private static String CreateElectronicCommunicationDetails(IList<ElectronicCommunicationDetail> electronicCommunicationDetails)
        {
          var stringReturn = String.Empty;

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

            for (int i = 0; i < electronicCommunicationDetails.Count(); i++)
            {
              if (electronicCommunicationDetails[i] != null)
              {
                string usages = string.Empty;
                for (int index = 0; index < electronicCommunicationDetails[i].Usage.Count; index++)
                {
                  usages += electronicCommunicationDetails[i].Usage[index];

                  if (index + 1 < electronicCommunicationDetails[i].Usage.Count)
                  {
                    usages += ", ";
                  }
                }

                if (electronicCommunicationDetails[i].Medium == ElectronicCommunicationMedium.Email)
                {
                  stringReturn += string.Format("{0}{1}{2}", DELIMITEREMAILSTART, electronicCommunicationDetails[i].Narrative, DELIMITEREMAILEND);
                }
                else
                {
                  stringReturn += string.Format("{0} ({2})", electronicCommunicationDetails[i].Narrative, electronicCommunicationDetails[i].Medium.GetAttributeValue<NameAttribute, string>(x => x.Name), !usages.IsNullOrEmptyWhitespace() ? usages : string.Empty);
                  if (i + 1 < electronicCommunicationDetails.Count())
                    stringReturn += ", ";

                }
              }
            }
          }

          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)
            {
                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.StreetType != StreetType.Undefined)
                    {
                      stringReturn += (!stringReturn.IsNullOrEmptyWhitespace() ? " " : String.Empty) +
                                      address.AustralianAddress.StreetType.GetAttributeValue<NameAttribute, String>(x => x.Name);
                    }

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

                    if (address.AustralianAddress.State != AustralianState.Undefined)
                    {
                      stringReturn += (!stringReturn.IsNullOrEmptyWhitespace() ? ", " : String.Empty) +
                                      address.AustralianAddress.State.GetAttributeValue<NameAttribute, String>(x => x.Code);
                    }

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

                stringReturn = address.AddressPurpose.GetAttributeValue<NameAttribute, String>(x => x.Name) + ": " + stringReturn;
            }

            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)
        {
          return duration == null ? string.Empty : 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(PCEHRPrescriptionItem item, IParticipationPrescriber prescriber, IParticipationSubjectOfCare subjectOfCare)
        {
            var strucDocTableList = new List<StrucDocTable>();
            var narrative = new List<List<String>>();
            var narrativeObject = new List<List<Object>>();
            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", "Value" };

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

                    //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 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.DispensingInformation.BrandSubstitutionPermitted.HasValue)
                      narrative.Add
                         (
                             CreateNarrativeEntry("Brand Substitution Permitted", item.DispensingInformation.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) 
                          );

                    // Convert the List<string> to a List<Object>
                    narrativeObject.AddRange(narrative.Select(narrativeItem => narrativeItem.Select(s => (object) s).ToList()));

                    // Prescription Record Link
                    if (item.PrescriptionRecordLink != null)
                      narrativeObject.Add(
                                   new List<object>{
                                   "Prescription Record Link",
                                   CreateLink(item.PrescriptionRecordLink)
                               });


                    //// Entitilements Subject Of Care
                    //if (subjectOfCare != null && 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 (prescriber != null && prescriber.Participant != null && prescriber.Participant.Person != null && 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
                                        (
                                            "Prescription Item",
                                            null,
                                            columnHeaders.ToArray(),
                                            null,
                                            narrativeObject
                                        ),
                                //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(PCEHRDispenseItem item, IParticipationDispenser dispenser, IParticipationDispenserOrganisation dispenserOrganisation, IParticipationSubjectOfCare subjectOfCare)
        {
          var strucDocTableList = new List<StrucDocTable>();
          var narrative = new List<List<String>>();
          var narrativeObject = new List<List<Object>>();
          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", "Value" };

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

            // Convert the List<string> to a List<Object>
            narrativeObject.AddRange(narrative.Select(narrativeItem => narrativeItem.Select(s => (object)s).ToList()));

            // Prescription Record Link
            if (item.DispenseRecordLink != null)
              narrativeObject.Add(
                           new List<object>{
                                   "Dispense Record Link",
                                   CreateLink(item.DispenseRecordLink)
                               });

            //// Entitilements Subject Of Care
            //if (subjectOfCare != null && 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 != null && dispenserOrganisation.Participant != null && 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
                                        (
                                            "Dispense Item",
                                            null,
                                            columnHeaders.ToArray(),
                                            null,
                                            narrativeObject
                                        ),
                                //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>
       /// Create a Narrative for an (PrescribingAndDispensingReports)
       /// </summary>
       /// <param name="prescribingAndDispensingReports">A PrescribingAndDispensingReports</param>
       /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(PrescribingAndDispensingReports prescribingAndDispensingReports)
       {              
          var strucDocTableList = new List<StrucDocTable>();

          if (prescribingAndDispensingReports.MedicationEntriesWithSummary != null)
          {
            foreach (var medicationEntriesWithSummary in prescribingAndDispensingReports.MedicationEntriesWithSummary)
            {

              var narrative = new List<List<String>>();
              if (medicationEntriesWithSummary != null && medicationEntriesWithSummary.SummaryOfMedicationEntries != null)
              {
                var summary = medicationEntriesWithSummary.SummaryOfMedicationEntries;

                var columnHeaders = new List<string> { "Field", "Value" };

                if (summary.DateTimeOfLatestDispenseEvent != null)
                  narrative.Add
                      (
                           CreateNarrativeEntry("Date Time Of Latest Dispense Event", summary.DateTimeOfLatestDispenseEvent)
                      );

                if (summary.DateTimeOfEarliestDispenseEvent != null)
                  narrative.Add
                      (
                           CreateNarrativeEntry("DateTime Of Earliest Dispense Event", summary.DateTimeOfEarliestDispenseEvent)
                      );

                if (summary.DateTimePrescriptionWritten != null)
                  narrative.Add
                      (
                           CreateNarrativeEntry("Date Time Prescription Written", summary.DateTimePrescriptionWritten)
                      );

                if (summary.MaximumNumberOfPermittedSupplies != null)
                  narrative.Add
                      (
                           CreateNarrativeEntry("Maximum Number Of Permitted Supplies", summary.MaximumNumberOfPermittedSupplies)
                      );

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

                if (summary.TotalNumberOfKnownSupplies != null)
                  narrative.Add
                      (
                           CreateNarrativeEntry("Total Number Of Known Supplies", summary.TotalNumberOfKnownSupplies)
                      );

                // Add body Height Narrative
                strucDocTableList.Add
                    (
                        PopulateTable
                            (
                                "Prescribing and Dispensing Reports",
                                null,
                                columnHeaders.ToArray(),
                                null,
                                narrative
                            )
                    );
              }
            }
          }
                
          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", "Quantity"};

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

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

                    // Add body Height Narrative
                    strucDocTableList.Add
                        (
                            PopulateTable
                                (
                                    "Observation Weight Height",
                                    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)
            {
                        narrative.Add
                            (
                                new List<String>
                                    {
                                        CreateNarrativeEntry(eventDetails.ClinicalSynopsisDescription) 
                                    }
                            );


                    // Add body Height Narrative
                    strucDocTableList.Add
                        (
                            PopulateTable
                                (
                                    "Clinical Synopsis Description",
                                    null,
                                    new[] { "Description" }, 
                                    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="medications">A list of medicationItems</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(IEnumerable<IMedicationItem> medications)
        {
          List<List<String>> narrative;
          var strucDocTableList = new List<StrucDocTable>();

          if (medications != null)
            {
              var narativeHeader = new List<string>()
                                             {
                                                 "Medication",
                                                 "Directions",
                                                 "Clinical Indication",
                                                 "Change Status",
                                                 "Change Description",
                                                 "Change Reason",
                                                 "Comment"
                                             };

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

              foreach (var medication in medications)
              {
                string changeStatus;
                if (medication.ChangeTypeNullFlavour.HasValue) // because if there is no change status, the fact of whether this is a recommendation or change is irrelevant
                  changeStatus = "No change information";
                else
                {
                  changeStatus = medication.ChangeType != null ? medication.ChangeType.Value.GetAttributeValue<NameAttribute, String>(x => x.Name) : string.Empty;
                  // if there's no change, or recommendation or change value, we don't say anything about it
                  if (medication.ChangeType != null && (medication.ChangeType.Value != ChangeType.Unchanged && !medication.RecommendationOrChangeNullFlavour.HasValue))
                  {
                    if (medication.RecommendationOrChange.HasValue && medication.RecommendationOrChange.Value == RecomendationOrChange.TheChangeHasBeenMade)
                      changeStatus = changeStatus + " (done)";
                    else
                      changeStatus = "Recommendation: " + changeStatus + " (not done)";
                  }
                }

                var medicationList = new List<String>
                                              {
                                                  medication.Medicine != null ? medication.Medicine.NarrativeText : null,
                                                  !medication.Directions.IsNullOrEmptyWhitespace() ? medication.Directions : medication.DirectionsNullFlavour.GetAttributeValue<NameAttribute, String>(x => x.Name),
                                                  medication.ClinicalIndication,
                                                  changeStatus,
                                                  !medication.ChangeDescription.IsNullOrEmptyWhitespace() ? medication.ChangeDescription : null,
                                                  !medication.ChangeReason.IsNullOrEmptyWhitespace() ? medication.ChangeReason : null,
                                                  !medication.Comment.IsNullOrEmptyWhitespace() ? medication.Comment : null
                                              };

                narrative.Add(medicationList);
              }

              StripEmptyColoums(ref narativeHeader, ref narrative, new List<int> {3, 4, 5, 6});

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

            var strucDocText = new StrucDocText();

            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
            }

            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 strucDocText = new StrucDocText();

         List<ProblemDiagnosis> problemDiagnosisList = null;
         if (diagnosesIntervention.ProblemDiagnosis != null)
         {
            problemDiagnosisList = diagnosesIntervention.ProblemDiagnosis.ConvertAll(x => x as ProblemDiagnosis);
         }

         List<Procedure> proceduresList = null;
         if (diagnosesIntervention.Procedures != null)
         {
            proceduresList = diagnosesIntervention.Procedures.ConvertAll(x => x as Procedure);
         }

         List<MedicalHistoryItem> medicalHistoryItemList = null;
         if (diagnosesIntervention.MedicalHistoryItem != null)
         {
           medicalHistoryItemList = diagnosesIntervention.MedicalHistoryItem.ConvertAll(x => x as MedicalHistoryItem);
         }

         var table = CreateNarrative(problemDiagnosisList, proceduresList, medicalHistoryItemList);

         if (table != null)
         {
            strucDocText.table = new [] {table};
         }
         else
         {
            strucDocText.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
         }

         return strucDocText;
       }

        /// <summary>
        /// This method creates the narrative for Diagnoses Intervention
        /// </summary>
        /// <returns>StrucDocText</returns>
        public StrucDocTable CreateNarrative(List<ProblemDiagnosis> problemDiagnosisList, List<Procedure> proceduresList, List<MedicalHistoryItem> medicalHistoryItemList)
        {
          var headerList = new List<string>
                                 {
                                    "Item", 
                                    "Date",
                                    "Comment"
                                 };

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

            var list = new List<KeyValuePair<DateTime, List<string>>>();

                // Add Problem Diagnosis for Diagnoses Intervention
              if (problemDiagnosisList != null && problemDiagnosisList.Any())
              {
                foreach (var problemDiagnosis in problemDiagnosisList)
                {
                       var intervalText = string.Empty;
                       if (problemDiagnosis.DateOfOnset != null && problemDiagnosis.DateOfResolutionRemission != null)
                           intervalText = CdaInterval.CreateLowHigh(problemDiagnosis.DateOfOnset, problemDiagnosis.DateOfResolutionRemission).NarrativeText();

                       if (problemDiagnosis.DateOfOnset != null && problemDiagnosis.DateOfResolutionRemission == null)
                           intervalText = string.Format("{0} ->", problemDiagnosis.DateOfOnset.NarrativeText());

                        list.Add(new KeyValuePair<DateTime, List<string>>
                                   (
                                      problemDiagnosis.DateOfOnset != null ? problemDiagnosis.DateOfOnset.DateTime : DateTime.MinValue,
                                      new List<string>
                                        {
                                          problemDiagnosis.ProblemDiagnosisIdentification != null
                                            ? problemDiagnosis.ProblemDiagnosisIdentification.NarrativeText
                                            : null,
                                          intervalText,
                                          problemDiagnosis.Comment.IsNullOrEmptyWhitespace() ? null : problemDiagnosis.Comment

                                        }
                                   )
                                 );
                    }                
              }

              // Add procedure for Diagnoses Intervention
              if (proceduresList != null && proceduresList.Any())
                foreach (var procedure in proceduresList)
                  {

                    list.Add(new KeyValuePair<DateTime, List<string>>
                               (
                                  procedure.Start != null ? procedure.Start.DateTime : DateTime.MinValue,
                                  new List<String>
                                          {
                                              procedure.ProcedureName != null ? procedure.ProcedureName.NarrativeText : null,
                                              procedure.Start != null ? procedure.Start.NarrativeText() : null,
                                              procedure.Comment.IsNullOrEmptyWhitespace() ? null : procedure.Comment
                                          }
                               )
                             );
                  }

                // Add MedicalHistoryItem
              if (medicalHistoryItemList != null && medicalHistoryItemList.Any())
                foreach (var medicalHistoryItem in medicalHistoryItemList)
                  {
                    list.Add(new KeyValuePair<DateTime, List<string>>
                                   (
                                    medicalHistoryItem.DateTimeInterval != null 
                                    ? CdaIntervalFormatter.GetFirstDateTimeOfDurrationForNarrativeSorting(medicalHistoryItem.DateTimeInterval) 
                                    : DateTime.MinValue,
                                    new List<String>
                                            {
                                              medicalHistoryItem.ItemDescription,
                                              CreateDuration(medicalHistoryItem.DateTimeInterval),
                                              medicalHistoryItem.ItemComment,
                                            }
                                   )
                                 );
                  }

              // Sort List
              list.Sort(Compare);

              // Copy Sorted list into the narrative
              narrative = list.Select(item => item.Value).ToList();

              StripEmptyColoums(ref headerList, ref narrative, new List<int> {2});

              if (narrative.Any())
                strucDocTable =
                (
                    PopulateTable
                    (
                        "Medical History",
                        null,
                        headerList.ToArray(),
                        new string[0],
                        narrative
                    )
                );

            return strucDocTable;
        }

        // Compare strings
        static int Compare(KeyValuePair<DateTime, List<string>> a, KeyValuePair<DateTime, List<string>> b)
        {
          return a.Key.CompareTo(b.Key);
        }

        /// <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 strucDocText = new StrucDocText();

            if (immunisations != null && immunisations.Any())
            {
              strucDocText.table = CreateNarrativeEntry(immunisations).ToArray();
            }
            else
            {
              strucDocText.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
            }

            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)
        {
            var narrative = new List<List<String>>();
            var header = new [] {"Field", "Value"};

            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)
                        narrative.Add
                        (
                            CreateNarrativeEntry("Service Scheduled", requestedService.ServiceScheduled.NarrativeText())
                        );

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

                    // 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
                    (
                        "Requested Service",
                        null,
                        header,
                        new string[0],
                        narrative
                    )
            );

            var strucDocText = new StrucDocText();


            if (strucDocTableList.Any())
            {
                strucDocText.table = strucDocTableList.ToArray();
            }
            else
            {
                strucDocText.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
            }

            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 StrucDocItem CreateExclusionStrucDocItem(string caption, Statement statement)
        {
          StrucDocItem strucDocItem = new StrucDocItem();
          strucDocItem.Text = new [] { string.Format("{0} {1}", caption, statement.Value.GetAttributeValue<NameAttribute, string>(x => x.Name)) };
          return strucDocItem;
        }

        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}",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}", 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) || rowData[i][j].Contains(DELIMITEREMAILSTART) || rowData[i][j].Contains(DELIMITEREMAILEND))
                            )
                           {
                             // CHECK FOR DELIMITER CHAR FOR LIST
                             if (rowData[i][j] != null && (rowData[i][j].Contains(DELIMITEREMAILSTART)) || rowData[i][j].Contains(DELIMITEREMAILEND))
                             {
                               var data = rowData[i][j];
                               var linkHTML = new List<StrucDocLinkHtml>();
                               var list = new List<string>();
                               while (!GetSubstringByString(DELIMITEREMAILSTART, DELIMITEREMAILEND, data).IsNullOrEmptyWhitespace() )
                               {
                                 var email = GetSubstringByString(DELIMITEREMAILSTART, DELIMITEREMAILEND, data);

                                 linkHTML.Add(
                                   new StrucDocLinkHtml
                                   {
                                     Text = new[] { email },
                                     href = string.Format("mailto:{0}", email)
                                   }
                                 );

                                 data = data.Replace(DELIMITEREMAILSTART + email + DELIMITEREMAILEND, string.Empty);
                               }

                               var strucDocList = new List<StrucDocContent>();

                               strucDocList.Add(new StrucDocContent { Text = new[] { data } });


                               if (strucDocList.Any())
                                  strucDocTable.tbody[0].tr[i].td[j].content = strucDocList.ToArray();

                               if (linkHTML.Any())
                                  strucDocTable.tbody[0].tr[i].td[j].linkHtml = linkHTML.ToArray();

                               // ReSet the Row Data without the DELIMITEREMAILSTART & DELIMITEREMAILEND tags for the next section
                               rowData[i][j] = data;
                             }

                            // CHECK FOR DELIMITER CHAR FOR LIST
                            if (rowData[i][j] != null && (rowData[i][j].Contains(DELIMITER)))
                            {
                                var data = rowData[i][j];

                                var listItems = SplitWord(data, DELIMITER);

                                var items = new List<StrucDocItem>();
                                foreach(var item in listItems)
                                {
                                  if (!item.IsNullOrEmptyWhitespace())
                                  items.Add(new StrucDocItem { Text = new [] {item}});

                                  data = data.Replace(item + DELIMITER, string.Empty);
                                }

                                //For Lists for the Cell rather than 
                                strucDocTable.tbody[0].tr[i].td[j].list = new [] { new StrucDocList { item = items.ToArray() }};

                                // ReSet the Row Data without the DELIMITEREMAILSTART & DELIMITEREMAILEND tags for the next section
                                rowData[i][j] = data;
                             }

                            // CHECK FOR DELIMITER CHAR FOR LIST
                            if (rowData[i][j] != null && (rowData[i][j].Contains(DELIMITERBREAK)))
                            {
                                var data = rowData[i][j];

                                var listBreaks = SplitWord(data, DELIMITERBREAK);

                                var strucDocList = new List<StrucDocContent>();
                                var firstTimeThrough = true;
                                foreach (var line in listBreaks)
                                {
                                    if (firstTimeThrough)
                                    {
                                        strucDocList.Add(new StrucDocContent {Text = new [] {line}});
                                        firstTimeThrough = false;
                                    } 
                                    else 
                                    {
                                        strucDocList.Add(new StrucDocContent { Text = new [] { line }, br = new [] { 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;
        }


          public static IEnumerable<string> SplitWord(string source, string delim)
          {
            // argument null checking etc omitted for brevity

            int oldIndex = 0, newIndex;
            while ((newIndex = source.IndexOf(delim, oldIndex)) != -1)
            {
              yield return source.Substring(oldIndex, newIndex - oldIndex);
              oldIndex = newIndex + delim.Length;
            }
            yield return source.Substring(oldIndex);
          }

          public static string GetSubstringByString(string a, string b, string c)
          {
            try
            {
              return c.Substring((c.IndexOf(a) + a.Length), (c.IndexOf(b) - c.IndexOf(a) - a.Length));
            }
            catch (Exception)
            {
              return null;
            }
          }

        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 {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) || ((string)rowData[rowCounter][cellCounter]).Contains(DELIMITEREMAILSTART) || ((string)rowData[rowCounter][cellCounter]).Contains(DELIMITEREMAILEND) ))
                        {


                          // CHECK FOR DELIMITER CHAR FOR LIST
                          if (rowData[rowCounter][cellCounter] != null && (((string)rowData[rowCounter][cellCounter]).Contains(DELIMITEREMAILSTART)) || ((string)rowData[rowCounter][cellCounter]).Contains(DELIMITEREMAILEND))
                          {
                            var data = rowData[rowCounter][cellCounter];
                            var linkHTML = new List<StrucDocLinkHtml>();
                            var list = new List<string>();
                            while (!GetSubstringByString(DELIMITEREMAILSTART, DELIMITEREMAILEND, ((string)data)).IsNullOrEmptyWhitespace())
                            {
                              var email = GetSubstringByString(DELIMITEREMAILSTART, DELIMITEREMAILEND, ((string)data));

                              linkHTML.Add(
                                new StrucDocLinkHtml
                                {
                                  Text = new[] { email },
                                  href = string.Format("mailto:{0}", email)
                                }
                              );

                              data = ((string)data).Replace(DELIMITEREMAILSTART + email + DELIMITEREMAILEND, string.Empty);
                            }

                            var strucDocList = new List<StrucDocContent>();

                            strucDocList.Add(new StrucDocContent { Text = new[] { ((string)data) } });


                            if (strucDocList.Any())
                              strucDocTable.tbody[0].tr[rowCounter].td[cellCounter].content = strucDocList.ToArray();

                            if (linkHTML.Any())
                              strucDocTable.tbody[0].tr[rowCounter].td[cellCounter].linkHtml = linkHTML.ToArray();

                            // ReSet the Row Data without the DELIMITEREMAILSTART & DELIMITEREMAILEND tags for the next section
                            rowData[rowCounter][cellCounter] = data;
                          }

                          // CHECK FOR DELIMITER CHAR FOR LIST
                          if (rowData[rowCounter][cellCounter] != null && (((string)rowData[rowCounter][cellCounter]).Contains(DELIMITER)))
                          {
                            var data = rowData[rowCounter][cellCounter];

                            var listItems = SplitWord(((string)data), DELIMITER);

                            var items = new List<StrucDocItem>();
                            foreach (var item in listItems)
                            {
                              if (!item.IsNullOrEmptyWhitespace())
                                items.Add(new StrucDocItem { Text = new[] { item } });

                              data = ((string)data).Replace(item + DELIMITER, string.Empty);
                            }

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

                            // ReSet the Row Data without the DELIMITEREMAILSTART & DELIMITEREMAILEND tags for the next section
                            rowData[rowCounter][cellCounter] = data;
                          }

                          // CHECK FOR DELIMITER CHAR FOR LIST
                          if (rowData[rowCounter][cellCounter] != null && (((string)rowData[rowCounter][cellCounter]).Contains(DELIMITERBREAK)))
                          {
                            var data = rowData[rowCounter][cellCounter];

                            var listBreaks = SplitWord(((string)data), DELIMITERBREAK);

                            var strucDocList = new List<StrucDocContent>();
                            var firstTimeThrough = true;
                            foreach (var line in listBreaks)
                            {
                              if (firstTimeThrough)
                              {
                                strucDocList.Add(new StrucDocContent { Text = new[] { line } });
                                firstTimeThrough = false;
                              }
                              else
                              {
                                strucDocList.Add(new StrucDocContent { Text = new[] { line }, br = new[] { 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 && dataItem.ExternalDataMediaType != MediaType.TIFF)
                        {
                            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 ExclusionStatement section
        /// </summary>
        /// <param name="australianChildhoodImmunisationRegisterEntries">australianChildhoodImmunisationRegisterEntries</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(AustralianChildhoodImmunisationRegisterEntries australianChildhoodImmunisationRegisterEntries)
        {
          var strucDocText = new StrucDocText();
          var strucDocTableList = new List<StrucDocTable>();
          var header = new[] { "Field", "Value" }; 
          int count = 0;

          if (australianChildhoodImmunisationRegisterEntries.AustralianChildhoodImmunisationRegisterEntry != null)
            foreach (var entry in australianChildhoodImmunisationRegisterEntries.AustralianChildhoodImmunisationRegisterEntry)
            {
              count++;
              var narrativeVaccineAdministrationEntry = new List<List<String>>();
              var narrativeVaccineCancellationEntry = new List<List<String>>();
              var narrativeVaccineCancellationReason = new List<List<String>>();
              var narrativeLink = new List<List<object>>();

              if (entry != null)
              {
                // Vaccine Administration Entry
                if (entry.VaccineAdministrationEntry != null)
                {

                  if (entry.VaccineAdministrationEntry.VaccineType != null)
                    narrativeVaccineAdministrationEntry.Add
                      (
                        new List<String>
                        {
                          "Vaccine Type",
                          entry.VaccineAdministrationEntry.VaccineType.NarrativeText
                        }
                      );

                  if (entry.VaccineAdministrationEntry.DateVaccinationReceived != null)
                    narrativeVaccineAdministrationEntry.Add
                      (
                        new List<String>
                          {
                            "Date Vaccination Received",
                            entry.VaccineAdministrationEntry.DateVaccinationReceived.NarrativeText()
                          }
                      );


                  if (entry.VaccineAdministrationEntry.MedicareAntigenCode != null)
                  {
                    var codes = entry.VaccineAdministrationEntry.MedicareAntigenCode.Aggregate(string.Empty, (current, code) => current + (code.NarrativeText + "<BR>"));

                    narrativeVaccineAdministrationEntry.Add
                      (
                        new List<String>
                          {
                            "Medicare Antigen Code",
                            codes
                          }
                      );
                  }

                  if (entry.VaccineAdministrationEntry.VaccineDoseNumber != null)
                    narrativeVaccineAdministrationEntry.Add
                      (
                        new List<String>
                          {
                            "Vaccine Dose Number",
                            entry.VaccineAdministrationEntry.VaccineDoseNumber.Value.ToString(CultureInfo.InvariantCulture)
                          }
                      );

                }

                // Vaccine Cancellation Entry
                if (entry.VaccineCancellationEntry != null)
                {

                  if (entry.VaccineCancellationEntry.VaccineType != null)
                    narrativeVaccineCancellationEntry.Add
                      (
                        new List<String>
                        {
                          "VaccineType",
                          entry.VaccineCancellationEntry.VaccineType.NarrativeText
                        }
                      );

                  narrativeVaccineCancellationEntry.Add
                    (
                      new List<String>
                        {
                          "Date Vaccination Cancelled",
                          entry.VaccineCancellationEntry.DateVaccinationCancelled.NarrativeText()
                        }
                    );

                  if (entry.VaccineCancellationEntry.MedicareAntigenCode != null)
                  {
                    var codes = entry.VaccineCancellationEntry.MedicareAntigenCode.Aggregate(string.Empty, (current, code) => current + (code.NarrativeText + "<BR>"));

                    narrativeVaccineCancellationEntry.Add
                      (
                        new List<String>
                          {
                            "Medicare Antigen Code",
                            codes
                          }
                      );
                  }

                  if (entry.VaccineCancellationEntry.VaccineDoseNumber.HasValue)
                    narrativeVaccineCancellationEntry.Add
                      (
                        new List<String>
                        {
                          "Vaccine Dose Number",
                          entry.VaccineCancellationEntry.VaccineDoseNumber.Value.ToString(CultureInfo.InvariantCulture)
                        }
                      );
                }

                // Vaccine Cancellation Entry
                if (entry.VaccineCancellationReason != null)
                {
                  foreach (var cancellationReason in entry.VaccineCancellationReason)
                  {
                    string reasonForCancel = null;    
                    if (cancellationReason.VaccineType.HasValue)
                      reasonForCancel = cancellationReason.VaccineType.Value.ToString();

                    if (cancellationReason.VaccineTypeNullFlavour.HasValue)
                      reasonForCancel = cancellationReason.VaccineTypeNullFlavour.Value.ToString();


                    narrativeVaccineCancellationReason.Add
                      (
                        new List<String>
                          {
                            cancellationReason.VaccineCancellationReasonPeriod != null ? CdaIntervalFormatter.Format(cancellationReason.VaccineCancellationReasonPeriod) : null,   
                            !cancellationReason.VaccineCancellationReasonComment.IsNullOrEmptyWhitespace() ? cancellationReason.VaccineCancellationReasonComment : null,
                            reasonForCancel ?? null
                          }
                      );
                  }
                }

                if (narrativeVaccineAdministrationEntry.Any())
                  strucDocTableList.Add
                    (
                      PopulateTable
                        (
                          "Vaccine Administration Entry",
                          null,
                          header,
                          null,
                          narrativeVaccineAdministrationEntry
                        )
                    );

                if (narrativeVaccineCancellationEntry.Any())
                  strucDocTableList.Add
                    (
                      PopulateTable
                        (
                          "Vaccine Cancellation Entry",
                          null,
                          header,
                          null,
                          narrativeVaccineCancellationEntry
                        )
                    );

                if (narrativeVaccineCancellationReason.Any())
                  strucDocTableList.Add
                    (
                      PopulateTable
                        (
                          "Vaccine Cancellation Reason",
                          null,
                          new[] { "Reason Period", "Reason Comment", "Vaccine Type"},
                          null,
                          narrativeVaccineCancellationReason
                        )
                    );



                // Record Link
                if (australianChildhoodImmunisationRegisterEntries.AustralianChildhoodImmunisationRegisterDocumentProvenanceLink != null)
                {
                  narrativeLink.Add(
                               new List<object>{
                                   "Australian Childhood Immunisation Register",
                                   CreateLink(australianChildhoodImmunisationRegisterEntries.AustralianChildhoodImmunisationRegisterDocumentProvenanceLink)
                               });

                  strucDocTableList.Add
                    (
                      PopulateTable
                        (
                          "Australian Childhood Immunisation Register Entries Document",
                          null,
                          header,
                          null,
                          narrativeLink
                        )
                    );
                }   
              }
            }

          strucDocText.table = strucDocTableList.ToArray();

          return strucDocText;

        }

        /// <summary>
        /// This method creates the narrative for the ExclusionStatement section
        /// </summary>
        /// <param name="exclusionStatement">ExclusionStatement</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(ExclusionStatement exclusionStatement)
        {
          var strucDocText = new StrucDocText();
          if (exclusionStatement != null)
          {
            strucDocText.paragraph = CreateParagraph(exclusionStatement.GeneralStatement);
          }

          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();
          var strucDocTableList = new List<StrucDocTable>();
          var header = new[] { "Field", "Value" }; 
          var narrativeLink = new List<List<object>>();

          var count = 0;


          // Service Requester
          if (medicareDVAFundedServices.MedicareDVAFundedService != null)
            foreach (var medicareDVAFundedService in medicareDVAFundedServices.MedicareDVAFundedService)
            {
              count++;

              var medicareDvaFundedServicesNarrative = new List<List<String>>();

              // Report Date
              if (medicareDVAFundedService.DateOfService != null)
                medicareDvaFundedServicesNarrative.Add
                  (
                    new List<string>
                      {
                        "Date Of Service",
                        medicareDVAFundedService.DateOfService.NarrativeText()
                      }
                  );

              // Medicare MBS/DVA Item
              if (medicareDVAFundedService.MedicareMBSDVAItem != null)
                medicareDvaFundedServicesNarrative.Add
                  (
                    new List<string>
                      {
                        "Medicare MBS/DVA Item",
                        medicareDVAFundedService.MedicareMBSDVAItem.NarrativeText
                      }
                  );

              // Service in Hospital Indicator
              if (medicareDVAFundedService.ServiceInHospitalIndicator.HasValue)
                medicareDvaFundedServicesNarrative.Add
                  (
                    new List<string>
                      {
                        "Service in Hospital Indicator",
                        medicareDVAFundedService.ServiceInHospitalIndicator.Value.ToString()
                      }
                  );

              strucDocTableList.Add
                (
                  PopulateTable
                    (
                      string.Format("Medicare/DVA Funded Service {0}", count.ToString(CultureInfo.InvariantCulture)),
                      null,
                      header,
                      null,
                      medicareDvaFundedServicesNarrative
                    )
                );

              if (medicareDVAFundedService.ServiceRequester != null)
              {
                var serviceRequester = medicareDVAFundedService.ServiceRequester;

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

                // Get organisation name
                String organisationName = null;

                if (serviceRequester.Participant != null)
                {
                  if (serviceRequester.Participant.Organisation != null)
                    if (!serviceRequester.Participant.Organisation.Name.IsNullOrEmptyWhitespace())
                      organisationName = serviceRequester.Participant.Organisation.Name;

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

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

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

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

                strucDocTableList.Add
                  (
                    PopulateTable
                      (
                        string.Format("Service Requester"),
                        null,
                        new[] {"Field", "Value"},
                        null,
                        narrative
                      )
                  );
              }

              if (medicareDVAFundedService.ServiceProvider != null)
              {

                var serviceProvider = medicareDVAFundedService.ServiceProvider;

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

                // Get organisation name
                String organisationName = null;

                if (serviceProvider.Participant != null)
                {
                  if (serviceProvider.Participant.Organisation != null)
                    if (!serviceProvider.Participant.Organisation.Name.IsNullOrEmptyWhitespace())
                      organisationName = serviceProvider.Participant.Organisation.Name;

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

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

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

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

                strucDocTableList.Add
                  (
                    PopulateTable
                      (
                        string.Format("Service Provider"),
                        null,
                        new[] {"Field", "Value"},
                        null,
                        narrative
                      )
                  );
              }
            }

          // Record Link
          if (medicareDVAFundedServices.MedicareDVAFundedServicesDocumentProvenance != null)
          {
            narrativeLink.Add(
                         new List<object>{
                                   "Medicare DVA Funded Services",
                                   CreateLink(medicareDVAFundedServices.MedicareDVAFundedServicesDocumentProvenance)
                               });

            strucDocTableList.Add
              (
                PopulateTable
                  (
                    "Medicare DVA Funded Services Document",
                    null,
                    header,
                    null,
                    narrativeLink
                  )
              );
          }
          strucDocText.table = strucDocTableList.ToArray();
          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();
          var strucDocTableList = new List<StrucDocTable>();
          var header = new[] { "Field", "Value" };
          var narrativeLink = new List<List<object>>();

          var narrativeAustralianOrganDonorRegisterEntry = new List<List<String>>();

          // Australian Organ Donor Register Entry
          if (australianOrganDonorRegisterDetails.AustralianOrganDonorRegisterEntry != null)
          {
              var item = australianOrganDonorRegisterDetails.AustralianOrganDonorRegisterEntry;

              narrativeAustralianOrganDonorRegisterEntry.Add
                (
                  new List<String>
                          {
                             item.DateOfInitialRegistration == null ? null : item.DateOfInitialRegistration.NarrativeText(),
                             !item.DonationDecision.HasValue ? null : item.DonationDecision.Value.ToString(CultureInfo.InvariantCulture)
                          }
                );

            strucDocTableList.Add
              (
                PopulateTable
                  (
                    "Australian Organ Donor Register Entry",
                    null,
                    new[] { "Date of Initial Registration", "Donation Decision"},
                    null,
                    narrativeAustralianOrganDonorRegisterEntry
                  )
              );

            // Organ And Tissue Donation Details
            if (australianOrganDonorRegisterDetails.AustralianOrganDonorRegisterEntry.OrganAndTissueDonationDetails != null)
            {
              var narrativeOrganAndTissueDonationDetails = new List<List<String>>();

              var detail = australianOrganDonorRegisterDetails.AustralianOrganDonorRegisterEntry.OrganAndTissueDonationDetails;

              if (detail.BoneTissueIndicator.HasValue)
                narrativeOrganAndTissueDonationDetails.Add
                  (
                    new List<String>
                        {
                          "Bone Tissue Indicator",
                          detail.BoneTissueIndicator.Value.ToString(CultureInfo.InvariantCulture)
                        }
                  );

              if (detail.EyeTissueIndicator.HasValue)
                narrativeOrganAndTissueDonationDetails.Add
                  (
                    new List<String>
                        {
                          "Eye Tissue Indicator",
                          detail.EyeTissueIndicator.Value.ToString(CultureInfo.InvariantCulture)
                        }
                  );

              if (detail.HeartIndicator.HasValue)
                narrativeOrganAndTissueDonationDetails.Add
                  (
                    new List<String>
                        {
                          "Heart Indicator",
                          detail.HeartIndicator.Value.ToString(CultureInfo.InvariantCulture)
                        }
                  );

              if (detail.HeartValveIndicator.HasValue)
                narrativeOrganAndTissueDonationDetails.Add
                  (
                    new List<String>
                        {
                          "Heart Valve Indicator",
                          detail.HeartValveIndicator.Value.ToString(CultureInfo.InvariantCulture)
                        }
                  );


              if (detail.KidneyIndicator.HasValue)
                narrativeOrganAndTissueDonationDetails.Add
                  (
                    new List<String>
                        {
                          "Kidney Indicator",
                          detail.KidneyIndicator.Value.ToString(CultureInfo.InvariantCulture)
                        }
                  );

              if (detail.LiverIndicator.HasValue)
                narrativeOrganAndTissueDonationDetails.Add
                  (
                    new List<String>
                        {
                          "Liver Indicator",
                          detail.LiverIndicator.Value.ToString(CultureInfo.InvariantCulture)
                        }
                  );

              if (detail.LungsIndicator.HasValue)
                narrativeOrganAndTissueDonationDetails.Add
                  (
                    new List<String>
                        {
                          "Lungs Indicator",
                          detail.LungsIndicator.Value.ToString(CultureInfo.InvariantCulture)
                        }
                  );

              if (detail.PancreasIndicator.HasValue)
                narrativeOrganAndTissueDonationDetails.Add
                  (
                    new List<String>
                        {
                          "Pancreas Indicator",
                          detail.PancreasIndicator.Value.ToString(CultureInfo.InvariantCulture)
                        }
                  );

              if (detail.SkinTissueIndicator.HasValue)
                narrativeOrganAndTissueDonationDetails.Add
                  (
                    new List<String>
                        {
                          "Skin Tissue Indicator",
                          detail.SkinTissueIndicator.Value.ToString(CultureInfo.InvariantCulture)
                        }
                  );

              strucDocTableList.Add
                (
                  PopulateTable
                    (
                      "Organ And Tissue Donation Details",
                      null,
                      new[] { "Field", "Value" },
                      null,
                      narrativeOrganAndTissueDonationDetails
                    )
                );
            }

          }

          // Record Link
          if (australianOrganDonorRegisterDetails.AustralianOrganDonorRegisterDetailsProvenanceLink != null)
          {
            narrativeLink.Add(
                         new List<object>{
                                   "Australian Organ Donor Register Details",
                                   CreateLink(australianOrganDonorRegisterDetails.AustralianOrganDonorRegisterDetailsProvenanceLink)
                               });

            strucDocTableList.Add
              (
                PopulateTable
                  (
                    "Australian Organ Donor Register Details Document",
                    null,
                    header,
                    null,
                    narrativeLink
                  )
              );
          }
          strucDocText.table = strucDocTableList.ToArray();
          return strucDocText;
        }

        /// <summary>
        /// Create a Narrative for the Achievement Section
        /// </summary>
        /// <param name="achievements">A List of Achievements</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(List<Achievement> achievements)
        {
          var strucDocText = new StrucDocText();
          var strucDocTableList = new List<StrucDocTable>();
          var header = new[] { "Field", "Value" };

          var count = 0;

          foreach (var achievement in achievements)
          {
            var narrative = new List<List<Object>>();

            count++;

            if (achievement != null)
            {
              // Achievement Date
              if (achievement.AchievementDate != null)
                narrative.Add
                  (
                    new List<Object>
                        {
                          "Achievement Date",
                          achievement.AchievementDate.NarrativeText()
                        }
                  );

              // Achievement Topic
              if (achievement.AchievementTopic != null)
                narrative.Add
                  (
                    new List<Object>
                        {
                          "Achievement Topic",
                          achievement.AchievementTopic
                        }
                  );

              // Achievement Description
              if (achievement.AchievementDescription != null)
                narrative.Add
                  (
                    new List<Object>
                        {
                          "Achievement Description",
                          achievement.AchievementDescription
                        }
                  );

              if (achievement.InformationProvider != null && achievement.InformationProvider.Participant != null)
              {

                var personOrganisation = achievement.InformationProvider.Participant.Person != null && achievement.InformationProvider.Participant.Person.PersonNames != null ? BuildPersonNames(achievement.InformationProvider.Participant.Person.PersonNames) : null;

                narrative.Add
                  (
                    new List<Object>
                        {
                          "Information Provider",
                          personOrganisation
                        }
                  );

                if (achievement.InformationProvider.Participant.Addresses != null || achievement.InformationProvider.Participant.ElectronicCommunicationDetails != null)
                {
                  narrative.Add
                    (
                      new List<Object>
                        {
                          "Information Provider - Details",
                          CreateAddress(achievement.InformationProvider.Participant.Addresses, achievement.InformationProvider.Participant.ElectronicCommunicationDetails)
                        }
                    );
                }
              }

              strucDocTableList.Add
                (
                  PopulateTable
                    (
                      string.Format("Achievement {0}", count.ToString(CultureInfo.InvariantCulture)),
                      null,
                      header,
                      null,
                      narrative
                    )
                );
            }
          }

          strucDocText.table = strucDocTableList.ToArray();
          
          return strucDocText;
        }


        #region ATS ETP

        /// <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(IEPrescriptionItem item, IParticipationPrescriber prescriber, IParticipationSubjectOfCare subjectOfCare)
        {
          var strucDocTableList = new List<StrucDocTable>();
          var narrative = new List<List<String>>();
          var narrativeTiming = new List<List<String>>();
          var narrativeAdministrationDetails = new List<List<String>>();
          var narrativeStructuredDose = new List<List<String>>();
          var narrativeQuantityToDispense = new List<List<String>>();
          var narrativePBSExtemporaneousIngredient = new List<List<String>>();
          var narrativeEntitlements = new List<List<String>>();

          if (item != null)
          {

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

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

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

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

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

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

            if (item.StructuredDose != null)
            {
              //Quantity of Therapeutic Good
              if (item.StructuredDose.Quantity != null)
                narrativeStructuredDose.Add
                   (
                       CreateNarrativeEntry("Quantity", item.StructuredDose.Quantity.NarrativeText)
                   );

              //Structured Dose - Dose Unit
              if (item.StructuredDose.Unit != null)
                narrativeStructuredDose.Add
                   (
                       CreateNarrativeEntry("Dose Unit", item.StructuredDose.Unit.NarrativeText)
                   );

              //Structured Dose - Quantity Description
              if (item.StructuredDose.QuantityDescription != null)
                narrativeStructuredDose.Add
                   (
                       CreateNarrativeEntry("Quantity Description", item.StructuredDose.QuantityDescription)
                   );
            }

            if (item.Timing != null)
            {
              //Timing
              if (!item.Timing.TimingDescription.IsNullOrEmptyWhitespace())
                narrativeTiming.Add
                   (
                       CreateNarrativeEntry("TimingDescription", item.Timing.TimingDescription)
                   );

              //Structured Timing EffectiveTime
              if (item.Timing.StructuredTiming != null && item.Timing.StructuredTiming.EffectiveTime != null)
              {

                if (!item.Timing.StructuredTiming.NarrativeText.IsNullOrEmptyWhitespace())
                {

                  narrativeTiming.Add
                     (
                         CreateNarrativeEntry("EffectiveTime", item.Timing.StructuredTiming.NarrativeText)
                     );

                } else
                {
                  //Structured Timing EffectiveTime
                    narrativeTiming.Add
                        (
                          new List<string>
                        {
                          "EffectiveTime",
                          CreateTimingEntry(item.Timing.StructuredTiming.EffectiveTime)
                        }
                      );
                }
              }

              //PRN
              if (item.Timing.PRN.HasValue)
                narrativeTiming.Add
                   (
                       CreateNarrativeEntry("PRN", item.Timing.PRN.Value.ToString(CultureInfo.InvariantCulture))
                   );

              //Timing - StartCriterion
              if (item.Timing.StartCriterion.HasValue)
                narrativeTiming.Add
                   (
                       CreateNarrativeEntry("StartCriterion", item.Timing.StartCriterion.Value.ToString(CultureInfo.InvariantCulture))
                   );

              //Timing - StartDate
              if (item.Timing.StartDate != null)
                narrativeTiming.Add
                   (
                       CreateNarrativeEntry("StartDate", item.Timing.StartDate)
                   );

              //Timing - StopCriterion
              if (item.Timing.StopCriterion.HasValue)
                narrativeTiming.Add
                   (
                       CreateNarrativeEntry("StopCriterion", item.Timing.StopCriterion.Value.ToString(CultureInfo.InvariantCulture))
                   );

              //Timing - StopDate
              if (item.Timing.StopDate != null)
                narrativeTiming.Add
                   (
                       CreateNarrativeEntry("StopDate", item.Timing.StopDate)
                   );

              if (item.Timing.NumberOfAdministrations != null)
              {
                  var numberOfAdministrations = string.Empty;

                  //Timing - Number of Administrations - Numerator
                  if ( item.Timing.NumberOfAdministrations.NullFlavor != null)
                    numberOfAdministrations += item.Timing.NumberOfAdministrations.NullFlavor.Value.GetAttributeValue<NameAttribute, String>(x => x.Name) + " ";

                  //Timing - Number of Administrations - Denominator
                  if (item.Timing.NumberOfAdministrations.Denominator != null)
                    numberOfAdministrations += item.Timing.NumberOfAdministrations.Denominator.NarrativeText ;
 
                  //Timing - Number of Administrations - Numerator
                  if (item.Timing.NumberOfAdministrations.Numerator != null)
                  {
                    if (!numberOfAdministrations.IsNullOrEmptyWhitespace())
                      numberOfAdministrations += " - ";

                    numberOfAdministrations += item.Timing.NumberOfAdministrations.Numerator.NarrativeText + " ";
                  }

                  if (!numberOfAdministrations.IsNullOrEmptyWhitespace())
                    narrativeTiming.Add
                       (
                           CreateNarrativeEntry("Number of Administrations", numberOfAdministrations)
                       );
              }

              //Timing - LongTerm
              if (item.Timing.LongTerm.HasValue)
                narrativeTiming.Add
                   (
                       CreateNarrativeEntry("Long Term", item.Timing.LongTerm.Value.ToString(CultureInfo.InvariantCulture))
                   );
            }

            if (item.AdministrationDetails != null)
            {
                //AdministrationDetails - Route
                if (item.AdministrationDetails.Route != null)
                  narrativeAdministrationDetails.Add
                     (
                         CreateNarrativeEntry("Route", item.AdministrationDetails.Route.NarrativeText)
                     );

                //AdministrationDetails - AnatomicalSite
                if (item.AdministrationDetails.AnatomicalSite != null)
                  narrativeAdministrationDetails.Add
                     (
                         CreateNarrativeEntry("AnatomicalSite", item.AdministrationDetails.AnatomicalSite.NarrativeText)
                     );

                //AdministrationDetails - MedicationDeliveryMethod
                if (item.AdministrationDetails.MedicationDeliveryMethod != null)
                  narrativeAdministrationDetails.Add
                     (
                         CreateNarrativeEntry("Medication Delivery Method", item.AdministrationDetails.MedicationDeliveryMethod.NarrativeText)
                     );
            }

            if (item.QuantityToDispense != null)
            {
                //QuantityToDispense - Quantity
                if (item.QuantityToDispense.Quantity != null)
                  narrativeQuantityToDispense.Add
                     (
                         CreateNarrativeEntry("Quantity", item.QuantityToDispense.Quantity.NarrativeText)
                     );

                //QuantityToDispense - Dispensing Unit
                if (item.QuantityToDispense.Unit != null)
                  narrativeQuantityToDispense.Add
                     (
                         CreateNarrativeEntry("Dispensing Unit", item.QuantityToDispense.Unit.NarrativeText)
                     );

                //QuantityToDispense - QuantityDescription
                if (!item.QuantityToDispense.QuantityDescription.IsNullOrEmptyWhitespace())
                  narrativeQuantityToDispense.Add
                     (
                         CreateNarrativeEntry("Quantity Description", item.QuantityToDispense.QuantityDescription)
                     );
            }

            //Brand Substitute Allowed
            if (item.BrandSubstituteAllowed != null)
              narrative.Add
                 (
                     CreateNarrativeEntry("Brand Substitute Allowed", item.BrandSubstituteAllowed)
                 );

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

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

            // PBS Prescription Type
            if (item.PBSPrescriptionType.HasValue)
              narrative.Add
                 (
                     CreateNarrativeEntry("PBS Prescription Type", item.PBSPrescriptionType.Value.GetAttributeValue<NameAttribute, String>(x => x.Name))
                 );

              // Medical Benefit Category Type
            if (item.MedicalBenefitCategoryType.HasValue && item.MedicalBenefitCategoryType.Value != MedicalBenefitCategoryType.Undefined)
                narrative.Add
                   (
                       CreateNarrativeEntry("Medical Benefit Category Type", item.MedicalBenefitCategoryType.GetAttributeValue<NameAttribute, String>(x => x.Name))
                   );

            // PBS Close the Gap Benefit
            if (item.PBSCloseTheGapBenefit != null)
              narrative.Add
                 (
                     CreateNarrativeEntry("PBS Close the Gap Benefit", item.PBSCloseTheGapBenefit.NarrativeText)
                 );

            // PBS/RPBS Item Code
            if (item.PBSRPBSItemCode != null)
              narrative.Add
                 (
                     CreateNarrativeEntry("PBS/RPBS Item Code", item.PBSRPBSItemCode.NarrativeText)
                 );

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


            // PBS/RPBS Manufacturer Code
            if (item.PBSExtemporaneousIngredient != null)
            {
              for (int index = 0; index < item.PBSExtemporaneousIngredient.Count; index++)
              {
                var extemporaneousIngredient = item.PBSExtemporaneousIngredient[index];

                if (extemporaneousIngredient != null && extemporaneousIngredient.IngredientName != null || extemporaneousIngredient.IngredientQuantity != null)
                  narrativePBSExtemporaneousIngredient.Add
                  (
                    CreateNarrativeEntry(extemporaneousIngredient.IngredientName != null     ? extemporaneousIngredient.IngredientName.NarrativeText : null,
                                         extemporaneousIngredient.IngredientQuantity != null ? extemporaneousIngredient.IngredientQuantity.NarrativeText : null)
                  );

              }
            }

            // Grounds for Concurrent Supply
            if (item.GroundsForConcurrentSupply.HasValue && item.GroundsForConcurrentSupply != GroundsForConcurrentSupply.Undefined)
              narrative.Add
                 (
                     CreateNarrativeEntry("Grounds for Concurrent Supply", item.GroundsForConcurrentSupply.GetAttributeValue<NameAttribute, String>(x => x.Name))
                 );

            // PBS/RPBS Authority Prescription Number
            if (!item.PBSRPBSAuthorityPrescriptionNumber.IsNullOrEmptyWhitespace())
              narrative.Add
                 (
                     CreateNarrativeEntry("PBS/RPBS Authority Prescription Number", item.PBSRPBSAuthorityPrescriptionNumber)
                 );

            // PBS/RPBS Authority Approval Number
            if (!item.PBSRPBSAuthorityApprovalNumber.IsNullOrEmptyWhitespace())
              narrative.Add
                 (
                     CreateNarrativeEntry("PBS/RPBS Authority Approval Number", item.PBSRPBSAuthorityApprovalNumber)
                 );


            // Streamlined Authority Approval Number
            if (!item.StreamlinedAuthorityApprovalNumber.IsNullOrEmptyWhitespace())
              narrative.Add
                 (
                     CreateNarrativeEntry("Streamlined Authority Approval Number", item.StreamlinedAuthorityApprovalNumber)
                 );

            // State Authority Number
            if (item.StateAuthorityNumber != null)
              narrative.Add
                 (
                     CreateNarrativeEntry("State Authority Number", item.StateAuthorityNumber.NarrativeText)
                 );


            // Reason for Therapeutic Good
            if (!item.ReasonForTherapeuticGood.IsNullOrEmptyWhitespace())
              narrative.Add
                 (
                     CreateNarrativeEntry("Reason for Therapeutic Good", item.ReasonForTherapeuticGood)
                 );

            // Additional Comments
            if (!item.AdditionalComments.IsNullOrEmptyWhitespace())
              narrative.Add
                 (
                     CreateNarrativeEntry("Additional Comments", item.AdditionalComments)
                 );

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

            // Medication Instruction Identifier
            if (item.MedicationInstructionIdentifier != null)
              narrative.Add
                 (
                     CreateNarrativeEntry("Medication Instruction Identifier", item.MedicationInstructionIdentifier.NarrativeText)
                 );

            // The Prescription Note
            if (!item.NoteDetail.IsNullOrEmptyWhitespace())
            {
              narrative.Add
                      (
                          CreateNarrativeEntry("Prescription Note Detail", item.NoteDetail)
                      );

            }

            // Entitilements Subject Of Care
            if (subjectOfCare.Participant.Entitlements != null && subjectOfCare.Participant.Entitlements.Count > 0)
            {
              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
                  };
                }

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

            // Entitilements Prescriber
            if (prescriber.Participant.Person.Entitlements != null && prescriber.Participant.Person.Entitlements.Count > 0)
            {
              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
                  };
                }

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

            strucDocTableList.AddRange
                (
                   new List<StrucDocTable>
                           {
                                narrative.Any() ? PopulateTable
                                        (
                                            "Prescription Item",
                                            null ,
                                            new []  { "Field", "Value" },
                                            null,
                                            narrative
                                        ) : null,
                                narrativeTiming.Any() ? PopulateTable
                                        (
                                            "Timing",
                                            null ,
                                            new []  { "Field", "Value" },
                                            null,
                                            narrativeTiming
                                        ): null,
                                narrativeStructuredDose.Any() ? PopulateTable
                                        (
                                            "Structured Dose",
                                            null ,
                                            new []  { "Field", "Value" },
                                            null,
                                            narrativeStructuredDose
                                        ) : null,
                                narrativeQuantityToDispense.Any() ? PopulateTable
                                        (
                                            "Quantity To Dispense",
                                            null ,
                                            new []  { "Field", "Value" },
                                            null,
                                            narrativeQuantityToDispense
                                        ) : null,
                                narrativePBSExtemporaneousIngredient.Any() ? PopulateTable
                                        (
                                            "PBS Extemporaneous Ingredient",
                                            null ,
                                            new []  { "Ingredient Name", "Ingredient Quantity" },
                                            null,
                                            narrativePBSExtemporaneousIngredient
                                        ) : null,
                                narrativeAdministrationDetails.Any() ? PopulateTable
                                        (
                                            "Administration Details",
                                            null ,
                                            new []  { "Field", "Value" },
                                            null,
                                            narrativeAdministrationDetails
                                        ) : null,
                                narrativeEntitlements.Any() ?  PopulateTable
                                        (
                                            "Entitlements",
                                            null,
                                            new []  { "Entitlements", "ResultValue" },
                                            null,
                                            narrativeEntitlements
                                        ) : null
                           }
                );
          }

          var strucDocText = new StrucDocText();

          if (strucDocTableList.Count > 0)
          {
            strucDocText.table = strucDocTableList.ToArray();
          }

          return strucDocText;
        }

        /// <summary>
        /// Create a Narrative for an DispenseItemATS
        /// </summary>
        /// <param name="item">A DispenseItemATS</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(DispenseItem item)
        {
          var strucDocTableList = new List<StrucDocTable>();
          var narrative = new List<List<String>>();
          var narrativeQuantityToDispense = new List<List<String>>();
          var narrativePBSExtemporaneousIngredient = new List<List<String>>();

          if (item != null)
          {

            // Status Code
            if (item.StatusCode != StatusCode.Undefined)
              narrative.Add
                  (
                      CreateNarrativeEntry("Status", item.StatusCode.ToString())
                  );

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

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

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

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

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

            if (item.QuantityToDispense != null)
            {
              //QuantityToDispense - Quantity
              if (item.QuantityToDispense.Quantity != null)
                narrativeQuantityToDispense.Add
                   (
                       CreateNarrativeEntry("Quantity", item.QuantityToDispense.Quantity.NarrativeText)
                   );

              //QuantityToDispense - Dispensing Unit
              if (item.QuantityToDispense.Unit != null)
                narrativeQuantityToDispense.Add
                   (
                       CreateNarrativeEntry("Dispensing Unit", item.QuantityToDispense.Unit.NarrativeText)
                   );

              //QuantityToDispense - QuantityDescription
              if (!item.QuantityToDispense.QuantityDescription.IsNullOrEmptyWhitespace())
                narrativeQuantityToDispense.Add
                   (
                       CreateNarrativeEntry("Quantity Description", item.QuantityToDispense.QuantityDescription)
                   );
            }

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

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

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

            // PBS Close the Gap Benefit
            if (item.PBSCloseTheGapBenefit != null)
              narrative.Add
                 (
                     CreateNarrativeEntry("PBS Close the Gap Benefit", item.PBSCloseTheGapBenefit.NarrativeText)
                 );

            // PBS/RPBS Item Code
            if (item.PBSRPBSItemCode != null)
              narrative.Add
                 (
                     CreateNarrativeEntry("PBS/RPBS Item Code", item.PBSRPBSItemCode.NarrativeText)
                 );

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

            // Claim Category Type
            if (item.ClaimCategoryType != ClaimCategoryType.Undefined)
              narrative.Add
                 (
                     CreateNarrativeEntry("Claim Category Type", item.ClaimCategoryType.GetAttributeValue<NameAttribute, String>(x => x.Name))
                 );

            // Claim Category Type
            if (item.UnderCoPayment != ClaimCategoryType.Undefined)
              narrative.Add
                 (
                     CreateNarrativeEntry("Under Co-payment", item.UnderCoPayment.GetAttributeValue<NameAttribute, String>(x => x.Name))
                 );


            // Claim Category Type
            if (item.EarySupplyWithPharmaceuticalBenefit.HasValue)
              narrative.Add
                 (
                     CreateNarrativeEntry("Early Supply With Pharmaceutical Benefit", item.EarySupplyWithPharmaceuticalBenefit.Value.ToString(CultureInfo.InvariantCulture))
                 );

            // PBS/RPBS Manufacturer Code
            if (item.PBSExtemporaneousIngredient != null)
            {
              for (int index = 0; index < item.PBSExtemporaneousIngredient.Count; index++)
              {
                var extemporaneousIngredient = item.PBSExtemporaneousIngredient[index];

                if (extemporaneousIngredient != null && extemporaneousIngredient.IngredientName != null || extemporaneousIngredient.IngredientQuantity != null)
                  narrativePBSExtemporaneousIngredient.Add
                  (
                    CreateNarrativeEntry(extemporaneousIngredient.IngredientQuantity != null ? extemporaneousIngredient.IngredientQuantity.NarrativeText : null,
                                        extemporaneousIngredient.IngredientName != null ? extemporaneousIngredient.IngredientName.NarrativeText : null)
                  );
              }
            }

            // Additional Comments
            if (!item.AdditionalComments.IsNullOrEmptyWhitespace())
              narrative.Add
                 (
                     CreateNarrativeEntry("Additional CommentsA", item.AdditionalComments)
                 );

            strucDocTableList.AddRange
                (
                   new List<StrucDocTable>
                           {
                                narrative.Any() ? PopulateTable
                                        (
                                            "Prescription Item",
                                            null ,
                                            new []  { "Field", "Value" },
                                            null,
                                            narrative
                                        ) : null,
                                narrativeQuantityToDispense.Any() ? PopulateTable
                                        (
                                            "Quantity To Dispense",
                                            null ,
                                            new []  { "Field", "Value" },
                                            null,
                                            narrativeQuantityToDispense
                                        ) : null,
                                narrativePBSExtemporaneousIngredient.Any() ? PopulateTable
                                        (
                                            "PBS Extemporaneous Ingredient",
                                            null ,
                                            new []  { "Ingredient Name", "Ingredient Quantity" },
                                            null,
                                            narrativePBSExtemporaneousIngredient
                                        ) : null
                           }
                );
          }

          var strucDocText = new StrucDocText();

          if (strucDocTableList.Count > 0)
          {
            strucDocText.table = strucDocTableList.ToArray();
          }

          return strucDocText;
        }
        #endregion  

        /// <summary>
        /// Returns narrative text for list of times
        /// </summary>
        /// <param name="listTime">A list of time </param>
        /// <returns>A narrative text describing the list of times</returns>
        public string CreateTimingEntry(List<ITime> listTime)
        {
          return listTime.Aggregate(string.Empty, (current, time) => current + (time.NarrativeText() + DELIMITERBREAK));
        }

        /// <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();
          var strucDocTableList = new List<StrucDocTable>();
          var header = new[] { "Field", "Value" };
          var narrativeLink = new List<List<object>>();


          var count = 0;

          if (pharmaceuticalBenefitItems != null && pharmaceuticalBenefitItems.PharmaceuticalBenefitItemList != null)
          foreach (var pharmaceuticalBenefitItem in pharmaceuticalBenefitItems.PharmaceuticalBenefitItemList)
          {
            var narrative = new List<List<String>>();

            count++;

            if (pharmaceuticalBenefitItem != null)
            {
              // PBS/RPBS Item Code
              if (pharmaceuticalBenefitItem.PBSRPBSItemCode != null)
                narrative.Add
                  (
                    new List<String>
                        {
                          "PBS/RPBS Item Code",
                          pharmaceuticalBenefitItem.PBSRPBSItemCode
                        }
                  );

              // PBS/RPBS Manufacturer Code
              if (pharmaceuticalBenefitItem.PBSRPBSManufacturerCode != null)
                narrative.Add
                  (
                    new List<String>
                        {
                          "PBS/RPBS Manufacturer Code",
                          pharmaceuticalBenefitItem.PBSRPBSManufacturerCode
                        }
                  );

              // Brand (Pharmaceutical Item Brand)
              if (pharmaceuticalBenefitItem.Brand != null)
                narrative.Add
                  (
                    new List<String>
                        {
                          "Brand (Pharmaceutical Item Brand)",
                          pharmaceuticalBenefitItem.Brand
                        }
                  );

              // Item Generic Name (Pharmaceutical Item Generic Name)
              if (pharmaceuticalBenefitItem.ItemGenericName != null)
                narrative.Add
                  (
                    new List<String>
                        {
                          "Item Generic Name (Pharmaceutical Item Generic Name)",
                          pharmaceuticalBenefitItem.ItemGenericName
                        }
                  );

              // Item Form and Strength (Pharmaceutical Item Form and Strength)
              if (pharmaceuticalBenefitItem.ItemFormAndStrength != null)
                narrative.Add
                  (
                    new List<String>
                        {
                          "Item Form and Strength (Pharmaceutical Item Form and Strength)",
                          pharmaceuticalBenefitItem.ItemFormAndStrength
                        }
                  );

              // Date of Supply
              if (pharmaceuticalBenefitItem.DateOfSupply != null)
                narrative.Add
                  (
                    new List<String>
                        {
                          "Date of Supply",
                          pharmaceuticalBenefitItem.DateOfSupply.NarrativeText()
                        }
                  );

              // Date Of Prescribing
              if (pharmaceuticalBenefitItem.DateOfPrescribing != null)
                narrative.Add
                  (
                    new List<String>
                        {
                          "Date Of Prescribing",
                          pharmaceuticalBenefitItem.DateOfPrescribing.NarrativeText()
                        }
                  );

              // Quantity
              if (pharmaceuticalBenefitItem.Quantity.HasValue)
                narrative.Add
                  (
                    new List<String>
                        {
                          "Quantity",
                          pharmaceuticalBenefitItem.Quantity.Value.ToString(CultureInfo.InvariantCulture)
                        }
                  );

              // Number of Repeats
              if (pharmaceuticalBenefitItem.NumberOfRepeats.HasValue)
                narrative.Add
                  (
                    new List<String>
                        {
                          "Number of Repeats",
                          pharmaceuticalBenefitItem.NumberOfRepeats.Value.ToString(CultureInfo.InvariantCulture)
                        }
                  );

              strucDocTableList.Add
                (
                  PopulateTable
                    (
                      string.Format("Pharmaceutical Benefit Item {0}", count.ToString(CultureInfo.InvariantCulture)),
                      null,
                      header,
                      null,
                      narrative
                    )
                );
            }
          }

          // Record Link
          if (pharmaceuticalBenefitItems.PharmaceuticalBenefitItemsDocumentProvenanceLink != null)
          {
            narrativeLink.Add(
                         new List<object>{
                                   "Pharmaceutical Benefit Items Document",
                                   CreateLink(pharmaceuticalBenefitItems.PharmaceuticalBenefitItemsDocumentProvenanceLink)
                               });

            strucDocTableList.Add
              (
                PopulateTable
                  (
                    "Pharmaceutical Benefit Items Document Provenance Link",
                    null,
                    header,
                    null,
                    narrativeLink
                  )
              );
          }
          strucDocText.table = strucDocTableList.ToArray();
          return strucDocText;
        }

        /// <summary>
        /// Create a Narrative for an prescriberInstructionDetail Section
        /// </summary>
        /// <param name="prescriberInstructionDetail">A prescriberInstructionDetail</param>
        /// <param name="participationPrescriber">A IParticipationPrescriber</param>
        /// <param name="participationPrescriberOrganisation">A IParticipationPrescriberOrganisation</param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(
                PrescriberInstructionDetail prescriberInstructionDetail,
                IParticipationPrescriber participationPrescriber,
                IParticipationPrescriberOrganisation participationPrescriberOrganisation
        )
        {
          var strucDocTableList = new List<StrucDocTable>();
          var narrative = new List<List<String>>();

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

            if (prescriberInstructionDetail.PrescriberInstructionReceived != null)
              narrative.Add
                  (
                  CreateNarrativeEntry("Date and Time Prescriber Instruction Received", prescriberInstructionDetail.PrescriberInstructionReceived)
                  );

            if (!String.IsNullOrEmpty(prescriberInstructionDetail.PrescriberInstruction))
              narrative.Add
                  (
                  CreateNarrativeEntry("Prescriber Instruction", prescriberInstructionDetail.PrescriberInstruction)
                  );

            if (prescriberInstructionDetail.PrescriberInstructionSource != PrescriberInstructionSource.Undefined)
              narrative.Add
                  (
                  CreateNarrativeEntry("Prescriber Instruction Source", prescriberInstructionDetail.PrescriberInstructionSource.GetAttributeValue<NameAttribute, String>(x => x.Name))
                  );

            if (prescriberInstructionDetail.PrescriberInstructionCommunicationMedium != PrescriberInstructionCommunicationMedium.Undefined)
              narrative.Add
                  (
                  CreateNarrativeEntry("Prescriber Instruction Communication Medium", prescriberInstructionDetail.PrescriberInstructionCommunicationMedium.GetAttributeValue<NameAttribute, String>(x => x.Name))
                  );

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


            // Prescriber Instruction Detail
            if (prescriberInstructionDetail.PrescriberInstructionRecipient != null &&
                prescriberInstructionDetail.PrescriberInstructionRecipient.Participant != null &&
                prescriberInstructionDetail.PrescriberInstructionRecipient.Participant.Person.PersonNames != null)
            {
              var participant = prescriberInstructionDetail.PrescriberInstructionRecipient.Participant;

              columnHeaders = new List<string>
                                            {
                                                "Provider Person Name",
                                                "Provider Role",
                                                "Qualifications",
                                                "Address/Contact"
                                            };

              // Add narrative
              narrative = new List<List<string>>();
              narrative.Add(
                  new List<String>
                            {
                                participant.Person.PersonNames == null ? null :  BuildPersonNames(participant.Person.PersonNames),
                                "Pharmacist",
                                // Fixed as per Spec
                                participant.Person.Qualifications,      
                                CreateAddress(participant.Addresses, participant.ElectronicCommunicationDetails)

                            }
                  );

              strucDocTableList.Add
                  (
                  PopulateTable
                      (
                      "Prescriber Instruction Detail",
                      null,
                      columnHeaders.ToArray(),
                      null,
                      narrative
                      )
                  );
            }

            // Prescriber
            if (participationPrescriber != null && participationPrescriber.Participant != null &&
                participationPrescriber.Participant.Person != null)
            {
              var participant = participationPrescriber.Participant;

              columnHeaders = new List<string>
                                            {
                                                "Provider Person Name",
                                                "Provider Role",
                                                "Entitlements",
                                                "Address/Contact"

                                            };

              // Add narrative
              narrative = new List<List<string>>();
              narrative.Add(
                  new List<String>
                            {
                                participant.Person == null ? null : BuildPersonNames(participant.Person.PersonNames),
                                participationPrescriber.Role != null ? participationPrescriber.Role.NarrativeText : String.Empty,
                                // Fixed as per Spec
                                participant.Person != null && participant.Person.Entitlements != null && participant.Person.Entitlements.Count > 0 ? CreateEntitlement(participant.Person.Entitlements) : String.Empty,
                                CreateAddress(participant.Addresses, participant.ElectronicCommunicationDetails),
                                //participationPrescriber.Participant.Person.Occupation != null ? participationPrescriber.Participant.Person.Occupation.Value.GetAttributeValue<NameAttribute, String>(x => x.Name) : String.Empty,
                                //participationPrescriber.Participant.Person.Qualifications
                            }
                  );

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

            // Prescriber Organisation
            if (participationPrescriberOrganisation != null && participationPrescriberOrganisation.Participant != null)
            {
              var participant = participationPrescriberOrganisation.Participant;

              columnHeaders = new List<string>
                                        {
                                            "Organisation Role",
                                            "Address/Contact",
                                            "Organisation Name",
                                            "Organisation Name Usage",
                                            "Department/Unit"
                                        };

              IOrganisation organisation = null;
              if (participationPrescriberOrganisation.Participant.Organisation != null)
                organisation = participationPrescriberOrganisation.Participant.Organisation;

              // Add narrative
              narrative = new List<List<string>>();
              narrative.Add(
                  new List<String>
                            {
                                participationPrescriberOrganisation.Role != null ? participationPrescriberOrganisation.Role.NarrativeText : String.Empty,
                                // Fixed as per Spec
                                CreateAddress(participant.Addresses, participant.ElectronicCommunicationDetails),
                                organisation != null ? organisation.Name : String.Empty,
                                organisation != null && organisation.NameUsage != null ? organisation.NameUsage.Value.GetAttributeValue<NameAttribute, String>(x => x.Name) : String.Empty,
                                organisation != null ? participationPrescriberOrganisation.Participant.Organisation.Department : String.Empty
                            }
                  );

              strucDocTableList.Add
                  (
                  PopulateTable
                      (
                      "Prescriber Organisation",
                      null,
                      columnHeaders.ToArray(),
                      null,
                      narrative
                      )
                  );
            }
          }

          var strucDocText = new StrucDocText();

          if (strucDocTableList.Count > 0)
          {
            strucDocText.table = strucDocTableList.ToArray();
          }
          else
          {
            strucDocText.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
          }

          return strucDocText;
        }

        /// <summary>
        /// Create a Narrative for an PrescriptionRequestItem Section
        /// </summary>
        /// <param name="item">The PrescriptionRequestItem</param>
        /// <param name="subjectOfCare">The subjectOfCare</param>
        /// <param name="dispenserOrganisation">The dispenser Organisation</param>
        /// <param name="requesterNote">The requesterNote </param>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(PrescriptionRequestItem item, IParticipationSubjectOfCare subjectOfCare, IParticipationDispenserOrganisation dispenserOrganisation, String requesterNote)
        {
          var strucDocTableList = new List<StrucDocTable>();
          var narrative = new List<List<String>>();
          var narrativeTiming = new List<List<String>>();
          var narrativeAdministrationDetails = new List<List<String>>();
          var narrativeStructuredDose = new List<List<String>>();
          var narrativeQuantityToDispense = new List<List<String>>();
          var narrativePBSExtemporaneousIngredient = new List<List<String>>();
          var narrativeEntitlements = new List<List<String>>();

          if (item != null)
          {

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

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

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

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

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

            if (item.StructuredDose != null)
            {
              //Quantity of Therapeutic Good
              if (item.StructuredDose.Quantity != null)
                narrativeStructuredDose.Add
                   (
                       CreateNarrativeEntry("Quantity", item.StructuredDose.Quantity.NarrativeText)
                   );

              //Structured Dose - Dose Unit
              if (item.StructuredDose.Unit != null)
                narrativeStructuredDose.Add
                   (
                       CreateNarrativeEntry("Dose Unit", item.StructuredDose.Unit.NarrativeText)
                   );

              //Structured Dose - Quantity Description
              if (item.StructuredDose.QuantityDescription != null)
                narrativeStructuredDose.Add
                   (
                       CreateNarrativeEntry("Quantity Description", item.StructuredDose.QuantityDescription)
                   );
            }

            if (item.Timing != null)
            {
              //Timing
              if (!item.Timing.TimingDescription.IsNullOrEmptyWhitespace())
                narrativeTiming.Add
                   (
                       CreateNarrativeEntry("TimingDescription", item.Timing.TimingDescription)
                   );

              //Structured Timing EffectiveTime
              if (item.Timing.StructuredTiming != null && item.Timing.StructuredTiming.EffectiveTime != null)
              {

                if (!item.Timing.StructuredTiming.NarrativeText.IsNullOrEmptyWhitespace())
                {

                  narrativeTiming.Add
                     (
                         CreateNarrativeEntry("EffectiveTime", item.Timing.StructuredTiming.NarrativeText)
                     );

                }
                else
                {
                  //Structured Timing EffectiveTime
                  narrativeTiming.Add
                      (
                        new List<string>
                        {
                          "EffectiveTime",
                          CreateTimingEntry(item.Timing.StructuredTiming.EffectiveTime)
                        }
                    );
                }
              }

              //PRN
              if (item.Timing.PRN.HasValue)
                narrativeTiming.Add
                   (
                       CreateNarrativeEntry("PRN", item.Timing.PRN.Value.ToString(CultureInfo.InvariantCulture))
                   );

              //Timing - StartCriterion
              if (item.Timing.StartCriterion.HasValue)
                narrativeTiming.Add
                   (
                       CreateNarrativeEntry("StartCriterion", item.Timing.StartCriterion.Value.ToString(CultureInfo.InvariantCulture))
                   );

              //Timing - StartDate
              if (item.Timing.StartDate != null)
                narrativeTiming.Add
                   (
                       CreateNarrativeEntry("StartDate", item.Timing.StartDate)
                   );

              //Timing - StopCriterion
              if (item.Timing.StopCriterion.HasValue)
                narrativeTiming.Add
                   (
                       CreateNarrativeEntry("StopCriterion", item.Timing.StopCriterion.Value.ToString(CultureInfo.InvariantCulture))
                   );

              //Timing - StopDate
              if (item.Timing.StopDate != null)
                narrativeTiming.Add
                   (
                       CreateNarrativeEntry("StopDate", item.Timing.StopDate)
                   );

              if (item.Timing.NumberOfAdministrations != null)
              {
                var numberOfAdministrations = string.Empty;

                //Timing - Number of Administrations - Numerator
                if (item.Timing.NumberOfAdministrations.NullFlavor != null)
                  numberOfAdministrations += item.Timing.NumberOfAdministrations.NullFlavor.Value.GetAttributeValue<NameAttribute, String>(x => x.Name) + " ";

                //Timing - Number of Administrations - Denominator
                if (item.Timing.NumberOfAdministrations.Denominator != null)
                  numberOfAdministrations += item.Timing.NumberOfAdministrations.Denominator.NarrativeText;

                //Timing - Number of Administrations - Numerator
                if (item.Timing.NumberOfAdministrations.Numerator != null)
                {
                  if (!numberOfAdministrations.IsNullOrEmptyWhitespace())
                    numberOfAdministrations += " - ";

                  numberOfAdministrations += item.Timing.NumberOfAdministrations.Numerator.NarrativeText + " ";
                }

                if (!numberOfAdministrations.IsNullOrEmptyWhitespace())
                  narrativeTiming.Add
                     (
                         CreateNarrativeEntry("Number of Administrations", numberOfAdministrations)
                     );
              }

              //Timing - LongTerm
              if (item.Timing.LongTerm.HasValue)
                narrativeTiming.Add
                   (
                       CreateNarrativeEntry("Long-Term", item.Timing.LongTerm.Value.ToString(CultureInfo.InvariantCulture))
                   );
            }

            if (item.AdministrationDetails != null)
            {
              //AdministrationDetails - Route
              if (item.AdministrationDetails.Route != null)
                narrativeAdministrationDetails.Add
                   (
                       CreateNarrativeEntry("Route", item.AdministrationDetails.Route.NarrativeText)
                   );

              //AdministrationDetails - AnatomicalSite
              if (item.AdministrationDetails.AnatomicalSite != null)
                narrativeAdministrationDetails.Add
                   (
                       CreateNarrativeEntry("AnatomicalSite", item.AdministrationDetails.AnatomicalSite.NarrativeText)
                   );

              //AdministrationDetails - MedicationDeliveryMethod
              if (item.AdministrationDetails.MedicationDeliveryMethod != null)
                narrativeAdministrationDetails.Add
                   (
                       CreateNarrativeEntry("Medication Delivery Method", item.AdministrationDetails.MedicationDeliveryMethod.NarrativeText)
                   );
            }

            if (item.QuantityToDispense != null)
            {
              //QuantityToDispense - Quantity
              if (item.QuantityToDispense.Quantity != null)
                narrativeQuantityToDispense.Add
                   (
                       CreateNarrativeEntry("Quantity", item.QuantityToDispense.Quantity.NarrativeText)
                   );

              //QuantityToDispense - Dispensing Unit
              if (item.QuantityToDispense.Unit != null)
                narrativeQuantityToDispense.Add
                   (
                       CreateNarrativeEntry("Dispensing Unit", item.QuantityToDispense.Unit.NarrativeText)
                   );

              //QuantityToDispense - QuantityDescription
              if (!item.QuantityToDispense.QuantityDescription.IsNullOrEmptyWhitespace())
                narrativeQuantityToDispense.Add
                   (
                       CreateNarrativeEntry("Quantity Description", item.QuantityToDispense.QuantityDescription)
                   );
            }

            //Brand Substitute Allowed
            if (item.BrandSubstituteAllowed != null)
              narrative.Add
                 (
                     CreateNarrativeEntry("Brand Substitute Allowed", item.BrandSubstituteAllowed)
                 );

            // PBS Prescription Type
            if (item.PBSPrescriptionType.HasValue)
              narrative.Add
                 (
                     CreateNarrativeEntry("PBS Prescription Type", item.PBSPrescriptionType.Value.GetAttributeValue<NameAttribute, String>(x => x.Name))
                 );

            // Medical Benefit Category Type
            if (item.MedicalBenefitCategoryType.HasValue && item.MedicalBenefitCategoryType.Value != MedicalBenefitCategoryType.Undefined)
              narrative.Add
                 (
                     CreateNarrativeEntry("Medical Benefit Category Type", item.MedicalBenefitCategoryType.GetAttributeValue<NameAttribute, String>(x => x.Name))
                 );

            // PBS Close the Gap Benefit
            if (item.PBSCloseTheGapBenefit != null)
              narrative.Add
                 (
                     CreateNarrativeEntry("PBS Close the Gap Benefit", item.PBSCloseTheGapBenefit.NarrativeText)
                 );

            // PBS/RPBS Item Code
            if (item.PBSRPBSItemCode != null)
              narrative.Add
                 (
                     CreateNarrativeEntry("PBS/RPBS Item Code", item.PBSRPBSItemCode.NarrativeText)
                 );

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


            // PBS/RPBS Manufacturer Code
            if (item.PBSExtemporaneousIngredient != null)
            {
              for (int index = 0; index < item.PBSExtemporaneousIngredient.Count; index++)
              {
                var extemporaneousIngredient = item.PBSExtemporaneousIngredient[index];

                if (extemporaneousIngredient != null && extemporaneousIngredient.IngredientName != null || extemporaneousIngredient.IngredientQuantity != null)
                  narrativePBSExtemporaneousIngredient.Add
                  (
                    CreateNarrativeEntry(extemporaneousIngredient.IngredientQuantity != null ? extemporaneousIngredient.IngredientQuantity.NarrativeText : null,
                                        extemporaneousIngredient.IngredientName != null ? extemporaneousIngredient.IngredientName.NarrativeText : null)
                  );

              }
            }

            // PBS/RPBS Authority Prescription Number
            if (!item.PBSRPBSAuthorityPrescriptionNumber.IsNullOrEmptyWhitespace())
              narrative.Add
                 (
                     CreateNarrativeEntry("PBS/RPBS Authority Prescription Number", item.PBSRPBSAuthorityPrescriptionNumber)
                 );

            // PBS/RPBS Authority Approval Number
            if (!item.PBSRPBSAuthorityApprovalNumber.IsNullOrEmptyWhitespace())
              narrative.Add
                 (
                     CreateNarrativeEntry("PBS/RPBS Authority Approval Number", item.PBSRPBSAuthorityApprovalNumber)
                 );


            // Streamlined Authority Approval Number
            if (!item.StreamlinedAuthorityApprovalNumber.IsNullOrEmptyWhitespace())
              narrative.Add
                 (
                     CreateNarrativeEntry("Streamlined Authority Approval Number", item.StreamlinedAuthorityApprovalNumber)
                 );

            // State Authority Number
            if (item.StateAuthorityNumber != null)
              narrative.Add
                 (
                     CreateNarrativeEntry("State Authority Number", item.StateAuthorityNumber.NarrativeText)
                 );


            // Additional Comments
            if (!item.AdditionalComments.IsNullOrEmptyWhitespace())
              narrative.Add
                 (
                     CreateNarrativeEntry("Additional Comments", item.AdditionalComments)
                 );

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


            // The Prescription Note
            if (!requesterNote.IsNullOrEmptyWhitespace())
            {
              narrative.Add
                      (
                          CreateNarrativeEntry("Requester Note", requesterNote)
                      );

            }

            // Entitilements Subject Of Care
            if (subjectOfCare.Participant.Entitlements != null && subjectOfCare.Participant.Entitlements.Count > 0)
            {
              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
                  };
                }

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

            // Entitilements Prescriber
            if (dispenserOrganisation.Participant.Entitlements != null && dispenserOrganisation.Participant.Entitlements.Count > 0)
            {
              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
                  };
                }

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

            strucDocTableList.AddRange
                (
                   new List<StrucDocTable>
                           {
                                narrative.Any() ? PopulateTable
                                        (
                                            "Prescription Item",
                                            null ,
                                            new []  { "Field", "Value" },
                                            null,
                                            narrative
                                        ) : null,
                                narrativeTiming.Any() ? PopulateTable
                                        (
                                            "Timing",
                                            null ,
                                            new []  { "Field", "Value" },
                                            null,
                                            narrativeTiming
                                        ): null,
                                narrativeStructuredDose.Any() ? PopulateTable
                                        (
                                            "Structured Dose",
                                            null ,
                                            new []  { "Field", "Value" },
                                            null,
                                            narrativeStructuredDose
                                        ) : null,
                                narrativeQuantityToDispense.Any() ? PopulateTable
                                        (
                                            "Quantity To Dispense",
                                            null ,
                                            new []  { "Field", "Value" },
                                            null,
                                            narrativeQuantityToDispense
                                        ) : null,
                                narrativePBSExtemporaneousIngredient.Any() ? PopulateTable
                                        (
                                            "PBS Extemporaneous Ingredient",
                                            null ,
                                            new []  { "Ingredient Name", "Ingredient Quantity" },
                                            null,
                                            narrativePBSExtemporaneousIngredient
                                        ) : null,
                                narrativeAdministrationDetails.Any() ? PopulateTable
                                        (
                                            "Administration Details",
                                            null ,
                                            new []  { "Field", "Value" },
                                            null,
                                            narrativeAdministrationDetails
                                        ) : null,
                                narrativeEntitlements.Any() ?  PopulateTable
                                        (
                                            "Entitlements",
                                            null,
                                            new []  { "Entitlements", "ResultValue" },
                                            null,
                                            narrativeEntitlements
                                        ) : null
                           }
                );
          }

          var strucDocText = new StrucDocText();

          if (strucDocTableList.Count > 0)
          {
            strucDocText.table = strucDocTableList.ToArray();
          }

          return strucDocText;
        }


        private StrucDocLinkHtml CreateLink(Link link)
        {
          var stackTrace = new StackTrace();
          // For now only show PCEHRAssignedIdentifierRepository POCD_MT000040Reference for MedicareOverview.
          // This code will be removed when the Medicare Information View IG guides is updated.
          bool mdicareInformationView = stackTrace.GetFrame(3).GetMethod().Name.Contains(CDADocumentType.MedicareOverview.ToString());

          var extentionIdentifier = "^";
          if (mdicareInformationView)
          {
            extentionIdentifier = ":";
          }

          return new StrucDocLinkHtml
                   {
                     ID = link.id.ToString(),
                     Text = new[] { link.TemplateId.GetAttributeValue<NameAttribute, string>(x => x.Title) },
                     href = string.Format("pcehr:{0}/{1}{2}",
                                          link.RepositoryIdentifier,
                                          link.DocumentIdentifier,
                                          link.DocumentIdentifierExtension.IsNullOrEmptyWhitespace()
                                          ? string.Empty
                                          : extentionIdentifier + link.DocumentIdentifierExtension)
                   };
        }


        #endregion

        #region Physical Measurements

        /// <summary>
        /// Physical Measurements
        /// </summary>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(PhysicalMeasurement physicalMeasurement)
        {
          var strucDocTableList = new List<StrucDocTable>();

          if (physicalMeasurement != null)
          {

           if (physicalMeasurement.HeadCircumference != null)
           {
            var headCircumferenceNarrative =  new List<List<String>>();

            // Body Part Circumference Date Time
            if (physicalMeasurement.HeadCircumference.BodyPartCircumferenceDateTime != null)
            {
              headCircumferenceNarrative.Add
                  (
                      CreateNarrativeEntry("Body Part Circumference DateTime", physicalMeasurement.HeadCircumference.BodyPartCircumferenceDateTime)
                  );
            }

            // Name Of Location
            if (physicalMeasurement.HeadCircumference.NameOfLocation != null)
            {
              headCircumferenceNarrative.Add
                  (
                      CreateNarrativeEntry("Name Of Location", physicalMeasurement.HeadCircumference.NameOfLocation.NarrativeText)
                  );
            }

            // Circumference
            if (physicalMeasurement.HeadCircumference.Circumference != null)
            {
              headCircumferenceNarrative.Add
                  (
                      CreateNarrativeEntry("Circumference", physicalMeasurement.HeadCircumference.Circumference.NarrativeText)
                  );
            }

            // Circumference Normal Status
            if (physicalMeasurement.HeadCircumference.CircumferenceNormalStatus != null)
            {
              headCircumferenceNarrative.Add
                  (
                      CreateNarrativeEntry("Circumference Normal Status", physicalMeasurement.HeadCircumference.CircumferenceNormalStatus.Value.GetAttributeValue<NameAttribute, string>(x => x.Name) )
                  );
            }

            // Circumference Reference Range Details
            if (physicalMeasurement.HeadCircumference.CircumferenceReferenceRangeDetails != null && physicalMeasurement.HeadCircumference.CircumferenceReferenceRangeDetails .Any())
            {
              var narrativeText = physicalMeasurement.HeadCircumference.CircumferenceReferenceRangeDetails.Aggregate(string.Empty, (current, circumferenceReferenceRangeDetails) => current + DELIMITERBREAK + circumferenceReferenceRangeDetails.NarrativeText);

              headCircumferenceNarrative.Add
                  (
                      CreateNarrativeEntry("Circumference Reference Range Details", narrativeText )
                  );
            }

            // Comment (Measurement Comment)
            if (physicalMeasurement.HeadCircumference.Comment != null)
            {
              headCircumferenceNarrative.Add
                  (
                      CreateNarrativeEntry("Comment (Measurement Comment)", physicalMeasurement.HeadCircumference.Comment )
                  );
            }

            // Confounding Factor
            if (physicalMeasurement.HeadCircumference.ConfoundingFactor != null && physicalMeasurement.HeadCircumference.ConfoundingFactor.Any())
            {
              var narrativeText = physicalMeasurement.HeadCircumference.ConfoundingFactor.Aggregate(string.Empty, (current, confoundingFactor) => current + (DELIMITERBREAK + confoundingFactor.NarrativeText));

              headCircumferenceNarrative.Add
                  (
                      CreateNarrativeEntry("Confounding Factor", narrativeText )
                  );
            }

            // Information Provider
            if (physicalMeasurement.HeadCircumference.InformationProvider != null)
            {
              headCircumferenceNarrative.Add
                  (
                      CreateNarrativeEntry("Information Provider", CreateInformationProvider(physicalMeasurement.HeadCircumference.InformationProvider))
                  );
            }

            if (physicalMeasurement.HeadCircumference.Device != null)
              headCircumferenceNarrative.Add
                  (
                      CreateNarrativeEntry("Device", string.Format("{0}", physicalMeasurement.HeadCircumference.Device.SoftwareName))
                  );

            strucDocTableList.AddRange
               (
                 new List<StrucDocTable>
                   {
                     headCircumferenceNarrative.Any()
                       ? PopulateTable
                           (
                             "Head Circumference (BODY PART CIRCUMFERENCE)",
                             null,
                             new[] {"Field", "Value"},
                             null,
                             headCircumferenceNarrative
                           )
                       : null,
                   }
               );
            }

           if (physicalMeasurement.PhysicalMeasurementBodyWeight != null)
           {
             var physicalMeasurementBodyWeightNarrative = new List<List<String>>();

             // Body Weight DateTime
             if (physicalMeasurement.PhysicalMeasurementBodyWeight.BodyWeightDateTime != null)
             {
               physicalMeasurementBodyWeightNarrative.Add
                   (
                       CreateNarrativeEntry("Body Weight DateTime", physicalMeasurement.PhysicalMeasurementBodyWeight.BodyWeightDateTime)
                   );
             }

             // Weight
             if (physicalMeasurement.PhysicalMeasurementBodyWeight.Weight != null)
             {
               physicalMeasurementBodyWeightNarrative.Add
                   (
                       CreateNarrativeEntry("Weight", physicalMeasurement.PhysicalMeasurementBodyWeight.Weight.NarrativeText)
                   );
             }

             // Weight Normal Status
             if (physicalMeasurement.PhysicalMeasurementBodyWeight.WeightNormalStatus != null)
             {
               physicalMeasurementBodyWeightNarrative.Add
                   (
                       CreateNarrativeEntry("Weight Normal Status", physicalMeasurement.PhysicalMeasurementBodyWeight.WeightNormalStatus.Value.GetAttributeValue<NameAttribute, string>(x => x.Name))
                   );
             }

             // Weight Reference Range Details
             if (physicalMeasurement.PhysicalMeasurementBodyWeight.WeightReferenceRangeDetails != null && physicalMeasurement.PhysicalMeasurementBodyWeight.WeightReferenceRangeDetails.Any())
             {
               var narrativeText = physicalMeasurement.PhysicalMeasurementBodyWeight.WeightReferenceRangeDetails.Aggregate(string.Empty, (current, circumferenceReferenceRangeDetails) => current + DELIMITERBREAK + circumferenceReferenceRangeDetails.NarrativeText);

               physicalMeasurementBodyWeightNarrative.Add
                   (
                       CreateNarrativeEntry("Weight Reference Range Details", narrativeText)
                   );
             }

             // Comment (Measurement Comment)
             if (physicalMeasurement.PhysicalMeasurementBodyWeight.Comment != null)
             {
               physicalMeasurementBodyWeightNarrative.Add
                   (
                       CreateNarrativeEntry("Comment (Measurement Comment)", physicalMeasurement.PhysicalMeasurementBodyWeight.Comment)
                   );
             }

             // Weight
             if (physicalMeasurement.PhysicalMeasurementBodyWeight.StateOfDress != null)
             {
               physicalMeasurementBodyWeightNarrative.Add
                   (
                       CreateNarrativeEntry("State Of Dress", physicalMeasurement.PhysicalMeasurementBodyWeight.StateOfDress)
                   );
             }

             // Pregnant?
             if (physicalMeasurement.PhysicalMeasurementBodyWeight.Pregnant != null)
             {
               physicalMeasurementBodyWeightNarrative.Add
                   (
                       CreateNarrativeEntry("Pregnant?", physicalMeasurement.PhysicalMeasurementBodyWeight.Pregnant.ToString())
                   );
             }

             // Confounding Factor
             if (physicalMeasurement.PhysicalMeasurementBodyWeight.ConfoundingFactor != null && physicalMeasurement.PhysicalMeasurementBodyWeight.ConfoundingFactor.Any())
             {
               var narrativeText = physicalMeasurement.PhysicalMeasurementBodyWeight.ConfoundingFactor.Aggregate(string.Empty, (current, confoundingFactor) => current + (DELIMITERBREAK + confoundingFactor.NarrativeText));

               physicalMeasurementBodyWeightNarrative.Add
                   (
                       CreateNarrativeEntry("Confounding Factor", narrativeText)
                   );
             }

             // Weight Estimation Formula
             if (physicalMeasurement.PhysicalMeasurementBodyWeight.WeightEstimationFormula != null)
             {
               physicalMeasurementBodyWeightNarrative.Add
                   (
                       CreateNarrativeEntry("Weight Estimation Formula", physicalMeasurement.PhysicalMeasurementBodyWeight.WeightEstimationFormula)
                   );
             }

             // Body Weight Instance Identifier
             if (physicalMeasurement.PhysicalMeasurementBodyWeight.BodyWeightInstanceIdentifier != null)
             {
               physicalMeasurementBodyWeightNarrative.Add
                   (
                       CreateNarrativeEntry("Body Weight Instance Identifier", physicalMeasurement.PhysicalMeasurementBodyWeight.BodyWeightInstanceIdentifier.NarrativeText)
                   );
             }

             // Information Provider
             if (physicalMeasurement.PhysicalMeasurementBodyWeight.InformationProvider != null)
             {
               physicalMeasurementBodyWeightNarrative.Add
                   (
                       CreateNarrativeEntry("Information Provider", CreateInformationProvider(physicalMeasurement.PhysicalMeasurementBodyWeight.InformationProvider))
                   );
             }

             if (physicalMeasurement.PhysicalMeasurementBodyWeight.Device != null)
               physicalMeasurementBodyWeightNarrative.Add
                   (
                       CreateNarrativeEntry("Device", string.Format("{0}", physicalMeasurement.PhysicalMeasurementBodyWeight.Device.SoftwareName))
                   );

             strucDocTableList.AddRange
                (
                  new List<StrucDocTable>
                   {
                     physicalMeasurementBodyWeightNarrative.Any()
                       ? PopulateTable
                           (
                             "Body Weight",
                             null,
                             new[] {"Field", "Value"},
                             null,
                             physicalMeasurementBodyWeightNarrative
                           )
                       : null,
                   }
                );
           }

           if (physicalMeasurement.PhysicalMeasurementBodyHeightLength != null)
           {
             var physicalMeasurementBodyHeightLengthNarrative = new List<List<String>>();

             // Body Weight DateTime
             if (physicalMeasurement.PhysicalMeasurementBodyHeightLength.BodyHeightLengthDateTime != null)
             {
               physicalMeasurementBodyHeightLengthNarrative.Add
                   (
                       CreateNarrativeEntry("Body Height Length Date Time", physicalMeasurement.PhysicalMeasurementBodyHeightLength.BodyHeightLengthDateTime)
                   );
             }

             // Height/Length
             if (physicalMeasurement.PhysicalMeasurementBodyHeightLength.HeightLength != null)
             {
               physicalMeasurementBodyHeightLengthNarrative.Add
                   (
                       CreateNarrativeEntry("Height/Length", physicalMeasurement.PhysicalMeasurementBodyHeightLength.HeightLength.NarrativeText)
                   );
             }

             // Weight Normal Status
             if (physicalMeasurement.PhysicalMeasurementBodyHeightLength.HeightLengthNormalStatus != null)
             {
               physicalMeasurementBodyHeightLengthNarrative.Add
                   (
                       CreateNarrativeEntry("Height Length Normal Status", physicalMeasurement.PhysicalMeasurementBodyHeightLength.HeightLengthNormalStatus.Value.GetAttributeValue<NameAttribute, string>(x => x.Name))
                   );
             }

             // Height/length Reference Range Details
             if (physicalMeasurement.PhysicalMeasurementBodyHeightLength.HeightLengthReferenceRangeDetails != null && physicalMeasurement.PhysicalMeasurementBodyHeightLength.HeightLengthReferenceRangeDetails.Any())
             {
               var narrativeText = physicalMeasurement.PhysicalMeasurementBodyHeightLength.HeightLengthReferenceRangeDetails.Aggregate(string.Empty, (current, circumferenceReferenceRangeDetails) => current + DELIMITERBREAK + circumferenceReferenceRangeDetails.NarrativeText);

               physicalMeasurementBodyHeightLengthNarrative.Add
                   (
                       CreateNarrativeEntry("Height/length Reference Range Details", narrativeText)
                   );
             }

             // Comment (Measurement Comment)
             if (physicalMeasurement.PhysicalMeasurementBodyHeightLength.Comment != null)
             {
               physicalMeasurementBodyHeightLengthNarrative.Add
                   (
                       CreateNarrativeEntry("Comment (Measurement Comment)", physicalMeasurement.PhysicalMeasurementBodyHeightLength.Comment)
                   );
             }

             // Position
             if (physicalMeasurement.PhysicalMeasurementBodyHeightLength.Position != null)
             {
               physicalMeasurementBodyHeightLengthNarrative.Add
                   (
                       CreateNarrativeEntry("Position", physicalMeasurement.PhysicalMeasurementBodyHeightLength.Position)
                   );
             }

             // Confounding Factor
             if (physicalMeasurement.PhysicalMeasurementBodyHeightLength.ConfoundingFactor != null && physicalMeasurement.PhysicalMeasurementBodyHeightLength.ConfoundingFactor.Any())
             {
               var narrativeText = physicalMeasurement.PhysicalMeasurementBodyHeightLength.ConfoundingFactor.Aggregate(string.Empty, (current, confoundingFactor) => current + (DELIMITERBREAK + confoundingFactor.NarrativeText));

               physicalMeasurementBodyHeightLengthNarrative.Add
                   (
                       CreateNarrativeEntry("Confounding Factor", narrativeText)
                   );
             }

             // Body Weight Instance Identifier
             if (physicalMeasurement.PhysicalMeasurementBodyHeightLength.BodyHeightLengthInstanceIdentifier != null)
             {
               physicalMeasurementBodyHeightLengthNarrative.Add
                   (
                       CreateNarrativeEntry("Body Height Length Instance Identifier", physicalMeasurement.PhysicalMeasurementBodyHeightLength.BodyHeightLengthInstanceIdentifier.NarrativeText)
                   );
             }

             // Information Provider
             if (physicalMeasurement.PhysicalMeasurementBodyHeightLength.InformationProvider != null)
             {
               physicalMeasurementBodyHeightLengthNarrative.Add
                   (
                       CreateNarrativeEntry("Information Provider", CreateInformationProvider(physicalMeasurement.PhysicalMeasurementBodyHeightLength.InformationProvider))
                   );
             }

             if (physicalMeasurement.PhysicalMeasurementBodyHeightLength.Device != null)
               physicalMeasurementBodyHeightLengthNarrative.Add
                   (
                       CreateNarrativeEntry("Device", string.Format("{0}", physicalMeasurement.PhysicalMeasurementBodyHeightLength.Device.SoftwareName))
                   );

             strucDocTableList.AddRange
                (
                  new List<StrucDocTable>
                   {
                     physicalMeasurementBodyHeightLengthNarrative.Any()
                       ? PopulateTable
                           (
                             "Body Height/Length",
                             null,
                             new[] {"Field", "Value"},
                             null,
                             physicalMeasurementBodyHeightLengthNarrative
                           )
                       : null,
                   }
                );
           }

           if (physicalMeasurement.PhysicalMeasurementBodyMassIndex != null)
           {
             var physicalMeasurementBodyMassIndexNarrative = new List<List<String>>();

             // Body Mass Index DateTime
             if (physicalMeasurement.PhysicalMeasurementBodyMassIndex.BodyMassIndexDateTime != null)
             {
               physicalMeasurementBodyMassIndexNarrative.Add
                   (
                       CreateNarrativeEntry("Body Mass Index DateTime", physicalMeasurement.PhysicalMeasurementBodyMassIndex.BodyMassIndexDateTime)
                   );
             }

             // Body Mass Index
             if (physicalMeasurement.PhysicalMeasurementBodyMassIndex.BodyMassIndex != null)
             {
               physicalMeasurementBodyMassIndexNarrative.Add
                   (
                       CreateNarrativeEntry("Body Mass Index", physicalMeasurement.PhysicalMeasurementBodyMassIndex.BodyMassIndex.NarrativeText)
                   );
             }

             // Body Mass Index Normal Status
             if (physicalMeasurement.PhysicalMeasurementBodyMassIndex.BodyMassIndexNormalStatus.HasValue)
             {
               physicalMeasurementBodyMassIndexNarrative.Add
                   (
                       CreateNarrativeEntry("Body Mass Index Normal Status", physicalMeasurement.PhysicalMeasurementBodyMassIndex.BodyMassIndexNormalStatus.Value.GetAttributeValue<NameAttribute, string>(x => x.Name))
                   );
             }

             // Height/length Reference Range Details
             if (physicalMeasurement.PhysicalMeasurementBodyMassIndex.BodyMassIndexReferenceRangeDetails != null && physicalMeasurement.PhysicalMeasurementBodyMassIndex.BodyMassIndexReferenceRangeDetails.Any())
             {
               var narrativeText = physicalMeasurement.PhysicalMeasurementBodyMassIndex.BodyMassIndexReferenceRangeDetails.Aggregate(string.Empty, (current, circumferenceReferenceRangeDetails) => current + DELIMITERBREAK + circumferenceReferenceRangeDetails.NarrativeText);

               physicalMeasurementBodyMassIndexNarrative.Add
                   (
                       CreateNarrativeEntry("Body Mass Index Reference Range Details", narrativeText)
                   );
             }

             // Comment (Measurement Comment)
             if (physicalMeasurement.PhysicalMeasurementBodyMassIndex.Comment != null)
             {
               physicalMeasurementBodyMassIndexNarrative.Add
                   (
                       CreateNarrativeEntry("Comment (Measurement Comment)", physicalMeasurement.PhysicalMeasurementBodyMassIndex.Comment)
                   );
             }

             // Method
             if (physicalMeasurement.PhysicalMeasurementBodyMassIndex.Method != null)
             {
               physicalMeasurementBodyMassIndexNarrative.Add
                   (
                       CreateNarrativeEntry("Method", physicalMeasurement.PhysicalMeasurementBodyMassIndex.Method.NarrativeText)
                   );
             }

             // Formula (BMI Calculation Formula)
             if (physicalMeasurement.PhysicalMeasurementBodyMassIndex.Formula != null)
             {
               physicalMeasurementBodyMassIndexNarrative.Add
                   (
                       CreateNarrativeEntry("Formula (BMI Calculation Formula)", physicalMeasurement.PhysicalMeasurementBodyMassIndex.Formula)
                   );
             }

             // Body Weight Instance Identifier
             if (physicalMeasurement.PhysicalMeasurementBodyMassIndex.BodyMassIndexInstanceIdentifier != null)
             {
               physicalMeasurementBodyMassIndexNarrative.Add
                   (
                       CreateNarrativeEntry("Body Mass Index Instance Identifier", physicalMeasurement.PhysicalMeasurementBodyMassIndex.BodyMassIndexInstanceIdentifier.NarrativeText)
                   );
             }

             // Information Provider
             if (physicalMeasurement.PhysicalMeasurementBodyMassIndex.InformationProvider != null)
             {
               physicalMeasurementBodyMassIndexNarrative.Add
                   (
                       CreateNarrativeEntry("Information Provider", CreateInformationProvider(physicalMeasurement.PhysicalMeasurementBodyMassIndex.InformationProvider))
                   );
             }

             strucDocTableList.AddRange
                (
                  new List<StrucDocTable>
                   {
                     physicalMeasurementBodyMassIndexNarrative.Any()
                       ? PopulateTable
                           (
                             "Body Mass Index",
                             null,
                             new[] {"Field", "Value"},
                             null,
                             physicalMeasurementBodyMassIndexNarrative
                           )
                       : null,
                   }
                );
            }
          }

          var strucDocText = new StrucDocText();

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

        /// <summary>
        /// Physical Measurements
        /// </summary>
        /// <param name="informationProvider">Physical Measurements</param>
        /// <returns>StrucDocText</returns>
        public string CreateInformationProvider(IInformationProviderCollection informationProvider)
        {               
            string narrativeText = string.Empty;
            if (informationProvider != null)
            {
              if (informationProvider is Device)
              {
                var device = informationProvider as Device;
                narrativeText += string.Format("{0}", device.SoftwareName);
              }

              // Both types are of type Participation so use the Participant to determin the type 
              if (informationProvider is Participation)
              {
                var informationProviderHealthcareProvider = informationProvider as IParticipationInformationProviderHealthcareProvider;
                var informationProviderNonHealthcareProvider = informationProvider as IParticipationInformationProviderNonHealthcareProvider;

                if (informationProviderHealthcareProvider.Participant != null)
                {
                   narrativeText = informationProviderHealthcareProvider.Participant.Person != null && informationProviderHealthcareProvider.Participant.Person.PersonNames != null ? BuildPersonNames(informationProviderHealthcareProvider.Participant.Person.PersonNames) : null;

                  if (informationProviderHealthcareProvider.Participant.Person != null && informationProviderHealthcareProvider.Participant.Person.Organisation != null)
                    if (!informationProviderHealthcareProvider.Participant.Person.Organisation.Name.IsNullOrEmptyWhitespace())
                      narrativeText += DELIMITERBREAK + informationProviderHealthcareProvider.Participant.Person.Organisation.Name;

                  narrativeText += DELIMITERBREAK + CreateAddress(informationProviderHealthcareProvider.Participant.Addresses, informationProviderHealthcareProvider.Participant.ElectronicCommunicationDetails);
                }

                if (informationProviderNonHealthcareProvider.Participant != null)
                {
                   narrativeText = informationProviderNonHealthcareProvider.Participant.Person != null && informationProviderNonHealthcareProvider.Participant.Person.PersonNames != null ? BuildPersonNames(informationProviderNonHealthcareProvider.Participant.Person.PersonNames) : null;
                   narrativeText += DELIMITERBREAK + CreateAddress(informationProviderNonHealthcareProvider.Participant.Addresses, informationProviderNonHealthcareProvider.Participant.ElectronicCommunicationDetails);
                }
            }             
        }
          return narrativeText;
        }

        #endregion

        #region CeHR

        /// <summary>
        /// Create a Narrative for the Measurement Information
        /// </summary>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(MeasurementInformation measurementInformation)
        {
          StrucDocText strucDocText = null;
          List<StrucDocTable> strucDocTableList = null;

          if (measurementInformation != null)
          {

            strucDocTableList = new List<StrucDocTable>();

            var headerList = new List<String>() 
              { 
                  "Observation Date", 
                  "Measurement Type", 
                  "Measurement" 
              };

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

                if (measurementInformation.HeadCircumference != null) 
                    narrative.Add(new List<string>
                    {
                        measurementInformation.ObservationDate != null ? measurementInformation.ObservationDate.NarrativeText() : string.Empty,
                        "Head Circumference",
                        measurementInformation.HeadCircumference != null ? measurementInformation.HeadCircumference.NarrativeText : string.Empty
                    });

                if (measurementInformation.BodyHeight != null)
                    narrative.Add(new List<string>
                    {
                        measurementInformation.ObservationDate != null ? measurementInformation.ObservationDate.NarrativeText() : string.Empty,
                        "Body Height",
                        measurementInformation.BodyHeight != null ? measurementInformation.BodyHeight.NarrativeText : string.Empty
                    }); 

                if (measurementInformation.BodyWeight != null)
                    narrative.Add(new List<string>
                    {
                        measurementInformation.ObservationDate != null ? measurementInformation.ObservationDate.NarrativeText() : string.Empty,
                        "Body Weight",
                        measurementInformation.BodyWeight != null ? measurementInformation.BodyWeight.NarrativeText : string.Empty
                    });

                if (measurementInformation.BodyMassIndex != null)
                narrative.Add(new List<string>
                    {
                        measurementInformation.ObservationDate != null ? measurementInformation.ObservationDate.NarrativeText() : string.Empty,
                        "Body Mass Index",
                        measurementInformation.BodyMassIndex != null ? measurementInformation.BodyMassIndex.NarrativeText : string.Empty
                    });


            strucDocTableList.Add
            (
                PopulateTable
                (
                    "Measurement Information",
                    null,
                    headerList.ToArray(),
                    new string[0],
                    narrative
                )
            );

              strucDocText = new StrucDocText();
              // Structured Tables
              if (strucDocTableList.Any() && narrative.Any())
              {
                 strucDocText.table = strucDocTableList.ToArray();
              } 
              else
              {
                 strucDocText.paragraph = CreateParagraph(SECTIONEMPTYTEXT);
              }
          }

          return strucDocText;
        }

        /// <summary>
        /// Create a Narrative for the Measurement Information
        /// </summary>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(List<MeasurementInformation> measurementInformations)
        {
          StrucDocText strucDocText = null;
          List<StrucDocTable> strucDocTableList = null;

          if (measurementInformations != null && measurementInformations.Any())
          {
              var headerList = new List<String>() 
              { 
                  "Observation Date", 
                  "Head Circumference", 
                  "Body Height",
 	              "Body Mass Index",
 
              };

              var narrative = new List<List<String>>();
              foreach (var item in measurementInformations)
              {

                  strucDocText = new StrucDocText();
                  strucDocTableList = new List<StrucDocTable>();

                  narrative.Add(new List<string>
                                {
                                   item.ObservationDate != null ? item.ObservationDate.NarrativeText() : string.Empty,
                                   item.HeadCircumference != null ? item.HeadCircumference.NarrativeText : string.Empty,
                                   item.BodyHeight != null ? item.BodyHeight.NarrativeText : string.Empty,
                                   item.BodyWeight != null ? item.BodyWeight.NarrativeText : string.Empty,
                                   item.BodyMassIndex != null ? item.BodyMassIndex.NarrativeText : string.Empty
                                }
                               );
              }

              strucDocTableList.Add
              (
                  PopulateTable
                  (
                      "Measurement Information",
                      null,
                      headerList.ToArray(),
                      new string[0],
                      narrative
                  )
              );


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

            return strucDocText;
        }

        /// <summary>
        /// Create a Narrative for the Questionnaire
        /// </summary>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(Questionnaire questionnaire)
        {
          StrucDocText strucDocText = null;
          List<StrucDocTable> strucDocTableList = null;

          if (questionnaire != null)
          {
            var headerList = new List<String>() 
              { 
                  "Date Time", 
                  "Question", 
                  "Responses"
              };

            strucDocText = new StrucDocText();
            strucDocTableList = new List<StrucDocTable>();

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

            if (questionnaire.AssessmentItems != null)
              foreach (var assessmentItem in questionnaire.AssessmentItems)
              {

                string response = string.Empty;
                if (!assessmentItem.FreeText.IsNullOrEmptyWhitespace())
                {
                  response = assessmentItem.FreeText;
                }

                if (assessmentItem.AnswersValue.HasValue)
                {
                    response = assessmentItem.AnswersValue.Value.GetAttributeValue<NameAttribute, String>(x => x.Name);
                }

                narrative.Add(
                                new List<string>
                                      {
                                          assessmentItem.DateTime != null ? assessmentItem.DateTime .NarrativeText() : null,
                                          assessmentItem.QuestionData != null ? assessmentItem.QuestionData.NarrativeText: null,
                                          response
                                      }
                             );
              }

            strucDocTableList.Add
            (
                PopulateTable
                (
                questionnaire.SectionCode.HasValue ? questionnaire.SectionCode.Value.GetAttributeValue<NameAttribute, String>(x => x.Name) : null,
                    null,
                    headerList.ToArray(),
                    new string[0],
                    narrative
                )
            );

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

          return strucDocText;
        }

        /// <summary>
        /// Create a Narrative for the Health Check Assesment
        /// </summary>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(HealthCheckAssesment healthCheckAssesment)
        {
          StrucDocText strucDocText = null;
          List<StrucDocTable> strucDocTableList = null;

          if (healthCheckAssesment != null)
          {
            var headerList = new List<String>() 
              { 
                  "Date Time", 
                  "Question", 
                  "Responses"
              };

            strucDocText = new StrucDocText();
            strucDocTableList = new List<StrucDocTable>();

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

            if (healthCheckAssesment.AssessmentItems != null)
            foreach (var assessmentItem in healthCheckAssesment.AssessmentItems)
            {

              string response = string.Empty;
              if (!assessmentItem.FreeText.IsNullOrEmptyWhitespace())
              {
                response = assessmentItem.FreeText;
              }

              if (assessmentItem.AnswersValue.HasValue)
              {
                  response = assessmentItem.AnswersValue.Value.GetAttributeValue<NameAttribute, String>(x => x.Name);
              }

              narrative.Add(
                             new List<string>
                                            {
                                                assessmentItem.DateTime != null ? assessmentItem.DateTime .NarrativeText() : null,
                                                assessmentItem.QuestionData != null ? assessmentItem.QuestionData.NarrativeText: null,
                                                response
                                            }
                             );
            }

            strucDocTableList.Add
            (
                PopulateTable
                (
                   healthCheckAssesment.SectionCode.HasValue ? healthCheckAssesment.SectionCode.Value.GetAttributeValue<NameAttribute, String>(x => x.Name) : null,
                    null,
                    headerList.ToArray(),
                    new string[0],
                    narrative
                )
            );

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

          return strucDocText;
        }

        /// <summary>
        /// Create a Narrative for Birth Details
        /// </summary>
        /// <returns>StrucDocText</returns>
        public StrucDocText CreateNarrative(BirthDetails birthDetails)
        {
          StrucDocText strucDocText = null;
          List<StrucDocTable> strucDocTableList = null;
          var renderMultiMediaList = new List<StrucDocRenderMultiMedia>();

          if (birthDetails != null)
          {
            var headerList = new List<String>() 
              { 
                  "Attachment Name", 
                  "Attachment"
              };

            strucDocText = new StrucDocText();
            strucDocTableList = new List<StrucDocTable>();

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

              foreach (var externalData in birthDetails.ExternalData)
              {

                narrative.Add(
                  new List<Object>
                    {
                      externalData.Caption,
                      CreateEncapsulatedData(externalData, ref renderMultiMediaList)
                    }
                 );

              }

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

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

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


          return strucDocText;
        }


        #endregion 

    }
        #endregion






}
    
