fmod ENTITIES2JSON is
  inc MAUDE2JSON-AUX .

****    ****    ****   Entities  ****    ****    ****    ****    ****    
**** There are three kinds of entity specification: simple, generic, and composite.

***(
A simple entity specification (SimpleEntitySpec) satisfies
{ "stype" : "sref",
  "name" : String,  
  "etype" : Etype,   
  "xref" : Xref,     
  "metadata" : JObject //  
}
Etype = {"Protein", "Chemical", "DNA", "RNA"} computed from maude sort
An Xref is an object satisfying
  {"stype" : "xref", 
   "db" : String,  
   "id" : String  
  }      
For Base Proteins db is "UNIPROT" "id" is "spnumber", omitted from json metadata

!!!! next round add msort (the opdecl type) to simple and generic templates

)


op srefTemplate : -> String .
eq srefTemplate =
"\n %name:{\"stype\" : \"sref\",\n\
\t \"name\" : %name,\n\
\t \"etype\" : %etype,\n\
\t \"xref\" : %xref,\n\
\t \"metadata\" : %metadata\n}" 
.

op xrefTemplate : -> String .
eq xrefTemplate =
   "{\"stype\" : \"xref\", \"db\" : %db, \"id\" : %id}" .

***(
A generic entity specification (GenericEntitySpec) satisfies
{ "stype" : "gref",
  "name" : String, 
  "etype" : "Protein",
  "members" : JArray[String],  //names of members from metadata 
  "metadata" : JObject   // omits members
}
)
op grefTemplate : -> String .
eq grefTemplate =
"\n %name:{\"stype\" : \"gref\",\n\
\t \"name\" : %name,\n\
\t \"etype\" : \"Protein\",\n\
\t \"members\" : %members,\n\
\t \"metadata\" : %metadata\n}" 
.


***(
A composite entity specification (CompositeEntitySpec) satisfies
{ "stype" : "cref",
  "name" : String, 
  "etype" : "Protein",
  "subunits" : JArray[String],  //names of subunits  from metadata
  "metadata" : JObject  // omits subunits
}
)
op crefTemplate : -> String .
eq crefTemplate =
"\n %name:{\"stype\" : \"cref\",\n\
\t \"name\" : %name,\n\
\t \"etype\" : \"Protein\",\n\
\t \"subunits\" : %subunits,\n\
\t \"metadata\" : %metadata\n}" 
.

op entitiesTemplate : -> String .
eq entitiesTemplate =
"{%proteinspecs,\n\
%chemicalspecs,\n\
%genespecs\n}" 
.

***(
**** malformed or missing metadata
  op badTemplate : -> String .
  eq badTemplate = 
"\n %name:{\"stype\" : \"BAD\",\n\
\t \"name\" : %name,\n\
\t \"badstr\" : %badstr\n}" 
.
)

  vars  modname qid protname chemname genename : Qid .
  vars str  tag val default mdstr  : String .
  vars  db id  name bstr cstr gstr badstr badstr1 : String .
  var next : FindResult .
  var sexp? : Sexp? .

  var alist alist1 : SexpL .
  var bindings : TBinds .


***!!!! need to do generic and composite proteins last
  op entities2json : Qid Qid Qid ~> String .
  eq entities2json(protname, chemname, genename) =  
   fillTemplate(entitiesTemplate,
      (("%proteinspecs" :~ prots2json(upOpDecls(protname,false),"","","","")),
       ("%chemicalspecs" :~  chems2json(upOpDecls(chemname,false),"")), 
       ("%genespecs" :~ genes2json(upOpDecls(genename,false),"")) )) .

****                        base   fam    composite   badMetadata                        
  op prots2json : OpDeclSet String String String String ~> String .
  op chems2json : OpDeclSet String ~> String .
  op genes2json : OpDeclSet String ~> String .

  op composite2json : Qid SexpL String ~> String .
  op   generic2json : Qid SexpL String ~> String .
  op      base2json : Qid SexpL String ~> String .
  op      gene2json : OpDecl String ~> String .
  op      chem2json : OpDecl String ~> String .


  eq prots2json(none,bstr,gstr,cstr,badstr) =
        bstr + sep?(bstr,",\n") 
      + gstr + sep?(gstr,",\n") 
      + cstr + sep?(cstr,",\n")
      + badstr . 

   ceq prots2json(od:OpDecl ods:OpDeclSet,bstr,gstr,cstr,badstr) = 
        (if t:Type == 'Composite  
         then  prots2json(ods:OpDeclSet,bstr,gstr,  
                          composite2json(qid,alist,cstr),badstr1)
         else (if atm2str(carl(alget(alist,"category")))  == "Family" 
               then  prots2json(ods:OpDeclSet,bstr,
                               generic2json(qid,alist,gstr), cstr,badstr1)
              else prots2json(ods:OpDeclSet,base2json(qid,alist,bstr),
                                   gstr,cstr,badstr1)  
             fi) fi)
  if (op qid : nil -> t:Type [atts:AttrSet].) := od:OpDecl
  /\ mdstr := getMetaData(atts:AttrSet)
  /\ ixs(next,sexp?) := readSexp(mdstr,0,length(mdstr)) 
  /\ alist := (if sexp? :: Sexp then sexp2l(sexp?) else nil fi) 
              [a("sort") a(string(t:Type))]   ---- keeping actual maude sort
  /\ badstr1 := 
       (if sexp? :: Sexp 
        then badstr 
        else badstr + sep?(badstr,",\n")
             + fillTemplate(badTemplate,
                            (("%name" :~ squote("!!!" + string(qid))), 
                             ("%badstr" :~ squote(mdstr)) )) 
        fi) .

