private void CheckForTemplateCompatibility(IContentTemplate contentTemplate, ILookupTemplate <IFhirTemplate> fhirTemplate, TemplateResult validationResult)
        {
            var deviceTemplates        = new List <MeasurementExtractor>();
            var fhirTemplates          = new List <CodeValueFhirTemplate>();
            var availableFhirTemplates = string.Empty;

            // TODO: Confirm that outer template factories are always collections for both Device and Fhir Mappings. This implies that
            // customers must always wrap their templates inside of a CollectionXXX Template.

            if (contentTemplate is CollectionContentTemplate collectionContentTemplate)
            {
                deviceTemplates.AddRange(collectionContentTemplate.Templates.Select(t => t as MeasurementExtractor));
            }

            if (fhirTemplate is FhirLookupTemplate fhirLookupTemplate)
            {
                fhirTemplates.AddRange(fhirLookupTemplate.Templates.Select(t => t as CodeValueFhirTemplate));
                availableFhirTemplates = string.Join(" ,", fhirTemplates.Select(t => t.TypeName));
            }

            foreach (var extractor in deviceTemplates)
            {
                try
                {
                    var innerTemplate                  = extractor.Template;
                    var matchingFhirTemplate           = fhirTemplate.GetTemplate(innerTemplate.TypeName) as CodeValueFhirTemplate;
                    var availableFhirValueNames        = new HashSet <string>(GetFhirValues(matchingFhirTemplate).Select(v => v.ValueName));
                    var availableFhirValueNamesDisplay = string.Join(" ,", availableFhirValueNames);

                    // Ensure all values are present
                    if (extractor.Template.Values != null)
                    {
                        foreach (var v in extractor.Template.Values)
                        {
                            if (!availableFhirValueNames.Contains(v.ValueName))
                            {
                                validationResult.CaptureWarning(
                                    $"The value [{v.ValueName}] in Device Mapping [{extractor.Template.TypeName}] is not represented within the Fhir Template of type [{innerTemplate.TypeName}]. Available values are: [{availableFhirValueNamesDisplay}]. No value will appear inside of Observations.",
                                    ValidationCategory.FHIRTRANSFORMATION,
                                    LineInfo.Default);
                            }
                        }
                    }
                }
                catch (TemplateNotFoundException)
                {
                    validationResult.CaptureWarning(
                        $"No matching Fhir Template exists for Device Mapping [{extractor.Template.TypeName}]. Ensure case matches. Available Fhir Templates: [{availableFhirTemplates}].",
                        ValidationCategory.FHIRTRANSFORMATION,
                        LineInfo.Default);
                }
                catch (Exception e)
                {
                    validationResult.CaptureException(e, ValidationCategory.FHIRTRANSFORMATION);
                }
            }
        }
        private (IFhirTemplate template, IFhirTemplateProcessor <IFhirTemplate, TObservation> processor) GetTemplateAndProcessor(string lookupValue, ILookupTemplate <IFhirTemplate> lookup)
        {
            EnsureArg.IsNotNullOrWhiteSpace(lookupValue, nameof(lookupValue));
            EnsureArg.IsNotNull(lookup, nameof(lookup));

            var template     = lookup.GetTemplate(lookupValue);
            var templateType = template.GetType();

            if (!_registeredTemplateProcessors.TryGetValue(templateType, out var processor))
            {
                throw new NotSupportedException($"No processor registered for template type {templateType}.");
            }

            return(template, processor);
        }