001package org.hl7.fhir.r5.renderers;
002
003import java.io.IOException;
004import java.nio.charset.StandardCharsets;
005import java.util.ArrayList;
006import java.util.Base64;
007import java.util.List;
008
009import org.hl7.fhir.r5.elementmodel.Element;
010import org.hl7.fhir.r5.model.Binary;
011import org.hl7.fhir.utilities.TextFile;
012import org.hl7.fhir.utilities.Utilities;
013import org.hl7.fhir.utilities.xhtml.NodeType;
014import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
015import org.hl7.fhir.utilities.xhtml.XhtmlNode;
016
017public class BinaryRenderer {
018
019  private String folder;
020  private List<String> filenames = new ArrayList<String>();
021
022  public BinaryRenderer(String folder) {
023    super();
024    this.folder = folder;
025  }
026
027  public String getFolder() {
028    return folder;
029  }
030
031  public List<String> getFilenames() {
032    return filenames;
033  }
034
035  public static String getBinContentAsString(byte[] bin) {
036    // for now, assume UTF8. To do: extract character encoding from mime type if possible (charset)
037    return new String(bin, StandardCharsets.UTF_8);
038  }
039
040  public String display(Binary bin) throws IOException {
041    XhtmlNode div = new XhtmlNode(NodeType.Element, "div");
042    render(div, bin);
043    return new XhtmlComposer(false, true).compose(div);
044  }
045
046  public String display(Element bin) throws IOException {
047    XhtmlNode div = new XhtmlNode(NodeType.Element, "div");
048    render(div, bin);
049    return new XhtmlComposer(false, true).compose(div);
050  }
051
052  public String display(String id, String ct, byte[] cnt) throws IOException {
053    XhtmlNode div = new XhtmlNode(NodeType.Element, "div");
054    render(div, id, ct, cnt);
055    return new XhtmlComposer(false, true).compose(div);
056  }
057
058  public void render(XhtmlNode x, Binary bin) throws IOException {
059    String ct = bin.getContentType();
060    byte[] cnt = bin.getContent();
061    render(x, bin.getId(), ct, cnt);
062  }
063
064  public void render(XhtmlNode x, Element bin) throws IOException {
065    String ct = bin.getNamedChildValue("contentType");
066    String id = bin.getNamedChildValue("id");
067    byte[] cnt = Base64.getMimeDecoder().decode(bin.getNamedChildValue("data"));
068    render(x, id, ct, cnt);
069  }
070  
071  public void render(XhtmlNode x, String id, String ct, byte[] cnt) throws IOException {
072    filenames.clear();
073    if (ct == null) {
074      error(x,"No Content Type");
075    } else if (ct.startsWith("image/")) {
076      image(x, id, ct, cnt);
077    } else if (isXml(ct)) {
078      xml(x, cnt);
079    } else if (isJson(ct)) {
080      json(x, cnt);      
081    } else if (isTtl(ct)) {
082      ttl(x, cnt);      
083    } else if (isText(ct)) {
084      text(x, cnt);      
085    } else {
086      error(x, "The Content Type '"+ct+"' is not rendered in this context");
087    }
088  }
089
090
091  private void image(XhtmlNode x, String id, String ct, byte[] cnt) throws IOException {
092    String ext = null;
093    if (ct.startsWith("image/png")) {
094      ext = ".png";
095    } else if (ct.startsWith("image/jpeg")) {
096      ext = ".jpg";
097    } else if (ct.startsWith("image/gif")) {
098      ext = ".gif";
099    } else if (ct.startsWith("image/svg")) {
100      ext = ".svg";
101    }
102    
103    if (ext == null) {
104      error(x, "The Image Type '"+ct+"' is not rendered in this context");
105    } else {
106      String fn = "Binary-Native-"+id+ext;
107      TextFile.bytesToFile(cnt, Utilities.path(folder, fn));
108      filenames.add(fn);
109      x.img("Binary-Native-"+id+ext, "binary");
110    }
111  }
112
113  private void error(XhtmlNode x, String message) {
114    x.tx("["+message+"]");
115  }
116
117  private boolean isXml(String ct) {
118    return ct.startsWith("text/xml") || ct.startsWith("application/xml") || ct.contains("+xml");
119  }
120
121  private void xml(XhtmlNode x, byte[] cnt) {
122    String content = "\r\n"+getBinContentAsString(cnt);
123    XhtmlNode pre = x.pre("xml");
124    pre.code(content);    
125  }
126  
127  private boolean isJson(String ct) {
128    return ct.startsWith("text/json") || ct.startsWith("application/json") || ct.contains("+json");
129  }
130  
131  private void json(XhtmlNode x, byte[] cnt) {
132    String content = "\r\n"+getBinContentAsString(cnt);
133    XhtmlNode pre = x.pre("json");
134    pre.code(content);    
135  }
136  
137  private boolean isTtl(String ct) {
138    return ct.startsWith("text/rdf") || ct.contains("+turtle");
139  }
140  
141  private void ttl(XhtmlNode x, byte[] cnt) {
142    String content = "\r\n"+getBinContentAsString(cnt);
143    XhtmlNode pre = x.pre("rdf language-turtle");
144    pre.code(content);    
145  }
146  
147
148  private boolean isText(String ct) {
149    return ct.startsWith("text/");
150  }
151  
152  private void text(XhtmlNode x, byte[] cnt) {
153    String content = "\r\n"+getBinContentAsString(cnt);
154    XhtmlNode pre = x.pre();
155    pre.code(content);    
156  }
157  
158
159}