**** hopefully not happen
  eq prots2json(od:OpDecl ods:OpDeclSet,bstr,gstr,cstr,badstr) = 
        prots2json(ods:OpDeclSet,bstr,gstr,cstr,badstr) [owise] .

  ceq base2json(qid,alist,str) =
      str + sep?(str,",\n") + fillTemplate(srefTemplate,bindings)
   if bindings := (("%name" :~ squote(string(qid))),
                   ("%etype" :~ squote("Protein")),
                   ("%xref" :~ 
                      (if (alookupd(alist,"spnumber","") == "")
                       then squote("{ }")   
                       else fillTemplate(xrefTemplate, 
                              (("%db" :~ squote("UNIPROT")),
                              ("%id" :~ squote(atm2str(carl(alget(alist,"spnumber")))))
                               ) )
                       fi)),
                  ("%metadata" :~ alist2json(alist,"spnumber","")) )  .

  ceq generic2json(qid,alist,str) =
      str + sep?(str,",\n") + fillTemplate(grefTemplate,bindings)
   if bindings := (("%name" :~ squote(string(qid))),
                   ("%etype" :~ squote("Protein")),
                   ("%members" :~ sexpl2jarr(alget(alist,"members"),"")),
                   ("%metadata" :~ alist2json(alist,"members","")) )  .

  ceq composite2json(qid,alist,str) =
      str + sep?(str,",\n") + fillTemplate(crefTemplate,bindings)
   if bindings := (("%name" :~ squote(string(qid))),
                   ("%etype" :~ squote("Protein")),
                   ("%subunits" :~ sexpl2jarr(alget(alist,"subunits"),"")),
                   ("%metadata" :~ alist2json(alist,"subunits","")) )  .

  eq chems2json(none,str) = str . 
  eq chems2json(od:OpDecl ods:OpDeclSet,str) = 
     chems2json(ods:OpDeclSet, chem2json(od:OpDecl,str))  .

  ceq chem2json((op qid : nil -> t:Type[atts:AttrSet].),str) =
      str + sep?(str,",\n") + fillTemplate(srefTemplate,bindings)
   if mdstr := getMetaData(atts:AttrSet)
   /\ ixs(next,sexp?) := readSexp(mdstr,0,length(mdstr)) 
   /\ alist := (if sexp? :: Sexp then sexp2l(sexp?) else nil fi) 
   /\ bindings := (("%name" :~ squote(string(qid)) ),
                   ("%etype" :~ squote("Chemical") ),
                   ("%xref" :~  "{ }"),
                   ("%metadata" :~ alist2json(alist,nil,"")))  .

  eq chem2json(od:OpDecl,str) = str [owise] .  *** only constants

  eq genes2json(none,str) = str . 
  eq genes2json(od:OpDecl ods:OpDeclSet,str) = 
     genes2json(ods:OpDeclSet, gene2json(od:OpDecl,str))  .

  ceq gene2json((op qid : nil -> t:Type[atts:AttrSet].),str) =
      str + sep?(str,",\n") + fillTemplate(srefTemplate,bindings)
   if mdstr := getMetaData(atts:AttrSet)
   /\ ixs(next,sexp?) := readSexp(mdstr,0,length(mdstr)) 
   /\ alist := (if sexp? :: Sexp then sexp2l(sexp?) else nil fi) 
   /\ bindings := (("%name" :~ squote(string(qid)) ),
                   ("%etype" :~ squote("Gene") ),
                   ("%xref" :~ "{ }" ),
                   ("%metadata" :~ alist2json(alist,nil,"")))  .

  eq gene2json(od:OpDecl,str) = str [owise] .  *** only constants



endfm