
001package org.hl7.fhir.dstu2.utils; 002 003import java.util.ArrayList; 004import java.util.HashMap; 005import java.util.List; 006import java.util.Map; 007 008import org.apache.commons.lang3.NotImplementedException; 009import org.hl7.fhir.dstu2.model.Base; 010import org.hl7.fhir.dstu2.model.BooleanType; 011import org.hl7.fhir.dstu2.model.Coding; 012import org.hl7.fhir.dstu2.model.DateTimeType; 013import org.hl7.fhir.dstu2.model.DateType; 014import org.hl7.fhir.dstu2.model.DecimalType; 015import org.hl7.fhir.dstu2.model.Element; 016import org.hl7.fhir.dstu2.model.ElementDefinition; 017import org.hl7.fhir.dstu2.model.ElementDefinition.ElementDefinitionBindingComponent; 018import org.hl7.fhir.dstu2.model.ElementDefinition.TypeRefComponent; 019import org.hl7.fhir.dstu2.model.Enumeration; 020import org.hl7.fhir.dstu2.model.Enumerations.BindingStrength; 021import org.hl7.fhir.dstu2.model.Enumerations.ConformanceResourceStatus; 022import org.hl7.fhir.dstu2.model.Factory; 023import org.hl7.fhir.dstu2.model.InstantType; 024import org.hl7.fhir.dstu2.model.IntegerType; 025import org.hl7.fhir.dstu2.model.Quantity; 026import org.hl7.fhir.dstu2.model.Questionnaire; 027import org.hl7.fhir.dstu2.model.Questionnaire.AnswerFormat; 028import org.hl7.fhir.dstu2.model.Questionnaire.GroupComponent; 029import org.hl7.fhir.dstu2.model.Questionnaire.QuestionComponent; 030import org.hl7.fhir.dstu2.model.Questionnaire.QuestionnaireStatus; 031import org.hl7.fhir.dstu2.model.QuestionnaireResponse; 032import org.hl7.fhir.dstu2.model.QuestionnaireResponse.QuestionAnswerComponent; 033import org.hl7.fhir.dstu2.model.QuestionnaireResponse.QuestionnaireResponseStatus; 034import org.hl7.fhir.dstu2.model.Reference; 035import org.hl7.fhir.dstu2.model.Resource; 036import org.hl7.fhir.dstu2.model.StringType; 037import org.hl7.fhir.dstu2.model.StructureDefinition; 038import org.hl7.fhir.dstu2.model.TimeType; 039import org.hl7.fhir.dstu2.model.Type; 040import org.hl7.fhir.dstu2.model.UriType; 041import org.hl7.fhir.dstu2.model.ValueSet; 042import org.hl7.fhir.dstu2.model.ValueSet.ValueSetExpansionComponent; 043import org.hl7.fhir.dstu2.model.ValueSet.ValueSetExpansionContainsComponent; 044import org.hl7.fhir.dstu2.terminologies.ValueSetExpander; 045import org.hl7.fhir.exceptions.DefinitionException; 046import org.hl7.fhir.exceptions.FHIRException; 047import org.hl7.fhir.utilities.Utilities; 048 049/* 050 Copyright (c) 2011+, HL7, Inc. 051 All rights reserved. 052 053 Redistribution and use in source and binary forms, with or without modification, 054 are permitted provided that the following conditions are met: 055 056 * Redistributions of source code must retain the above copyright notice, this 057 list of conditions and the following disclaimer. 058 * Redistributions in binary form must reproduce the above copyright notice, 059 this list of conditions and the following disclaimer in the documentation 060 and/or other materials provided with the distribution. 061 * Neither the name of HL7 nor the names of its contributors may be used to 062 endorse or promote products derived from this software without specific 063 prior written permission. 064 065 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 066 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 067 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 068 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 069 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 070 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 071 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 072 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 073 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 074 POSSIBILITY OF SUCH DAMAGE. 075 076 */ 077 078/** 079 * This class takes a profile, and builds a questionnaire from it 080 * 081 * If you then convert this questionnaire to a form using the XMLTools form 082 * builder, and then take the QuestionnaireResponse this creates, you can use 083 * QuestionnaireInstanceConvert to build an instance the conforms to the profile 084 * 085 * FHIR context: conceptLocator, codeSystems, valueSets, maps, client, profiles 086 * You don"t have to provide any of these, but the more you provide, the better 087 * the conversion will be 088 * 089 * @author Grahame 090 * 091 */ 092@Deprecated 093public class QuestionnaireBuilder { 094 095 private static final int MaxListboxCodings = 20; 096 private IWorkerContext context; 097 private int lastid = 0; 098 private Resource resource; 099 private StructureDefinition profile; 100 private Questionnaire questionnaire; 101 private QuestionnaireResponse response; 102 private String questionnaireId; 103 private Factory factory = new Factory(); 104 private Map<String, String> vsCache = new HashMap<String, String>(); 105 private ValueSetExpander expander; 106 107 // sometimes, when this is used, the questionnaire is already build and cached, 108 // and we are 109 // processing the response. for technical reasons, we still go through the 110 // process, but 111 // we don't do the intensive parts of the work (save time) 112 private Questionnaire prebuiltQuestionnaire; 113 114 public QuestionnaireBuilder(IWorkerContext context) { 115 super(); 116 this.context = context; 117 } 118 119 public Resource getReference() { 120 return resource; 121 } 122 123 public void setReference(Resource resource) { 124 this.resource = resource; 125 } 126 127 public StructureDefinition getProfile() { 128 return profile; 129 } 130 131 public void setProfile(StructureDefinition profile) { 132 this.profile = profile; 133 } 134 135 public Questionnaire getQuestionnaire() { 136 return questionnaire; 137 } 138 139 public void setQuestionnaire(Questionnaire questionnaire) { 140 this.questionnaire = questionnaire; 141 } 142 143 public QuestionnaireResponse getResponse() { 144 return response; 145 } 146 147 public void setResponse(QuestionnaireResponse response) { 148 this.response = response; 149 } 150 151 public String getQuestionnaireId() { 152 return questionnaireId; 153 } 154 155 public void setQuestionnaireId(String questionnaireId) { 156 this.questionnaireId = questionnaireId; 157 } 158 159 public Questionnaire getPrebuiltQuestionnaire() { 160 return prebuiltQuestionnaire; 161 } 162 163 public void setPrebuiltQuestionnaire(Questionnaire prebuiltQuestionnaire) { 164 this.prebuiltQuestionnaire = prebuiltQuestionnaire; 165 } 166 167 public ValueSetExpander getExpander() { 168 return expander; 169 } 170 171 public void setExpander(ValueSetExpander expander) { 172 this.expander = expander; 173 } 174 175 public void build() throws FHIRException { 176 if (profile == null) 177 throw new DefinitionException("QuestionnaireBuilder.build: no profile found"); 178 179 if (resource != null) 180 if (!profile.getConstrainedType().equals(resource.getResourceType().toString())) 181 throw new DefinitionException("Wrong Type"); 182 183 if (prebuiltQuestionnaire != null) 184 questionnaire = prebuiltQuestionnaire; 185 else 186 questionnaire = new Questionnaire(); 187 if (resource != null) 188 response = new QuestionnaireResponse(); 189 processMetadata(); 190 191 List<ElementDefinition> list = new ArrayList<ElementDefinition>(); 192 List<QuestionnaireResponse.GroupComponent> answerGroups = new ArrayList<QuestionnaireResponse.GroupComponent>(); 193 194 if (resource != null) 195 answerGroups.add(response.getGroup()); 196 if (prebuiltQuestionnaire != null) { 197 // give it a fake group to build 198 Questionnaire.GroupComponent group = new Questionnaire.GroupComponent(); 199 buildGroup(group, profile, profile.getSnapshot().getElement().get(0), list, answerGroups); 200 } else 201 buildGroup(questionnaire.getGroup(), profile, profile.getSnapshot().getElement().get(0), list, answerGroups); 202 // 203 // NarrativeGenerator ngen = new NarrativeGenerator(context); 204 // ngen.generate(result); 205 // 206 // if FResponse <> nil then 207 // FResponse.collapseAllContained; 208 } 209 210 private void processMetadata() { 211 // todo: can we derive a more informative identifier from the questionnaire if 212 // we have a profile 213 if (prebuiltQuestionnaire == null) { 214 questionnaire.addIdentifier().setSystem("urn:ietf:rfc:3986").setValue(questionnaireId); 215 questionnaire.setVersion(profile.getVersion()); 216 questionnaire.setStatus(convertStatus(profile.getStatus())); 217 questionnaire.setDate(profile.getDate()); 218 questionnaire.setPublisher(profile.getPublisher()); 219 questionnaire.setGroup(new Questionnaire.GroupComponent()); 220 questionnaire.getGroup().getConcept().addAll(profile.getCode()); 221 questionnaire.setId(nextId("qs")); 222 } 223 224 if (response != null) { 225 // no identifier - this is transient 226 response.setQuestionnaire(factory.makeReference("#" + questionnaire.getId())); 227 response.getContained().add(questionnaire); 228 response.setStatus(QuestionnaireResponseStatus.INPROGRESS); 229 response.setGroup(new QuestionnaireResponse.GroupComponent()); 230 response.getGroup().setUserData("object", resource); 231 } 232 233 } 234 235 private QuestionnaireStatus convertStatus(ConformanceResourceStatus status) { 236 switch (status) { 237 case ACTIVE: 238 return QuestionnaireStatus.PUBLISHED; 239 case DRAFT: 240 return QuestionnaireStatus.DRAFT; 241 case RETIRED: 242 return QuestionnaireStatus.RETIRED; 243 default: 244 return QuestionnaireStatus.NULL; 245 } 246 } 247 248 private String nextId(String prefix) { 249 lastid++; 250 return prefix + Integer.toString(lastid); 251 } 252 253 private void buildGroup(GroupComponent group, StructureDefinition profile, ElementDefinition element, 254 List<ElementDefinition> parents, List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 255 group.setLinkId(element.getPath()); // todo: this will be wrong when we start slicing 256 group.setTitle(element.getShort()); // todo - may need to prepend the name tail... 257 group.setText(element.getComments()); 258 ToolingExtensions.addFlyOver(group, element.getDefinition()); 259 group.setRequired(element.getMin() > 0); 260 group.setRepeats(!element.getMax().equals("1")); 261 262 for (org.hl7.fhir.dstu2.model.QuestionnaireResponse.GroupComponent ag : answerGroups) { 263 ag.setLinkId(group.getLinkId()); 264 ag.setTitle(group.getTitle()); 265 ag.setText(group.getText()); 266 } 267 268 // now, we iterate the children 269 List<ElementDefinition> list = ProfileUtilities.getChildList(profile, element); 270 for (ElementDefinition child : list) { 271 272 if (!isExempt(element, child) && !parents.contains(child)) { 273 List<ElementDefinition> nparents = new ArrayList<ElementDefinition>(); 274 nparents.addAll(parents); 275 nparents.add(child); 276 GroupComponent childGroup = group.addGroup(); 277 278 List<QuestionnaireResponse.GroupComponent> nResponse = new ArrayList<QuestionnaireResponse.GroupComponent>(); 279 processExisting(child.getPath(), answerGroups, nResponse); 280 // if the element has a type, we add a question. else we add a group on the 281 // basis that 282 // it will have children of it's own 283 if (child.getType().isEmpty() || isAbstractType(child.getType())) 284 buildGroup(childGroup, profile, child, nparents, nResponse); 285 else 286 buildQuestion(childGroup, profile, child, child.getPath(), nResponse); 287 } 288 } 289 } 290 291 private boolean isAbstractType(List<TypeRefComponent> type) { 292 return type.size() == 1 293 && (type.get(0).getCode().equals("Element") || type.get(0).getCode().equals("BackboneElement")); 294 } 295 296 private boolean isExempt(ElementDefinition element, ElementDefinition child) { 297 String n = tail(child.getPath()); 298 String t = ""; 299 if (!element.getType().isEmpty()) 300 t = element.getType().get(0).getCode(); 301 302 // we don't generate questions for the base stuff in every element 303 if (t.equals("Resource") && (n.equals("text") || n.equals("language") || n.equals("contained"))) 304 return true; 305 // we don't generate questions for extensions 306 else if (n.equals("extension") || n.equals("modifierExtension")) { 307 if (child.getType().size() > 0 && !child.getType().get(0).hasProfile()) 308 return false; 309 else 310 return true; 311 } else 312 return false; 313 } 314 315 private String tail(String path) { 316 return path.substring(path.lastIndexOf('.') + 1); 317 } 318 319 private void processExisting(String path, List<QuestionnaireResponse.GroupComponent> answerGroups, 320 List<QuestionnaireResponse.GroupComponent> nResponse) { 321 // processing existing data 322 for (QuestionnaireResponse.GroupComponent ag : answerGroups) { 323 List<Base> children = ((Element) ag.getUserData("object")).listChildrenByName(tail(path)); 324 for (Base child : children) { 325 if (child != null) { 326 QuestionnaireResponse.GroupComponent ans = ag.addGroup(); 327 ans.setUserData("object", child); 328 nResponse.add(ans); 329 } 330 } 331 } 332 } 333 334 private void buildQuestion(GroupComponent group, StructureDefinition profile, ElementDefinition element, String path, 335 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 336 group.setLinkId(path); 337 338 // in this context, we don't have any concepts to mark... 339 group.setText(element.getShort()); // prefix with name? 340 group.setRequired(element.getMin() > 0); 341 group.setRepeats(!element.getMax().equals('1')); 342 343 for (QuestionnaireResponse.GroupComponent ag : answerGroups) { 344 ag.setLinkId(group.getLinkId()); 345 ag.setTitle(group.getTitle()); 346 ag.setText(group.getText()); 347 } 348 349 if (!Utilities.noString(element.getComments())) 350 ToolingExtensions.addFlyOver(group, element.getDefinition() + " " + element.getComments()); 351 else 352 ToolingExtensions.addFlyOver(group, element.getDefinition()); 353 354 if (element.getType().size() > 1 || element.getType().get(0).getCode().equals("*")) { 355 List<TypeRefComponent> types = expandTypeList(element.getType()); 356 Questionnaire.QuestionComponent q = addQuestion(group, AnswerFormat.CHOICE, element.getPath(), "_type", "type", 357 null, makeTypeList(profile, types, element.getPath())); 358 for (TypeRefComponent t : types) { 359 Questionnaire.GroupComponent sub = q.addGroup(); 360 sub.setLinkId(element.getPath() + "._" + t.getUserData("text")); 361 sub.setText((String) t.getUserData("text")); 362 // always optional, never repeats 363 364 List<QuestionnaireResponse.GroupComponent> selected = new ArrayList<QuestionnaireResponse.GroupComponent>(); 365 selectTypes(profile, sub, t, answerGroups, selected); 366 processDataType(profile, sub, element, element.getPath() + "._" + t.getUserData("text"), t, selected); 367 } 368 } else 369 // now we have to build the question panel for each different data type 370 processDataType(profile, group, element, element.getPath(), element.getType().get(0), answerGroups); 371 372 } 373 374 private List<TypeRefComponent> expandTypeList(List<TypeRefComponent> types) { 375 List<TypeRefComponent> result = new ArrayList<TypeRefComponent>(); 376 for (TypeRefComponent t : types) { 377 if (t.hasProfile()) 378 result.add(t); 379 else if (t.getCode().equals("*")) { 380 result.add(new TypeRefComponent().setCode("integer")); 381 result.add(new TypeRefComponent().setCode("decimal")); 382 result.add(new TypeRefComponent().setCode("dateTime")); 383 result.add(new TypeRefComponent().setCode("date")); 384 result.add(new TypeRefComponent().setCode("instant")); 385 result.add(new TypeRefComponent().setCode("time")); 386 result.add(new TypeRefComponent().setCode("string")); 387 result.add(new TypeRefComponent().setCode("uri")); 388 result.add(new TypeRefComponent().setCode("boolean")); 389 result.add(new TypeRefComponent().setCode("Coding")); 390 result.add(new TypeRefComponent().setCode("CodeableConcept")); 391 result.add(new TypeRefComponent().setCode("Attachment")); 392 result.add(new TypeRefComponent().setCode("Identifier")); 393 result.add(new TypeRefComponent().setCode("Quantity")); 394 result.add(new TypeRefComponent().setCode("Range")); 395 result.add(new TypeRefComponent().setCode("Period")); 396 result.add(new TypeRefComponent().setCode("Ratio")); 397 result.add(new TypeRefComponent().setCode("HumanName")); 398 result.add(new TypeRefComponent().setCode("Address")); 399 result.add(new TypeRefComponent().setCode("ContactPoint")); 400 result.add(new TypeRefComponent().setCode("Timing")); 401 result.add(new TypeRefComponent().setCode("Reference")); 402 } else 403 result.add(t); 404 } 405 return result; 406 } 407 408 private ValueSet makeTypeList(StructureDefinition profile, List<TypeRefComponent> types, String path) { 409 ValueSet vs = new ValueSet(); 410 vs.setName("Type options for " + path); 411 vs.setDescription(vs.getName()); 412 vs.setStatus(ConformanceResourceStatus.ACTIVE); 413 vs.setExpansion(new ValueSetExpansionComponent()); 414 vs.getExpansion().setIdentifier(Factory.createUUID()); 415 vs.getExpansion().setTimestampElement(DateTimeType.now()); 416 for (TypeRefComponent t : types) { 417 ValueSetExpansionContainsComponent cc = vs.getExpansion().addContains(); 418 if (t.getCode().equals("Reference") && (t.hasProfile() 419 && t.getProfile().get(0).getValue().startsWith("http://hl7.org/fhir/StructureDefinition/"))) { 420 cc.setCode(t.getProfile().get(0).getValue().substring(40)); 421 cc.setSystem("http://hl7.org/fhir/resource-types"); 422 cc.setDisplay(cc.getCode()); 423 } else { 424 ProfileUtilities pu = new ProfileUtilities(context, null, null); 425 StructureDefinition ps = null; 426 if (t.hasProfile()) 427 ps = pu.getProfile(profile, t.getProfile().get(0).getValue()); 428 429 if (ps != null) { 430 cc.setCode(t.getProfile().get(0).getValue()); 431 cc.setDisplay(ps.getSnapshot().getElement().get(0).getType().get(0).getCode()); 432 cc.setSystem("http://hl7.org/fhir/resource-types"); 433 } else { 434 cc.setCode(t.getCode()); 435 cc.setDisplay(t.getCode()); 436 cc.setSystem("http://hl7.org/fhir/data-types"); 437 } 438 } 439 t.setUserData("text", cc.getCode()); 440 } 441 442 return vs; 443 } 444 445 private void selectTypes(StructureDefinition profile, GroupComponent sub, TypeRefComponent t, 446 List<QuestionnaireResponse.GroupComponent> source, List<QuestionnaireResponse.GroupComponent> dest) { 447 List<QuestionnaireResponse.GroupComponent> temp = new ArrayList<QuestionnaireResponse.GroupComponent>(); 448 449 for (QuestionnaireResponse.GroupComponent g : source) 450 if (instanceOf(t, (Element) g.getUserData("object"))) 451 temp.add(g); 452 for (QuestionnaireResponse.GroupComponent g : temp) 453 source.remove(g); 454 for (QuestionnaireResponse.GroupComponent g : temp) { 455 // 1st the answer: 456 assert (g.getQuestion().size() == 0); // it should be empty 457 QuestionnaireResponse.QuestionComponent q = g.addQuestion(); 458 q.setLinkId(g.getLinkId() + "._type"); 459 q.setText("type"); 460 461 Coding cc = new Coding(); 462 QuestionAnswerComponent a = q.addAnswer(); 463 a.setValue(cc); 464 if (t.getCode().equals("Reference") && t.hasProfile() 465 && t.getProfile().get(0).getValue().startsWith("http://hl7.org/fhir/StructureDefinition/")) { 466 cc.setCode(t.getProfile().get(0).getValue().substring(40)); 467 cc.setSystem("http://hl7.org/fhir/resource-types"); 468 } else { 469 ProfileUtilities pu = new ProfileUtilities(context, null, null); 470 StructureDefinition ps = null; 471 if (t.hasProfile()) 472 ps = pu.getProfile(profile, t.getProfile().get(0).getValue()); 473 474 if (ps != null) { 475 cc.setCode(t.getProfile().get(0).getValue()); 476 cc.setSystem("http://hl7.org/fhir/resource-types"); 477 } else { 478 cc.setCode(t.getCode()); 479 cc.setSystem("http://hl7.org/fhir/data-types"); 480 } 481 } 482 483 // 1st: create the subgroup 484 QuestionnaireResponse.GroupComponent subg = a.addGroup(); 485 dest.add(subg); 486 subg.setLinkId(sub.getLinkId()); 487 subg.setText(sub.getText()); 488 subg.setUserData("object", g.getUserData("object")); 489 } 490 } 491 492 private boolean instanceOf(TypeRefComponent t, Element obj) { 493 if (t.getCode().equals("Reference")) { 494 if (!(obj instanceof Reference)) { 495 return false; 496 } else { 497 String url = ((Reference) obj).getReference(); 498 // there are several problems here around profile matching. This process is 499 // degenerative, and there's probably nothing we can do to solve it 500 if (url.startsWith("http:") || url.startsWith("https:")) 501 return true; 502 else if (t.hasProfile() 503 && t.getProfile().get(0).getValue().startsWith("http://hl7.org/fhir/StructureDefinition/")) 504 return url.startsWith(t.getProfile().get(0).getValue().substring(40) + '/'); 505 else 506 return true; 507 } 508 } else if (t.getCode().equals("Quantity")) { 509 return obj instanceof Quantity; 510 } else 511 throw new NotImplementedException("Not Done Yet"); 512 } 513 514 private QuestionComponent addQuestion(GroupComponent group, AnswerFormat af, String path, String id, String name, 515 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 516 return addQuestion(group, af, path, id, name, answerGroups, null); 517 } 518 519 private QuestionComponent addQuestion(GroupComponent group, AnswerFormat af, String path, String id, String name, 520 List<QuestionnaireResponse.GroupComponent> answerGroups, ValueSet vs) throws FHIRException { 521 QuestionComponent result = group.addQuestion(); 522 if (vs != null) { 523 result.setOptions(new Reference()); 524 if (vs.getExpansion() == null) { 525 result.getOptions().setReference(vs.getUrl()); 526 ToolingExtensions.addFilterOnly(result.getOptions(), true); 527 } else { 528 if (Utilities.noString(vs.getId())) { 529 vs.setId(nextId("vs")); 530 questionnaire.getContained().add(vs); 531 vsCache.put(vs.getUrl(), vs.getId()); 532 vs.setText(null); 533 vs.setCodeSystem(null); 534 vs.setCompose(null); 535 vs.getContact().clear(); 536 vs.setPublisherElement(null); 537 vs.setCopyrightElement(null); 538 } 539 result.getOptions().setReference("#" + vs.getId()); 540 } 541 } 542 543 result.setLinkId(path + '.' + id); 544 result.setText(name); 545 result.setType(af); 546 result.setRequired(false); 547 result.setRepeats(false); 548 if (id.endsWith("/1")) 549 id = id.substring(0, id.length() - 2); 550 551 if (answerGroups != null) { 552 553 for (QuestionnaireResponse.GroupComponent ag : answerGroups) { 554 List<Base> children = new ArrayList<Base>(); 555 556 QuestionnaireResponse.QuestionComponent aq = null; 557 Element obj = (Element) ag.getUserData("object"); 558 if (isPrimitive((TypeRefComponent) obj)) 559 children.add(obj); 560 else if (obj instanceof Enumeration) { 561 String value = ((Enumeration) obj).toString(); 562 children.add(new StringType(value)); 563 } else 564 children = obj.listChildrenByName(id); 565 566 for (Base child : children) { 567 if (child != null) { 568 if (aq == null) { 569 aq = ag.addQuestion(); 570 aq.setLinkId(result.getLinkId()); 571 aq.setText(result.getText()); 572 } 573 aq.addAnswer().setValue(convertType(child, af, vs, result.getLinkId())); 574 } 575 } 576 } 577 } 578 return result; 579 } 580 581 @SuppressWarnings("unchecked") 582 private Type convertType(Base value, AnswerFormat af, ValueSet vs, String path) throws FHIRException { 583 switch (af) { 584 // simple cases 585 case BOOLEAN: 586 if (value instanceof BooleanType) 587 return (Type) value; 588 case DECIMAL: 589 if (value instanceof DecimalType) 590 return (Type) value; 591 case INTEGER: 592 if (value instanceof IntegerType) 593 return (Type) value; 594 case DATE: 595 if (value instanceof DateType) 596 return (Type) value; 597 case DATETIME: 598 if (value instanceof DateTimeType) 599 return (Type) value; 600 case INSTANT: 601 if (value instanceof InstantType) 602 return (Type) value; 603 case TIME: 604 if (value instanceof TimeType) 605 return (Type) value; 606 case STRING: 607 if (value instanceof StringType) 608 return (Type) value; 609 else if (value instanceof UriType) 610 return new StringType(((UriType) value).asStringValue()); 611 612 case TEXT: 613 if (value instanceof StringType) 614 return (Type) value; 615 case QUANTITY: 616 if (value instanceof Quantity) 617 return (Type) value; 618 619 // complex cases: 620 // ? AnswerFormatAttachment: ...? 621 case CHOICE: 622 case OPENCHOICE: 623 if (value instanceof Coding) 624 return (Type) value; 625 else if (value instanceof Enumeration) { 626 Coding cc = new Coding(); 627 cc.setCode(((Enumeration<Enum<?>>) value).asStringValue()); 628 cc.setSystem(getSystemForCode(vs, cc.getCode(), path)); 629 return cc; 630 } else if (value instanceof StringType) { 631 Coding cc = new Coding(); 632 cc.setCode(((StringType) value).asStringValue()); 633 cc.setSystem(getSystemForCode(vs, cc.getCode(), path)); 634 return cc; 635 } 636 637 case REFERENCE: 638 if (value instanceof Reference) 639 return (Type) value; 640 else if (value instanceof StringType) { 641 Reference r = new Reference(); 642 r.setReference(((StringType) value).asStringValue()); 643 } 644 } 645 646 throw new FHIRException("Unable to convert from '" + value.getClass().toString() + "' for Answer Format " 647 + af.toCode() + ", path = " + path); 648 } 649 650 private String getSystemForCode(ValueSet vs, String code, String path) throws FHIRException { 651// var 652// i, q : integer; 653// begin 654 String result = null; 655 if (vs == null) { 656 if (prebuiltQuestionnaire == null) 657 throw new FHIRException("Logic error at path = " + path); 658 for (Resource r : prebuiltQuestionnaire.getContained()) { 659 if (r instanceof ValueSet) { 660 vs = (ValueSet) r; 661 if (vs.hasExpansion()) { 662 for (ValueSetExpansionContainsComponent c : vs.getExpansion().getContains()) { 663 if (c.getCode().equals(code)) { 664 if (result == null) 665 result = c.getSystem(); 666 else 667 throw new FHIRException( 668 "Multiple matches in " + vs.getUrl() + " for code " + code + " at path = " + path); 669 } 670 } 671 } 672 } 673 } 674 } 675 676 for (ValueSetExpansionContainsComponent c : vs.getExpansion().getContains()) { 677 if (c.getCode().equals(code)) { 678 if (result == null) 679 result = c.getSystem(); 680 else 681 throw new FHIRException("Multiple matches in " + vs.getUrl() + " for code " + code + " at path = " + path); 682 } 683 } 684 if (result != null) 685 return result; 686 throw new FHIRException("Unable to resolve code " + code + " at path = " + path); 687 } 688 689 private boolean isPrimitive(TypeRefComponent t) { 690 return (t != null) && (t.getCode().equals("string") || t.getCode().equals("code") || t.getCode().equals("boolean") 691 || t.getCode().equals("integer") || t.getCode().equals("unsignedInt") || t.getCode().equals("positiveInt") 692 || t.getCode().equals("decimal") || t.getCode().equals("date") || t.getCode().equals("dateTime") 693 || t.getCode().equals("instant") || t.getCode().equals("time") || t.getCode().equals("Reference")); 694 } 695 696 private void processDataType(StructureDefinition profile, GroupComponent group, ElementDefinition element, 697 String path, TypeRefComponent t, List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 698 if (t.getCode().equals("code")) 699 addCodeQuestions(group, element, path, answerGroups); 700 else if (t.getCode().equals("string") || t.getCode().equals("id") || t.getCode().equals("oid") 701 || t.getCode().equals("markdown")) 702 addStringQuestions(group, element, path, answerGroups); 703 else if (t.getCode().equals("uri")) 704 addUriQuestions(group, element, path, answerGroups); 705 else if (t.getCode().equals("boolean")) 706 addBooleanQuestions(group, element, path, answerGroups); 707 else if (t.getCode().equals("decimal")) 708 addDecimalQuestions(group, element, path, answerGroups); 709 else if (t.getCode().equals("dateTime") || t.getCode().equals("date")) 710 addDateTimeQuestions(group, element, path, answerGroups); 711 else if (t.getCode().equals("instant")) 712 addInstantQuestions(group, element, path, answerGroups); 713 else if (t.getCode().equals("time")) 714 addTimeQuestions(group, element, path, answerGroups); 715 else if (t.getCode().equals("CodeableConcept")) 716 addCodeableConceptQuestions(group, element, path, answerGroups); 717 else if (t.getCode().equals("Period")) 718 addPeriodQuestions(group, element, path, answerGroups); 719 else if (t.getCode().equals("Ratio")) 720 addRatioQuestions(group, element, path, answerGroups); 721 else if (t.getCode().equals("HumanName")) 722 addHumanNameQuestions(group, element, path, answerGroups); 723 else if (t.getCode().equals("Address")) 724 addAddressQuestions(group, element, path, answerGroups); 725 else if (t.getCode().equals("ContactPoint")) 726 addContactPointQuestions(group, element, path, answerGroups); 727 else if (t.getCode().equals("Identifier")) 728 addIdentifierQuestions(group, element, path, answerGroups); 729 else if (t.getCode().equals("integer") || t.getCode().equals("positiveInt") || t.getCode().equals("unsignedInt")) 730 addIntegerQuestions(group, element, path, answerGroups); 731 else if (t.getCode().equals("Coding")) 732 addCodingQuestions(group, element, path, answerGroups); 733 else if (t.getCode().equals("Quantity")) 734 addQuantityQuestions(group, element, path, answerGroups); 735 else if (t.getCode().equals("SimpleQuantity")) 736 addSimpleQuantityQuestions(group, element, path, answerGroups); 737 else if (t.getCode().equals("Money")) 738 addMoneyQuestions(group, element, path, answerGroups); 739 else if (t.getCode().equals("Reference")) 740 addReferenceQuestions(group, element, path, t.hasProfile() ? t.getProfile().get(0).getValue() : null, 741 answerGroups); 742 else if (t.getCode().equals("Duration")) 743 addDurationQuestions(group, element, path, answerGroups); 744 else if (t.getCode().equals("base64Binary")) 745 addBinaryQuestions(group, element, path, answerGroups); 746 else if (t.getCode().equals("Attachment")) 747 addAttachmentQuestions(group, element, path, answerGroups); 748 else if (t.getCode().equals("Age")) 749 addAgeQuestions(group, element, path, answerGroups); 750 else if (t.getCode().equals("Range")) 751 addRangeQuestions(group, element, path, answerGroups); 752 else if (t.getCode().equals("Timing")) 753 addTimingQuestions(group, element, path, answerGroups); 754 else if (t.getCode().equals("Annotation")) 755 addAnnotationQuestions(group, element, path, answerGroups); 756 else if (t.getCode().equals("SampledData")) 757 addSampledDataQuestions(group, element, path, answerGroups); 758 else if (t.getCode().equals("Extension")) { 759 if (t.hasProfile()) 760 addExtensionQuestions(profile, group, element, path, t.getProfile().get(0).getValue(), answerGroups); 761 } else if (!t.getCode().equals("Narrative") && !t.getCode().equals("Resource") 762 && !t.getCode().equals("ElementDefinition") && !t.getCode().equals("Meta") && !t.getCode().equals("Signature")) 763 throw new NotImplementedException("Unhandled Data Type: " + t.getCode() + " on element " + element.getPath()); 764 } 765 766 private void addCodeQuestions(GroupComponent group, ElementDefinition element, String path, 767 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 768 ToolingExtensions.addType(group, "code"); 769 ValueSet vs = resolveValueSet(null, element.hasBinding() ? element.getBinding() : null); 770 addQuestion(group, AnswerFormat.CHOICE, path, "value", unCamelCase(tail(element.getPath())), answerGroups, vs); 771 group.setText(null); 772 for (QuestionnaireResponse.GroupComponent ag : answerGroups) 773 ag.setText(null); 774 } 775 776 private String unCamelCase(String s) { 777 StringBuilder result = new StringBuilder(); 778 779 for (int i = 0; i < s.length(); i++) { 780 if (Character.isUpperCase(s.charAt(i))) 781 result.append(' '); 782 result.append(s.charAt(i)); 783 } 784 return result.toString().toLowerCase(); 785 } 786 787 private void addStringQuestions(GroupComponent group, ElementDefinition element, String path, 788 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 789 ToolingExtensions.addType(group, "string"); 790 addQuestion(group, AnswerFormat.STRING, path, "value", group.getText(), answerGroups); 791 group.setText(null); 792 for (QuestionnaireResponse.GroupComponent ag : answerGroups) 793 ag.setText(null); 794 } 795 796 private void addTimeQuestions(GroupComponent group, ElementDefinition element, String path, 797 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 798 ToolingExtensions.addType(group, "time"); 799 addQuestion(group, AnswerFormat.TIME, path, "value", group.getText(), answerGroups); 800 group.setText(null); 801 for (QuestionnaireResponse.GroupComponent ag : answerGroups) 802 ag.setText(null); 803 } 804 805 private void addUriQuestions(GroupComponent group, ElementDefinition element, String path, 806 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 807 ToolingExtensions.addType(group, "uri"); 808 addQuestion(group, AnswerFormat.STRING, path, "value", group.getText(), answerGroups); 809 group.setText(null); 810 for (QuestionnaireResponse.GroupComponent ag : answerGroups) 811 ag.setText(null); 812 } 813 814 private void addBooleanQuestions(GroupComponent group, ElementDefinition element, String path, 815 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 816 ToolingExtensions.addType(group, "boolean"); 817 addQuestion(group, AnswerFormat.BOOLEAN, path, "value", group.getText(), answerGroups); 818 group.setText(null); 819 for (QuestionnaireResponse.GroupComponent ag : answerGroups) 820 ag.setText(null); 821 } 822 823 private void addDecimalQuestions(GroupComponent group, ElementDefinition element, String path, 824 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 825 ToolingExtensions.addType(group, "decimal"); 826 addQuestion(group, AnswerFormat.DECIMAL, path, "value", group.getText(), answerGroups); 827 group.setText(null); 828 for (QuestionnaireResponse.GroupComponent ag : answerGroups) 829 ag.setText(null); 830 } 831 832 private void addIntegerQuestions(GroupComponent group, ElementDefinition element, String path, 833 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 834 ToolingExtensions.addType(group, "integer"); 835 addQuestion(group, AnswerFormat.INTEGER, path, "value", group.getText(), answerGroups); 836 group.setText(null); 837 for (QuestionnaireResponse.GroupComponent ag : answerGroups) 838 ag.setText(null); 839 } 840 841 private void addDateTimeQuestions(GroupComponent group, ElementDefinition element, String path, 842 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 843 ToolingExtensions.addType(group, "datetime"); 844 addQuestion(group, AnswerFormat.DATETIME, path, "value", group.getText(), answerGroups); 845 group.setText(null); 846 for (QuestionnaireResponse.GroupComponent ag : answerGroups) 847 ag.setText(null); 848 } 849 850 private void addInstantQuestions(GroupComponent group, ElementDefinition element, String path, 851 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 852 ToolingExtensions.addType(group, "instant"); 853 addQuestion(group, AnswerFormat.INSTANT, path, "value", group.getText(), answerGroups); 854 group.setText(null); 855 for (QuestionnaireResponse.GroupComponent ag : answerGroups) 856 ag.setText(null); 857 } 858 859 private void addBinaryQuestions(GroupComponent group, ElementDefinition element, String path, 860 List<QuestionnaireResponse.GroupComponent> answerGroups) { 861 ToolingExtensions.addType(group, "binary"); 862 // ? Lloyd: how to support binary content 863 } 864 865 // Complex Types --------------------------------------------------------------- 866 867 private AnswerFormat answerTypeForBinding(ElementDefinitionBindingComponent binding) { 868 if (binding == null) 869 return AnswerFormat.OPENCHOICE; 870 else if (binding.getStrength() != BindingStrength.REQUIRED) 871 return AnswerFormat.OPENCHOICE; 872 else 873 return AnswerFormat.CHOICE; 874 } 875 876 private void addCodingQuestions(GroupComponent group, ElementDefinition element, String path, 877 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 878 ToolingExtensions.addType(group, "Coding"); 879 addQuestion(group, answerTypeForBinding(element.hasBinding() ? element.getBinding() : null), path, "value", 880 group.getText(), answerGroups, resolveValueSet(null, element.hasBinding() ? element.getBinding() : null)); 881 group.setText(null); 882 for (QuestionnaireResponse.GroupComponent ag : answerGroups) 883 ag.setText(null); 884 } 885 886 private void addCodeableConceptQuestions(GroupComponent group, ElementDefinition element, String path, 887 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 888 ToolingExtensions.addType(group, "CodeableConcept"); 889 addQuestion(group, answerTypeForBinding(element.hasBinding() ? element.getBinding() : null), path, "coding", 890 "code:", answerGroups, resolveValueSet(null, element.hasBinding() ? element.getBinding() : null)); 891 addQuestion(group, AnswerFormat.STRING, path, "text", "text:", answerGroups); 892 } 893 894 private ValueSet makeAnyValueSet() { 895 // TODO Auto-generated method stub 896 return null; 897 } 898 899 private void addPeriodQuestions(GroupComponent group, ElementDefinition element, String path, 900 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 901 ToolingExtensions.addType(group, "Period"); 902 addQuestion(group, AnswerFormat.DATETIME, path, "low", "start:", answerGroups); 903 addQuestion(group, AnswerFormat.DATETIME, path, "end", "end:", answerGroups); 904 } 905 906 private void addRatioQuestions(GroupComponent group, ElementDefinition element, String path, 907 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 908 ToolingExtensions.addType(group, "Ratio"); 909 addQuestion(group, AnswerFormat.DECIMAL, path, "numerator", "numerator:", answerGroups); 910 addQuestion(group, AnswerFormat.DECIMAL, path, "denominator", "denominator:", answerGroups); 911 addQuestion(group, AnswerFormat.STRING, path, "units", "units:", answerGroups); 912 } 913 914 private void addHumanNameQuestions(GroupComponent group, ElementDefinition element, String path, 915 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 916 ToolingExtensions.addType(group, "Name"); 917 addQuestion(group, AnswerFormat.STRING, path, "text", "text:", answerGroups); 918 addQuestion(group, AnswerFormat.STRING, path, "family", "family:", answerGroups).setRepeats(true); 919 addQuestion(group, AnswerFormat.STRING, path, "given", "given:", answerGroups).setRepeats(true); 920 } 921 922 private void addAddressQuestions(GroupComponent group, ElementDefinition element, String path, 923 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 924 ToolingExtensions.addType(group, "Address"); 925 addQuestion(group, AnswerFormat.STRING, path, "text", "text:", answerGroups); 926 addQuestion(group, AnswerFormat.STRING, path, "line", "line:", answerGroups).setRepeats(true); 927 addQuestion(group, AnswerFormat.STRING, path, "city", "city:", answerGroups); 928 addQuestion(group, AnswerFormat.STRING, path, "state", "state:", answerGroups); 929 addQuestion(group, AnswerFormat.STRING, path, "postalCode", "post code:", answerGroups); 930 addQuestion(group, AnswerFormat.STRING, path, "country", "country:", answerGroups); 931 addQuestion(group, AnswerFormat.CHOICE, path, "use", "use:", answerGroups, 932 resolveValueSet("http://hl7.org/fhir/vs/address-use")); 933 } 934 935 private void addContactPointQuestions(GroupComponent group, ElementDefinition element, String path, 936 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 937 ToolingExtensions.addType(group, "ContactPoint"); 938 addQuestion(group, AnswerFormat.CHOICE, path, "system", "type:", answerGroups, 939 resolveValueSet("http://hl7.org/fhir/vs/contact-point-system")); 940 addQuestion(group, AnswerFormat.STRING, path, "value", "value:", answerGroups); 941 addQuestion(group, AnswerFormat.CHOICE, path, "use", "use:", answerGroups, 942 resolveValueSet("http://hl7.org/fhir/vs/contact-point-use")); 943 } 944 945 private void addIdentifierQuestions(GroupComponent group, ElementDefinition element, String path, 946 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 947 ToolingExtensions.addType(group, "Identifier"); 948 addQuestion(group, AnswerFormat.STRING, path, "label", "label:", answerGroups); 949 addQuestion(group, AnswerFormat.STRING, path, "system", "system:", answerGroups); 950 addQuestion(group, AnswerFormat.STRING, path, "value", "value:", answerGroups); 951 } 952 953 private void addSimpleQuantityQuestions(GroupComponent group, ElementDefinition element, String path, 954 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 955 ToolingExtensions.addType(group, "Quantity"); 956 addQuestion(group, AnswerFormat.DECIMAL, path, "value", "value:", answerGroups); 957 addQuestion(group, AnswerFormat.STRING, path, "units", "units:", answerGroups); 958 addQuestion(group, AnswerFormat.STRING, path, "code", "coded units:", answerGroups); 959 addQuestion(group, AnswerFormat.STRING, path, "system", "units system:", answerGroups); 960 } 961 962 private void addQuantityQuestions(GroupComponent group, ElementDefinition element, String path, 963 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 964 ToolingExtensions.addType(group, "Quantity"); 965 addQuestion(group, AnswerFormat.CHOICE, path, "comparator", "comp:", answerGroups, 966 resolveValueSet("http://hl7.org/fhir/vs/quantity-comparator")); 967 addQuestion(group, AnswerFormat.DECIMAL, path, "value", "value:", answerGroups); 968 addQuestion(group, AnswerFormat.STRING, path, "units", "units:", answerGroups); 969 addQuestion(group, AnswerFormat.STRING, path, "code", "coded units:", answerGroups); 970 addQuestion(group, AnswerFormat.STRING, path, "system", "units system:", answerGroups); 971 } 972 973 private void addMoneyQuestions(GroupComponent group, ElementDefinition element, String path, 974 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 975 ToolingExtensions.addType(group, "Money"); 976 addQuestion(group, AnswerFormat.DECIMAL, path, "value", "value:", answerGroups); 977 addQuestion(group, AnswerFormat.STRING, path, "currency", "currency:", answerGroups); 978 } 979 980 private void addAgeQuestions(GroupComponent group, ElementDefinition element, String path, 981 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 982 ToolingExtensions.addType(group, "Age"); 983 addQuestion(group, AnswerFormat.CHOICE, path, "comparator", "comp:", answerGroups, 984 resolveValueSet("http://hl7.org/fhir/vs/quantity-comparator")); 985 addQuestion(group, AnswerFormat.DECIMAL, path, "value", "value:", answerGroups); 986 addQuestion(group, AnswerFormat.CHOICE, path, "units", "units:", answerGroups, 987 resolveValueSet("http://hl7.org/fhir/vs/duration-units")); 988 } 989 990 private void addDurationQuestions(GroupComponent group, ElementDefinition element, String path, 991 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 992 ToolingExtensions.addType(group, "Duration"); 993 addQuestion(group, AnswerFormat.DECIMAL, path, "value", "value:", answerGroups); 994 addQuestion(group, AnswerFormat.STRING, path, "units", "units:", answerGroups); 995 } 996 997 private void addAttachmentQuestions(GroupComponent group, ElementDefinition element, String path, 998 List<QuestionnaireResponse.GroupComponent> answerGroups) { 999 ToolingExtensions.addType(group, "Attachment"); 1000 // raise Exception.Create("addAttachmentQuestions not Done Yet"); 1001 } 1002 1003 private void addRangeQuestions(GroupComponent group, ElementDefinition element, String path, 1004 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 1005 ToolingExtensions.addType(group, "Range"); 1006 addQuestion(group, AnswerFormat.DECIMAL, path, "low", "low:", answerGroups); 1007 addQuestion(group, AnswerFormat.DECIMAL, path, "high", "high:", answerGroups); 1008 addQuestion(group, AnswerFormat.STRING, path, "units", "units:", answerGroups); 1009 } 1010 1011 private void addSampledDataQuestions(GroupComponent group, ElementDefinition element, String path, 1012 List<QuestionnaireResponse.GroupComponent> answerGroups) { 1013 ToolingExtensions.addType(group, "SampledData"); 1014 } 1015 1016 private void addTimingQuestions(GroupComponent group, ElementDefinition element, String path, 1017 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 1018 ToolingExtensions.addType(group, "Schedule"); 1019 addQuestion(group, AnswerFormat.STRING, path, "text", "text:", answerGroups); 1020 addQuestion(group, AnswerFormat.DATETIME, path, "date", "date:", answerGroups); 1021 QuestionComponent q = addQuestion(group, AnswerFormat.REFERENCE, path, "author", "author:", answerGroups); 1022 ToolingExtensions.addReference(q, "/Patient?"); 1023 ToolingExtensions.addReference(q, "/Practitioner?"); 1024 ToolingExtensions.addReference(q, "/RelatedPerson?"); 1025 } 1026 1027 private void addAnnotationQuestions(GroupComponent group, ElementDefinition element, String path, 1028 List<QuestionnaireResponse.GroupComponent> answerGroups) { 1029 ToolingExtensions.addType(group, "Annotation"); 1030 } 1031 // Special Types --------------------------------------------------------------- 1032 1033 private void addReferenceQuestions(GroupComponent group, ElementDefinition element, String path, String profileURL, 1034 List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 1035 // var 1036 // rn : String; 1037 // i : integer; 1038 // q : TFhirQuestionnaireGroupQuestion; 1039 ToolingExtensions.addType(group, "Reference"); 1040 1041 QuestionComponent q = addQuestion(group, AnswerFormat.REFERENCE, path, "value", group.getText(), answerGroups); 1042 group.setText(null); 1043 String rn = null; 1044 if (profileURL != null && profileURL.startsWith("http://hl7.org/fhir/StructureDefinition/")) 1045 rn = profileURL.substring(40); 1046 else 1047 rn = "Any"; 1048 if (rn.equals("Any")) 1049 ToolingExtensions.addReference(q, "/_search?subject=$subj&patient=$subj&encounter=$encounter"); 1050 else 1051 ToolingExtensions.addReference(q, "/" + rn + "?subject=$subj&patient=$subj&encounter=$encounter"); 1052 for (QuestionnaireResponse.GroupComponent ag : answerGroups) 1053 ag.setText(null); 1054 } 1055 1056 private void addExtensionQuestions(StructureDefinition profile, GroupComponent group, ElementDefinition element, 1057 String path, String url, List<QuestionnaireResponse.GroupComponent> answerGroups) throws FHIRException { 1058 // if this a profiled extension, then we add it 1059 if (!Utilities.noString(url)) { 1060 StructureDefinition ed = context.fetchResource(StructureDefinition.class, url); 1061 if (ed != null) { 1062 if (answerGroups.size() > 0) 1063 throw new NotImplementedException("Debug this"); 1064 buildQuestion(group, profile, ed.getSnapshot().getElement().get(0), path + ".extension[" + url + "]", 1065 answerGroups); 1066 } 1067 } 1068 } 1069 1070 private ValueSet resolveValueSet(String url) { 1071// if (prebuiltQuestionnaire != null) 1072 return null; // we don't do anything with value sets in this case 1073 1074// if (vsCache.containsKey(url)) 1075// return (ValueSet) questionnaire.getContained(vsCache.get(url)); 1076// else { 1077// ValueSet vs = context.findValueSet(url); 1078// if (vs != null) 1079// return expander.expand(vs, MaxListboxCodings, false); 1080// } 1081// 1082// /* on e: ETooCostly do 1083// begin 1084// result := TFhirValueSet.Create; 1085// try 1086// result.identifierST := ref.referenceST; 1087// result.link; 1088// finally 1089// result.Free; 1090// end; 1091// end; 1092// on e : Exception do 1093// raise; 1094// end;*/ 1095// } 1096 } 1097 1098 private ValueSet resolveValueSet(Object object, ElementDefinitionBindingComponent binding) { 1099 return null; 1100 } 1101 1102}