001package org.hl7.fhir.r5.renderers; 
002 
003import java.io.IOException;
004import java.io.UnsupportedEncodingException;
005
006import org.hl7.fhir.exceptions.DefinitionException;
007import org.hl7.fhir.exceptions.FHIRException;
008import org.hl7.fhir.exceptions.FHIRFormatError;
009import org.hl7.fhir.r5.extensions.ExtensionDefinitions;
010import org.hl7.fhir.r5.extensions.ExtensionUtilities;
011import org.hl7.fhir.r5.model.CanonicalType;
012import org.hl7.fhir.r5.model.Enumeration;
013import org.hl7.fhir.r5.model.Enumerations.FHIRTypes;
014import org.hl7.fhir.r5.model.Enumerations.VersionIndependentResourceTypesAll;
015import org.hl7.fhir.r5.model.Extension;
016import org.hl7.fhir.r5.model.OperationDefinition;
017import org.hl7.fhir.r5.model.OperationDefinition.OperationDefinitionParameterComponent;
018import org.hl7.fhir.r5.model.OperationDefinition.OperationKind;
019import org.hl7.fhir.r5.model.OperationDefinition.OperationParameterScope;
020import org.hl7.fhir.r5.model.Resource;
021import org.hl7.fhir.r5.model.StructureDefinition;
022import org.hl7.fhir.r5.renderers.utils.RenderingContext;
023import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType;
024import org.hl7.fhir.r5.renderers.utils.ResourceWrapper;
025import org.hl7.fhir.r5.utils.EOperationOutcome;
026
027import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
028import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage;
029import org.hl7.fhir.utilities.StandardsStatus;
030import org.hl7.fhir.utilities.Utilities;
031import org.hl7.fhir.utilities.xhtml.XhtmlNode; 
032 
033@MarkedToMoveToAdjunctPackage
034public class OperationDefinitionRenderer extends TerminologyRenderer { 
035 
036
037  public OperationDefinitionRenderer(RenderingContext context) { 
038    super(context); 
039  } 
040 
041  @Override
042  public void buildNarrative(RenderingStatus status, XhtmlNode x, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome {
043    if (r.isDirect()) {
044      renderResourceTechDetails(r, x);  
045      genSummaryTable(status, x, (OperationDefinition) r.getBase());    
046      render(status, x, (OperationDefinition) r.getBase());      
047    } else {
048      // the intention is to change this in the future
049      x.para().tx("OperationDefinitionRenderer only renders native resources directly");
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, OperationDefinition opd) throws IOException, FHIRException, EOperationOutcome { 
059    if (context.isShowSummaryTable()) { 
060      x.h2().addText(opd.getName()); 
061      x.para().addText(Utilities.capitalize(opd.getKind().toString())+": "+opd.getName());     
062      x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_OFFIC)+" "); 
063      x.pre().tx(opd.getUrl()); 
064      addMarkdown(x, opd.getDescription());} 
065 
066    if (opd.getKind() == OperationKind.QUERY) {
067      if (opd.getSystem()) {
068        x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URL, "?_query="+opd.getCode()+"&..."));
069      }
070      for (Enumeration<VersionIndependentResourceTypesAll> c : opd.getResource()) { 
071        if (opd.getType()) 
072          x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URL, c.getCode()+"?_query="+opd.getCode()+"&...")); 
073        if (opd.getInstance()) 
074          x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URL, c.getCode()+"/[id]?_query="+opd.getCode()+"&...")); 
075      } 
076    } else {
077      if (opd.getSystem()) {
078        x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URL, "$"+opd.getCode()));
079      }
080      for (Enumeration<VersionIndependentResourceTypesAll> c : opd.getResource()) { 
081        if (opd.getType()) 
082          x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URL, c.getCode()+"/$"+opd.getCode())); 
083        if (opd.getInstance()) 
084          x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URL, c.getCode()+"/[id]/$"+opd.getCode())); 
085      } 
086    }
087
088    if (opd.hasInputProfile()) { 
089      XhtmlNode p = x.para(); 
090      p.tx(context.formatPhrase(RenderingContext.OP_DEF_INPAR)); 
091      StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, opd.getInputProfile(), opd); 
092      if (sd == null) { 
093        p.pre().tx(opd.getInputProfile());         
094      } else { 
095        p.ah(context.prefixLocalHref(sd.getWebPath())).tx(sd.present());                  
096      }       
097    } 
098    if (opd.hasOutputProfile()) { 
099      XhtmlNode p = x.para(); 
100      p.tx(context.formatPhrase(RenderingContext.OP_DEF_OUTPAR)); 
101      StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, opd.getOutputProfile(), opd); 
102      if (sd == null) { 
103        p.pre().tx(opd.getOutputProfile());         
104      } else { 
105        p.ah(context.prefixLocalHref(sd.getWebPath())).tx(sd.present());                  
106      }       
107    }
108
109    x.h3().tx(context.formatPhrase(RenderingContext.GENERAL_PARS));
110    //x.para().tx(context.formatPhrase(RenderingContext.GENERAL_PARS)); 
111    XhtmlNode tbl = x.table( "grid", false); 
112    XhtmlNode tr = tbl.tr(); 
113    tr.td().b().tx(context.formatPhrase(RenderingContext.OP_DEF_USE)); 
114    tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_NAME)); 
115    tr.td().b().tx(context.formatPhrase(RenderingContext.OP_DEF_SCO)); 
116    tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_CARDINALITY)); 
117    tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_TYPE)); 
118    tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_BINDING)); 
119    tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_DOCUMENTATION)); 
120    for (OperationDefinitionParameterComponent p : opd.getParameter()) { 
121      genOpParam(tbl, "", p, opd); 
122    } 
123    addMarkdown(x, opd.getComment()); 
124  } 
125 
126  public void describe(XhtmlNode x, OperationDefinition opd) { 
127    x.tx(display(opd)); 
128  } 
129 
130  public String display(OperationDefinition opd) { 
131    return opd.present(); 
132  } 
133 
134  @Override 
135  public String display(Resource r) throws UnsupportedEncodingException, IOException { 
136    return ((OperationDefinition) r).present(); 
137  } 
138 
139  private void genOpParam(XhtmlNode tbl, String path, OperationDefinitionParameterComponent p, Resource opd) throws EOperationOutcome, FHIRException, IOException { 
140    XhtmlNode tr; 
141    tr = tbl.tr(); 
142    tr.td().addText(p.getUse().toString()); 
143    XhtmlNode td = tr.td(); 
144    td.addText(path+p.getName()); 
145    StandardsStatus ss = ExtensionUtilities.getStandardsStatus(p);
146    genStandardsStatus(td, ss); 
147    td = tr.td(); 
148    if (p.hasScope()) { 
149      CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); 
150      for (Enumeration<OperationParameterScope> s : p.getScope()) { 
151        b.append(s.getCode()); 
152      } 
153      td.tx(b.toString()); 
154    } 
155    tr.td().addText(Integer.toString(p.getMin())+".."+p.getMax()); 
156    td = tr.td(); 
157    String actualType = translateTypeToVersion(p.getTypeElement()); 
158    StructureDefinition sd = actualType != null ? context.getWorker().fetchTypeDefinition(actualType) : null; 
159    if (sd == null) {
160      td.tx(p.hasType() ? actualType : "");  
161    } else if (sd.getAbstract() && p.hasExtension(ExtensionDefinitions.EXT_ALLOWED_TYPE)) {
162      boolean first = true;  
163      for (Extension ex : p.getExtensionsByUrl(ExtensionDefinitions.EXT_ALLOWED_TYPE)) {  
164        if (first) first = false; else td.tx(" | ");  
165        String s = ex.getValue().primitiveValue();  
166        StructureDefinition sdt = context.getWorker().fetchTypeDefinition(s);  
167        if (sdt == null)  
168          td.tx(p.hasType() ? actualType : "");  
169        else  
170          td.ah(context.prefixLocalHref(sdt.getWebPath())).tx(s);           
171      }  
172    } else if (sd.getAbstract() && (p.hasAllowedType())) {
173      boolean first = true; 
174      for (Enumeration<FHIRTypes> ex : p.getAllowedType()) {
175        if (first) first = false; else td.tx(" | "); 
176        String s = ex.primitiveValue();
177        StructureDefinition sdt = context.getWorker().fetchTypeDefinition(s); 
178        if (sdt == null) 
179          td.tx(p.hasType() ? actualType : ""); 
180        else 
181          td.ah(context.prefixLocalHref(sdt.getWebPath())).tx(s);          
182      }
183    } else 
184      td.ah(context.prefixLocalHref(sd.getWebPath())).tx(actualType); 
185    if (p.hasTargetProfile()) { 
186      td.tx(" ("); 
187      boolean first = true; 
188      for (CanonicalType tp : p.getTargetProfile()) { 
189        if (first) { first = false;} else {td.tx(", ");}; 
190        StructureDefinition sdt = context.getWorker().fetchTypeDefinition(tp.asStringValue()); 
191        if (sdt == null || !sdt.hasWebPath()) { 
192          td.code().tx(tp.asStringValue()); 
193        } else { 
194          td.ah(context.prefixLocalHref(sdt.getWebPath()), tp.asStringValue()).tx(sdt.present()); 
195        } 
196      } 
197      td.tx(")"); 
198    } 
199    if (p.hasSearchType()) { 
200      td.br(); 
201      td.tx("("); 
202      td.ah(context.prefixLocalHref(context.getLink(KnownLinkType.SPEC, true) == null ? "search.html#"+p.getSearchType().toCode() : Utilities.pathURL(context.getLink(KnownLinkType.SPEC, true), "search.html#"+p.getSearchType().toCode()))).tx(p.getSearchType().toCode());        
203      td.tx(")"); 
204    } 
205    td = tr.td(); 
206    if (p.hasBinding() && p.getBinding().hasValueSet()) { 
207      AddVsRef(p.getBinding().getValueSet(), td, opd); 
208      td.tx(" ("+p.getBinding().getStrength().getDisplay()+")"); 
209    } 
210    addMarkdown(tr.td(), p.getDocumentation()); 
211    if (!p.hasType()) { 
212      for (OperationDefinitionParameterComponent pp : p.getPart()) { 
213        genOpParam(tbl, path+p.getName()+".", pp, opd); 
214      } 
215    } 
216  } 
217   
218  public static final String EXT_OPDEF_ORIGINAL_TYPE = "http://hl7.org/fhir/4.0/StructureDefinition/extension-OperationDefinition.parameter.type"; 
219 
220  private String translateTypeToVersion(Enumeration<FHIRTypes> src) { 
221    if (src.hasExtension(EXT_OPDEF_ORIGINAL_TYPE)) { 
222      return src.getExtensionString(EXT_OPDEF_ORIGINAL_TYPE); 
223    } else { 
224      return src.asStringValue(); 
225    } 
226  } 
227 
228 
229}