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