001package org.hl7.fhir.r5.renderers;
002
003import java.io.IOException;
004import java.io.UnsupportedEncodingException;
005import java.util.List;
006
007import org.hl7.fhir.exceptions.FHIRException;
008import org.hl7.fhir.r5.model.CodeType;
009import org.hl7.fhir.r5.model.Enumeration;
010import org.hl7.fhir.r5.model.Enumerations.SearchComparator;
011import org.hl7.fhir.r5.model.Enumerations.SearchModifierCode;
012import org.hl7.fhir.r5.model.Enumerations.VersionIndependentResourceTypesAll;
013import org.hl7.fhir.r5.model.OperationDefinition;
014import org.hl7.fhir.r5.model.Resource;
015import org.hl7.fhir.r5.model.SearchParameter;
016import org.hl7.fhir.r5.model.SearchParameter.SearchParameterComponentComponent;
017import org.hl7.fhir.r5.model.StringType;
018import org.hl7.fhir.r5.model.StructureDefinition;
019import org.hl7.fhir.r5.renderers.utils.RenderingContext;
020import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType;
021import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
022import org.hl7.fhir.r5.utils.EOperationOutcome;
023import org.hl7.fhir.r5.utils.ToolingExtensions;
024import org.hl7.fhir.utilities.StandardsStatus;
025import org.hl7.fhir.utilities.Utilities;
026import org.hl7.fhir.utilities.xhtml.XhtmlNode;
027
028public class SearchParameterRenderer extends TerminologyRenderer {
029
030  public SearchParameterRenderer(RenderingContext context) {
031    super(context);
032  }
033
034  public SearchParameterRenderer(RenderingContext context, ResourceContext rcontext) {
035    super(context, rcontext);
036  }
037  
038  public boolean render(XhtmlNode x, Resource dr) throws IOException, FHIRException, EOperationOutcome {
039    return render(x, (SearchParameter) dr);
040  }
041
042  public boolean render(XhtmlNode x, SearchParameter spd) throws IOException, FHIRException, EOperationOutcome {
043    XhtmlNode h2 = x.h2();
044    h2.addText(spd.getName());
045    StandardsStatus ss = ToolingExtensions.getStandardsStatus(spd);
046    if (ss != context.getDefaultStandardsStatus()) {
047      genStandardsStatus(h2, ss);
048    }
049    XhtmlNode p =  x.para();
050    p.tx("Parameter ");
051    p.code().tx(spd.getCode());
052    p.tx(":");
053    p.code().tx(spd.getType().toCode());
054    addMarkdown(x, spd.getDescription());
055
056    XhtmlNode tbl = x.table("grid");
057    XhtmlNode tr = tbl.tr();
058    tr.td().tx(Utilities.pluralize("Resource", spd.getBase().size()));
059    XhtmlNode td = tr.td();
060    for (Enumeration<VersionIndependentResourceTypesAll> t : spd.getBase()) {
061      StructureDefinition sd = context.getWorker().fetchTypeDefinition(t.getCode());
062      if (sd != null && sd.hasWebPath()) {
063        td.sep(", ");
064        td.ah(sd.getWebPath()).tx(t.getCode());
065      } else {
066        td.sep(", ");
067        td.tx(t.getCode());
068      }
069    }
070    tr = tbl.tr();
071    tr.td().tx("Expression");
072    if (spd.hasExpression()) {
073      tr.td().code().tx(spd.getExpression());
074    } else {
075      tr.td().tx("(none)");
076    }
077    if (spd.hasProcessingMode()) {
078      tr = tbl.tr();
079      tr.td().tx("Processing Mode");
080      tr.td().tx(spd.getProcessingMode().getDisplay());      
081    }
082    if (spd.hasTarget()) {
083      tr = tbl.tr();
084      tr.td().tx(Utilities.pluralize("Target Resources", spd.getTarget().size()));
085      td = tr.td();
086      if (isAllConcreteResources(spd.getTarget())) {
087        td.ah(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "resourcelist.html")).tx("All Resources");
088      } else {
089        for (Enumeration<VersionIndependentResourceTypesAll> t : spd.getTarget()) {
090          StructureDefinition sd = context.getWorker().fetchTypeDefinition(t.getCode());
091          if (sd != null && sd.hasWebPath()) {
092            td.sep(", ");
093            td.ah(sd.getWebPath()).tx(t.getCode());
094          } else {
095            td.sep(", ");
096            td.tx(t.getCode());
097          }
098        }
099      }
100    }
101    tr = tbl.tr();
102    tr.td().tx("Multiples");
103    if (spd.getMultipleAnd() && spd.getMultipleOr()) {
104      tr.td().tx("The parameter can repeat (and) and can have repeating values (or)");      
105    } else if (spd.getMultipleOr()) {
106      tr.td().tx("The parameter can repeat (and) but each repeat can only have one value");      
107    } else if (spd.getMultipleAnd()) {
108      tr.td().tx("The parameter cannot repeat (and) but the single parameter can have multiple values (or)");      
109    } else { 
110      tr.td().tx("The parameter cannot repeat or have multiple values");
111    }
112    if (spd.hasComparator()) {
113      tr = tbl.tr();
114      tr.td().tx("Comparators");
115      td = tr.td();
116      td.tx("Allowed: ");
117      for (Enumeration<SearchComparator> t : spd.getComparator()) {
118        td.sep(", ");
119        td.tx(t.asStringValue());
120      }      
121    }
122    if (spd.hasModifier()) {
123      tr = tbl.tr();
124      tr.td().tx("Modifiers");
125      td = tr.td();
126      td.tx("Allowed: ");
127      for (Enumeration<SearchModifierCode> t : spd.getModifier()) {
128        td.sep(", ");
129        td.tx(t.asStringValue());
130      }      
131    }
132    if (spd.hasChain()) {
133      tr = tbl.tr();
134      tr.td().tx("Chains");
135      td = tr.td();
136      td.tx("Allowed: ");
137      for (StringType t : spd.getChain()) {
138        td.sep(", ");
139        td.tx(t.asStringValue());
140      }      
141    }
142    
143    if (spd.hasComponent()) {
144      x.para().b().tx("Components");
145      tbl = x.table("grid");
146      for (SearchParameterComponentComponent t : spd.getComponent()) {
147        tr = tbl.tr();
148        SearchParameter tsp = context.getWorker().fetchResource(SearchParameter.class, t.getDefinition(), spd);
149        if (tsp != null && tsp.hasWebPath()) {
150          tr.td().ah(tsp.getWebPath()).tx(tsp.present());          
151        } else {
152          tr.td().tx(t.getDefinition());
153        }
154        tr.td().code().tx(t.getExpression());
155      }
156    }
157    return false;
158  }
159
160  private boolean isAllConcreteResources(List<Enumeration<VersionIndependentResourceTypesAll>> list) {
161    for (String s : context.getWorker().getResourceNames()) {
162      StructureDefinition sd = context.getWorker().fetchTypeDefinition(s);
163      if (!sd.getAbstract() && !Utilities.existsInList(sd.getType(), "Parameters")) {
164        boolean found = false;
165        for (Enumeration<VersionIndependentResourceTypesAll> c : list) {
166          found = found || sd.getName().equals(c.getCode());
167        }
168        if (!found) {
169          return false;
170        }
171      }
172    }
173    return true;
174  }
175
176  public void describe(XhtmlNode x, OperationDefinition opd) {
177    x.tx(display(opd));
178  }
179
180  public String display(OperationDefinition opd) {
181    return opd.present();
182  }
183
184  @Override
185  public String display(Resource r) throws UnsupportedEncodingException, IOException {
186    return ((SearchParameter) r).present();
187  }
188
189}