001package org.hl7.fhir.r4.elementmodel;
002
003/*-
004 * #%L
005 * org.hl7.fhir.r4
006 * %%
007 * Copyright (C) 2014 - 2019 Health Level 7
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022import java.io.ByteArrayInputStream;
023import java.io.ByteArrayOutputStream;
024import java.io.IOException;
025import java.util.ArrayList;
026import java.util.List;
027
028import org.hl7.fhir.exceptions.FHIRException;
029import org.hl7.fhir.r4.conformance.ProfileUtilities;
030import org.hl7.fhir.r4.context.IWorkerContext;
031import org.hl7.fhir.r4.formats.IParser.OutputStyle;
032import org.hl7.fhir.r4.model.Base;
033import org.hl7.fhir.r4.model.CodeableConcept;
034import org.hl7.fhir.r4.model.Coding;
035import org.hl7.fhir.r4.model.ElementDefinition;
036import org.hl7.fhir.r4.model.Factory;
037import org.hl7.fhir.r4.model.Identifier;
038import org.hl7.fhir.r4.model.PrimitiveType;
039import org.hl7.fhir.r4.model.Reference;
040import org.hl7.fhir.r4.model.Resource;
041import org.hl7.fhir.r4.model.StructureDefinition;
042import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
043import org.hl7.fhir.r4.model.Type;
044
045
046public class ObjectConverter  {
047
048  private IWorkerContext context;
049
050  public ObjectConverter(IWorkerContext context) {
051    this.context = context;
052  }
053
054  public Element convert(Resource ig) throws IOException, FHIRException {
055    if (ig == null)
056      return null;
057    ByteArrayOutputStream bs = new ByteArrayOutputStream();
058    org.hl7.fhir.r4.formats.JsonParser jp = new org.hl7.fhir.r4.formats.JsonParser();
059    jp.compose(bs, ig);
060    ByteArrayInputStream bi = new ByteArrayInputStream(bs.toByteArray());
061    return new JsonParser(context).parse(bi);
062  }
063
064  public Element convert(Property property, Type type) throws FHIRException {
065    return convertElement(property, type);
066  }
067  
068  private Element convertElement(Property property, Base base) throws FHIRException {
069    if (base == null)
070      return null;
071    String tn = base.fhirType();
072    StructureDefinition sd = context.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(tn, context.getOverrideVersionNs()));
073    if (sd == null)
074      throw new FHIRException("Unable to find definition for type "+tn);
075    Element res = new Element(property.getName(), property);
076    if (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) 
077      res.setValue(((PrimitiveType) base).asStringValue());
078
079    List<ElementDefinition> children = ProfileUtilities.getChildMap(sd, sd.getSnapshot().getElementFirstRep()); 
080    for (ElementDefinition child : children) {
081      String n = tail(child.getPath());
082      if (sd.getKind() != StructureDefinitionKind.PRIMITIVETYPE || !"value".equals(n)) {
083        Base[] values = base.getProperty(n.hashCode(), n, false);
084        if (values != null)
085          for (Base value : values) {
086            res.getChildren().add(convertElement(new Property(context, child, sd), value));
087          }
088      }
089    }
090    return res;
091  }
092
093  private String tail(String path) {
094    if (path.contains("."))
095      return path.substring(path.lastIndexOf('.')+1);
096    else
097      return path;
098  }
099
100  public Type convertToType(Element element) throws FHIRException {
101    Type b = new Factory().create(element.fhirType());
102    if (b instanceof PrimitiveType) {
103      ((PrimitiveType) b).setValueAsString(element.primitiveValue());
104    } else {
105      for (Element child : element.getChildren()) {
106        b.setProperty(child.getName(), convertToType(child));
107      }
108    }
109    return b;
110  }
111
112  public Resource convert(Element element) throws FHIRException {
113    ByteArrayOutputStream bo = new ByteArrayOutputStream();
114    try {
115      new JsonParser(context).compose(element, bo, OutputStyle.NORMAL, null);
116//      TextFile.bytesToFile(bo.toByteArray(), "c:\\temp\\json.json");
117      return new org.hl7.fhir.r4.formats.JsonParser().parse(bo.toByteArray());
118    } catch (IOException e) {
119      // won't happen
120      throw new FHIRException(e);
121    }
122    
123  }
124
125  public static CodeableConcept readAsCodeableConcept(Element element) {
126    CodeableConcept cc = new CodeableConcept();
127    List<Element> list = new ArrayList<Element>();
128    element.getNamedChildren("coding", list);
129    for (Element item : list)
130      cc.addCoding(readAsCoding(item));
131    cc.setText(element.getNamedChildValue("text"));
132    return cc;
133  }
134
135  public static Coding readAsCoding(Element item) {
136    Coding c = new Coding();
137    c.setSystem(item.getNamedChildValue("system"));
138    c.setVersion(item.getNamedChildValue("version"));
139    c.setCode(item.getNamedChildValue("code"));
140    c.setDisplay(item.getNamedChildValue("display"));
141    return c;
142  }
143
144  public static Identifier readAsIdentifier(Element item) {
145    Identifier r = new Identifier();
146    r.setSystem(item.getNamedChildValue("system"));
147    r.setValue(item.getNamedChildValue("value"));
148    return r;
149  }
150
151  public static Reference readAsReference(Element item) {
152    Reference r = new Reference();
153    r.setDisplay(item.getNamedChildValue("display"));
154    r.setReference(item.getNamedChildValue("reference"));
155    r.setType(item.getNamedChildValue("type"));
156    List<Element> identifier = item.getChildrenByName("identifier");
157    if (identifier.isEmpty() == false) {
158      r.setIdentifier(readAsIdentifier(identifier.get(0)));
159    }
160    return r;
161  }
162
163}