1 /**
2  * @file    OutputSBML.cpp
3  * @brief   MATLAB code for translating SBML-MATLAB structure into a SBML document.
4  * @author  Sarah Keating
5  *
6  * <!--------------------------------------------------------------------------
7  * This file is part of libSBML.  Please visit http://sbml.org for more
8  * information about SBML, and the latest version of libSBML.
9  *
10  * Copyright (C) 2020 jointly by the following organizations:
11  *     1. California Institute of Technology, Pasadena, CA, USA
12  *     2. University of Heidelberg, Heidelberg, Germany
13  *     3. University College London, London, UK
14  *
15  * Copyright (C) 2019 jointly by the following organizations:
16  *     1. California Institute of Technology, Pasadena, CA, USA
17  *     2. University of Heidelberg, Heidelberg, Germany
18  *
19  * Copyright (C) 2013-2018 jointly by the following organizations:
20  *     1. California Institute of Technology, Pasadena, CA, USA
21  *     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
22  *     3. University of Heidelberg, Heidelberg, Germany
23  *
24  * Copyright (C) 2009-2013 jointly by the following organizations:
25  *     1. California Institute of Technology, Pasadena, CA, USA
26  *     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
27  *
28  * Copyright (C) 2006-2008 by the California Institute of Technology,
29  *     Pasadena, CA, USA
30  *
31  * Copyright (C) 2002-2005 jointly by the following organizations:
32  *     1. California Institute of Technology, Pasadena, CA, USA
33  *     2. Japan Science and Technology Agency, Japan
34  *
35  * This library is free software; you can redistribute it and/or modify it
36  * under the terms of the GNU Lesser General Public License as published by
37  * the Free Software Foundation.  A copy of the license agreement is provided
38  * in the file named "LICENSE.txt" included with this software distribution
39  * and also available online as http://sbml.org/software/libsbml/license.html
40  * ---------------------------------------------------------------------- -->*/
41 
42 #include <stdio.h>
43 #include <string.h>
44 
45 #include <mex.h>
46 
47 #ifndef USE_OCTAVE
48 #include <matrix.h>
49 #endif
50 #include <algorithm>
51 
52 #include <sbml/SBMLReader.h>
53 #include <sbml/SBMLTypes.h>
54 #include <sbml/xml/XMLNode.h>
55 #include <sbml/math/ASTNode.h>
56 #include <sbml/extension/SBasePlugin.h>
57 #include <sbml/extension/SBMLExtensionRegistry.h>
58 
59 LIBSBML_CPP_NAMESPACE_USE
60 
61 #ifdef USE_FBC
62 #include <sbml/packages/fbc/common/FbcExtensionTypes.h>
63 #endif
64 
65 ////////////////////////////////
66 
67 // declarations - since a mex file cannot use local includes
68 
69 typedef enum
70 {
71     TYPE_BOOL
72   , TYPE_CHAR
73   , TYPE_DOUBLE
74   , TYPE_INT
75   , TYPE_ELEMENT
76   , TYPE_UINT
77   , TYPE_UNKNOWN
78 } FieldType_t;
79 
80 const char* FIELDTYPE_STRINGS[] =
81 {
82       "bool"
83     , "char"
84     , "double"
85     , "int"
86     , "structure"
87     , "uint"
88 };
89 
90 typedef enum {
91     OTHER_NAME = 0
92   , SBML_NOTES
93   , SBML_ANNOT
94   , OTHER_NAMESPACES
95   , OTHER_CVTERMS
96   , SBML_MATH
97   , SBML_RULE_TYPE
98   , SBML_ISSET
99   , SBML_MESSAGE
100   , OTHER_TIME_SYMBOL
101   , OTHER_DELAY_SYMBOL
102   , OTHER_AVOGADRO_SYMBOL
103   , OTHER_RATEOF_SYMBOL
104   , OTHER_ANOMALOUS_MATH
105   , FBC_ASSOCIATION
106 
107   , SBML_KNOWN_ATT_ELEM = 20
108 
109 } FieldnamesType_t;
110 
111 struct FieldValues_t {
112   std::string fieldName;
113   std::string sbmlName;
114   std::string prefix;
115   FieldType_t type;
116   bool isSBMLAttribute;
117   FieldnamesType_t fieldnameType;
118   std::string strValue;
119   int iValue;
120   double dValue;
121  };
122 
123 
124 class StructureFields
125 {
126 public:
127 
128   StructureFields(SBase* obj, mxArray* structure);
129 
130   StructureFields(SBase* obj);
131 
132   StructureFields(std::string& tc);
133 
134   ~StructureFields();
135 
136 
137   void addAttributes(const std::string& functionId, unsigned int index = 0,
138                      unsigned int total_no = 0);
139 
140   void createStructure(const std::string& functionId, SBase* base, bool usePlugin = false,
141                        const std::string& prefix = "");
142 
getTypeCode() const143   const std::string& getTypeCode() const { return sbmlTC; };
144 
getStructure() const145   mxArray* getStructure() const { return mxStructure; };
146 
147   static const std::string readString(mxArray* mxArray1, const std::string& name,
148                                       unsigned int index);
149 
150   static unsigned int readUint(mxArray* mxArry1, const std::string& name,
151                                unsigned int index);
152 
153   static int readInt(mxArray* mxArry1, const std::string& name, unsigned int index);
154 
155   static void reportReadError(const std::string& type, const std::string& name,
156                        unsigned int index, unsigned int total_no,
157                        const std::string& tc);
158 
159 private:
160   void populateFields();
161 
162   void determineTypeCode();
163 
164   void populateStructure(const std::string& functionId, SBase* base,
165                          unsigned int index);
166 
167   void addStructureField(const std::string& functionId, SBase* base,
168     unsigned int index, FieldValues_t field, bool usePlugin);
169 
170   void addChildElement(FieldValues_t field, unsigned int index);
171 
172   void setAttribute(FieldValues_t field,
173                     unsigned int index = 0, unsigned int total_no = 0);
174 
175 
176   const std::string getFieldname(unsigned int i, const std::string& id);
177   const std::string getDefaultValue(unsigned int i, const std::string& id);
178   void getDefaultValue(unsigned int i, const std::string& id, double& value);
179   void getDefaultValue(unsigned int i, const std::string& id, int& value);
180   const FieldType_t getValueType(unsigned int i, const std::string& id);
181   bool getIsSBMLAttribute(unsigned int i, const std::string& id);
182   const std::string getSBMLPrefix(unsigned int i, const std::string& id);
183   const std::string getSBMLName(unsigned int i, const std::string& id);
184   const FieldnamesType_t getNameEnumType(unsigned int i, const std::string& id);
185 
186   // read values from structure
187   int readInt(const std::string& name, unsigned int index, unsigned int total_no);
188 
189   double readDouble(const std::string& name, unsigned int index, unsigned int total_no);
190 
191   const std::string readString(const std::string& name, unsigned int index, unsigned int total_no);
192 
193   unsigned int readUint(const std::string& name, unsigned int index, unsigned int total_no);
194 
195   // need to further work out which type of rule
196   const std::string getRuleType(mxArray* mxRuleStructure, unsigned int index);
197   std::string getRuleTypeCode(SBase* base);
198   std::string getAssociationTypeCode(SBase* base);
199 
200 
201   void addAnomalousChild(FieldValues_t field);
202 
203   void addAnomalousChildStructure(const std::string& functionId, SBase* base,
204                           unsigned int index, FieldValues_t field);
205 
206   const ASTNode* getMathChild(const std::string& value);
207 
208   char * convertMathFormula(const std::string& pacFormula);
209 
210   void adjustForCSymbols(ASTNode * math);
211 
212   // read values from model or default
213   const std::string getStringValue(const std::string& functionId, SBase* base,
214     FieldValues_t field, bool usePlugin);
215 
216   double getDoubleValue(const std::string& functionId, SBase* base,
217     FieldValues_t field, bool usePlugin);
218 
219   bool getBoolValue(const std::string& functionId, SBase* base,
220     FieldValues_t field, bool usePlugin);
221 
222   unsigned int getUintValue(const std::string& functionId, SBase* base,
223     FieldValues_t field, bool usePlugin);
224 
225   int getIntValue(const std::string& functionId, SBase* base,
226     FieldValues_t field, bool usePlugin);
227 
228   std::string getMathString(SBase* base);
229 
230   char * GetMatlabFormula(char * pacFormula, std::string object);
231 
232   void lookForCSymbols(ASTNode* math);
233 
234   void dealWithTimeSymbol(ASTNode* math);
235 
236   void dealWithDelaySymbol(ASTNode* math);
237 
238   void dealWithAvogadroSymbol(ASTNode* math);
239 
240   void dealWithRateOfSymbol(ASTNode* math);
241 
242   bool determineStatus(const std::string& name, unsigned int index);
243 
244   void reportReadError(const std::string& type, const std::string& name,
245                        unsigned int index, unsigned int total_no);
246 
247 
248   bool usingPlugin(const std::string& prefix, SBase* base = NULL);
249 
250   mxArray* getNamespacesStructure();
251 
252   mxArray* getCVTermsStructure(SBase* base);
253 
254   void addCVTerms(unsigned int index);
255 
256   void freeStructureMemory();
257 
258 protected:
259 
260   mxArray* mxFieldnames;
261   mxArray* mxDefaultValues;
262   mxArray* mxValueTypes;
263 
264   size_t nNumberFields;
265 
266   mxArray* mxStructure;
267 
268   SBase* mSBase;
269   std::string sbmlTC;
270 
271   std::vector<FieldValues_t> mFields;
272 };
273 
274 typedef std::map<const std::string, unsigned int> PkgMap;
275 typedef PkgMap::iterator  PkgIter;
276 
277 class ModelDetails
278 {
279 public:
280   ModelDetails();
281 
282   ModelDetails(SBMLDocument *doc);
283 
~ModelDetails()284   ~ModelDetails() { };
285 
getLevel()286   unsigned int getLevel() {return mLevel; } ;
getVersion()287   unsigned int getVersion() { return mVersion; } ;
288 
getDelaySymbol()289   const std::string& getDelaySymbol() { return mDelaySymbol; } ;
getTimeSymbol()290   const std::string& getTimeSymbol() { return mTimeSymbol; } ;
getAvogadroSymbol()291   const std::string& getAvogadroSymbol() { return mAvogadroSymbol; } ;
getRateOfSymbol()292   const std::string& getRateOfSymbol() { return mRateOfSymbol; } ;
293 
setDelaySymbol(const std::string & symbol)294   void setDelaySymbol(const std::string& symbol) { mDelaySymbol = symbol; } ;
setAvogadroSymbol(const std::string & symbol)295   void setAvogadroSymbol(const std::string& symbol) { mAvogadroSymbol = symbol; } ;
setTimeSymbol(const std::string & symbol)296   void setTimeSymbol(const std::string& symbol) { mTimeSymbol = symbol; } ;
setRateOfSymbol(const std::string & symbol)297   void setRateOfSymbol(const std::string& symbol) { mRateOfSymbol = symbol; } ;
298 
getNamespaces()299   SBMLNamespaces* getNamespaces() { return mSBMLns; };
300 
getPackages()301   PkgMap getPackages() { return mPackageMap; };
302 
303   bool isPackagePresent(const std::string& pkg);
304 
305 
306 protected:
307 
308   void populateNamespaces();
309   void populateNamespaces(SBMLDocument* doc);
310   void populatePkgMap();
311   void populatePkgMap(SBMLDocument* doc);
312   void populateSupportedPackages();
313 
314   bool isSupportedPackageNS(const std::string& uri, const std::string prefix);
315 
316   unsigned int mLevel;
317   unsigned int mVersion;
318 
319   std::string mDelaySymbol;
320   std::string mTimeSymbol;
321   std::string mAvogadroSymbol;
322   std::string mRateOfSymbol;
323 
324   SBMLNamespaces *mSBMLns;
325 
326   IdList mSupportedPackages;
327 
328   PkgMap mPackageMap;
329 
330 };
331 
332 ///////////////////////////////////////////////////////////////////////////////
333 
334 // global variables
335 mxArray *modelArray = NULL;
336 bool freeMemory;
337 ModelDetails * details;
338 
339 IdList reqdPkgPrefixes;
340 IdList unreqdPkgPrefixes;
341 
342 bool fbcUsingId;
343 bool fbcAddGeneProducts;
344 bool onlyExpectedFields;
345 bool applyUserValidation;
346 
347 //////////////////////////////////////////////////////////////////////////////
348 //
349 // StructureFields.cpp
350 
351 //////////////////////////////////////////////////////////////////////////////
352 //
353 // report error/free memory and exit when error encountered
354 
FreeMem(void)355 void FreeMem(void)
356 {
357   /* destroy arrays created */
358   mxDestroyArray(modelArray);
359 }
360 
361 void
reportError(const std::string & id,const std::string & message)362 reportError(const std::string&id, const std::string& message)
363 {
364   if (freeMemory)
365   {
366     FreeMem();
367   }
368 
369   mexErrMsgIdAndTxt(id.c_str(), message.c_str());
370 }
371 
372 ////////////////////////////////////////////////////////////////////////////
373 
374 // useful global functions
375 
376 mxArray *
CreateIntScalar(int nValue)377 CreateIntScalar (int nValue)
378 {
379   mxArray * pArray;
380   int * panData;
381 
382   pArray = mxCreateNumericMatrix(1,1,mxINT32_CLASS, mxREAL);
383   panData = (int *)mxGetData(pArray);
384   panData[0] = nValue;
385 
386   return pArray;
387 }
388 
389 
390 FieldType_t
getFieldType(const char * type)391 getFieldType(const char* type)
392 {
393   if (type != NULL)
394   {
395     const FieldType_t lo = TYPE_BOOL;
396     const FieldType_t hi = (const FieldType_t)(TYPE_UNKNOWN - 1);
397 
398     return (FieldType_t)util_bsearchStringsI(FIELDTYPE_STRINGS, type, lo, hi);
399   }
400   else
401     return TYPE_UNKNOWN;
402 }
403 
404 // only used by OutputSBML
getRequiredStatus(const std::string & prefix)405 bool getRequiredStatus(const std::string& prefix)
406 {
407   bool required = false;
408 
409   if (reqdPkgPrefixes.contains(prefix))
410   {
411     required = true;
412   }
413 
414   return required;
415 }
416 
populatePackageLists()417 void populatePackageLists()
418 {
419   //reqdPkgPrefixes.append("comp");
420   //reqdPkgPrefixes.append("spatial");
421 
422   unreqdPkgPrefixes.append("fbc");
423   unreqdPkgPrefixes.append("qual");
424   unreqdPkgPrefixes.append("groups");
425 }
426 
427 // only used by OutputSBML
428 bool
isUnknownType(std::string tc)429 isUnknownType(std::string tc)
430 {
431   // TO DO
432   if (tc == "(Unknown SBML Type)")
433     return true;
434   else if (tc == "(Unknown SBML Fbc Type)")
435     return true;
436   else if (tc == "(Unknown SBML Groups Type)")
437     return true;
438   else if (tc == "(Unknown SBML Qual Type)")
439     return true;
440   else
441     return false;
442 }
443 
444 //////////////////////////////////////////////////////////////////////////////
445 //
446 // class to store the structure/retrieve fields and write the SBML Model
447 
448 // only used by OutputSBML
StructureFields(SBase * obj,mxArray * structure)449 StructureFields::StructureFields(SBase* obj, mxArray* structure) :
450     mSBase ( NULL)
451   , mxStructure ( NULL )
452   , sbmlTC ("")
453 {
454   mSBase = obj;
455   mxStructure = structure;
456 
457   determineTypeCode();
458   populateFields();
459 }
460 
461 // only used by OutputSBML
StructureFields(SBase * obj)462 StructureFields::StructureFields(SBase* obj) :
463     mSBase ( NULL)
464   , mxStructure ( NULL )
465   , sbmlTC ("")
466 {
467   mSBase = obj;
468 
469   determineTypeCode();
470   populateFields();
471 }
472 
473 // only used by TranslateSBML
StructureFields(std::string & tc)474 StructureFields::StructureFields(std::string& tc) :
475     mSBase ( NULL)
476   , mxStructure ( NULL )
477   , sbmlTC ( tc )
478 {
479   populateFields();
480 }
481 
482 
~StructureFields()483 StructureFields::~StructureFields()
484 {
485   mFields.clear();
486   // must not do this as it can be a part of a larger model
487 //  delete mSBase;
488 
489   // MATLAB says dont call destroy array in a destructor
490   // https://uk.mathworks.com/help/matlab/matlab_external/memory-management-issues.html
491   //mxDestroyArray(mxStructure);
492   //mxDestroyArray(mxFieldnames);
493   //mxDestroyArray(mxDefaultValues);
494   //mxDestroyArray(mxValueTypes);
495 }
496 
497 void
freeStructureMemory()498 StructureFields::freeStructureMemory()
499 {
500   mxDestroyArray(mxFieldnames);
501   mxDestroyArray(mxDefaultValues);
502   mxDestroyArray(mxValueTypes);
503   // do not delete in output as the structure is being recursively used
504   //if (mxStructure)
505   //  mxDestroyArray(mxStructure);
506 }
507 
508 void
determineTypeCode()509 StructureFields::determineTypeCode()
510 {
511   if (!sbmlTC.empty()) return;
512   else if (mSBase == NULL) return;
513 
514   PkgMap pm = details->getPackages();
515 
516   sbmlTC = SBMLTypeCode_toString(mSBase->getTypeCode(), "core");
517   // check whether we are using a package object
518   PkgIter it = pm.begin();
519 
520   while (isUnknownType(sbmlTC) && it != pm.end())
521   {
522     sbmlTC = SBMLTypeCode_toString(mSBase->getTypeCode(), (it->first).c_str());
523     sbmlTC[0] = tolower(sbmlTC[0]);
524     ++it;
525   }
526 }
527 
528 void
populateFields()529 StructureFields::populateFields()
530 {
531   // the array size will need to accomadate all packages
532   PkgMap pm = details->getPackages();
533   mxArray *mxOutputs[4];
534   unsigned int numPlugins = (unsigned int)(pm.size());
535   if (numPlugins > 0)
536   {
537     int numberInputs = 5;
538 
539     mxArray *mxInput[5];
540 
541     std::string id = std::string("StructureFields:populateFields:") + sbmlTC;
542 
543     // hack for level 1 rules
544     if (sbmlTC == "AssignmentRule" || sbmlTC == "RateRule")
545     {
546       int L1TC = ((Rule*)(mSBase))->getL1TypeCode();
547       if (L1TC == SBML_UNKNOWN)
548       {
549         mxInput[0] = mxCreateString(sbmlTC.c_str());
550       }
551       else
552       {
553         mxInput[0] = mxCreateString(SBMLTypeCode_toString(L1TC, "core"));
554       }
555     }
556     else
557     {
558       mxInput[0] = mxCreateString(sbmlTC.c_str());
559     }
560     mxInput[1] = CreateIntScalar(details->getLevel());
561     mxInput[2] = CreateIntScalar(details->getVersion());
562     mwSize dims[1] = { numPlugins };
563     mxInput[3] = mxCreateCellArray(1, dims);
564     mxInput[4] = mxCreateDoubleMatrix(1, numPlugins, mxREAL);
565     double *pinput4 = mxGetPr(mxInput[4]);
566     unsigned int inputCount = 0;
567     for (PkgIter it = pm.begin(); it != pm.end(); ++it)
568     {
569       mxSetCell(mxInput[3], inputCount, mxCreateString((it->first).c_str()));
570       pinput4[inputCount] = it->second;
571       inputCount++;
572     }
573 
574     mxArray * exception = NULL;
575     exception = mexCallMATLABWithTrap(4, mxOutputs, numberInputs, mxInput, "getStructure");
576     if (exception != 0)
577     {
578       mexCallMATLAB(0, (mxArray **)NULL, 1, &exception, "throw");
579 
580       reportError(id, "Failed to get fieldnames");
581     }
582     mxDestroyArray(mxInput[0]);
583     mxDestroyArray(mxInput[1]);
584     mxDestroyArray(mxInput[2]);
585     mxDestroyArray(mxInput[3]);
586     mxDestroyArray(mxInput[4]);
587   }
588   else
589   {
590     int numberInputs = 3;
591 
592     mxArray *mxInput[3];
593 
594     std::string id = std::string("StructureFields:populateFields:") + sbmlTC;
595 
596     // hack for level 1 rules
597     if (sbmlTC == "AssignmentRule" || sbmlTC == "RateRule")
598     {
599       int L1TC = ((Rule*)(mSBase))->getL1TypeCode();
600       if (L1TC == SBML_UNKNOWN)
601       {
602         mxInput[0] = mxCreateString(sbmlTC.c_str());
603       }
604       else
605       {
606         mxInput[0] = mxCreateString(SBMLTypeCode_toString(L1TC, "core"));
607       }
608     }
609     else
610     {
611       mxInput[0] = mxCreateString(sbmlTC.c_str());
612     }
613     mxInput[1] = CreateIntScalar(details->getLevel());
614     mxInput[2] = CreateIntScalar(details->getVersion());
615 
616     mxArray * exception = NULL;
617     exception = mexCallMATLABWithTrap(4, mxOutputs, numberInputs, mxInput, "getStructure");
618     if (exception != 0)
619     {
620       mexCallMATLAB(0, (mxArray **)NULL, 1, &exception, "throw");
621 
622       reportError(id, "Failed to get fieldnames");
623     }
624     mxDestroyArray(mxInput[0]);
625     mxDestroyArray(mxInput[1]);
626     mxDestroyArray(mxInput[2]);
627   }
628 
629   mxFieldnames = mxDuplicateArray(mxOutputs[0]);
630   mxDefaultValues = mxDuplicateArray(mxOutputs[1]);
631   mxValueTypes = mxDuplicateArray(mxOutputs[2]);
632   nNumberFields = (int)mxGetScalar(mxOutputs[3]);
633 
634   mxDestroyArray(mxOutputs[0]);
635   mxDestroyArray(mxOutputs[1]);
636   mxDestroyArray(mxOutputs[2]);
637   mxDestroyArray(mxOutputs[3]);
638 
639   for (unsigned int i = 0; i < nNumberFields; ++i)
640   {
641     FieldValues_t field;
642     field.fieldName = getFieldname(i, "populate");
643     field.type = getValueType(i, "populate");
644     field.sbmlName = getSBMLName(i, "populate");
645     field.prefix = getSBMLPrefix(i, "populate");
646     field.isSBMLAttribute = getIsSBMLAttribute(i, "populate");
647     field.fieldnameType = getNameEnumType(i, "populate");
648     switch (field.type)
649     {
650     case TYPE_BOOL:
651     case TYPE_INT:
652     case TYPE_UINT:
653       getDefaultValue(i, "populate", field.iValue);
654       break;
655     case TYPE_CHAR:
656     case TYPE_UNKNOWN:
657       field.strValue = getDefaultValue(i, "populate");
658       break;
659     case TYPE_DOUBLE:
660       getDefaultValue(i, "populate", field.dValue);
661       break;
662     default:
663       break;
664     }
665     mFields.push_back(field);
666   }
667 }
668 
669 
670 const std::string
getSBMLPrefix(unsigned int i,const std::string & id)671 StructureFields::getSBMLPrefix(unsigned int i, const std::string& id)
672 {
673   mxArray* mxField = mxGetCell(mxFieldnames, i);
674   mxArray* mxAttPrefix = mxGetCell(mxField, 2);
675   size_t nBuflen = (mxGetM(mxAttPrefix)*mxGetN(mxAttPrefix) + 1);
676   char * fieldname = (char *)mxCalloc(nBuflen, sizeof(char));
677   if (mxGetString(mxAttPrefix, (char *)fieldname, (mwSize)(nBuflen)) != 0)
678   {
679     reportError(id, "Failed in getSBMLPrefix");
680   }
681   const std::string f = std::string(fieldname);
682   mxFree(fieldname);
683   return f;
684 }
685 
686 const std::string
getSBMLName(unsigned int i,const std::string & id)687 StructureFields::getSBMLName(unsigned int i, const std::string& id)
688 {
689   mxArray* mxField = mxGetCell(mxFieldnames, i);
690   mxArray* mxAttPrefix = mxGetCell(mxField, 1);
691   size_t nBuflen = (mxGetM(mxAttPrefix)*mxGetN(mxAttPrefix) + 1);
692   char * fieldname = (char *)mxCalloc(nBuflen, sizeof(char));
693   if (mxGetString(mxAttPrefix, (char *)fieldname, (mwSize)(nBuflen)) != 0)
694   {
695     reportError(id, "Failed in getSBMLName");
696   }
697   const std::string f = std::string(fieldname);
698   mxFree(fieldname);
699   return f;
700 }
701 
702 bool
getIsSBMLAttribute(unsigned int i,const std::string & id)703 StructureFields::getIsSBMLAttribute(unsigned int i, const std::string& id)
704 {
705   mxArray* mxField = mxGetCell(mxFieldnames, i);
706   mxArray* mxSBMLAtt = mxGetCell(mxField, 3);
707   int value = (int)mxGetScalar(mxSBMLAtt);
708   if (value == 0) return false;
709   else return true;
710 }
711 
712 const FieldnamesType_t
getNameEnumType(unsigned int i,const std::string & id)713 StructureFields::getNameEnumType(unsigned int i, const std::string& id)
714 {
715   mxArray* mxField = mxGetCell(mxFieldnames, i);
716   mxArray* mxSBMLAtt = mxGetCell(mxField, 4);
717   int value = (int)mxGetScalar(mxSBMLAtt);
718   return (FieldnamesType_t)(value);
719 
720 }
721 
722 const std::string
getFieldname(unsigned int i,const std::string & id)723 StructureFields::getFieldname(unsigned int i, const std::string& id)
724 {
725   mxArray* mxField = mxGetCell(mxFieldnames, i);
726   mxArray* mxName = mxGetCell(mxField, 0);
727   size_t nBuflen = (mxGetM(mxName)*mxGetN(mxName)+1);
728   char * fieldname = (char *) mxCalloc(nBuflen, sizeof(char));
729   if (mxGetString(mxName, (char *) fieldname, (mwSize)(nBuflen)) != 0)
730   {
731     reportError(id, "Failed in GetFieldname");
732   }
733   const std::string f = std::string(fieldname);
734   mxFree(fieldname);
735   return f;
736 }
737 
738 const std::string
getDefaultValue(unsigned int i,const std::string & id)739 StructureFields::getDefaultValue(unsigned int i, const std::string& id)
740 {
741   mxArray* mxName = mxGetCell(mxDefaultValues, i);
742   size_t nBuflen = (mxGetM(mxName)*mxGetN(mxName)+1);
743   char * fieldname = (char *) mxCalloc(nBuflen, sizeof(char));
744   if (mxGetString(mxName, (char *) fieldname, (mwSize)(nBuflen)) != 0)
745   {
746     reportError(id, "Failed in GetDefaultValue");
747   }
748   const std::string f = std::string(fieldname);
749   mxFree(fieldname);
750   return f;
751 }
752 
753 void
getDefaultValue(unsigned int i,const std::string & id,double & value)754 StructureFields::getDefaultValue(unsigned int i, const std::string& id, double& value)
755 {
756   mxArray* mxName = mxGetCell(mxDefaultValues, i);
757   value = (double) mxGetScalar(mxName);
758 }
759 
760 void
getDefaultValue(unsigned int i,const std::string & id,int & value)761 StructureFields::getDefaultValue(unsigned int i, const std::string& id, int& value)
762 {
763   mxArray* mxName = mxGetCell(mxDefaultValues, i);
764   value = (int) mxGetScalar(mxName);
765 }
766 
767 const FieldType_t
getValueType(unsigned int i,const std::string & id)768 StructureFields::getValueType(unsigned int i, const std::string& id)
769 {
770   mxArray* mxName = mxGetCell(mxValueTypes, i);
771   size_t nBuflen = (mxGetM(mxName)*mxGetN(mxName)+1);
772   char * fieldname = (char *) mxCalloc(nBuflen, sizeof(char));
773   if (mxGetString(mxName, (char *) fieldname, (mwSize)(nBuflen)) != 0)
774   {
775     mxFree(fieldname);
776     reportError(id, "Failed in GetValueType");
777   }
778   FieldType_t ft = getFieldType(fieldname);
779   mxFree(fieldname);
780   return ft;
781 }
782 
783 //////////////////////////
784 
785 // functions for creating structure from SBML
786 
787 void
createStructure(const std::string & functionId,SBase * base,bool usePlugin,const std::string & prefix)788 StructureFields::createStructure(const std::string& functionId, SBase* base,
789                                  bool usePlugin, const std::string& prefix)
790 {
791   std::string fieldname;
792   unsigned int total_no = base->getNumObjects(sbmlTC);
793   if (usePlugin)
794   {
795     total_no = base->getPlugin(prefix)->getNumObjects(sbmlTC);
796   }
797   mwSize dims[2] = {1, total_no};
798 
799   char **field_names = (char**)(safe_malloc(nNumberFields * sizeof(char*)));
800   for (unsigned int i = 0; i < nNumberFields; ++i)
801   {
802     fieldname = mFields.at(i).fieldName;
803     field_names[i] = (char*)(safe_malloc((fieldname.size() * sizeof(char))+ 1));
804     field_names[i] = safe_strdup(fieldname.c_str());
805   }
806 
807   mxStructure = mxCreateStructArray(2, dims, nNumberFields, (const char**)(field_names));
808   safe_free(field_names);
809 
810   for (unsigned int i = 0; i < total_no; ++i)
811   {
812     SBase* child = base->getObject(sbmlTC, i);
813     if (usePlugin)
814     {
815       child = base->getPlugin(prefix)->getObject(sbmlTC, i);
816     }
817     populateStructure(functionId, child, i);
818   }
819 
820 }
821 
822 void
populateStructure(const std::string & functionId,SBase * base,unsigned int index)823 StructureFields::populateStructure(const std::string& functionId, SBase* base, unsigned int index)
824 {
825   if (base == NULL) return;
826 
827   FieldType_t type;
828   FieldnamesType_t nameType;
829 
830   for (unsigned int i = 0; i < nNumberFields; ++i)
831   {
832     FieldValues_t field = mFields.at(i);
833     type = field.type;
834     nameType = field.fieldnameType;
835     bool usePlugin = usingPlugin(field.prefix, base);
836 
837     if (type == TYPE_ELEMENT)
838     {
839       switch (nameType) {
840       case OTHER_NAMESPACES:
841           mxSetField(mxStructure, index, field.fieldName.c_str(), getNamespacesStructure());
842           break;
843       case OTHER_CVTERMS:
844           mxSetField(mxStructure, index, field.fieldName.c_str(), getCVTermsStructure(base));
845           break;
846       default:
847           StructureFields *sf = new StructureFields(field.sbmlName);
848           sf->createStructure(functionId + ":" + field.fieldName, base, usePlugin, field.prefix);
849           mxSetField(mxStructure, index, field.fieldName.c_str(), mxDuplicateArray(sf->getStructure()));
850           sf->freeStructureMemory();
851           delete sf;
852           break;
853       }
854     }
855     else if (field.fieldnameType == OTHER_ANOMALOUS_MATH)
856     {
857       addAnomalousChildStructure(functionId, base, index, field);
858     }
859     else
860     {
861       addStructureField(functionId, base, index, field, usePlugin);
862     }
863 
864   }
865 }
866 
867 void
addAnomalousChildStructure(const std::string & functionId,SBase * base,unsigned int index,FieldValues_t field)868 StructureFields::addAnomalousChildStructure(const std::string& functionId, SBase* base,
869                          unsigned int index, FieldValues_t field)
870 {
871   std::string value;
872   SBase* child = base->getObject(field.fieldName, 0);
873   if (child == NULL)
874   {
875     value = field.strValue;
876   }
877   else
878   {
879     value = getMathString(child);
880   }
881 
882   mxSetField(mxStructure, index, field.fieldName.c_str() ,mxCreateString(value.c_str()));
883 }
884 
885 mxArray*
getNamespacesStructure()886 StructureFields::getNamespacesStructure()
887 {
888   mxArray* mxNSReturn = NULL;
889 
890   const XMLNamespaces * NS = details->getNamespaces()->getNamespaces();
891   int n = NS->getLength();
892   mwSize dims[2] = {1, (mwSize)(n)};
893 
894   /* fields within a namespace structure */
895   const int nNoFields = 2;
896   const char *field_names[] = {
897     "prefix",
898     "uri"
899   };
900 
901 
902   const char * pacPrefix = NULL;
903   const char * pacURI = NULL;
904 
905   int i;
906 
907   mxNSReturn = mxCreateStructArray(2, dims, nNoFields, field_names);
908 
909   for (i = 0; i < n; ++i)
910   {
911     pacPrefix = safe_strdup(NS->getPrefix(i).c_str());
912     pacURI    = safe_strdup(NS->getURI(i).c_str());
913 
914     /**
915     * check for NULL strings - Matlab doesnt like creating
916     * a string that is NULL
917     */
918     if (pacPrefix == NULL) {
919       pacPrefix = "";
920     }
921     if (pacURI == NULL) {
922       pacURI = "";
923     }
924 
925     mxSetField(mxNSReturn, i, "prefix", mxCreateString(pacPrefix));
926     mxSetField(mxNSReturn, i, "uri",    mxCreateString(pacURI));
927 
928     safe_free((void*)(pacPrefix));
929     safe_free((void*)(pacURI));
930   }
931 
932   return mxNSReturn;
933 }
934 
935 mxArray*
createCVTermStructure(int num)936 createCVTermStructure(int num)
937 {
938   mxArray* mxCVTermReturn;
939   mwSize dims[2] = {1, (mwSize)(num)};
940 
941   /* fields within a cvterm structure */
942   const int nNoFields = 4;
943   const char *field_names[] = {
944     "qualifierType",
945     "qualifier",
946     "resources",
947     "cvterms"
948   };
949 
950   mxCVTermReturn = mxCreateStructArray(2, dims, nNoFields, field_names);
951 
952   return mxCVTermReturn;
953 }
954 
955 
956 
957 void
addCVTerm(mxArray * mxCVTermReturn,int i,CVTerm * cv)958   addCVTerm (mxArray* mxCVTermReturn, int i, CVTerm* cv)
959 {
960   const char * pacQualifier = NULL;
961   const char * pacQualifierType = NULL;
962   mxArray* mxResources = NULL;
963 
964   if (cv->getQualifierType() == BIOLOGICAL_QUALIFIER)
965   {
966     std::string bq = "biological";
967     pacQualifierType = (char*)(safe_malloc((bq.size() * sizeof(char))+ 1));
968     pacQualifierType = safe_strdup(bq.c_str());
969 
970     size_t s = sizeof((const char *)(BiolQualifierType_toString(cv->getBiologicalQualifierType()))) * sizeof(char);
971     pacQualifier = (char*)(safe_malloc(s + 1));
972     pacQualifier = safe_strdup(BiolQualifierType_toString(cv->getBiologicalQualifierType()));
973   }
974   else if  (cv->getQualifierType() == MODEL_QUALIFIER)
975   {
976     std::string bq = "model";
977     pacQualifierType = (char*)(safe_malloc((bq.size() * sizeof(char))+ 1));
978     pacQualifierType = safe_strdup(bq.c_str());
979 
980     size_t s = sizeof((const char *)(ModelQualifierType_toString(cv->getModelQualifierType()))) * sizeof(char);
981     pacQualifier = (char*)(safe_malloc(s + 1));
982     pacQualifier = safe_strdup(ModelQualifierType_toString(cv->getModelQualifierType()));
983   }
984   else
985   {
986     std::string bq = "unknown";
987     pacQualifierType = (char*)(safe_malloc((bq.size() * sizeof(char))+ 1));
988     pacQualifierType = safe_strdup(bq.c_str());
989 
990     pacQualifier = (char*)(safe_malloc((bq.size() * sizeof(char))+ 1));
991     pacQualifier = safe_strdup(bq.c_str());
992 
993   }
994   mwSize num = cv->getNumResources();
995   std::string fieldname;
996 
997   char **resources = (char**)(safe_malloc(num * sizeof(char*)));
998   for (unsigned int j = 0; j < num; j++)
999   {
1000     fieldname = cv->getResourceURI(j);
1001     size_t s = (fieldname.size() * sizeof(char)) + 1;
1002     resources[j] = (char*)(safe_malloc(s));
1003     resources[j] = safe_strdup(fieldname.c_str());
1004   }
1005 
1006   mxResources = mxCreateCellMatrix(1, num);
1007   for (unsigned int j = 0; j < num; j++)
1008   {
1009     mxSetCell(mxResources, j, mxCreateString(resources[j]));
1010   }
1011 
1012   mxSetField(mxCVTermReturn, i, "qualifierType", mxCreateString(pacQualifierType));
1013   mxSetField(mxCVTermReturn, i, "qualifier", mxCreateString(pacQualifier));
1014   mxSetField(mxCVTermReturn, i, "resources",   mxResources);
1015 
1016   unsigned int numNested = cv->getNumNestedCVTerms();
1017   if (cv->getNumNestedCVTerms() > 0)
1018   {
1019     mxArray* mxNested = createCVTermStructure(numNested);
1020     for (unsigned int j = 0; j < numNested; j++)
1021     {
1022       addCVTerm(mxNested, j, cv->getNestedCVTerm(j));
1023     }
1024     mxSetField(mxCVTermReturn, i, "cvterms",   mxNested);
1025   }
1026 
1027   safe_free((void*)(pacQualifier));
1028   safe_free((void*)(pacQualifierType));
1029   safe_free(resources);
1030 }
1031 
1032 
1033 mxArray*
getCVTermsStructure(SBase * base)1034 StructureFields::getCVTermsStructure(SBase* base)
1035 {
1036   mxArray* mxCVTermReturn = NULL;
1037 
1038   int n = base->getNumCVTerms();
1039   if (n > 0)
1040   {
1041     mxCVTermReturn = createCVTermStructure(n);
1042   }
1043 
1044   for (int i = 0; i < n; ++i)
1045   {
1046     CVTerm * cv = base->getCVTerm(i);
1047     addCVTerm(mxCVTermReturn, i, cv);
1048   }
1049 
1050   return mxCVTermReturn;
1051 }
1052 
1053 
1054 void
addStructureField(const std::string & functionId,SBase * base,unsigned int index,FieldValues_t field,bool usePlugin)1055 StructureFields::addStructureField(const std::string& functionId, SBase* base,
1056   unsigned int index, FieldValues_t field,
1057   bool usePlugin)
1058 {
1059   std::string value;
1060   int ivalue;
1061   unsigned int uvalue;
1062   bool bvalue;
1063   double dvalue;
1064   switch (field.type)
1065   {
1066   case TYPE_UNKNOWN:
1067 
1068   case TYPE_CHAR:
1069     value = getStringValue(functionId, base, field, usePlugin);
1070     mxSetField(mxStructure, index, field.fieldName.c_str(), mxCreateString(value.c_str()));
1071     break;
1072   case TYPE_BOOL:
1073     bvalue = getBoolValue(functionId, base, field, usePlugin);
1074     mxSetField(mxStructure, index, field.fieldName.c_str(), CreateIntScalar(bvalue));
1075     break;
1076   case TYPE_UINT:
1077     uvalue = getUintValue(functionId, base, field, usePlugin);
1078     mxSetField(mxStructure, index, field.fieldName.c_str(), CreateIntScalar(uvalue));
1079     break;
1080   case TYPE_INT:
1081     ivalue = getIntValue(functionId, base, field, usePlugin);
1082     mxSetField(mxStructure, index, field.fieldName.c_str(), CreateIntScalar(ivalue));
1083     break;
1084   case TYPE_DOUBLE:
1085     dvalue = getDoubleValue(functionId, base, field, usePlugin);
1086     mxSetField(mxStructure, index, field.fieldName.c_str(), mxCreateDoubleScalar(dvalue));
1087     break;
1088   case TYPE_ELEMENT:
1089   default:
1090     break;
1091   }
1092 }
1093 
1094 const std::string
getStringValue(const std::string & functionId,SBase * base,FieldValues_t field,bool usePlugin)1095 StructureFields::getStringValue(const std::string& functionId, SBase* base,
1096   FieldValues_t field,
1097   bool usePlugin)
1098 {
1099   std::string value;
1100 
1101   if (field.isSBMLAttribute)
1102   {
1103     bool useDefault = true;
1104     switch (field.fieldnameType)
1105     {
1106     case SBML_NOTES:
1107       value = base->getNotesString();
1108       useDefault = false;
1109       break;
1110     case SBML_ANNOT:
1111       value = base->getAnnotationString();
1112       useDefault = false;
1113       break;
1114     case SBML_MESSAGE:
1115       value = base->getMessageString();
1116       useDefault = false;
1117       break;
1118     case SBML_MATH:
1119       value = getMathString(base);
1120       useDefault = false;
1121       break;
1122     default:
1123       if (!usePlugin && base->isSetAttribute(field.sbmlName))
1124       {
1125         base->getAttribute(field.sbmlName, value);
1126         useDefault = false;
1127       }
1128       else if (usePlugin && base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName))
1129       {
1130         base->getPlugin(field.prefix)->getAttribute(field.sbmlName, value);
1131         useDefault = false;
1132       }
1133       break;
1134 
1135     }
1136 #ifdef USE_FBC
1137 
1138     if (field.fieldnameType == FBC_ASSOCIATION)
1139     {
1140       value = static_cast<FbcAssociation*>(base)->toInfix(fbcUsingId);//FbcAssociation_toInfix(static_cast<FbcAssociation*>(base));
1141       useDefault = false;
1142     }
1143 #endif
1144 
1145     if (useDefault)
1146     {
1147       value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1148     }
1149   }
1150   else
1151   {
1152     switch (field.fieldnameType)
1153     {
1154     case SBML_RULE_TYPE:
1155       value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1156       if (field.fieldName == "type" && base->getTypeCode() == SBML_RATE_RULE)
1157       {
1158         value = "rate";
1159       }
1160       break;
1161     case OTHER_AVOGADRO_SYMBOL:
1162       if (!details->getAvogadroSymbol().empty())
1163       {
1164         value = details->getAvogadroSymbol();
1165       }
1166       else
1167       {
1168         value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1169       }
1170       break;
1171     case OTHER_DELAY_SYMBOL:
1172       if (!details->getDelaySymbol().empty())
1173       {
1174         value = details->getDelaySymbol();
1175       }
1176       else
1177       {
1178         value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1179       }
1180       break;
1181     case OTHER_TIME_SYMBOL:
1182       if (!details->getTimeSymbol().empty())
1183       {
1184         value = details->getTimeSymbol();
1185       }
1186       else
1187       {
1188         value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1189       }
1190       break;
1191     case OTHER_RATEOF_SYMBOL:
1192       if (!details->getRateOfSymbol().empty())
1193       {
1194         value = details->getRateOfSymbol();
1195       }
1196       else
1197       {
1198         value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1199       }
1200       break;
1201     default:
1202       value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1203      /* hack for rules that all use the same fieldnames/defaults */
1204       if (value == "SBML_ALGEBRAIC_RULE")
1205       {
1206         value = getRuleTypeCode(base);
1207       }
1208       else if (value == "SBML_FBC_ASSOCIATION")
1209       {
1210         value = getAssociationTypeCode(base);
1211       }
1212       break;
1213     }
1214   }
1215 
1216   return (const std::string)(value);
1217 }
1218 
1219 double
getDoubleValue(const std::string & functionId,SBase * base,FieldValues_t field,bool usePlugin)1220 StructureFields::getDoubleValue(const std::string& functionId, SBase* base,
1221   FieldValues_t field,
1222   bool usePlugin)
1223 {
1224   double value;
1225 
1226   if (field.isSBMLAttribute)
1227   {
1228     if (!usePlugin && base->isSetAttribute(field.sbmlName))
1229     {
1230       base->getAttribute(field.sbmlName, value);
1231     }
1232     else if (usePlugin && base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName))
1233     {
1234       base->getPlugin(field.prefix)->getAttribute(field.sbmlName, value);
1235     }
1236     else
1237     {
1238       value = field.dValue;
1239     }
1240   }
1241   else
1242   {
1243     value = field.dValue;
1244   }
1245 
1246   return value;
1247 }
1248 
1249 
1250 int
getIntValue(const std::string & functionId,SBase * base,FieldValues_t field,bool usePlugin)1251 StructureFields::getIntValue(const std::string& functionId, SBase* base,
1252   FieldValues_t field,
1253   bool usePlugin)
1254 {
1255   int value;
1256 
1257   if (field.isSBMLAttribute)
1258   {
1259     if (!usePlugin && base->isSetAttribute(field.sbmlName))
1260     {
1261       base->getAttribute(field.sbmlName, value);
1262     }
1263     else if (usePlugin && base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName))
1264     {
1265       base->getPlugin(field.prefix)->getAttribute(field.sbmlName, value);
1266     }
1267     else
1268     {
1269       value = field.iValue;
1270     }
1271   }
1272   else
1273   {
1274     value = field.iValue;
1275   }
1276 
1277   return value;
1278 }
1279 
1280 
1281 unsigned int
getUintValue(const std::string & functionId,SBase * base,FieldValues_t field,bool usePlugin)1282 StructureFields::getUintValue(const std::string& functionId, SBase* base,
1283   FieldValues_t field,
1284   bool usePlugin)
1285 {
1286   unsigned int value;
1287   int ivalue;
1288   bool useDefault = false;
1289   if (field.isSBMLAttribute)
1290   {
1291     if (!usePlugin && base->isSetAttribute(field.sbmlName))
1292     {
1293       base->getAttribute(field.sbmlName, value);
1294     }
1295     else if (usePlugin && base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName))
1296     {
1297       base->getPlugin(field.prefix)->getAttribute(field.sbmlName, value);
1298     }
1299     else
1300     {
1301       ivalue = field.iValue;// getDefaultValue(fieldIndex, functionId, ivalue);
1302       useDefault = true;
1303     }
1304   }
1305   else
1306   {
1307     ivalue = field.iValue;
1308     useDefault = true;
1309   }
1310 
1311   if (useDefault)
1312   {
1313     return (unsigned int)(ivalue);
1314   }
1315   else
1316   {
1317     return value;
1318   }
1319 }
1320 
1321 
1322 bool
getBoolValue(const std::string & functionId,SBase * base,FieldValues_t field,bool usePlugin)1323 StructureFields::getBoolValue(const std::string& functionId, SBase* base,
1324   FieldValues_t field,
1325   bool usePlugin)
1326 {
1327   bool bvalue;
1328   int value;
1329   if (field.isSBMLAttribute)
1330   {
1331     if (!usePlugin && base->isSetAttribute(field.sbmlName))
1332     {
1333       base->getAttribute(field.sbmlName, bvalue);
1334       return bvalue;
1335     }
1336     else if (usePlugin && base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName))
1337     {
1338       base->getPlugin(field.prefix)->getAttribute(field.sbmlName, bvalue);
1339       return bvalue;
1340     }
1341     else
1342     {
1343       value = field.iValue;// getDefaultValue(fieldIndex, functionId, value);
1344     }
1345   }
1346   else if (field.fieldnameType == SBML_ISSET)
1347   {
1348     if (!usePlugin)
1349     {
1350       value = base->isSetAttribute(field.sbmlName);
1351     }
1352     else
1353     {
1354       value = base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName);
1355     }
1356   }
1357   else
1358   {
1359     value = field.iValue;// getDefaultValue(fieldIndex, functionId, value);
1360   }
1361 
1362   return (value == 0) ? false : true;
1363 }
1364 
1365 
1366 std::string
getMathString(SBase * base)1367 StructureFields::getMathString(SBase* base)
1368 {
1369   const ASTNode* ast = base->getMath();
1370   lookForCSymbols(const_cast<ASTNode*>(ast));
1371   char * formula = SBML_formulaToString(ast);
1372   char * matlab = GetMatlabFormula(formula, sbmlTC);
1373   std::string math = std::string(matlab);
1374   mxFree(matlab);
1375   return math;
1376 
1377 }
1378 
1379 char *
GetMatlabFormula(char * pacFormula,std::string object)1380 StructureFields::GetMatlabFormula(char * pacFormula, std::string object)
1381 {
1382   mxArray *mxInput[1];
1383   mxArray *mxOutput[1];
1384   int nStatus;
1385   size_t nBuflen;
1386   char * formula;
1387 
1388   /* convert MathML infix formula to MATLAB */
1389 
1390   mxInput[0] = mxCreateString(pacFormula);
1391   nStatus = mexCallMATLAB(1, mxOutput, 1, mxInput, "CheckAndConvert");
1392 
1393   if (nStatus != 0)
1394   {
1395     std::string id = std::string("TranslateSBML:GetMatlabFormula:") + object;
1396     reportError(id.c_str(), "Failed to convert formula");
1397   }
1398 
1399   /* get the formula returned */
1400   nBuflen = (mxGetM(mxOutput[0])*mxGetN(mxOutput[0])+1);
1401   formula = (char *) mxCalloc(nBuflen, sizeof(char));
1402   nStatus = mxGetString(mxOutput[0], (char *) formula, (mwSize)(nBuflen));
1403 
1404   if (nStatus != 0)
1405   {
1406     std::string id = std::string("TranslateSBML:GetMatlabFormula") + object;
1407     reportError(id.c_str(), "Cannot copy formula");
1408   }
1409 
1410   mxDestroyArray(mxInput[0]);
1411   mxDestroyArray(mxOutput[0]);
1412 
1413   return formula;
1414 }
1415 
1416 void
lookForCSymbols(ASTNode * math)1417 StructureFields::lookForCSymbols(ASTNode* math)
1418 {
1419   if (math == NULL) return;
1420 
1421   unsigned int nChild = math->getNumChildren();
1422   ASTNodeType_t type = math->getType();
1423 
1424   switch (type)
1425   {
1426   case AST_NAME_AVOGADRO:
1427     dealWithAvogadroSymbol(math);
1428     break;
1429   case AST_NAME_TIME:
1430     dealWithTimeSymbol(math);
1431     break;
1432   case AST_FUNCTION_DELAY:
1433     dealWithDelaySymbol(math);
1434     break;
1435   case AST_FUNCTION_RATE_OF:
1436     dealWithRateOfSymbol(math);
1437     break;
1438   default:
1439     break;
1440   }
1441 
1442   for (unsigned int i = 0; i < nChild; ++i)
1443   {
1444     ASTNode* child = math->getChild(i);
1445     lookForCSymbols(child);
1446   }
1447 }
1448 
1449 void
dealWithAvogadroSymbol(ASTNode * math)1450 StructureFields::dealWithAvogadroSymbol(ASTNode* math)
1451 {
1452   if (math == NULL) return;
1453   if (details->getAvogadroSymbol().empty())
1454   {
1455     details->setAvogadroSymbol(math->getName());
1456   }
1457   else
1458   {
1459     math->setName(details->getAvogadroSymbol().c_str());
1460   }
1461 }
1462 
1463 void
dealWithTimeSymbol(ASTNode * math)1464 StructureFields::dealWithTimeSymbol(ASTNode* math)
1465 {
1466   if (math == NULL) return;
1467   if (details->getTimeSymbol().empty())
1468   {
1469     details->setTimeSymbol(math->getName());
1470   }
1471   else
1472   {
1473     math->setName(details->getTimeSymbol().c_str());
1474   }
1475 }
1476 
1477 void
dealWithDelaySymbol(ASTNode * math)1478 StructureFields::dealWithDelaySymbol(ASTNode* math)
1479 {
1480   if (math == NULL) return;
1481   if (details->getDelaySymbol().empty())
1482   {
1483     details->setDelaySymbol(math->getName());
1484   }
1485   else
1486   {
1487     math->setName(details->getDelaySymbol().c_str());
1488   }
1489 }
1490 
1491 void
dealWithRateOfSymbol(ASTNode * math)1492 StructureFields::dealWithRateOfSymbol(ASTNode* math)
1493 {
1494   if (math == NULL) return;
1495   if (details->getRateOfSymbol().empty())
1496   {
1497     details->setRateOfSymbol(math->getName());
1498   }
1499   else
1500   {
1501     math->setName(details->getRateOfSymbol().c_str());
1502   }
1503 }
1504 
1505 //////////////////////////////////////////////////////////////
1506 
1507 // general need to know function
1508 
1509 bool
usingPlugin(const std::string & prefix,SBase * base)1510 StructureFields::usingPlugin(const std::string& prefix, SBase* base)
1511 {
1512   bool usePlugin = false;
1513   if (prefix.size() > 0)
1514   {
1515     if (mSBase != NULL && mSBase->getPackageName() != prefix)
1516     {
1517       usePlugin = true;
1518     }
1519     else if (base != NULL && base->getPlugin(prefix) != NULL)
1520     {
1521       usePlugin = true;
1522     }
1523   }
1524 
1525   return usePlugin;
1526 }
1527 
1528 //////////////////////////
1529 
1530 // functions for creating SBML from structure
1531 void
addAttributes(const std::string & functionId,unsigned int index,unsigned int total_no)1532 StructureFields::addAttributes(const std::string& functionId, unsigned int index,
1533                                unsigned int total_no)
1534 {
1535   FieldType_t type;
1536   FieldnamesType_t nameType;
1537 
1538   for (unsigned int i = 0; i < nNumberFields; ++i)
1539   {
1540     FieldValues_t field = mFields.at(i);
1541     type = field.type;
1542     nameType = field.fieldnameType;
1543     if (nameType != OTHER_CVTERMS && !field.isSBMLAttribute)
1544     {
1545       continue;
1546     }
1547     if (type == TYPE_ELEMENT)
1548     {
1549       if (nameType == OTHER_CVTERMS)
1550       {
1551         addCVTerms(index);
1552       }
1553       else
1554       {
1555        addChildElement(field, index);
1556       }
1557     }
1558     else if (field.fieldnameType == OTHER_ANOMALOUS_MATH)
1559     {
1560       addAnomalousChild(field);
1561     }
1562     else
1563     {
1564       setAttribute(field, index, total_no);
1565     }
1566 
1567   }
1568 }
1569 
1570 CVTerm *
getCVTerm(mxArray * mxCVTerms,unsigned int i)1571 getCVTerm(mxArray* mxCVTerms, unsigned int i)
1572 {
1573   CVTerm *cv;
1574   std::string qualType = StructureFields::readString(mxCVTerms, "qualifierType", i);
1575   std::string qual = StructureFields::readString(mxCVTerms, "qualifier", i);
1576   if (qualType == "biological")
1577   {
1578     cv = new CVTerm(BIOLOGICAL_QUALIFIER);
1579     cv->setBiologicalQualifierType(qual);
1580   }
1581   else if (qualType == "model")
1582   {
1583     cv = new CVTerm(MODEL_QUALIFIER);
1584     cv->setModelQualifierType(qual);
1585   }
1586   else
1587   {
1588     cv = new CVTerm();
1589   }
1590 
1591   mxArray* mxResources = mxGetField(mxCVTerms, i, "resources");
1592   size_t numRes = mxGetNumberOfElements(mxResources);
1593 
1594   for (unsigned int j = 0; j < numRes; j++)
1595   {
1596     mxArray* mxField = mxGetCell(mxResources, j);
1597     char *value = mxArrayToString(mxField);
1598     if (value != NULL)
1599     {
1600       cv->addResource(std::string(value));
1601     }
1602   }
1603 
1604   mxArray* mxNestedCV = mxGetField(mxCVTerms, i, "cvterms");
1605   if (mxNestedCV != NULL)
1606   {
1607     size_t numNested = mxGetNumberOfElements(mxNestedCV);
1608 
1609     for (unsigned int n = 0; n < numNested; n++)
1610     {
1611       CVTerm *nested = getCVTerm(mxNestedCV, n);
1612       cv->addNestedCVTerm(nested);
1613       delete nested;
1614     }
1615   }
1616 
1617   return cv;
1618 }
1619 
1620 void
addCVTerms(unsigned int index)1621 StructureFields::addCVTerms(unsigned int index)
1622 {
1623   mxArray* mxCVTerms = mxGetField(mxStructure, index, "cvterms");
1624   if (mxCVTerms == NULL)
1625     return;
1626 
1627   size_t numCV = mxGetNumberOfElements(mxCVTerms);
1628 
1629   for (unsigned int i = 0; i < numCV; ++i)
1630   {
1631     CVTerm *cv = getCVTerm(mxCVTerms, i);
1632     if (!mSBase->isSetMetaId())
1633       mSBase->setMetaId("temp");
1634     mSBase->addCVTerm(cv);
1635     delete cv;
1636   }
1637 
1638 }
1639 
1640 void
addChildElement(FieldValues_t field,unsigned int index)1641 StructureFields::addChildElement(FieldValues_t field, unsigned int index)
1642 {
1643   mxArray* mxChild = mxGetField(mxStructure, index, field.fieldName.c_str());
1644   SBase *pChild = NULL;
1645 
1646   size_t n = mxGetNumberOfElements(mxChild);
1647   if (mxChild == NULL) return;
1648   else if (n == 0) return;
1649 
1650   bool usePlugin = usingPlugin(field.prefix);
1651 
1652   for (unsigned int i = 0; i < n; ++i)
1653   {
1654     // hack for rules - since a list of rules contains assignmentRule etc..
1655     if (field.fieldName == "rule")
1656     {
1657       pChild = mSBase->createChildObject(getRuleType(mxChild, i));
1658     }
1659     else
1660     {
1661       if (usePlugin)
1662       {
1663         pChild = mSBase->getPlugin(field.prefix)->createChildObject(field.sbmlName);
1664       }
1665       else
1666       {
1667         pChild = mSBase->createChildObject(field.sbmlName);
1668       }
1669     }
1670 
1671     if (pChild != NULL)
1672     {
1673       StructureFields *sf = new StructureFields(pChild, mxChild);
1674 
1675       std::string id = std::string("OutputSBML:addChildElement:") + sf->getTypeCode();
1676       sf->addAttributes(id, i, n);
1677 
1678       sf->freeStructureMemory();
1679     }
1680   }
1681 }
1682 
1683 void
addAnomalousChild(FieldValues_t field)1684 StructureFields::addAnomalousChild(FieldValues_t field)
1685 {
1686   std::string value = readString(field.fieldName, 0, 0);
1687 
1688   if (!value.empty())
1689   {
1690     SBase *pChild = mSBase->createChildObject(field.fieldName);
1691     if (pChild != NULL)
1692     {
1693       std::string value = readString(field.fieldName, 0, 0);
1694       const ASTNode* ast = getMathChild(value);
1695       pChild->setMath(ast);
1696    }
1697   }
1698 }
1699 
1700 const ASTNode*
getMathChild(const std::string & value)1701 StructureFields::getMathChild(const std::string& value)
1702 {
1703   /* convert MATLAB formula to MathML infix */
1704   char * cvalue = convertMathFormula(value);
1705   L3ParserSettings settings;
1706   settings.setParseLog(L3P_PARSE_LOG_AS_LN);
1707   const ASTNode *ast = SBML_parseL3FormulaWithSettings(cvalue, &settings);
1708   adjustForCSymbols(const_cast<ASTNode*>(ast));
1709   mxFree(cvalue);
1710   return ast;
1711 }
1712 
1713 void
adjustForCSymbols(ASTNode * math)1714 StructureFields::adjustForCSymbols(ASTNode * math)
1715 {
1716   if (math == NULL)
1717   {
1718     return;
1719   }
1720 
1721   ASTNodeType_t type = math->getType();
1722   switch (type)
1723   {
1724   case AST_FUNCTION:
1725     if (math->getName() == details->getDelaySymbol())
1726     {
1727       math->setType(AST_FUNCTION_DELAY);
1728     }
1729     else if (math->getName() == details->getRateOfSymbol())
1730     {
1731       math->setType(AST_FUNCTION_RATE_OF);
1732     }
1733     break;
1734   case AST_NAME:
1735     if (math->getName() == details->getTimeSymbol())
1736     {
1737       math->setType(AST_NAME_TIME);
1738     }
1739     else if (math->getName() == details->getAvogadroSymbol())
1740     {
1741       math->setType(AST_NAME_AVOGADRO);
1742     }
1743     break;
1744   default:
1745     break;
1746   }
1747 
1748   for (unsigned int i = 0; i < math->getNumChildren(); ++i)
1749   {
1750     adjustForCSymbols(math->getChild(i));
1751   }
1752 }
1753 
1754 
1755 void
setAttribute(FieldValues_t field,unsigned int index,unsigned int total_no)1756 StructureFields::setAttribute(FieldValues_t field,
1757                               unsigned int index, unsigned int total_no)
1758 {
1759   std::string value;
1760   int ivalue;
1761   unsigned int uvalue;
1762   bool bvalue;
1763   double dvalue;
1764   bool usePlugin = usingPlugin(field.prefix);
1765   const ASTNode *ast = NULL;
1766 
1767   switch(field.type)
1768   {
1769   case TYPE_CHAR:
1770     value = readString(field.fieldName, index, total_no);
1771     switch (field.fieldnameType) {
1772     case SBML_MATH:
1773       ast = getMathChild(value);
1774       mSBase->setMath(ast);
1775       break;
1776     case SBML_NOTES:
1777       mSBase->setNotes(value);
1778       break;
1779     case SBML_ANNOT:
1780       mSBase->setAnnotation(value);
1781       break;
1782     case SBML_MESSAGE:
1783       mSBase->setMessage(value);
1784       break;
1785     default:
1786       if (usePlugin)
1787       {
1788         mSBase->getPlugin(field.prefix)->setAttribute(field.sbmlName, value);
1789       }
1790       else
1791       {
1792         mSBase->setAttribute(field.sbmlName, value);
1793       }
1794       break;
1795     }
1796     break;
1797 
1798   case TYPE_INT:
1799     ivalue = readInt(field.fieldName, index, total_no);
1800     if (determineStatus(field.fieldName, index))
1801     {
1802       if (usePlugin)
1803       {
1804         mSBase->getPlugin(field.prefix)->setAttribute(field.sbmlName, ivalue);
1805       }
1806       else
1807       {
1808         mSBase->setAttribute(field.sbmlName, ivalue);
1809       }
1810     }
1811     break;
1812 
1813   case TYPE_UINT:
1814     uvalue = readUint(field.fieldName, index, total_no);
1815     if (determineStatus(field.fieldName, index))
1816     {
1817       if (usePlugin)
1818       {
1819         mSBase->getPlugin(field.prefix)->setAttribute(field.sbmlName, uvalue);
1820       }
1821       else
1822       {
1823         mSBase->setAttribute(field.sbmlName, uvalue);
1824       }
1825     }
1826     break;
1827 
1828   case TYPE_DOUBLE:
1829     dvalue = readDouble(field.fieldName, index, total_no);
1830     if (determineStatus(field.fieldName, index))
1831     {
1832       if (usePlugin)
1833       {
1834         mSBase->getPlugin(field.prefix)->setAttribute(field.sbmlName, dvalue);
1835       }
1836       else
1837       {
1838         mSBase->setAttribute(field.sbmlName, dvalue);
1839       }
1840     }
1841     break;
1842 
1843   case TYPE_BOOL:
1844     ivalue = readInt(field.fieldName, index, total_no);
1845     bvalue = true ? ivalue == 1 : false;
1846     if (determineStatus(field.fieldName, index))
1847     {
1848       if (usePlugin)
1849       {
1850         mSBase->getPlugin(field.prefix)->setAttribute(field.sbmlName, bvalue);
1851       }
1852       else
1853       {
1854         mSBase->setAttribute(field.sbmlName, bvalue);
1855       }
1856     }
1857 
1858   case TYPE_UNKNOWN:
1859   default:
1860     break;
1861   }
1862 }
1863 
1864 const std::string
getRuleType(mxArray * mxRuleStructure,unsigned int index)1865 StructureFields::getRuleType(mxArray* mxRuleStructure, unsigned int index)
1866 {
1867   std::string value = readString(mxRuleStructure, "typecode", index);
1868   std::string retvalue;
1869   if (value == "SBML_ALGEBRAIC_RULE")
1870   {
1871     retvalue = "algebraicRule";
1872   }
1873   else if (value == "SBML_ASSIGNMENT_RULE")
1874   {
1875     retvalue = "assignmentRule";
1876   }
1877   else if (value == "SBML_RATE_RULE")
1878   {
1879     retvalue = "rateRule";
1880   }
1881   else
1882   {
1883     std::string type = readString(mxRuleStructure, "type", index);
1884     if (value == "SBML_PARAMETER_RULE")
1885       if (type == "scalar")
1886         retvalue = "parameterAssignmentRule";
1887       else
1888         retvalue = "parameterRateRule";
1889     else if (value == "SBML_SPECIES_CONCENTRATION_RULE")
1890       if (type == "scalar")
1891         retvalue = "speciesAssignmentRule";
1892       else
1893         retvalue = "speciesRateRule";
1894     else if (value == "SBML_COMPARTMENT_VOLUME_RULE")
1895       if (type == "scalar")
1896         retvalue = "compartmentAssignmentRule";
1897       else
1898         retvalue = "compartmentRateRule";
1899     else
1900       retvalue = "rule";
1901   }
1902 
1903   return retvalue;
1904 }
1905 
1906 std::string
getAssociationTypeCode(SBase * base)1907 StructureFields::getAssociationTypeCode(SBase* base)
1908 {
1909   std::string value = SBMLTypeCode_toString(base->getTypeCode(), "fbc");
1910   std::string retvalue = "SBML_FBC_ASSOCIATION";
1911   if (value == "GeneProductRef")
1912   {
1913     retvalue = "SBML_FBC_GENE_PRODUCT_REF";
1914   }
1915   else if (value == "FbcAnd")
1916   {
1917     retvalue = "SBML_FBC_AND";
1918   }
1919   else if (value == "FbcOr")
1920   {
1921     retvalue = "SBML_FBC_OR";
1922   }
1923   return retvalue;
1924 }
1925 
1926 std::string
getRuleTypeCode(SBase * base)1927 StructureFields::getRuleTypeCode(SBase* base)
1928 {
1929   std::string value = SBMLTypeCode_toString(base->getTypeCode(), "core");
1930   std::string retvalue = "rule";
1931   if (value == "AlgebraicRule")
1932   {
1933     retvalue = "SBML_ALGEBRAIC_RULE";
1934   }
1935   else if (value == "AssignmentRule")
1936   {
1937     if (base->getLevel() > 1)
1938     {
1939       retvalue = "SBML_ASSIGNMENT_RULE";
1940     }
1941     else
1942     {
1943       Model *m = static_cast<Model*>(base->getAncestorOfType(SBML_MODEL));
1944       if (m != NULL)
1945       {
1946         if (m->getCompartment(static_cast<Rule*>(base)->getVariable()) != NULL)
1947         {
1948           retvalue = "SBML_COMPARTMENT_VOLUME_RULE";
1949         }
1950         if (m->getSpecies(static_cast<Rule*>(base)->getVariable()) != NULL)
1951         {
1952           retvalue = "SBML_SPECIES_CONCENTRATION_RULE";
1953         }
1954         if (m->getParameter(static_cast<Rule*>(base)->getVariable()) != NULL)
1955         {
1956           retvalue = "SBML_PARAMETER_RULE";
1957         }
1958       }
1959     }
1960   }
1961   else if (value == "RateRule")
1962   {
1963     if (base->getLevel() > 1)
1964     {
1965       retvalue = "SBML_RATE_RULE";
1966     }
1967     else
1968     {
1969       Model *m = static_cast<Model*>(base->getAncestorOfType(SBML_MODEL));
1970       if (m != NULL)
1971       {
1972         std::string var = static_cast<Rule*>(base)->getVariable();
1973         if (m->getCompartment(var) != NULL)
1974         {
1975           retvalue = "SBML_COMPARTMENT_VOLUME_RULE";
1976         }
1977         if (m->getSpecies(var) != NULL)
1978         {
1979           retvalue = "SBML_SPECIES_CONCENTRATION_RULE";
1980         }
1981         if (m->getParameter(var) != NULL)
1982         {
1983           retvalue = "SBML_PARAMETER_RULE";
1984         }
1985       }
1986     }
1987   }
1988   return retvalue;
1989 }
1990 
1991 
1992 char *
convertMathFormula(const std::string & pacFormula)1993 StructureFields::convertMathFormula(const std::string& pacFormula)
1994 {
1995   mxArray *mxInput[1];
1996   mxArray *mxOutput[1];
1997   int nStatus;
1998   size_t nBuflen;
1999   char * formula;
2000 
2001   /* convert MATLAB formula to MathML infix */
2002 
2003   mxInput[0] = mxCreateString(pacFormula.c_str());
2004   nStatus = mexCallMATLAB(1, mxOutput, 1, mxInput, "ConvertFormulaToMathML");
2005 
2006   if (nStatus != 0)
2007   {
2008     std::string id = std::string("OutputSBML:GetMathMLFormula:") + sbmlTC;
2009     reportError(id, "Failed to convert formula");
2010   }
2011 
2012   /* get the formula returned */
2013   nBuflen = (mxGetM(mxOutput[0])*mxGetN(mxOutput[0])+1);
2014   formula = (char *) mxCalloc(nBuflen, sizeof(char));
2015   nStatus = mxGetString(mxOutput[0], (char *) formula, (mwSize)(nBuflen));
2016 
2017   if (nStatus != 0)
2018   {
2019     std::string id = std::string("OutputSBML:GetMathMLFormula") + sbmlTC;
2020     reportError(id, "Cannot copy formula");
2021   }
2022 
2023   mxDestroyArray(mxInput[0]);
2024   mxDestroyArray(mxOutput[0]);
2025 
2026   return formula;
2027 }
2028 
2029 int
readInt(const std::string & name,unsigned int index,unsigned int total_no)2030 StructureFields::readInt(const std::string& name, unsigned int index, unsigned int total_no)
2031 {
2032   mxArray * mxField;
2033   int value = 0;
2034   int nStatus = 1;
2035 
2036   /* get field */
2037   mxField = mxGetField(mxStructure, index, name.c_str());
2038   if (mxField != NULL)
2039   {
2040     if (!mxIsEmpty(mxField))
2041     {
2042       if (mxIsNumeric(mxField))
2043       {
2044         value = (int)(mxGetScalar(mxField));
2045         nStatus = 0;
2046       }
2047     }
2048     else
2049     {
2050       value = 0;
2051       nStatus = 0;
2052     }
2053 
2054     if (nStatus != 0)
2055     {
2056       reportReadError("Int", name, index, total_no);
2057     }
2058   }
2059   return value;
2060 }
2061 
2062 // static version
2063 int
readInt(mxArray * mxArray1,const std::string & name,unsigned int index)2064 StructureFields::readInt(mxArray* mxArray1, const std::string& name, unsigned int index)
2065 {
2066   mxArray * mxField;
2067   int value = 0;
2068   int nStatus = 1;
2069 
2070   /* get field */
2071   mxField = mxGetField(mxArray1, index, name.c_str());
2072   if (mxField != NULL)
2073   {
2074     if (!mxIsEmpty(mxField))
2075     {
2076       if (mxIsNumeric(mxField))
2077       {
2078         value = (int)(mxGetScalar(mxField));
2079         nStatus = 0;
2080       }
2081     }
2082     else
2083     {
2084       value = 0;
2085       nStatus = 0;
2086     }
2087 
2088     if (nStatus != 0)
2089     {
2090       reportReadError("Int", name, index, 0, "static");
2091     }
2092   }
2093 
2094   return value;
2095 }
2096 
2097 double
readDouble(const std::string & name,unsigned int index,unsigned int total_no)2098 StructureFields::readDouble(const std::string& name, unsigned int index, unsigned int total_no)
2099 {
2100   mxArray * mxField;
2101   double value = 0;
2102   int nStatus = 1;
2103 
2104   /* get field */
2105   mxField = mxGetField(mxStructure, index, name.c_str());
2106   if (mxField != NULL)
2107   {
2108     if (!mxIsEmpty(mxField))
2109     {
2110       if (mxIsNumeric(mxField))
2111       {
2112         value = mxGetScalar(mxField);
2113         nStatus = 0;
2114       }
2115     }
2116     else
2117     {
2118       value = util_NaN();
2119       nStatus = 0;
2120     }
2121 
2122     if (nStatus != 0)
2123     {
2124       reportReadError("Double", name, index, total_no);
2125     }
2126   }
2127   return value;
2128 }
2129 
2130 const std::string
readString(const std::string & name,unsigned int index,unsigned int total_no)2131 StructureFields::readString(const std::string& name, unsigned int index, unsigned int total_no)
2132 {
2133   mxArray * mxField;
2134   char *value = NULL;
2135   int nStatus = 1;
2136   std::string f = "";
2137 
2138   /* get field */
2139   mxField = mxGetField(mxStructure, index, name.c_str());
2140   if (mxField != NULL)
2141   {
2142     value = mxArrayToString(mxField);
2143     if (value != NULL)
2144     {
2145       nStatus = 0;
2146       f = std::string(value);
2147     }
2148 
2149     if (nStatus != 0)
2150     {
2151       reportReadError("String", name, index, total_no);
2152     }
2153   }
2154   return f;
2155 }
2156 
2157 //static version
2158 const std::string
readString(mxArray * mxArray1,const std::string & name,unsigned int index)2159 StructureFields::readString(mxArray* mxArray1, const std::string& name, unsigned int index)
2160 {
2161   mxArray * mxField;
2162   char *value = NULL;
2163   int nStatus = 1;
2164   std::string f = "";
2165   /* get field */
2166   mxField = mxGetField(mxArray1, index, name.c_str());
2167   if (mxField != NULL)
2168   {
2169     value = mxArrayToString(mxField);
2170     if (value != NULL)
2171     {
2172       nStatus = 0;
2173       f = std::string(value);
2174     }
2175     if (nStatus != 0)
2176     {
2177       reportReadError("String", name, index, 0, "static");
2178     }
2179   }
2180   return f;
2181 }
2182 
2183 unsigned int
readUint(const std::string & name,unsigned int index,unsigned int total_no)2184 StructureFields::readUint(const std::string& name, unsigned int index, unsigned int total_no)
2185 {
2186   mxArray * mxField;
2187   unsigned int value = 0;
2188   int nStatus = 1;
2189 
2190   /* get field */
2191   mxField = mxGetField(mxStructure, index, name.c_str());
2192   if (mxField != NULL)
2193   {
2194     if (!mxIsEmpty(mxField))
2195     {
2196       if (mxIsNumeric(mxField))
2197       {
2198         value = (unsigned int)(mxGetScalar(mxField));
2199         nStatus = 0;
2200       }
2201     }
2202     else
2203     {
2204       value = 0;
2205       nStatus = 0;
2206     }
2207 
2208     if (nStatus != 0)
2209     {
2210       reportReadError("Uint", name, index, total_no);
2211     }
2212   }
2213 
2214   return value;
2215 }
2216 
2217 // static version
2218 unsigned int
readUint(mxArray * mxArray1,const std::string & name,unsigned int index)2219 StructureFields::readUint(mxArray* mxArray1, const std::string& name,
2220                           unsigned int index)
2221 {
2222   mxArray * mxField;
2223   unsigned int value = 0;
2224   int nStatus = 1;
2225 
2226   /* get field */
2227   mxField = mxGetField(mxArray1, index, name.c_str());
2228   if (mxField != NULL)
2229   {
2230     if (!mxIsEmpty(mxField))
2231     {
2232       if (mxIsNumeric(mxField))
2233       {
2234         value = (unsigned int)(mxGetScalar(mxField));
2235         nStatus = 0;
2236       }
2237     }
2238     else
2239     {
2240       value = 0;
2241       nStatus = 0;
2242     }
2243 
2244     if (nStatus != 0)
2245     {
2246       reportReadError("Uint", name, index, 0, "static");
2247     }
2248   }
2249   return value;
2250 }
2251 
2252 bool
determineStatus(const std::string & name,unsigned int index)2253 StructureFields::determineStatus(const std::string& name, unsigned int index)
2254 {
2255   bool setStatus = true;
2256   mxArray * mxField;
2257   // if the field itself is empty then it is clearly not set
2258   mxField = mxGetField(mxStructure, index, name.c_str());
2259   if (mxField == NULL || mxIsEmpty(mxField))
2260   {
2261     return false;
2262   }
2263 
2264   // want to know whether there is an isSetXYZ field coming from matlab
2265   // and if so what is its value
2266   unsigned int value = 0;
2267   int nStatus = 1;
2268   const char * cname = name.c_str();
2269   char * cpname = safe_strdup(cname);
2270   const char * isset = "isSet";
2271   char * isSet = safe_strcat(isset, cpname);
2272   cpname[0] = toupper(cpname[0]);
2273   char * isSet1 = safe_strcat(isset, cpname);
2274 
2275   /* get field */
2276   mxField = mxGetField(mxStructure, index, isSet1);
2277   // possibly have isSet followed by lower case
2278   if (mxField == NULL)
2279     mxField = mxGetField(mxStructure, index, isSet);
2280   if (mxField != NULL)
2281   {
2282     if (!mxIsEmpty(mxField) && mxIsNumeric(mxField))
2283     {
2284       value = (unsigned int)(mxGetScalar(mxField));
2285       nStatus = 0;
2286     }
2287 
2288     if (nStatus == 0)
2289     {
2290       setStatus = true ? value == 1 : false;
2291     }
2292   }
2293 
2294   safe_free(cpname);
2295   safe_free(isSet);
2296   safe_free(isSet1);
2297 
2298   return setStatus;
2299 }
2300 ///////////////////////////////////////////
2301 
2302 // report error
2303 
2304 void
reportReadError(const std::string & type,const std::string & name,unsigned int index,unsigned int total_no)2305 StructureFields::reportReadError(const std::string& type, const std::string& name,
2306                                  unsigned int index, unsigned int total_no)
2307 {
2308    std::string mid = "OutputSBML:read" + type + ":" + sbmlTC;
2309 
2310    std::ostringstream errMsg;
2311    if (total_no == 0)
2312      errMsg << " Cannot copy " << sbmlTC << "." << name << " field";
2313    else
2314      errMsg << " Cannot copy " << sbmlTC << "(" << index+1 << ")." << name << " field";
2315 
2316    reportError(mid, errMsg.str());
2317 }
2318 
2319 // static version
2320 void
reportReadError(const std::string & type,const std::string & name,unsigned int index,unsigned int total_no,const std::string & tc)2321 StructureFields::reportReadError(const std::string& type, const std::string& name,
2322                                  unsigned int index, unsigned int total_no,
2323                                  const std::string& tc)
2324 {
2325    std::string mid = "OutputSBML:read" + type + ":" + tc;
2326 
2327    std::ostringstream errMsg;
2328    if (total_no == 0)
2329      errMsg << " Cannot copy " << tc << "." << name << " field";
2330    else
2331      errMsg << " Cannot copy " << tc << "(" << index+1 << ")." << name << " field";
2332 
2333    reportError(mid, errMsg.str());
2334 }
2335 
2336 ///////////////////////////////////////////////////////////////////////////////
2337 //
2338 // class to store model details
2339 
ModelDetails()2340 ModelDetails::ModelDetails()
2341 {
2342   mPackageMap.clear();
2343   mSupportedPackages.clear();
2344 
2345   mLevel = StructureFields::readUint(modelArray, "SBML_level", 0);
2346   mVersion = StructureFields::readUint(modelArray, "SBML_version", 0);
2347 
2348   mDelaySymbol = StructureFields::readString(modelArray, "delay_symbol", 0);
2349   mTimeSymbol = StructureFields::readString(modelArray, "time_symbol", 0);
2350   mAvogadroSymbol = StructureFields::readString(modelArray, "avogadro_symbol", 0);
2351 
2352   populateNamespaces();
2353   populatePkgMap();
2354 }
2355 
ModelDetails(SBMLDocument * doc)2356 ModelDetails::ModelDetails(SBMLDocument* doc)
2357 {
2358   mPackageMap.clear();
2359   mSupportedPackages.clear();
2360 
2361   mLevel = doc->getLevel();
2362   mVersion = doc->getVersion();
2363 
2364   mDelaySymbol = "";
2365   mTimeSymbol = "";
2366   mAvogadroSymbol = "";
2367 
2368   populateNamespaces(doc);
2369   populatePkgMap(doc);
2370 }
2371 
2372 
2373 void
populateNamespaces()2374 ModelDetails::populateNamespaces()
2375 {
2376   mSBMLns = new SBMLNamespaces(getLevel(), getVersion());
2377 
2378   XMLNamespaces *xmlns = new XMLNamespaces();
2379   mxArray* mxNamespaces = mxGetField(modelArray, 0, "namespaces");
2380   size_t nNoNamespaces = mxGetNumberOfElements(mxNamespaces);
2381 
2382   for (unsigned int i = 0; i < nNoNamespaces; ++i)
2383   {
2384     std::string uri = StructureFields::readString(mxNamespaces, "uri", i);
2385     std::string prefix = StructureFields::readString(mxNamespaces, "prefix", i);
2386     xmlns->add(uri, prefix);
2387   }
2388 
2389   mSBMLns->addNamespaces(xmlns);
2390 }
2391 
2392 void
populateNamespaces(SBMLDocument * doc)2393 ModelDetails::populateNamespaces(SBMLDocument* doc)
2394 {
2395   mSBMLns = doc->getSBMLNamespaces();
2396 }
2397 
2398 void
populateSupportedPackages()2399 ModelDetails::populateSupportedPackages()
2400 {
2401   for (unsigned int i = 0; i <  SBMLExtensionRegistry::getNumRegisteredPackages(); ++i)
2402   {
2403     mSupportedPackages.append(SBMLExtensionRegistry::getRegisteredPackageName(i));
2404   }
2405 }
2406 
2407 void
populatePkgMap()2408 ModelDetails::populatePkgMap()
2409 {
2410   populateSupportedPackages();
2411   XMLNamespaces *xmlns = mSBMLns->getNamespaces();
2412   for (int i = 0; i < xmlns->getNumNamespaces(); ++i)
2413   {
2414     if (isSupportedPackageNS(xmlns->getURI(i), xmlns->getPrefix(i)))
2415     {
2416       std::string prefix = xmlns->getPrefix(i);
2417       std::string name = prefix + "_version";
2418       unsigned int version = StructureFields::readUint(modelArray, name, 0);
2419       mPackageMap.insert(std::pair<const std::string, unsigned int>(prefix, version));
2420     }
2421   }
2422 }
2423 
2424 void
populatePkgMap(SBMLDocument * doc)2425 ModelDetails::populatePkgMap(SBMLDocument* doc)
2426 {
2427   populateSupportedPackages();
2428   XMLNamespaces *xmlns = mSBMLns->getNamespaces();
2429   for (int i = 0; i < xmlns->getNumNamespaces(); ++i)
2430   {
2431     if (isSupportedPackageNS(xmlns->getURI(i), xmlns->getPrefix(i)))
2432     {
2433       std::string prefix = xmlns->getPrefix(i);
2434       unsigned int version = doc->getPlugin(prefix)->getPackageVersion();
2435       mPackageMap.insert(std::pair<const std::string, unsigned int>(prefix, version));
2436     }
2437   }
2438 }
2439 
2440 bool
isSupportedPackageNS(const std::string & uri,const std::string prefix)2441 ModelDetails::isSupportedPackageNS(const std::string& uri, const std::string prefix)
2442 {
2443   bool supported = false;
2444   if (prefix.empty())
2445     return supported;
2446 
2447   size_t pos = uri.find("http://www.sbml.org/sbml/level3/version");
2448   if (pos == 0 && mSupportedPackages.contains(prefix))
2449   {
2450     supported = true;
2451   }
2452 
2453   return supported;
2454 }
2455 
2456 bool
isPackagePresent(const std::string & pkg)2457 ModelDetails::isPackagePresent(const std::string& pkg)
2458 {
2459   bool present = false;
2460 
2461   for (PkgIter it = mPackageMap.begin(); it != mPackageMap.end(); ++it)
2462   {
2463     if (it->first == pkg)
2464     {
2465       present = true;
2466       break;
2467     }
2468   }
2469   return present;
2470 }
2471 
2472 ////////////////////////////////////////////////////////////////////////////
2473 //
2474 // Filenames.cpp
2475 
2476 ////////////////////////////////////////////////////////////////////////////
2477 //
2478 // ensure reading of unicode filenames
2479 
2480 #if defined(WIN32) && !defined(CYGWIN) && !defined(USE_OCTAVE)
2481 #define FILE_CHAR wchar_t*
2482 #define FILE_FOPEN(file) _wfopen(file, L"r")
2483 #define USE_FILE_WCHAR 1
2484 #else
2485 #define FILE_CHAR char*
2486 #define FILE_FOPEN(file) fopen(file, "r")
2487 #endif
2488 
2489 #ifndef uint16_t
2490 #define uint16_t unsigned short
2491 #endif
2492 
2493 
readUnicodeString(const mxArray * prhs,mwSize length)2494 FILE_CHAR readUnicodeString(const mxArray *prhs, mwSize length)
2495 {
2496 #ifdef USE_OCTAVE
2497   char* ansii = (char *) mxCalloc(length, sizeof(char));
2498   mxGetString(prhs, ansii, length);
2499   return ansii;
2500 #else
2501   wchar_t* utf16 = (wchar_t *) mxCalloc(length, sizeof(wchar_t));
2502   char* utf8 = NULL;
2503   uint16_T *ch = (uint16_T *) mxGetData(prhs);
2504   wchar_t* p = utf16;
2505   mwSize i;
2506   for ( i = 0; i < length-1; ++i)
2507     *p++ = *ch++;
2508   *p = 0;
2509 
2510 #if USE_FILE_WCHAR
2511   return utf16;
2512 #else
2513 
2514   utf8 = (char*)mxCalloc(length*2, sizeof(char));
2515 
2516   wcstombs(utf8, utf16, length*2);
2517 
2518   /*mxFree(utf16);*/
2519 
2520   if (utf8 != NULL && strlen(utf8) == 0 && length > 0)
2521   {
2522     reportError("readUnicodeString",
2523       "This string uses characters that cannot be "
2524       "expressed in UTF8, please rename the file.");
2525   }
2526 
2527   return utf8;
2528 #endif /* USE_FILE_WCHAR */
2529 
2530 #endif /* USE_OCTAVE*/
2531 
2532 }
2533 
2534 
readUnicodeStringFromArrays(mxArray * mxFilename[2])2535 FILE_CHAR readUnicodeStringFromArrays(mxArray *mxFilename[2])
2536 
2537 {
2538   mwSize nBuflen = (mxGetM(mxFilename[0])*mxGetN(mxFilename[0])+1);
2539   FILE_CHAR pacTempString1 = readUnicodeString(mxFilename[0],nBuflen);
2540 
2541   mwSize nBufferLen = (mxGetM(mxFilename[1])*mxGetN(mxFilename[1])+1);
2542   FILE_CHAR  pacTempString2 = readUnicodeString(mxFilename[1],nBufferLen);
2543 
2544 #if USE_FILE_WCHAR
2545   FILE_CHAR  pacFilename = (wchar_t *) mxCalloc(nBufferLen+nBuflen, sizeof(wchar_t));
2546   wcscpy(pacFilename, pacTempString2);
2547   wcscat(pacFilename, pacTempString1);
2548 #else
2549   FILE_CHAR  pacFilename = (char *) mxCalloc(nBufferLen+nBuflen, sizeof(char));
2550   strcpy(pacFilename, pacTempString2);
2551   strcat(pacFilename, pacTempString1);
2552 #endif
2553 
2554   /*mxFree(pacTempString1);*/
2555   /*mxFree(pacTempString2);*/
2556   return pacFilename;
2557 }
2558 
2559 #if USE_FILE_WCHAR
2560 
endsWith(const wchar_t * fileName,const char * ext)2561 int endsWith(const wchar_t* fileName, const char* ext)
2562 {
2563   size_t len = wcslen(fileName), i;
2564   size_t targetLen = strlen(ext);
2565   wchar_t* temp1 =  (wchar_t*)malloc((targetLen + 1) * sizeof(wchar_t));
2566   char* temp2 =  (char*)malloc((targetLen+1)*sizeof(char));
2567   int result = 0;
2568 
2569   memset(temp1, 0, targetLen*sizeof(wchar_t));
2570   memset(temp2, 0, targetLen*sizeof(char));
2571 
2572   for (i = 0; i < targetLen; ++i)
2573   {
2574     temp1[i] = fileName[len - targetLen + i];
2575   }
2576 
2577   wcstombs(temp2,temp1, targetLen);
2578   result = strcmp_insensitive(temp2, ext);
2579 
2580   /*mxFree(temp1);*/
2581   /*mxFree(temp2);*/
2582   free(temp1);
2583   free(temp2);
2584   return result;
2585 }
2586 
2587 #endif
2588 
2589 FILE_CHAR
browseForFilename()2590 browseForFilename()
2591 {
2592   FILE_CHAR filename = NULL;
2593   mxArray * mxFilename[2], * mxExt[1];
2594   mxExt[0] = mxCreateString(".xml");
2595   int nStatus = mexCallMATLAB(2, mxFilename, 1, mxExt, "uigetfile");
2596 
2597   if (nStatus != 0)
2598   {
2599     reportError("TranslateSBML:GUIInput:filename",
2600       "Failed to read filename");
2601   }
2602 
2603   /* get the filename returned */
2604   filename = readUnicodeStringFromArrays(mxFilename);
2605 
2606   mxDestroyArray(mxExt[0]);
2607   mxDestroyArray(mxFilename[1]);
2608   mxDestroyArray(mxFilename[0]);
2609 
2610   return filename;
2611 }
2612 
2613 ////////////////////////////////////////////////////////////////////////////
2614 //
2615 // Arguments.cpp
2616 
2617 /* determine whether we are in octave or matlab */
2618 unsigned int
determinePlatform()2619 determinePlatform()
2620 {
2621   unsigned int usingOctave = 0;
2622   mxArray * mxOctave[1];
2623 
2624   mexCallMATLAB(1, mxOctave, 0, NULL, "isoctave");
2625 
2626   size_t nBuflen = (mxGetM(mxOctave[0])*mxGetN(mxOctave[0])+1);
2627   char * pacTempString1 = (char *)(safe_calloc(nBuflen, sizeof(char)));
2628   int nStatus = mxGetString(mxOctave[0], pacTempString1, (mwSize)(nBuflen));
2629 
2630   if (nStatus != 0)
2631   {
2632     reportError("OutputSBML:platformDetection",
2633       "Could not determine platform");
2634   }
2635 
2636   safe_free(pacTempString1);
2637   mxDestroyArray(mxOctave[0]);
2638 
2639   return usingOctave;
2640 }
2641 
2642 bool
answerYesToQuestion(const std::string & question)2643 answerYesToQuestion(const std::string& question)
2644 {
2645   bool answer = false;
2646   mxArray *mxPrompt[2], *mxReply[1];
2647   char *pacReply;
2648   mxPrompt[0]= mxCreateString(question.c_str());
2649   mxPrompt[1]= mxCreateString("s");
2650   mexCallMATLAB(1, mxReply, 2, mxPrompt, "input");
2651   mxDestroyArray(mxPrompt[0]);
2652   mxDestroyArray(mxPrompt[1]);
2653 
2654   size_t nBufferLen = (mxGetM(mxReply[0])*mxGetN(mxReply[0])+1);
2655   pacReply = (char *) (safe_calloc(nBufferLen, sizeof(char)));
2656   mxGetString(mxReply[0], pacReply, (mwSize)(nBufferLen));
2657   mxDestroyArray(mxReply[0]);
2658 
2659   if (strcmp_insensitive(pacReply, "y") == 0)
2660   {
2661     answer = true;
2662   }
2663   safe_free(pacReply);
2664 
2665   return answer;
2666 }
2667 
2668 ///////////////////////////////////////////////////////////////////////////////
2669 //
2670 // functions used to check arguments for OutputSBML
2671 
2672 void
validateNumberOfInputsForOutput(int nrhs,const mxArray * prhs[],unsigned int usingOctave,unsigned int & outputVersion,int nlhs)2673 validateNumberOfInputsForOutput(int nrhs, const mxArray *prhs[],
2674   unsigned int usingOctave, unsigned int& outputVersion, int nlhs)
2675 {
2676   if (nlhs > 0 && nrhs == 0)
2677   {
2678     outputVersion = 1;
2679   }
2680   else
2681   {
2682     if (nrhs < 1)
2683     {
2684       reportError("OutputSBML:inputArgs",
2685         "Must supply at least the model as an input argument\n"
2686         "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2687     }
2688     if (usingOctave == 1 && nrhs < 2)
2689     {
2690       reportError("OutputSBML:Octave:needFilename",
2691         "Octave requires the filename to be specified\n"
2692         "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2693     }
2694     if (nrhs > 5)
2695     {
2696       reportError("OutputSBML:inputArguments", "Too many input arguments\n"
2697         "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2698     }
2699 
2700     if (nrhs > 1 && ((mxIsChar(prhs[1]) != 1) || (mxGetM(prhs[1]) != 1)))
2701     {
2702       reportError("OutputSBML:inputArguments:invalidFilename",
2703         "Second argument must be a filename\n"
2704         "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2705     }
2706     if (nrhs > 2 && !mxIsNumeric(prhs[2]))
2707     {
2708       reportError("OutputSBML:inputArguments:exclusiveFlag",
2709         "exclusiveFlag is an optional argument but must be a number\n"
2710         "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2711     }
2712 
2713     if (nrhs > 3 && !mxIsNumeric(prhs[3]))
2714     {
2715       reportError("OutputSBML:inputArguments:applyUserValidation",
2716         "applyUserValidation is an optional argument but must be a number\n"
2717         "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2718     }
2719 
2720     if (nrhs > 4 && (!mxIsNumeric(prhs[4]) || (mxGetM(prhs[4]) != 1) || (mxGetN(prhs[4]) != 2)))
2721     {
2722       reportError("OutputSBML:inputArguments:fbcGeneProductOptions",
2723         "fbcGeneProductOptions is an optional argument but must be an array with two numbers\n"
2724         "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2725     }
2726 
2727   }
2728 
2729 }
2730 
2731 void
validateNumberOfOutputsForOutput(int nlhs)2732 validateNumberOfOutputsForOutput(int nlhs)
2733 {
2734   if (nlhs > 0)
2735   {
2736     reportError("OutputSBML:outputArguments", "Too many output arguments\n"
2737       "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag))");
2738   }
2739 }
2740 
2741 void
populateModelArray(int nrhs,const mxArray * prhs[])2742 populateModelArray(int nrhs, const mxArray *prhs[])
2743 {
2744   modelArray = mxDuplicateArray(prhs[0]);
2745 
2746   /**
2747   * note second argument may be the filename
2748   *
2749   * we now have the option of a third argument that indicates that we
2750   * want the structure to ONLY contain expected fields or not
2751   *
2752   * and a fourth argument that tells us whether to apply user
2753   * specific validation
2754   *
2755   * and a fifth argument saying whether to use ids/lebels in fbc
2756   */
2757   if (nrhs > 4)
2758   {
2759     double *pr2 = mxGetPr(prhs[2]);
2760     if (*pr2 == 0)
2761     {
2762       onlyExpectedFields = false;
2763     }
2764     else
2765     {
2766       onlyExpectedFields = true;
2767     }
2768     double *pr3 = mxGetPr(prhs[3]);
2769     if (*pr3 == 0)
2770     {
2771       applyUserValidation = false;
2772     }
2773     else
2774     {
2775       applyUserValidation = true;
2776     }
2777     double *pr = mxGetPr(prhs[4]);
2778 
2779     if (*pr == 0)
2780     {
2781       fbcUsingId = false;
2782     }
2783     else
2784     {
2785       fbcUsingId = true;
2786     }
2787     pr++;
2788     if (*pr == 0)
2789     {
2790       fbcAddGeneProducts = false;
2791     }
2792     else
2793     {
2794       fbcAddGeneProducts = true;
2795     }
2796   }
2797   else if (nrhs > 3)
2798   {
2799     double *pr2 = mxGetPr(prhs[2]);
2800     if (*pr2 == 0)
2801     {
2802       onlyExpectedFields = false;
2803     }
2804     else
2805     {
2806       onlyExpectedFields = true;
2807     }
2808     double *pr3 = mxGetPr(prhs[3]);
2809     if (*pr3 == 0)
2810     {
2811       applyUserValidation = false;
2812     }
2813     else
2814     {
2815       applyUserValidation = true;
2816     }
2817     fbcUsingId = false;
2818     fbcAddGeneProducts = true;
2819   }
2820   else if ( nrhs > 2)
2821   {
2822     double *pr2 = mxGetPr(prhs[2]);
2823     if (*pr2 == 0)
2824     {
2825       onlyExpectedFields = false;
2826     }
2827     else
2828     {
2829       onlyExpectedFields = true;
2830     }
2831     applyUserValidation = false;
2832     fbcUsingId = false;
2833     fbcAddGeneProducts = true;
2834   }
2835   else
2836   {
2837     onlyExpectedFields = true;
2838     applyUserValidation = false;
2839     fbcUsingId = false;
2840     fbcAddGeneProducts = true;
2841   }
2842 
2843   // we have made memory - need to free it is we exit prematurely
2844   freeMemory = true;
2845 }
2846 
2847 void
validateModel()2848 validateModel()
2849 {
2850   mxArray * mxCheckStructure[2];
2851   mxArray * mxModel[3];
2852   mxModel[0] = modelArray;
2853   if (onlyExpectedFields)
2854   {
2855     mxModel[1] = mxCreateDoubleScalar(1);
2856   }
2857   else
2858   {
2859 
2860     mxModel[1] = mxCreateDoubleScalar(0);
2861   }
2862   if (applyUserValidation)
2863   {
2864     mxModel[2] = mxCreateDoubleScalar(1);
2865   }
2866   else
2867   {
2868 
2869     mxModel[2] = mxCreateDoubleScalar(0);
2870   }
2871   int nStatus = mexCallMATLAB(2, mxCheckStructure, 3, mxModel, "isSBML_Model");
2872 
2873   int value = (int)(mxGetScalar(mxCheckStructure[0]));
2874   if ((nStatus != 0) || (value != 1))
2875   {
2876     /* there are errors - use the pacTempString1 char * to list these to the user */
2877     size_t nBuflen = (mxGetM(mxCheckStructure[1])*mxGetN(mxCheckStructure[1])+1);
2878     char * pacTempString1 = (char *)safe_calloc(nBuflen, sizeof(char));
2879     nStatus = mxGetString(mxCheckStructure[1], pacTempString1, (mwSize)(nBuflen));
2880     std::ostringstream errMsg;
2881     if (nStatus == 0)
2882     {
2883       errMsg << "\nFirst input must be a valid MATLAB_SBML Structure\n\n" <<
2884         "Errors reported: " << pacTempString1 << "\nUSAGE: OutputSBML(SBMLModel"
2885         << ", (filename), (exclusiveFlag), (applyUserValidation))";
2886       reportError("OutputSBML:inputArguments:invalidModelSupplied", errMsg.str());
2887     }
2888     else
2889     {
2890       errMsg << "\nFirst input must be a valid MATLAB_SBML Structure\n\n" <<
2891         "\nUSAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation))";
2892       reportError("OutputSBML:inputArguments:invalidStructureSupplied", errMsg.str());
2893     }
2894     safe_free(pacTempString1);
2895   }
2896 
2897   mxDestroyArray(mxCheckStructure[0]);
2898   mxDestroyArray(mxCheckStructure[1]);
2899 }
2900 
validateFilenameForOutput(int nrhs,const mxArray * prhs[])2901 FILE_CHAR validateFilenameForOutput(int nrhs, const mxArray *prhs[])
2902 {
2903   FILE_CHAR filename = NULL;
2904   if (nrhs >= 2)
2905   {
2906     if (mxIsChar(prhs[1]) != 1)
2907     {
2908       reportError("OutputSBML:inputArguments:invalidFilename",
2909         "Second input must be a filename\n"
2910         "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag))");
2911     }
2912 
2913     size_t nBuflen = (mxGetM(prhs[1])*mxGetN(prhs[1])+1);
2914     filename = readUnicodeString(prhs[1], (mwSize)nBuflen);
2915   }
2916   else
2917   {
2918     filename = browseForFilename();
2919   }
2920 
2921      /*
2922     * check that the extension has been used
2923     */
2924 #if USE_FILE_WCHAR
2925     if (wcsstr(filename, L".xml") == NULL)
2926     {
2927       wcscat(filename, L".xml");
2928     }
2929 #else
2930     /* check that the extension has been used  */
2931     if (strstr(filename, ".xml") == NULL)
2932     {
2933       strcat(filename, ".xml");
2934     }
2935 #endif
2936 
2937 
2938   return filename;
2939 }
2940 
2941 //////////////
2942 
2943 // functions for TranslatSBML
2944 void
validateNumberOfInputsForTranslate(int nrhs,const mxArray * prhs[],unsigned int usingOctave)2945 validateNumberOfInputsForTranslate(int nrhs, const mxArray *prhs[],
2946                                    unsigned int usingOctave)
2947 {
2948   if (nrhs > 4)
2949   {
2950     reportError("TranslateSBML:inputArguments", "Too many input arguments\n"
2951       "USAGE: [model, (errors), (version)] = "
2952       "TranslateSBML((filename), (validateFlag), (verboseFlag), (fbcGeneProductOptions))");
2953   }
2954 
2955   if (nrhs > 0 && ((mxIsChar(prhs[0]) != 1) || (mxGetM(prhs[0]) != 1)))
2956   {
2957     reportError("TranslateSBML:inputArguments:invalidFilename",
2958       "First argument must be a filename\n"
2959       "USAGE: [model, (errors), (version)] = "
2960       "TranslateSBML((filename), (validateFlag), (verboseFlag), (fbcGeneProductOptions))");
2961   }
2962   if (nrhs > 1 && !mxIsNumeric(prhs[1]))
2963   {
2964     reportError("TranslateSBML:inputArguments:validateFlag",
2965       "validateFlag is an optional argument but must be a number\n"
2966       "USAGE: [model, (errors), (version)] = "
2967       "TranslateSBML((filename), (validateFlag), (verboseFlag), (fbcGeneProductOptions))");
2968   }
2969 
2970   if (nrhs > 2 && !mxIsNumeric(prhs[2]))
2971   {
2972     reportError("TranslateSBML:inputArguments:verboseFlag",
2973       "verboseFlag is an optional argument but must be a number\n"
2974       "USAGE: [model, (errors), (version)] = "
2975       "TranslateSBML((filename), (validateFlag), (verboseFlag), (fbcGeneProductOptions))");
2976   }
2977 
2978   if (nrhs > 3 && (!mxIsNumeric(prhs[3]) || (mxGetM(prhs[3]) != 1) || (mxGetN(prhs[3]) != 2)))
2979   {
2980     reportError("TranslateSBML:inputArguments:fbcGeneProductOptions",
2981       "fbcGeneProductOptions is an optional argument but must be an array with two numbers\n"
2982       "USAGE: [model, (errors), (version)] = "
2983       "TranslateSBML((filename), (validateFlag), (verboseFlag), (fbcGeneProductOptions))");
2984   }
2985 
2986   if (usingOctave && nrhs == 0)
2987   {
2988     reportError("TranslateSBML:Octave:needFilename",
2989       "Octave requires the filename to be specified\n"
2990         "USAGE: [model, (errors), (version)] = "
2991         "TranslateSBML(filename, (validateFlag), (verboseFlag))");
2992   }
2993 }
2994 
2995 void
validateNumberOfOutputsForTranslate(int nlhs,mxArray * plhs[],unsigned int & outputErrors,unsigned int & outputVersion)2996 validateNumberOfOutputsForTranslate(int nlhs, mxArray *plhs[],
2997                                     unsigned int& outputErrors,
2998                                     unsigned int& outputVersion)
2999 {
3000   switch (nlhs)
3001   {
3002   case 3:
3003     outputErrors = 1;
3004     outputVersion = 1;
3005     break;
3006   case 2:
3007     outputErrors = 1;
3008     break;
3009   case 1:
3010   case 0:
3011     break;
3012   default:
3013     reportError("TranslateSBML:outputArguments", "Too many output arguments\n"
3014       "USAGE: [model, (errors), (version)] = "
3015       "TranslateSBML((filename), (validateFlag), (verboseFlag))");
3016     break;
3017   }
3018 }
3019 
3020 void
checkFileExists(FILE_CHAR filename)3021 checkFileExists(FILE_CHAR filename)
3022 {
3023     FILE *fp;
3024     fp = FILE_FOPEN(filename);
3025     if(fp == NULL)
3026     {
3027       char * msgTxt = NULL;
3028 #if USE_FILE_WCHAR
3029       msgTxt = (char *) safe_calloc(wcslen(filename)+35, sizeof(char));
3030       sprintf(msgTxt, "File %ws does not exist on this path", filename);
3031 #else
3032       msgTxt = (char *) safe_calloc(strlen(filename)+35, sizeof(char));
3033       sprintf(msgTxt, "File %s does not exist on this path", filename);
3034 #endif
3035       reportError("TranslateSBML:inputArguments:filename", msgTxt);
3036       safe_free(msgTxt);
3037     }
3038     else
3039     {
3040       fclose(fp);
3041     }
3042 
3043 }
3044 
3045 FILE_CHAR
getGivenFilename(const mxArray * prhs[])3046 getGivenFilename(const mxArray* prhs[])
3047 {
3048   FILE_CHAR filename = NULL;
3049   size_t nBufferLen  = mxGetNumberOfElements (prhs[0]) + 1;
3050   filename = readUnicodeString(prhs[0], nBufferLen);
3051 
3052   if (filename == NULL)
3053   {
3054     reportError("TranslateSBML:inputArguments:filename",
3055       "Failed to read filename");
3056   }
3057 
3058   checkFileExists(filename);
3059   return filename;
3060 }
3061 
3062 FILE_CHAR
getFilename(int nrhs,const mxArray * prhs[],unsigned int & validateFlag,unsigned int & verboseFlag)3063 getFilename(int nrhs, const mxArray* prhs[], unsigned int& validateFlag,
3064             unsigned int& verboseFlag)
3065 {
3066   FILE_CHAR filename = NULL;
3067 
3068   double *pr = 0;
3069   switch (nrhs)
3070   {
3071   case 4:
3072     // arg 3
3073     pr = mxGetPr(prhs[3]);
3074 
3075     if (*pr == 0)
3076     {
3077       fbcUsingId = false;
3078     }
3079     else
3080     {
3081       fbcUsingId = true;
3082     }
3083     pr++;
3084     if (*pr == 0)
3085     {
3086       fbcAddGeneProducts = false;
3087     }
3088     else
3089     {
3090       fbcAddGeneProducts = true;
3091     }
3092     // arg 2
3093     verboseFlag = (int)mxGetScalar(prhs[2]);
3094     // arg 1
3095     validateFlag = (int)mxGetScalar(prhs[1]);
3096     // arg 0
3097     filename = getGivenFilename(prhs);
3098     break;
3099   case 3:
3100     // arg 2
3101     verboseFlag = (int)mxGetScalar(prhs[2]);
3102     // arg 1
3103     validateFlag = (int)mxGetScalar(prhs[1]);
3104     // arg 0
3105     filename = getGivenFilename(prhs);
3106     break;
3107   case 2:
3108     // arg 1
3109     validateFlag = (int)mxGetScalar(prhs[1]);
3110     // arg 0
3111     filename = getGivenFilename(prhs);
3112     break;
3113   case 1:
3114     // arg 0
3115     filename = getGivenFilename(prhs);
3116     break;
3117   case 0:
3118     filename = browseForFilename();
3119     if (answerYesToQuestion("Do you want to validate the model? Enter y/n "))
3120     {
3121       validateFlag = 1;
3122     }
3123     fbcUsingId = false;
3124     fbcAddGeneProducts = true;
3125     break;
3126   default:
3127     break;
3128   }
3129   return filename;
3130 }
3131 
3132 ///////////////////////////////////////////////////////////////////////////
3133 
3134 // functions called by main functions
3135 FILE_CHAR
validateInputOutputForOutput(int nlhs,mxArray * plhs[],int nrhs,const mxArray * prhs[],unsigned int usingOctave,unsigned int & outputVersion)3136 validateInputOutputForOutput(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[],
3137                     unsigned int usingOctave, unsigned int& outputVersion)
3138 {
3139   FILE_CHAR filename = NULL;
3140   validateNumberOfInputsForOutput(nrhs, prhs, usingOctave, outputVersion, nlhs);
3141   if (outputVersion == 0)
3142   {
3143     validateNumberOfOutputsForOutput(nlhs);
3144 
3145     populateModelArray(nrhs, prhs);
3146     validateModel();
3147     filename = validateFilenameForOutput(nrhs, prhs);
3148   }
3149   return filename;
3150 }
3151 
3152 FILE_CHAR
validateInputOutputForTranslate(int nlhs,mxArray * plhs[],int nrhs,const mxArray * prhs[],unsigned int usingOctave,unsigned int & outputErrors,unsigned int & outputVersion,unsigned int & validateFlag,unsigned int & verboseFlag)3153 validateInputOutputForTranslate(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[],
3154                     unsigned int usingOctave, unsigned int& outputErrors,
3155                     unsigned int& outputVersion, unsigned int& validateFlag,
3156                     unsigned int& verboseFlag)
3157 {
3158   FILE_CHAR filename = NULL;
3159   validateNumberOfInputsForTranslate(nrhs, prhs, usingOctave);
3160   validateNumberOfOutputsForTranslate(nlhs, plhs, outputErrors, outputVersion);
3161   filename = getFilename(nrhs, prhs, validateFlag, verboseFlag);
3162 
3163   return filename;
3164 }
3165 
3166 
3167 void
OutputVersionInformation(mxArray * plhs[])3168 OutputVersionInformation(mxArray *plhs[])
3169 {
3170   const char *version_struct[] =
3171   {
3172     "libSBML_version",
3173     "libSBML_version_string",
3174     "XML_parser",
3175     "XML_parser_version",
3176     "isFBCEnabled",
3177     "packagesEnabled"
3178   };
3179 
3180   const char *xml_parsers[] =
3181   {
3182     "libxml2" ,
3183     "expat" ,
3184     "xerces",
3185     "not found"
3186   };
3187 
3188   mwSize dims[2] = {1, 1};
3189 
3190   const char * parser = xml_parsers[0];
3191   unsigned int i = 0;
3192   populatePackageLists();
3193 
3194   plhs[0] = mxCreateStructArray(2, dims, 6, version_struct);
3195 
3196   mxSetField(plhs[0], 0, "libSBML_version", CreateIntScalar(getLibSBMLVersion()));
3197   mxSetField(plhs[0], 0, "libSBML_version_string", mxCreateString(getLibSBMLDottedVersion()));
3198 
3199   while (isLibSBMLCompiledWith(parser) == 0 && i < 3)
3200   {
3201     ++i;
3202     parser = xml_parsers[i];
3203   }
3204 
3205   mxSetField(plhs[0], 0, "XML_parser", mxCreateString(parser));
3206   mxSetField(plhs[0], 0, "XML_parser_version", mxCreateString(getLibSBMLDependencyVersionOf(parser)));
3207 
3208 #ifdef USE_FBC
3209   mxSetField(plhs[0], 0, "isFBCEnabled", mxCreateString("enabled"));
3210 
3211 #else
3212   mxSetField(plhs[0], 0, "isFBCEnabled", mxCreateString("disabled"));
3213 
3214 #endif
3215   std::ostringstream oss;
3216   bool first = true;
3217   for (unsigned int i = 0; i < SBMLExtensionRegistry::getNumRegisteredPackages(); ++i)
3218   {
3219     std::string name = SBMLExtensionRegistry::getRegisteredPackageName(i);
3220     if (reqdPkgPrefixes.contains(name) || unreqdPkgPrefixes.contains(name))
3221     {
3222       if (!first)
3223       {
3224         oss << ";";
3225       }
3226       oss << name;
3227       first = false;
3228     }
3229   }
3230 
3231   std::string msg = oss.str();
3232   mxSetField(plhs[0], 0, "packagesEnabled", mxCreateString(msg.c_str()));
3233 }
3234 
3235 ////////////////////////////////////////////////////////////////////////////
3236 //
3237 // OutputSBML.cpp
3238 
3239 SBMLDocument *
createSBMLDocument()3240 createSBMLDocument()
3241 {
3242   SBMLDocument * sbmlDocument;
3243   sbmlDocument = new SBMLDocument(details->getNamespaces());
3244 
3245   PkgMap pm = details->getPackages();
3246   for (PkgIter it = pm.begin(); it != pm.end(); ++it)
3247   {
3248     const std::string& prefix = it->first;
3249     sbmlDocument->setPackageRequired(prefix, getRequiredStatus(prefix));
3250   }
3251   return sbmlDocument;
3252 
3253 }
3254 
3255 //////////////////////////////////////////////////////////////////////////
3256 
3257 // here deal with things that do not fit with 'normal'
3258 // hopefully this is the only place that manual coding will be necessary
3259 #ifdef USE_FBC
3260 
3261 mxArray*
getAssociation(unsigned int i)3262 getAssociation(unsigned int i)
3263 {
3264   mxArray* mxAssociation = NULL;
3265   mxArray* mxRn = NULL;
3266   mxArray* mxGPA = NULL;
3267   mxRn = mxGetField(modelArray, 0, "reaction");
3268   if (mxRn != NULL && mxIsStruct(mxRn))
3269   {
3270     mxGPA = mxGetField(mxRn, i, "fbc_geneProductAssociation");
3271     if (mxGPA != NULL)
3272     {
3273       mxAssociation = mxGetField(mxGPA, 0, "fbc_association");
3274     }
3275   }
3276   return mxAssociation;
3277 }
3278 
3279 void
addGPAAttributes(FbcAssociation * pAssociation,mxArray * mxAssociation)3280 addGPAAttributes(FbcAssociation* pAssociation, mxArray* mxAssociation)
3281 {
3282   IdList* atts = new IdList();
3283   atts->append("notes");
3284   atts->append("annotation");
3285   atts->append("metaid");
3286   atts->append("id");
3287   atts->append("name");
3288 
3289   for (unsigned int i = 0; i < atts->size(); i++)
3290   {
3291     std::string name = atts->at(i);
3292     std::string value = StructureFields::readString(mxAssociation, name, 0);
3293     if (!value.empty())
3294     {
3295       if (name == "notes")
3296       {
3297         pAssociation->setNotes(value);
3298       }
3299       else if (name == "annotation")
3300       {
3301         pAssociation->setAnnotation(value);
3302       }
3303       else
3304       {
3305         pAssociation->setAttribute(name, value);
3306       }
3307     }
3308   }
3309   int sbo = StructureFields::readInt(mxAssociation, "sboTerm", 0);
3310   if (sbo != -1)
3311   {
3312     pAssociation->setSBOTerm(sbo);
3313   }
3314 }
3315 
3316 void
addGeneProductAssociations(SBMLDocument * sbmlDocument)3317 addGeneProductAssociations(SBMLDocument* sbmlDocument)
3318 {
3319   FbcModelPlugin* mplug = static_cast<FbcModelPlugin*>(sbmlDocument->getModel()->getPlugin("fbc"));
3320   for (unsigned int i = 0; i < sbmlDocument->getModel()->getNumReactions(); i++)
3321   {
3322     Reaction * rn = sbmlDocument->getModel()->getReaction(i);
3323     FbcReactionPlugin* plug = static_cast<FbcReactionPlugin*>(rn->getPlugin("fbc"));
3324     if (plug->isSetGeneProductAssociation())
3325     {
3326       mxArray* mxAssoc = NULL;
3327       mxAssoc = getAssociation(i);
3328       if (mxAssoc != NULL)
3329       {
3330         std::string association = StructureFields::readString(mxAssoc, "fbc_association", 0);
3331         if (!association.empty())
3332         {
3333           FbcAssociation* pAssociation = FbcAssociation::parseFbcInfixAssociation(association, mplug,
3334             fbcUsingId, fbcAddGeneProducts);
3335           plug->getGeneProductAssociation()->setAssociation(pAssociation);
3336           addGPAAttributes(plug->getGeneProductAssociation()->getAssociation(), mxAssoc);
3337         }
3338       }
3339     }
3340   }
3341 }
3342 
3343 void
dealWithAnomalies(SBMLDocument * sbmlDocument)3344 dealWithAnomalies(SBMLDocument* sbmlDocument)
3345 {
3346   bool fbcPresent = details->isPackagePresent("fbc");
3347 
3348   if (fbcPresent)
3349   {
3350     // the fbc active objective on the listOfObjectives
3351     std::string obj = StructureFields::readString(modelArray, "fbc_activeObjective", 0);
3352     if (!obj.empty())
3353     {
3354       FbcModelPlugin* plug = static_cast<FbcModelPlugin*>(sbmlDocument->getModel()->getPlugin("fbc"));
3355       plug->setActiveObjectiveId(obj);
3356     }
3357 
3358     // the gene product associations in fbc v2
3359     unsigned int vers = StructureFields::readUint(modelArray, "fbc_version", 0);
3360     if (vers == 2)
3361     {
3362       addGeneProductAssociations(sbmlDocument);
3363     }
3364   }
3365 
3366 }
3367 #endif
3368 
3369 ///////////////////////////////////////////////////////////////////////////////
3370 /**
3371  * NAME:    mexFunction
3372  *
3373  * PARAMETERS:  int     nlhs     -  number of output arguments
3374  *              mxArray *plhs[]  -  output arguments
3375  *              int     nrhs     -  number of input arguments
3376  *              mxArray *prhs[]  -  input arguments
3377  *
3378  * RETURNS:
3379  *
3380  * FUNCTION:  MATLAB standard dll export function
3381  *            any returns are made through the mxArray * plhs
3382  */
3383 void
mexFunction(int nlhs,mxArray * plhs[],int nrhs,const mxArray * prhs[])3384 mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
3385 {
3386   // we have not made persistent memory
3387   freeMemory = false;
3388   FILE_CHAR pacFilename = NULL;
3389   SBMLDocument *sbmlDocument;
3390   Model *sbmlModel;
3391   unsigned int outputVersion = 0;
3392 
3393   /* determine whether we are in octave or matlab */
3394   unsigned int usingOctave = determinePlatform();
3395 
3396   /***************************************************************************
3397   * validate inputs and outputs
3398   ****************************************************************************/
3399 
3400   pacFilename = validateInputOutputForOutput(nlhs, plhs, nrhs, prhs,
3401                                              usingOctave, outputVersion);
3402 
3403   // output required structures
3404   if (outputVersion == 1)
3405   {
3406     OutputVersionInformation(plhs);
3407   }
3408   else
3409   {
3410     /**************************************************************************
3411     * get the details of the model
3412     ***************************************************************************/
3413     populatePackageLists();
3414     details = new ModelDetails();
3415 
3416     sbmlDocument = createSBMLDocument();
3417 
3418     /* create a model within the document */
3419     sbmlModel = sbmlDocument->createModel();
3420 
3421     StructureFields *sf = new StructureFields(sbmlModel, modelArray);
3422 
3423     std::string id = std::string("OutputSBML:GetModel:") + sf->getTypeCode();
3424     sf->addAttributes(id);
3425 
3426 #ifdef USE_FBC
3427     dealWithAnomalies(sbmlDocument);
3428 #endif
3429     /**********************************************************************
3430     * output the resulting model to specified file
3431     **************************************************************************/
3432 
3433     /* write the SBML document to the filename specified */
3434     unsigned int nStatus = 0;
3435 #if USE_FILE_WCHAR
3436     {
3437       char* sbml = writeSBMLToString(sbmlDocument);
3438       if (sbml != NULL)
3439       {
3440         size_t len = strlen(sbml);
3441         FILE* fp = _wfopen(pacFilename, L"w");
3442         if (fp != NULL)
3443         {
3444           fwrite(sbml, sizeof(char), len, fp);
3445           fclose(fp);
3446           nStatus = 1;
3447         }
3448 
3449         free(sbml);
3450       }
3451     }
3452 #else
3453     nStatus = writeSBML(sbmlDocument, pacFilename);
3454 #endif
3455 
3456     if (nStatus != 1)
3457     {
3458       reportError("OutputSBML:writeFile", "Failed to write file");
3459     }
3460     else
3461     {
3462       mexPrintf("Document written\n");
3463     }
3464 
3465     delete sbmlDocument;
3466     delete details;
3467     delete sf;
3468   }
3469 }
3470