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