private List <ElementDefinition.TypeRefComponent> GetProfileDataTypes(StructureDefinition structure, TemplateConstraint constraint)
        {
            if (structure == null || structure.Snapshot == null)
            {
                return(null);
            }

            string path    = constraint.GetFhirPath();
            var    element = structure.Snapshot.Element.FirstOrDefault(y => y.Path == path);

            if (element == null)
            {
                return(null);
            }

            return(element.Type);
        }
        public Template Convert(StructureDefinition strucDef, Template template = null)
        {
            if (string.IsNullOrEmpty(strucDef.Type))
            {
                throw new Exception("StructureDefinition.type is required");
            }

            string strucDefDescription = strucDef.Description != null ? strucDef.Description.Value : null;

            if (template == null)
            {
                ImplementationGuide unassignedImplementationGuide = this.tdb.ImplementationGuides.SingleOrDefault(y =>
                                                                                                                  y.Name == STU3Helper.DEFAULT_IG_NAME &&
                                                                                                                  y.ImplementationGuideTypeId == this.implementationGuideType.Id);

                if (unassignedImplementationGuide == null)
                {
                    unassignedImplementationGuide = new ImplementationGuide()
                    {
                        Name = STU3Helper.DEFAULT_IG_NAME,
                        ImplementationGuideType = this.implementationGuideType,
                        Organization            = this.tdb.Organizations.Single(y => y.Name == STU3Helper.DEFAULT_ORG_NAME)
                    };
                    this.tdb.ImplementationGuides.AddObject(unassignedImplementationGuide);
                }

                template = new Template()
                {
                    OwningImplementationGuide = unassignedImplementationGuide,
                    ImplementationGuideType   = this.implementationGuideType,
                    Author = this.tdb.Users.Single(y => y.UserName == STU3Helper.DEFAULT_USER_NAME),
                    IsOpen = true
                };
            }

            // Name
            if (template.Name != strucDef.Name)
            {
                template.Name = strucDef.Name;
            }

            // Descrition
            if (template.Description != strucDefDescription)
            {
                template.Description = strucDefDescription;
            }

            // Identifier -> Oid
            string identifier = strucDef.Url;

            if (string.IsNullOrEmpty(identifier))
            {
                identifier = string.Format(STU3Helper.STRUCDEF_NEW_IDENTIFIER_FORMAT, Guid.NewGuid());
            }

            if (template.Oid != identifier)
            {
                template.Oid = identifier;
            }

            string fhirBaseType = strucDef.Type != null?strucDef.Type.ToString() : string.Empty;

            // ConstrainedType -> Template Type
            TemplateType templateType = this.tdb.TemplateTypes.SingleOrDefault(y =>
                                                                               y.ImplementationGuideTypeId == this.implementationGuideType.Id &&
                                                                               y.RootContextType == fhirBaseType);

            if (templateType == null)
            {
                throw new Exception("Could not find Template Type for " + strucDef.Type);
            }

            if (template.TemplateType != templateType)
            {
                template.TemplateType = templateType;
            }

            if (template.PrimaryContext != template.TemplateType.RootContext)
            {
                template.PrimaryContext = template.TemplateType.RootContext;
            }

            if (template.PrimaryContextType != template.TemplateType.RootContextType)
            {
                template.PrimaryContextType = template.TemplateType.RootContextType;
            }

            // Bookmark
            template.Bookmark = Template.GenerateBookmark(template.Name, template.TemplateType.Name.ToUpper());

            if (strucDef.Snapshot != null && strucDef.Differential == null)
            {
                throw new Exception("Trifolia does not support snapshots for DSTU2, yet");
            }

            // Differential.Element -> Constraint
            if (strucDef.Differential != null)
            {
                // Remove all current constraints from the template so that we re-create
                foreach (var cc in template.ChildConstraints.ToList())
                {
                    this.tdb.TemplateConstraints.DeleteObject(cc);
                }

                ElementNavigator   navigator = new ElementNavigator(strucDef.Differential.Element);
                TemplateConstraint current   = null;

                if (navigator.MoveToFirstChild() && navigator.MoveToFirstChild())
                {
                    while (true)
                    {
                        if (navigator.Current.Slicing != null)
                        {
                            if (!navigator.MoveToNext())
                            {
                                if (current != null && current.ParentConstraint != null && navigator.MoveToParent())
                                {
                                    current = current.ParentConstraint;
                                }
                                else
                                {
                                    break;
                                }
                            }
                            continue;
                        }

                        TemplateConstraint next = new TemplateConstraint();
                        next.Context          = navigator.PathName;
                        next.ParentConstraint = current;
                        next.Order            = current != null?current.ChildConstraints.Count() : template.ChildConstraints.Count(y => y.ParentConstraint == null);

                        if (navigator.Elements.Any(y => y.Path == navigator.Path && y.Slicing != null))
                        {
                            next.IsBranch = true;
                        }

                        template.ChildConstraints.Add(next);

                        string cardinality = string.Format("{0}..{1}",
                                                           navigator.Current.Min == null ? 0 : navigator.Current.Min,
                                                           string.IsNullOrEmpty(navigator.Current.Max) ? "*" : navigator.Current.Max);

                        if (next.Cardinality != cardinality)
                        {
                            next.Cardinality = cardinality;
                        }

                        string conformance = cardinality.StartsWith("1") ? "SHALL" : "SHOULD";

                        if (next.Conformance != conformance)
                        {
                            next.Conformance = conformance;
                        }

                        if (navigator.MoveToFirstChild())
                        {
                            current = next;
                            continue;
                        }
                        else if (navigator.MoveToNext())
                        {
                            continue;
                        }
                        else if (navigator.MoveToParent() && navigator.MoveToNext())
                        {
                            current = current.ParentConstraint;
                            continue;
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }

            return(template);
        }
        public void CreateElementDefinition(
            StructureDefinition strucDef,
            TemplateConstraint constraint,
            SimpleSchema.SchemaObject schemaObject)
        {
            if (constraint.IsPrimitive)     // Skip primitives (for now, at least)
            {
                return;
            }

            string sliceName           = constraint.GetSliceName();
            string elementPath         = constraint.GetElementPath(strucDef.Type != null ? strucDef.Type.ToString() : null);
            var    igSettings          = GetIGSettings(constraint);
            var    constraintFormatter = FormattedConstraintFactory.NewFormattedConstraint(this.tdb, igSettings, this.igTypePlugin, constraint);
            string definition          = constraintFormatter.GetPlainText(false, false, false);

            if (definition == null)
            {
                definition = string.Empty;
            }

            ElementDefinition newElementDef = new ElementDefinition()
            {
                Short      = !string.IsNullOrEmpty(constraint.Label) ? constraint.Label : constraint.Context,
                Label      = !string.IsNullOrEmpty(constraint.Label) ? constraint.Label : null,
                Comment    = !string.IsNullOrEmpty(constraint.Notes) ? constraint.Notes : null,
                Path       = elementPath,
                SliceName  = sliceName,
                Definition = definition,
                ElementId  = constraint.GetElementId()
            };

            if (constraint.IsChoice)
            {
                newElementDef.Slicing = new ElementDefinition.SlicingComponent();
                newElementDef.Slicing.Discriminator.Add(new ElementDefinition.DiscriminatorComponent()
                {
                    Type = ElementDefinition.DiscriminatorType.Type,
                    Path = "$this"
                });
                newElementDef.Slicing.Rules = ElementDefinition.SlicingRules.Open;
            }
            else if (constraint.Parent != null && constraint.Parent.IsChoice)
            {
                newElementDef.SliceName = constraint.Context;
            }

            // Cardinality
            if (!string.IsNullOrEmpty(constraint.Cardinality))
            {
                newElementDef.Min = constraint.CardinalityType.Left;
                newElementDef.Max = constraint.CardinalityType.Right == Cardinality.MANY ? "*" : constraint.CardinalityType.Right.ToString();
            }

            // Binding
            string valueConformance = string.IsNullOrEmpty(constraint.ValueConformance) ? constraint.Conformance : constraint.ValueConformance;
            bool   hasBinding       = constraint.References.Any(y => y.ReferenceType == ConstraintReferenceTypes.Template);

            if (constraint.ValueSet != null && valueConformance.IndexOf("NOT") < 0)
            {
                hasBinding            = true;
                newElementDef.Binding = new ElementDefinition.ElementDefinitionBindingComponent()
                {
                    ValueSet = new ResourceReference()
                    {
                        Reference = constraint.ValueSet.GetIdentifier(ValueSetIdentifierTypes.HTTP),
                        Display   = constraint.ValueSet.Name
                    }
                };

                if (valueConformance == "SHALL")
                {
                    newElementDef.Binding.Strength = BindingStrength.Required;
                }
                else if (valueConformance == "SHOULD")
                {
                    newElementDef.Binding.Strength = BindingStrength.Preferred;
                }
                else if (valueConformance == "MAY")
                {
                    newElementDef.Binding.Strength = BindingStrength.Example;
                }
            }

            // Single-Value Binding
            if (schemaObject != null && (!string.IsNullOrEmpty(constraint.Value) || !string.IsNullOrEmpty(constraint.DisplayName)))
            {
                Element elementBinding = null;

                hasBinding = true;
                switch (schemaObject.DataType)
                {
                case "CodeableConcept":
                    var codableConceptBinding = new CodeableConcept();
                    var coding = new Coding();
                    codableConceptBinding.Coding.Add(coding);

                    if (!string.IsNullOrEmpty(constraint.Value))
                    {
                        coding.Code = constraint.Value;
                    }

                    if (constraint.CodeSystem != null)
                    {
                        coding.System = constraint.CodeSystem.Oid;
                    }

                    if (!string.IsNullOrEmpty(constraint.DisplayName))
                    {
                        coding.Display = constraint.DisplayName;
                    }

                    elementBinding = codableConceptBinding;
                    break;

                case "Coding":
                    var codingBinding = new Coding();

                    if (!string.IsNullOrEmpty(constraint.Value))
                    {
                        codingBinding.Code = constraint.Value;
                    }

                    if (constraint.CodeSystem != null)
                    {
                        codingBinding.System = constraint.CodeSystem.Oid;
                    }

                    if (!string.IsNullOrEmpty(constraint.DisplayName))
                    {
                        codingBinding.Display = constraint.DisplayName;
                    }

                    elementBinding = codingBinding;
                    break;

                case "code":
                    var codeBinding = new Code();
                    codeBinding.Value = !string.IsNullOrEmpty(constraint.Value) ? constraint.Value : constraint.DisplayName;
                    elementBinding    = codeBinding;
                    break;

                default:
                    var stringBinding = new FhirString();
                    stringBinding.Value = !string.IsNullOrEmpty(constraint.Value) ? constraint.Value : constraint.DisplayName;
                    elementBinding      = stringBinding;
                    break;
                }

                if (constraint.IsFixed)
                {
                    newElementDef.Fixed = elementBinding;
                }
                else
                {
                    newElementDef.Pattern = elementBinding;
                }
            }

            // Add the type of the element when bound to a value set
            if (hasBinding && schemaObject != null && !string.IsNullOrEmpty(schemaObject.DataType))
            {
                StructureDefinition profile = GetBaseProfile(constraint.Template);
                newElementDef.Type = GetProfileDataTypes(profile, constraint);

                var containedTemplates = (from tcr in constraint.References
                                          join t in this.tdb.Templates on tcr.ReferenceIdentifier equals t.Oid
                                          where tcr.ReferenceType == ConstraintReferenceTypes.Template
                                          select new { Identifier = t.Oid, t.PrimaryContextType });

                // If there is a contained template/profile, make sure it supports a "Reference" type, and then output the profile identifier in the type
                if (containedTemplates.Count() > 0 && newElementDef.Type.Exists(y => y.Code == "Reference" || y.Code == "Extension"))
                {
                    if (!string.IsNullOrEmpty(newElementDef.SliceName))
                    {
                        var foundMatchingElement = strucDef.Differential.Element.SingleOrDefault(y => y.Path == newElementDef.Path && y.SliceName == newElementDef.SliceName);

                        if (foundMatchingElement != null)
                        {
                            foundMatchingElement.Definition += " " + definition;
                            newElementDef = foundMatchingElement;
                        }
                    }

                    var containedTypes = new List <ElementDefinition.TypeRefComponent>();
                    foreach (var containedTemplate in containedTemplates)
                    {
                        bool isExtension = containedTemplate.PrimaryContextType == "Extension" && newElementDef.Type.Exists(y => y.Code == "Extension");

                        containedTypes.Add(new ElementDefinition.TypeRefComponent()
                        {
                            Code          = isExtension ? "Extension" : "Reference",
                            Profile       = isExtension ? containedTemplate.Identifier : null,
                            TargetProfile = !isExtension ? containedTemplate.Identifier : null
                        });
                    }

                    newElementDef.Type = containedTypes;
                }
            }

            // Add the element to the list if it's new
            if (!strucDef.Differential.Element.Contains(newElementDef))
            {
                strucDef.Differential.Element.Add(newElementDef);
            }

            // Children
            foreach (var childConstraint in constraint.ChildConstraints.OrderBy(y => y.Order))
            {
                var childSchemaObject = schemaObject != null?schemaObject.Children.SingleOrDefault(y => y.Name == childConstraint.Context) : null;

                CreateElementDefinition(strucDef, childConstraint, childSchemaObject);
            }
        }
Example #4
0
        public void CreateElementDefinition(
            StructureDefinition strucDef,
            TemplateConstraint constraint,
            SimpleSchema.SchemaObject schemaObject,
            string sliceName = null)
        {
            if (constraint.IsPrimitive)     // Skip primitives (for now, at least)
            {
                return;
            }

            string newSliceName = null;

            if (constraint.IsBranch)
            {
                newSliceName = string.Format("{0}_slice_pos{1}", constraint.Context, constraint.Order);
            }

            var igSettings          = GetIGSettings(constraint);
            var constraintFormatter = FormattedConstraintFactory.NewFormattedConstraint(this.tdb, igSettings, constraint);

            ElementDefinition newElementDef = new ElementDefinition()
            {
                ElementId  = constraint.Id.ToString(),
                Short      = !string.IsNullOrEmpty(constraint.Label) ? constraint.Label : constraint.Context,
                Label      = !string.IsNullOrEmpty(constraint.Label) ? constraint.Label : null,
                Comments   = !string.IsNullOrEmpty(constraint.Notes) ? constraint.Notes : null,
                Path       = constraint.GetElementPath(strucDef.Type != null ? strucDef.Type.ToString() : null),
                Name       = constraint.IsBranch ? newSliceName : sliceName,
                Definition = constraintFormatter.GetPlainText(false, false, false)
            };

            // Cardinality
            if (!string.IsNullOrEmpty(constraint.Cardinality))
            {
                newElementDef.Min = constraint.CardinalityType.Left;
                newElementDef.Max = constraint.CardinalityType.Right == Cardinality.MANY ? "*" : constraint.CardinalityType.Right.ToString();
            }

            // Binding
            string valueConformance = string.IsNullOrEmpty(constraint.ValueConformance) ? constraint.Conformance : constraint.ValueConformance;
            bool   hasBinding       = constraint.ContainedTemplate != null;

            if (constraint.ValueSet != null && valueConformance.IndexOf("NOT") < 0)
            {
                hasBinding            = true;
                newElementDef.Binding = new ElementDefinition.BindingComponent()
                {
                    ValueSet = new ResourceReference()
                    {
                        Reference = constraint.ValueSet.Oid,
                        Display   = constraint.ValueSet.Name
                    }
                };

                if (valueConformance == "SHALL")
                {
                    newElementDef.Binding.Strength = BindingStrength.Required;
                }
                else if (valueConformance == "SHOULD")
                {
                    newElementDef.Binding.Strength = BindingStrength.Preferred;
                }
                else if (valueConformance == "MAY")
                {
                    newElementDef.Binding.Strength = BindingStrength.Example;
                }
            }

            // Single-Value Binding
            if (schemaObject != null && (!string.IsNullOrEmpty(constraint.Value) || !string.IsNullOrEmpty(constraint.DisplayName)))
            {
                hasBinding = true;
                switch (schemaObject.DataType)
                {
                case "CodeableConcept":
                    var fixedCodeableConcept = new CodeableConcept();
                    var coding = new Coding();
                    fixedCodeableConcept.Coding.Add(coding);

                    if (!string.IsNullOrEmpty(constraint.Value))
                    {
                        coding.Code = constraint.Value;
                    }

                    if (constraint.CodeSystem != null)
                    {
                        coding.System = constraint.CodeSystem.Oid;
                    }

                    if (!string.IsNullOrEmpty(constraint.DisplayName))
                    {
                        coding.Display = constraint.DisplayName;
                    }

                    newElementDef.Fixed = fixedCodeableConcept;
                    break;

                case "Coding":
                    var fixedCoding = new Coding();

                    if (!string.IsNullOrEmpty(constraint.Value))
                    {
                        fixedCoding.Code = constraint.Value;
                    }

                    if (constraint.CodeSystem != null)
                    {
                        fixedCoding.System = constraint.CodeSystem.Oid;
                    }

                    if (!string.IsNullOrEmpty(constraint.DisplayName))
                    {
                        fixedCoding.Display = constraint.DisplayName;
                    }

                    newElementDef.Fixed = fixedCoding;
                    break;

                case "code":
                    var fixedCode = new Code();
                    fixedCode.Value     = !string.IsNullOrEmpty(constraint.Value) ? constraint.Value : constraint.DisplayName;
                    newElementDef.Fixed = fixedCode;
                    break;

                default:
                    var fixedString = new FhirString();
                    fixedString.Value   = !string.IsNullOrEmpty(constraint.Value) ? constraint.Value : constraint.DisplayName;
                    newElementDef.Fixed = fixedString;
                    break;
                }
            }

            // Add the type of the element when bound to a value set
            if (hasBinding && schemaObject != null && !string.IsNullOrEmpty(schemaObject.DataType))
            {
                StructureDefinition profile = GetBaseProfile(constraint.Template);
                newElementDef.Type = GetProfileDataTypes(profile, constraint);

                // If there is a contained template/profile, make sure it supports a "Reference" type, and then output the profile identifier in the type
                if (constraint.ContainedTemplate != null && newElementDef.Type.Exists(y => y.Code == "Reference" || y.Code == "Extension"))
                {
                    bool isExtension = constraint.ContainedTemplate.PrimaryContextType == "Extension" && newElementDef.Type.Exists(y => y.Code == "Extension");

                    var containedTypes = new List <ElementDefinition.TypeRefComponent>();
                    containedTypes.Add(new ElementDefinition.TypeRefComponent()
                    {
                        Code    = isExtension ? "Extension" : "Reference",
                        Profile = constraint.ContainedTemplate.Oid
                    });

                    newElementDef.Type = containedTypes;
                }
            }

            // Add the element to the list
            strucDef.Differential.Element.Add(newElementDef);

            // Children
            foreach (var childConstraint in constraint.ChildConstraints.OrderBy(y => y.Order))
            {
                var childSchemaObject = schemaObject != null?schemaObject.Children.SingleOrDefault(y => y.Name == childConstraint.Context) : null;

                CreateElementDefinition(strucDef, childConstraint, childSchemaObject, newSliceName);
            }
        }