package org.hl7.fhir.dstu3.elementmodel;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.NotImplementedException;
import org.hl7.fhir.dstu3.formats.IParser.OutputStyle;
import org.hl7.fhir.dstu3.formats.JsonCreator;
import org.hl7.fhir.dstu3.formats.JsonCreatorCanonical;
import org.hl7.fhir.dstu3.formats.JsonCreatorGson;
import org.hl7.fhir.dstu3.context.IWorkerContext;
import org.hl7.fhir.utilities.Utilities;
public class JsonLDParser extends ParserBase {
private JsonCreator json;
private String base;
public JsonLDParser(IWorkerContext context) {
super(context);
}
@Override
public Element parse(InputStream stream) {
throw new NotImplementedException("not done yet");
}
protected void prop(String name, String value) throws IOException {
if (name != null)
json.name(name);
json.value(value);
}
protected void open(String name) throws IOException {
if (name != null)
json.name(name);
json.beginObject();
}
protected void close() throws IOException {
json.endObject();
}
protected void openArray(String name) throws IOException {
if (name != null)
json.name(name);
json.beginArray();
}
protected void closeArray() throws IOException {
json.endArray();
}
@Override
public void compose(Element e, OutputStream stream, OutputStyle style, String base) throws Exception {
this.base = base;
OutputStreamWriter osw = new OutputStreamWriter(stream, "UTF-8");
if (style == OutputStyle.CANONICAL)
json = new JsonCreatorCanonical(osw);
else
json = new JsonCreatorGson(osw);
json.setIndent(style == OutputStyle.PRETTY ? " " : "");
json.beginObject();
prop("@context", "http://hl7.org/fhir/jsonld/"+e.getType());
prop("resourceType", e.getType());
Set<String> done = new HashSet<String>();
for (Element child : e.getChildren()) {
compose(e.getName(), e, done, child);
}
json.endObject();
json.finish();
osw.flush();
}
private void compose(String path, Element e, Set<String> done, Element child) throws IOException {
if (!child.getProperty().isList()) {
compose(path, child);
} else if (!done.contains(child.getName())) {
done.add(child.getName());
List<Element> list = e.getChildrenByName(child.getName());
composeList(path, list);
}
}
private void composeList(String path, List<Element> list) throws IOException {
// there will be at least one element
String en = list.get(0).getProperty().getDefinition().getBase().getPath();
if (en == null)
en = list.get(0).getProperty().getDefinition().getPath();
boolean doType = false;
if (en.endsWith("[x]")) {
en = en.substring(0, en.length()-3);
doType = true;
}
if (doType)
en = en + Utilities.capitalize(list.get(0).getType());
openArray(en);
for (Element item : list) {
open(null);
if (item.isPrimitive() || isPrimitive(item.getType())) {
if (item.hasValue())
primitiveValue(item);
}
Set<String> done = new HashSet<String>();
for (Element child : item.getChildren()) {
compose(path+"."+item.getName(), item, done, child);
}
close();
}
closeArray();
}
private void primitiveValue(Element item) throws IOException {
json.name("value");
String type = item.getType();
if (Utilities.existsInList(type, "boolean"))
json.value(item.getValue().equals("true") ? new Boolean(true) : new Boolean(false));
else if (Utilities.existsInList(type, "integer", "unsignedInt", "positiveInt"))
json.value(new Integer(item.getValue()));
else if (Utilities.existsInList(type, "decimal"))
json.value(new BigDecimal(item.getValue()));
else
json.value(item.getValue());
}
private void compose(String path, Element element) throws IOException {
String en = element.getProperty().getDefinition().getBase().getPath();
if (en == null)
en = element.getProperty().getDefinition().getPath();
boolean doType = false;
if (en.endsWith("[x]")) {
en = en.substring(0, en.length()-3);
doType = true;
}
if (doType)
en = en + Utilities.capitalize(element.getType());
if (element.hasChildren() || element.hasComments() || element.hasValue()) {
open(en);
if (element.isPrimitive() || isPrimitive(element.getType())) {
if (element.hasValue())
primitiveValue(element);
}
if (element.getProperty().isResource()) {
prop("resourceType", element.getType());
element = element.getChildren().get(0);
}
Set<String> done = new HashSet<String>();
for (Element child : element.getChildren()) {
compose(path+"."+element.getName(), element, done, child);
}
if ("Coding".equals(element.getType()))
decorateCoding(element);
if ("CodeableConcept".equals(element.getType()))
decorateCodeableConcept(element);
if ("Reference".equals(element.getType()))
decorateReference(element);
close();
}
}
private void decorateReference(Element element) throws IOException {
String ref = element.getChildValue("reference");
if (ref != null && (ref.startsWith("http://") || ref.startsWith("https://"))) {
json.name("reference");
json.value(ref);
} else if (base != null && ref != null && ref.contains("/")) {
json.name("reference");
json.value(base+"/"+ref);
}
}
protected void decorateCoding(Element coding) throws IOException {
String system = coding.getChildValue("system");
String code = coding.getChildValue("code");
if (system == null)
return;
if ("http://snomed.info/sct".equals(system)) {
json.name("concept");
json.value("http://snomed.info/sct#"+code);
} else if ("http://loinc.org".equals(system)) {
json.name("concept");
json.value("http://loinc.org/owl#"+code);
}
}
private void decorateCodeableConcept(Element element) throws IOException {
for (Element c : element.getChildren("coding")) {
decorateCoding(c);
}
}
}