protected override Observation CreateObservationImpl(CodeValueFhirTemplate template, IObservationGroup grp)
        {
            EnsureArg.IsNotNull(template, nameof(template));
            EnsureArg.IsNotNull(grp, nameof(grp));

            var observation = new Observation
            {
                Status    = ObservationStatus.Final,
                Code      = ResolveCode(grp.Name, template.Codes),
                Issued    = DateTimeOffset.UtcNow,
                Effective = grp.Boundary.ToPeriod(),
            };

            if (template?.Category?.Count > 0)
            {
                observation.Category = ResolveCategory(template.Category);
            }

            var values = grp.GetValues();

            if (!string.IsNullOrWhiteSpace(template?.Value?.ValueName) && values.TryGetValue(template?.Value?.ValueName, out var obValues))
            {
                observation.Value = _valueProcessor.CreateValue(template.Value, CreateMergeData(grp.Boundary, grp.Boundary, obValues));
            }

            if (template?.Components?.Count > 0)
            {
                observation.Component = new List <Observation.ComponentComponent>(template.Components.Count);

                foreach (var component in template.Components)
                {
                    if (values.TryGetValue(component.Value.ValueName, out var compValues))
                    {
                        observation.Component.Add(
                            new Observation.ComponentComponent
                        {
                            Code  = ResolveCode(component.Value.ValueName, component.Codes),
                            Value = _valueProcessor.CreateValue(component.Value, CreateMergeData(grp.Boundary, grp.Boundary, compValues)),
                        });
                    }
                }
            }

            return(observation);
        }
        protected override Observation MergeObservationImpl(CodeValueFhirTemplate template, IObservationGroup grp, Observation existingObservation)
        {
            EnsureArg.IsNotNull(grp, nameof(grp));
            EnsureArg.IsNotNull(existingObservation, nameof(existingObservation));

            existingObservation.Status = ObservationStatus.Amended;

            existingObservation.Category = null;
            if (template?.Category?.Count > 0)
            {
                existingObservation.Category = ResolveCategory(template.Category);
            }

            var values = grp.GetValues();

            (DateTime start, DateTime end)observationPeriod = GetObservationPeriod(existingObservation);

            // Update observation value
            if (!string.IsNullOrWhiteSpace(template?.Value?.ValueName) && values.TryGetValue(template?.Value?.ValueName, out var obValues))
            {
                existingObservation.Value = _valueProcessor.MergeValue(template.Value, CreateMergeData(grp.Boundary, observationPeriod, obValues), existingObservation.Value);
            }

            // Update observation component values
            if (template?.Components?.Count > 0)
            {
                if (existingObservation.Component == null)
                {
                    existingObservation.Component = new List <Observation.ComponentComponent>(template.Components.Count);
                }

                foreach (var component in template.Components)
                {
                    if (values.TryGetValue(component.Value.ValueName, out var compValues))
                    {
                        var foundComponent = existingObservation.Component
                                             .Where(c => c.Code.Coding.Any(code => code.Code == component.Value.ValueName && code.System == FhirImportService.ServiceSystem))
                                             .FirstOrDefault();

                        if (foundComponent == null)
                        {
                            existingObservation.Component.Add(
                                new Observation.ComponentComponent
                            {
                                Code  = ResolveCode(component.Value.ValueName, component.Codes),
                                Value = _valueProcessor.CreateValue(component.Value, CreateMergeData(grp.Boundary, observationPeriod, compValues)),
                            });
                        }
                        else
                        {
                            foundComponent.Value = _valueProcessor.MergeValue(component.Value, CreateMergeData(grp.Boundary, observationPeriod, compValues), foundComponent.Value);
                        }
                    }
                }
            }

            // Update observation effective period if merge values exist outside the current period.
            if (grp.Boundary.Start < observationPeriod.start)
            {
                observationPeriod.start = grp.Boundary.Start;
            }

            if (grp.Boundary.End > observationPeriod.end)
            {
                observationPeriod.end = grp.Boundary.End;
            }

            existingObservation.Effective = observationPeriod.ToPeriod();

            return(existingObservation);
        }