1/**
2 * @file    SBO.cpp
3 * @brief   SBO utility functions
4 * @author  Ben Bornstein
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) 2019 jointly by the following organizations:
11 *     1. California Institute of Technology, Pasadena, CA, USA
12 *     2. University of Heidelberg, Heidelberg, Germany
13 *
14 * Copyright (C) 2013-2018 jointly by the following organizations:
15 *     1. California Institute of Technology, Pasadena, CA, USA
16 *     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
17 *     3. University of Heidelberg, Heidelberg, Germany
18 *
19 * Copyright (C) 2009-2013 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 *
23 * Copyright (C) 2006-2008 by the California Institute of Technology,
24 *     Pasadena, CA, USA
25 *
26 * Copyright (C) 2002-2005 jointly by the following organizations:
27 *     1. California Institute of Technology, Pasadena, CA, USA
28 *     2. Japan Science and Technology Agency, Japan
29 *
30 * This library is free software; you can redistribute it and/or modify it
31 * under the terms of the GNU Lesser General Public License as published by
32 * the Free Software Foundation.  A copy of the license agreement is provided
33 * in the file named "LICENSE.txt" included with this software distribution
34 * and also available online as http://sbml.org/software/libsbml/license.html
35 * ---------------------------------------------------------------------- -->*/
36
37#include <iomanip>
38#include <sstream>
39#include <iterator>
40
41#include <sbml/xml/XMLAttributes.h>
42#include <sbml/xml/XMLOutputStream.h>
43#include <sbml/xml/XMLErrorLog.h>
44
45#include <sbml/SBMLError.h>
46#include <sbml/SBMLErrorLog.h>
47
48#include <sbml/SBO.h>
49
50/** @cond doxygenIgnored */
51using namespace std;
52/** @endcond */
53
54LIBSBML_CPP_NAMESPACE_BEGIN
55
56#ifdef __cplusplus
57
58/** @cond doxygenLibsbmlInternal */
59/*
60 * @return true if sboTerm is in the correct format (a zero-padded, seven
61 * digit string preceded by SBO:), false otherwise.
62 */
63bool
64SBO::checkTerm (const std::string& sboTerm)
65{
66  string::size_type size = sboTerm.size();
67  bool              okay = (size == 11);
68
69  char sbo[4]    = {83, 66, 79, 58};
70  unsigned int n = 0;
71
72  while (okay && n < 4)
73  {
74    okay = (sboTerm[n] == sbo[n]);
75    n++;
76  }
77
78  for (n = 4; okay && n < size; ++n) okay = isdigit(sboTerm[n]);
79
80  return okay;
81}
82/** @endcond */
83
84
85/** @cond doxygenLibsbmlInternal */
86/*
87 * @return true if sboTerm is in the range [0 -- 9999999], false
88 * otherwise.
89 */
90bool
91SBO::checkTerm (int sboTerm)
92{
93  return (sboTerm >= 0 && sboTerm <= 9999999);
94}
95/** @endcond */
96
97/** @cond doxygenLibsbmlInternal */
98/*
99 * Reads (and checks) sboTerm from the given XMLAttributes set.
100 *
101 * @return the sboTerm as an integer or -1 if the sboTerm was not in the
102 * correct format or not found.
103 */
104int
105SBO::readTerm (const XMLAttributes& attributes, SBMLErrorLog* log,
106               unsigned int level, unsigned int version,
107               unsigned int line, unsigned int column)
108{
109  int index = attributes.getIndex("sboTerm");
110  if (index == -1)
111  {
112    return -1;
113  }
114  else if (!checkTerm(attributes.getValue(index)))
115  {
116    log->logError(InvalidSBOTermSyntax, level, version, "", line, column);
117    return -1;
118  }
119  else
120  {
121    return stringToInt( attributes.getValue(index) );
122  }
123}
124
125
126/*
127 * Writes sboTerm as an XMLAttribute to the given XMLOutputStream.
128 */
129void
130SBO::writeTerm (XMLOutputStream& stream, int sboTerm, const std::string& prefix)
131{
132  stream.writeAttribute( "sboTerm", prefix, intToString(sboTerm) );
133}
134/** @endcond */
135
136
137/** @cond doxygenLibsbmlInternal */
138/*
139 * @return the given string sboTerm as an integer.  If the sboTerm is not
140 * in the correct format (a zero-padded, seven digit string), -1 is
141 * returned.
142 */
143int
144SBO::stringToInt (const std::string& sboTerm)
145{
146  int result = -1;
147
148  if ( checkTerm(sboTerm) )
149  {
150    result  = (sboTerm[10] - 48);
151    result += (sboTerm[9] - 48) * 10;
152    result += (sboTerm[8] - 48) * 100;
153    result += (sboTerm[7] - 48) * 1000;
154    result += (sboTerm[6] - 48) * 10000;
155    result += (sboTerm[5] - 48) * 100000;
156    result += (sboTerm[4] - 48) * 1000000;
157  }
158
159  return result;
160}
161/** @endcond */
162
163
164/*
165 * @return the given integer sboTerm as a zero-padded seven digit string.
166 * If the sboTerm is not in the correct range ([0 -- 9999999]), an empty
167 * string is returned.
168 */
169string
170SBO::intToString (int sboTerm)
171{
172  string result = "";
173
174  if ( checkTerm(sboTerm) )
175  {
176    ostringstream stream;
177    stream << "SBO:";
178    stream << setw(7) << setfill('0') << sboTerm;
179    result = stream.str();
180  }
181
182  return result;
183}
184
185
186/**
187  * functions for checking the SBO term is from correct part of SBO
188  * Unary Functor returns the parent portion of a ParentMap pair.
189  */
190struct GetSecond : public unary_function<const pair<const int, int>, int>
191{
192  int operator() (const pair<const int, int>& pair) { return pair.second; }
193};
194
195
196/** @cond doxygenLibsbmlInternal */
197/**
198  * functions for checking the SBO term is from correct part of SBO
199  * returns true if the term is-a parent, false otherwise
200  */
201bool
202SBO::isChildOf(unsigned int term, unsigned int parent)
203{
204  bool        result = false;
205  if (mParent.empty())
206  {
207    populateSBOTree();
208  }
209  ParentRange range  = mParent.equal_range((int)term);
210  deque<unsigned int>  nodes;
211
212
213  // Copy parents of term to nodes.
214  transform(range.first, range.second, back_inserter(nodes), GetSecond());
215
216  // Search nodes DFS for parent.
217  // (For BFS, change back() and pop_back() to front() and pop_front().)
218  while ( !nodes.empty() )
219  {
220    const unsigned int p = nodes.back();
221    nodes.pop_back();
222
223    if (p == parent)
224    {
225      result = true;
226      break;
227    }
228
229    // Copy parents of p to nodes and continue search.
230    range = mParent.equal_range((int)p);
231    transform(range.first, range.second, back_inserter(nodes), GetSecond());
232  }
233
234  return result;
235}
236/** @endcond */
237
238
239/**
240  * functions for checking the SBO term is from correct part of SBO
241  * returns true if the term is-a QuantitativeParameter, false otherwise
242  */
243bool
244SBO::isQuantitativeParameter  (unsigned int sboTerm)
245{
246  if (sboTerm == 2)
247    return true;
248  else
249  {
250    return isChildOf(sboTerm, 2);
251  }
252}
253
254
255/**
256  * functions for checking the SBO term is from correct part of SBO
257  * returns true if the term is-a ParticipantRole, false otherwise
258  */
259bool
260SBO::isParticipantRole  (unsigned int sboTerm)
261{
262  if (sboTerm == 3)
263    return true;
264  else
265  {
266    return isChildOf(sboTerm, 3);
267  }
268}
269
270
271/**
272  * functions for checking the SBO term is from correct part of SBO
273  * returns true if the term is-a ModellingFramework, false otherwise
274  */
275bool
276SBO::isModellingFramework  (unsigned int sboTerm)
277{
278  if (sboTerm == 4)
279    return true;
280  else
281  {
282    return isChildOf(sboTerm, 4);
283  }
284}
285
286
287/**
288  * functions for checking the SBO term is from correct part of SBO
289  * returns true if the term is-a MathematicalExpression, false otherwise
290  */
291bool
292SBO::isMathematicalExpression  (unsigned int sboTerm)
293{
294  if (sboTerm == 64)
295    return true;
296  else
297  {
298    return isChildOf(sboTerm, 64);
299  }
300}
301
302
303/**
304  * functions for checking the SBO term is from correct part of SBO
305  * returns true if the term is-a KineticConstant, false otherwise
306  */
307bool
308SBO::isKineticConstant  (unsigned int sboTerm)
309{
310  if (sboTerm == 9)
311    return true;
312  else
313  {
314    return isChildOf(sboTerm, 9);
315  }
316}
317
318
319/**
320  * functions for checking the SBO term is from correct part of SBO
321  * returns true if the term is-a Reactant, false otherwise
322  */
323bool
324SBO::isReactant  (unsigned int sboTerm)
325{
326  if (sboTerm == 10)
327    return true;
328  else
329  {
330    return isChildOf(sboTerm, 10);
331  }
332}
333
334
335/**
336  * functions for checking the SBO term is from correct part of SBO
337  * returns true if the term is-a Product, false otherwise
338  */
339bool
340SBO::isProduct  (unsigned int sboTerm)
341{
342  if (sboTerm == 11)
343    return true;
344  else
345  {
346    return isChildOf(sboTerm, 11);
347  }
348}
349
350
351/**
352  * functions for checking the SBO term is from correct part of SBO
353  * returns true if the term is-a isModifier, false otherwise
354  */
355bool
356SBO::isModifier  (unsigned int sboTerm)
357{
358  if (sboTerm == 19)
359    return true;
360  else
361  {
362    return isChildOf(sboTerm, 19);
363  }
364}
365
366
367/**
368  * functions for checking the SBO term is from correct part of SBO
369  * returns true if the term is-a RateLaw, false otherwise
370  */
371bool
372SBO::isRateLaw  (unsigned int sboTerm)
373{
374  if (sboTerm == 1)
375    return true;
376  else
377  {
378    return isChildOf(sboTerm, 1);
379  }
380}
381
382
383/**
384  * functions for checking the SBO term is from correct part of SBO
385  * returns true if the term is-a Event, false otherwise
386  */
387bool
388SBO::isEvent  (unsigned int sboTerm)
389{
390  if (sboTerm == 231)
391    return true;
392  else
393  {
394    return isChildOf(sboTerm, 231);
395  }
396}
397
398
399/**
400  * functions for checking the SBO term is from correct part of SBO
401  * returns true if the term is-a PhysicalParticipant, false otherwise
402  */
403bool
404SBO::isPhysicalParticipant  (unsigned int sboTerm)
405{
406  if (sboTerm == 236)
407    return true;
408  else
409  {
410    return isChildOf(sboTerm, 236);
411  }
412}
413
414
415/**
416  * functions for checking the SBO term is from correct part of SBO
417  * returns true if the term is-a Participant, false otherwise
418  */
419bool
420SBO::isParticipant  (unsigned int sboTerm)
421{
422  if (sboTerm == 235)
423    return true;
424  else
425  {
426    return isChildOf(sboTerm, 235);
427  }
428}
429
430/*
431 * Function for checking the SBO term is from correct part of SBO.
432 *
433 * @return true if the term is-a Interaction, false otherwise
434 */
435bool
436SBO::isInteraction  (unsigned int sboTerm)
437{
438  return SBO::isEvent(sboTerm);
439}
440
441/*
442 * Function for checking the SBO term is from correct part of SBO.
443 *
444 * @return true if the term is-a Entity, false otherwise
445 */
446bool
447SBO::isEntity  (unsigned int sboTerm)
448{
449  return SBO::isPhysicalParticipant(sboTerm);
450}
451
452/*
453 * Function for checking the SBO term is from correct part of SBO.
454 *
455 * @return true if the term is-a FunctionalEntity, false otherwise
456 */
457bool
458SBO::isFunctionalEntity  (unsigned int sboTerm)
459{
460  if (sboTerm == 241)
461    return true;
462  else
463  {
464    return isChildOf(sboTerm, 241);
465  }
466}
467
468/*
469 * Function for checking the SBO term is from correct part of SBO.
470 *
471 * @return true if the term is-a MaterialEntity, false otherwise
472 */
473bool
474SBO::isMaterialEntity  (unsigned int sboTerm)
475{
476  if (sboTerm == 240)
477    return true;
478  else
479  {
480    return isChildOf(sboTerm, 240);
481  }
482}
483
484/*
485 * Function for checking the SBO term is from correct part of SBO.
486 *
487 * @return true if the term is-a ConservationLaw, false otherwise
488 */
489bool
490SBO::isConservationLaw  (unsigned int sboTerm)
491{
492  if (sboTerm == 355)
493    return true;
494  else
495  {
496    return isChildOf(sboTerm, 355);
497  }
498}
499
500/*
501 * Function for checking the SBO term is from correct part of SBO.
502 *
503 * @return true if the term is-a SteadyStateExpression, false otherwise
504 */
505bool
506SBO::isSteadyStateExpression  (unsigned int sboTerm)
507{
508  if (sboTerm == 391)
509    return true;
510  else
511  {
512    return isChildOf(sboTerm, 391);
513  }
514}
515
516/*
517 * Function for checking the SBO term is from correct part of SBO.
518 *
519 * @return true if the term is-a FunctionalCompartment, false otherwise
520 */
521bool
522SBO::isFunctionalCompartment  (unsigned int sboTerm)
523{
524  if (sboTerm == 289)
525    return true;
526  else
527  {
528    return isChildOf(sboTerm, 289);
529  }
530}
531
532/*
533 * Function for checking the SBO term is from correct part of SBO.
534 *
535 * @return true if the term is-a ContinuousFramework, false otherwise
536 */
537bool
538SBO::isContinuousFramework  (unsigned int sboTerm)
539{
540  if (sboTerm == 62)
541    return true;
542  else
543  {
544    return isChildOf(sboTerm, 62);
545  }
546}
547
548/*
549 * Function for checking the SBO term is from correct part of SBO.
550 *
551 * @return true if the term is-a DiscreteFramework, false otherwise
552 */
553bool
554SBO::isDiscreteFramework  (unsigned int sboTerm)
555{
556  if (sboTerm == 63)
557    return true;
558  else
559  {
560    return isChildOf(sboTerm, 63);
561  }
562}
563
564/*
565 * Function for checking the SBO term is from correct part of SBO.
566 *
567 * @return true if the term is-a LogicalFramework, false otherwise
568 */
569bool
570SBO::isLogicalFramework  (unsigned int sboTerm)
571{
572  if (sboTerm == 234)
573    return true;
574  else
575  {
576    return isChildOf(sboTerm, 234);
577  }
578}
579
580
581/*
582 * Function for checking the SBO term is from correct part of SBO.
583 *
584 * @return true if the term is-a MetadataRepresentation, false otherwise
585 */
586bool
587SBO::isMetadataRepresentation  (unsigned int sboTerm)
588{
589  if (sboTerm == 544)
590    return true;
591  else
592  {
593    return isChildOf(sboTerm, 544);
594  }
595}
596
597
598/*
599 * Function for checking the SBO term is from correct part of SBO.
600 *
601 * @return true if the term is-a OccurringEntityRepresentation, false otherwise
602 */
603bool
604SBO::isOccurringEntityRepresentation  (unsigned int sboTerm)
605{
606  if (sboTerm == 231)
607    return true;
608  else
609  {
610    return isChildOf(sboTerm, 231);
611  }
612}
613
614
615/*
616 * Function for checking the SBO term is from correct part of SBO.
617 *
618 * @return true if the term is-a PhysicalEntityRepresentation, false otherwise
619 */
620bool
621SBO::isPhysicalEntityRepresentation  (unsigned int sboTerm)
622{
623  if (sboTerm == 236)
624    return true;
625  else
626  {
627    return isChildOf(sboTerm, 236);
628  }
629}
630
631
632/*
633 * Function for checking the SBO term is from correct part of SBO.
634 *
635 * @return true if the term is-a SystemsDescriptionParameter, false otherwise
636 */
637bool
638SBO::isSystemsDescriptionParameter  (unsigned int sboTerm)
639{
640  if (sboTerm == 545)
641    return true;
642  else
643  {
644    return isChildOf(sboTerm, 545);
645  }
646}
647
648
649/**
650  * functions for checking the SBO term is from correct part of SBO
651  * returns true if the term is-a QuantitativeSystemsDescriptionParameter, false otherwise
652  */
653bool
654SBO::isQuantitativeSystemsDescriptionParameter  (unsigned int sboTerm)
655{
656  return SBO::isQuantitativeParameter(sboTerm);
657}
658
659
660/*
661 * Function for checking the SBO term is Obselete
662 *
663 * @return true if the term is-a Obselete, false otherwise
664 */
665bool
666SBO::isObselete  (unsigned int sboTerm)
667{
668  if (sboTerm == 1000)
669    return true;
670  else
671  {
672    return isChildOf(sboTerm, 1000);
673  }
674}
675
676
677/** @cond doxygenLibsbmlInternal */
678unsigned int
679SBO::getParentBranch(unsigned int term)
680{
681  if (isMathematicalExpression(term))
682    return 64;
683  else if (isMetadataRepresentation(term))
684    return 544;
685  else if (isModellingFramework(term))
686    return 4;
687  else if (isOccurringEntityRepresentation(term))
688    return 231;
689  else if (isParticipantRole(term))
690    return 3;
691  else if (isPhysicalEntityRepresentation(term))
692    return 236;
693  else if (isSystemsDescriptionParameter(term))
694    return 545;
695  else
696    return 1000;
697}
698/** @endcond */
699
700/** @cond doxygenLibsbmlInternal */
701/**
702  * functions for checking the SBO term is from correct part of SBO
703  * populates the parent-child map
704  */
705void
706SBO::populateSBOTree()
707{
708  // generated from SBO on ${DATE}
709${NEW_TERMS}
710}
711/** @endcond */
712
713#endif /* __cplusplus */
714/** @cond doxygenIgnored */
715/** @endcond */
716
717LIBSBML_CPP_NAMESPACE_END
718