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.DefinitionException;
008import org.hl7.fhir.exceptions.FHIRException;
009import org.hl7.fhir.exceptions.FHIRFormatError;
010import org.hl7.fhir.r5.model.Enumeration;
011import org.hl7.fhir.r5.model.Enumerations.SearchComparator;
012import org.hl7.fhir.r5.model.Enumerations.SearchModifierCode;
013import org.hl7.fhir.r5.model.Enumerations.VersionIndependentResourceTypesAll;
014import org.hl7.fhir.r5.model.OperationDefinition;
015import org.hl7.fhir.r5.model.Resource;
016import org.hl7.fhir.r5.model.SearchParameter;
017import org.hl7.fhir.r5.model.SearchParameter.SearchParameterComponentComponent;
018import org.hl7.fhir.r5.model.StringType;
019import org.hl7.fhir.r5.model.StructureDefinition;
020import org.hl7.fhir.r5.renderers.utils.RenderingContext;
021import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType;
022import org.hl7.fhir.r5.renderers.utils.ResourceWrapper;
023import org.hl7.fhir.r5.utils.EOperationOutcome;
024import org.hl7.fhir.r5.utils.ToolingExtensions;
025import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage;
026import org.hl7.fhir.utilities.StandardsStatus;
027import org.hl7.fhir.utilities.Utilities;
028import org.hl7.fhir.utilities.xhtml.XhtmlNode;
029
030@MarkedToMoveToAdjunctPackage
031public class SearchParameterRenderer extends TerminologyRenderer {
032
033
034  public SearchParameterRenderer(RenderingContext context) { 
035    super(context); 
036  } 
037 
038  @Override
039  public void buildNarrative(RenderingStatus status, XhtmlNode x, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome {
040    if (r.isDirect()) {
041      renderResourceTechDetails(r, x);
042      genSummaryTable(status, x, (SearchParameter) r.getBase());
043
044      render(status, x, (SearchParameter) r.getBase());      
045    } else {
046      // the intention is to change this in the future
047      x.para().tx("SearchParameterRenderer only renders native resources directly");
048    }
049  }
050  
051  
052  @Override
053  public String buildSummary(ResourceWrapper r) throws UnsupportedEncodingException, IOException {
054    return canonicalTitle(r);
055  }
056
057  public void render(RenderingStatus status, XhtmlNode x, SearchParameter spd) throws IOException, FHIRException, EOperationOutcome {
058    XhtmlNode h2 = x.h2();
059    h2.addText(spd.getName());
060    StandardsStatus ss = ToolingExtensions.getStandardsStatus(spd);
061    if (ss != context.getDefaultStandardsStatus()) {
062      genStandardsStatus(h2, ss);
063    }
064    XhtmlNode p =  x.para();
065    p.tx(context.formatPhrase(RenderingContext.GENERAL_PAR)+" ");
066    p.code().tx(spd.getCode());
067    p.tx(":");
068    p.code().tx(spd.getType().toCode());
069    addMarkdown(x, spd.getDescription());
070
071    XhtmlNode tbl = x.table("grid", false);
072    XhtmlNode tr = tbl.tr();
073    tr.td().tx(Utilities.pluralize(context.formatPhrase(RenderingContext.GENERAL_RESOURCE), spd.getBase().size()));
074    XhtmlNode td = tr.td();
075    for (Enumeration<VersionIndependentResourceTypesAll> t : spd.getBase()) {
076      StructureDefinition sd = context.getWorker().fetchTypeDefinition(t.getCode());
077      if (sd != null && sd.hasWebPath()) {
078        td.sep(", ");
079        td.ah(context.prefixLocalHref(context.prefixLocalHref(sd.getWebPath()))).tx(t.getCode());
080      } else {
081        td.sep(", ");
082        td.tx(t.getCode());
083      }
084    }
085    tr = tbl.tr();
086    tr.td().tx(context.formatPhrase(RenderingContext.SEARCH_PAR_EXP));
087    if (spd.hasExpression()) {
088      tr.td().code().tx(spd.getExpression());
089    } else {
090      tr.td().tx(context.formatPhrase(RenderingContext.SEARCH_PAR_NONE));
091    }
092    if (spd.hasProcessingMode()) {
093      tr = tbl.tr();
094      tr.td().tx(context.formatPhrase(RenderingContext.SEARCH_PAR_PROC));
095      tr.td().tx(spd.getProcessingMode().getDisplay());      
096    }
097    if (spd.hasTarget()) {
098      tr = tbl.tr();
099      tr.td().tx(Utilities.pluralize(context.formatPhrase(RenderingContext.SEARCH_PAR_REND_TARGET), spd.getTarget().size()));
100      td = tr.td();
101      if (isAllConcreteResources(spd.getTarget())) {
102        td.ah(context.prefixLocalHref(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "resourcelist.html"))).tx(context.formatPhrase(RenderingContext.SEARCH_PAR_RES));
103      } else {
104        for (Enumeration<VersionIndependentResourceTypesAll> t : spd.getTarget()) {
105          StructureDefinition sd = context.getWorker().fetchTypeDefinition(t.getCode());
106          if (sd != null && sd.hasWebPath()) {
107            td.sep(", ");
108            td.ah(context.prefixLocalHref(sd.getWebPath())).tx(t.getCode());
109          } else {
110            td.sep(", ");
111            td.tx(t.getCode());
112          }
113        }
114      }
115    }
116    tr = tbl.tr();    
117    tr.td().tx(context.formatPhrase(RenderingContext.SEARCH_PAR_MULTIPLES));
118    XhtmlNode ul = tr.td().ul();
119    if (!spd.hasMultipleAnd()) {
120      ul.li().tx(context.formatPhrase(RenderingContext.SEARCH_PAR_MULTIPLE_AND_SERVER));
121    } else if (spd.getMultipleAnd()) {
122      ul.li().tx(context.formatPhrase(RenderingContext.SEARCH_PAR_MULTIPLE_AND_REPEAT));
123    } else {
124      ul.li().tx(context.formatPhrase(RenderingContext.SEARCH_PAR_MULTIPLE_AND_APPEAR));
125    }
126    if (!spd.hasMultipleOr()) {
127      ul.li().tx(context.formatPhrase(RenderingContext.SEARCH_PAR_MULTIPLE_OR_SERVER));
128    } else if (spd.getMultipleOr()) {
129      ul.li().tx(context.formatPhrase(RenderingContext.SEARCH_PAR_MULTIPLE_OR_MULTIPLE));
130    } else {
131      ul.li().tx(context.formatPhrase(RenderingContext.SEARCH_PAR_MULTIPLE_OR_ONE));
132    }
133
134    if (spd.hasComparator()) {
135      tr = tbl.tr();
136      tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_COMPARATORS));
137      td = tr.td();
138      td.tx(context.formatPhrase(RenderingContext.SEARCH_PAR_ALLOWED)+" ");
139      for (Enumeration<SearchComparator> t : spd.getComparator()) {
140        td.sep(", ");
141        td.tx(t.asStringValue());
142      }      
143    }
144    if (spd.hasModifier()) {
145      tr = tbl.tr();
146      tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_MODIFIERS));
147      td = tr.td();
148      td.tx(context.formatPhrase(RenderingContext.SEARCH_PAR_ALLOWED)+" ");
149      for (Enumeration<SearchModifierCode> t : spd.getModifier()) {
150        td.sep(", ");
151        td.tx(t.asStringValue());
152      }      
153    }
154    if (spd.hasChain()) {
155      tr = tbl.tr();
156      tr.td().tx(context.formatPhrase(RenderingContext.SEARCH_PAR_CHAIN));
157      td = tr.td();
158      td.tx(context.formatPhrase(RenderingContext.SEARCH_PAR_ALLOWED)+" ");
159      for (StringType t : spd.getChain()) {
160        td.sep(", ");
161        td.tx(t.asStringValue());
162      }      
163    }
164    
165    if (spd.hasComponent()) {
166      x.para().b().tx(context.formatPhrase(RenderingContext.GENERAL_COMPARATORS));
167      tbl = x.table("grid", false);
168      for (SearchParameterComponentComponent t : spd.getComponent()) {
169        tr = tbl.tr();
170        SearchParameter tsp = context.getWorker().fetchResource(SearchParameter.class, t.getDefinition(), spd);
171        if (tsp != null && tsp.hasWebPath()) {
172          tr.td().ah(context.prefixLocalHref(tsp.getWebPath())).tx(tsp.present());          
173        } else {
174          tr.td().tx(t.getDefinition());
175        }
176        tr.td().code().tx(t.getExpression());
177      }
178    }
179  }
180
181  private boolean isAllConcreteResources(List<Enumeration<VersionIndependentResourceTypesAll>> list) {
182    for (String s : context.getWorker().getResourceNames()) {
183      StructureDefinition sd = context.getWorker().fetchTypeDefinition(s);
184      if (!sd.getAbstract() && !Utilities.existsInList(sd.getType(), context.formatPhrase(RenderingContext.GENERAL_PAR))) {
185        boolean found = false;
186        for (Enumeration<VersionIndependentResourceTypesAll> c : list) {
187          found = found || sd.getName().equals(c.getCode());
188        }
189        if (!found) {
190          return false;
191        }
192      }
193    }
194    return true;
195  }
196
197  public void describe(XhtmlNode x, OperationDefinition opd) {
198    x.tx(display(opd));
199  }
200
201  public String display(OperationDefinition opd) {
202    return opd.present();
203  }
204
205  @Override
206  public String display(Resource r) throws UnsupportedEncodingException, IOException {
207    return ((SearchParameter) r).present();
208  }
209
210}