001package org.hl7.fhir.r4.utils;
002
003import java.io.OutputStreamWriter;
004import java.util.ArrayList;
005import java.util.List;
006
007import org.hl7.fhir.exceptions.FHIRException;
008import org.hl7.fhir.r4.context.IWorkerContext;
009import org.hl7.fhir.r4.model.ElementDefinition;
010import org.hl7.fhir.r4.model.StructureDefinition;
011import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
012import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule;
013import org.hl7.fhir.utilities.Utilities;
014
015public class ProtoBufGenerator {
016
017  private IWorkerContext context;
018  private StructureDefinition definition;
019  private OutputStreamWriter destination;
020  private int cursor;
021  private Message message; 
022  
023  private class Field {
024    private String name;   
025    private boolean required;
026    private boolean repeating;
027    private String type;
028  }
029  
030  private class Message {
031    private String name;
032    private List<Field> fields = new ArrayList<Field>();
033    private List<Message> messages = new ArrayList<Message>();
034    public Message(String name) {
035      super();
036      this.name = name;
037    }
038    
039    
040  }
041  
042  public ProtoBufGenerator(IWorkerContext context) {
043    super();
044    this.context = context;
045  }
046
047  public ProtoBufGenerator(IWorkerContext context, StructureDefinition definition, OutputStreamWriter destination) {
048    super();
049    this.context = context;
050    this.definition = definition;
051    this.destination = destination;
052  }
053
054  public IWorkerContext getContext() {
055    return context;
056  }
057  
058  public StructureDefinition getDefinition() {
059    return definition;
060  }
061
062  public void setDefinition(StructureDefinition definition) {
063    this.definition = definition;
064  }
065
066  public OutputStreamWriter getDestination() {
067    return destination;
068  }
069
070  public void setDestination(OutputStreamWriter destination) {
071    this.destination = destination;
072  }
073
074
075  public void build() throws FHIRException {
076    if (definition == null)
077      throw new FHIRException("A definition must be provided");
078    if (destination == null)
079      throw new FHIRException("A destination must be provided");
080    
081    if (definition.getDerivation() == TypeDerivationRule.CONSTRAINT)
082      throw new FHIRException("derivation = constraint is not supported yet");
083    
084    message = new Message(definition.getSnapshot().getElement().get(0).getPath());
085    cursor = 1;
086    while (cursor < definition.getSnapshot().getElement().size()) {
087      ElementDefinition ed = definition.getSnapshot().getElement().get(0);
088      Field fld = new Field();
089      fld.name = tail(ed.getPath());
090      fld.required = (ed.getMin() == 1);
091      fld.repeating = (!ed.getMax().equals("1"));
092      message.fields.add(fld);
093      if (ed.getType().size() != 1)
094        fld.type = "Unknown";
095      else {
096        StructureDefinition td = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/"+ed.getTypeFirstRep().getCode());
097        if (td == null)
098          fld.type = "Unresolved";
099        else if (td.getKind() == StructureDefinitionKind.PRIMITIVETYPE) {
100          fld.type = protoTypeForFhirType(ed.getTypeFirstRep().getCode());
101          fld = new Field();
102          fld.name = tail(ed.getPath())+"Extra";
103          fld.repeating = (!ed.getMax().equals("1"));
104          fld.type = "Primitive";
105          message.fields.add(fld);
106        } else
107          fld.type = ed.getTypeFirstRep().getCode();
108      }   
109    }
110  }
111
112  private String protoTypeForFhirType(String code) {
113    if (Utilities.existsInList(code, "integer", "unsignedInt", "positiveInt"))
114      return "int23";
115    else if (code.equals("boolean"))
116      return "bool";
117    else 
118      return "string";
119  }
120
121  private String tail(String path) {
122    return path.substring(path.lastIndexOf(".")+1);
123  }
124  
125  
126}