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