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