]> git.mxchange.org Git - simgear.git/blob - simgear/props/condition.cxx
Melchior FRANZ: fix SGPropertyNode::LAST_USED_ATTRIBUTE
[simgear.git] / simgear / props / condition.cxx
1 // condition.cxx - Declarations and inline methods for property conditions.
2 //
3 // Written by David Megginson, started 2000.
4 // CLO May 2003 - Split out condition specific code.
5 //
6 // This file is in the Public Domain, and comes with no warranty.
7 //
8 // $Id$
9
10 #ifdef HAVE_CONFIG_H
11 #  include <simgear_config.h>
12 #endif
13
14 // #include <iostream>
15
16 #include <simgear/structure/exception.hxx>
17
18 #include "props.hxx"
19 #include "condition.hxx"
20
21 #include <simgear/math/SGMath.hxx>
22 #include <simgear/structure/SGExpression.hxx>
23
24 using std::istream;
25 using std::ostream;
26 \f
27 /**
28  * Condition for a single property.
29  *
30  * This condition is true only if the property returns a boolean
31  * true value.
32  */
33 class SGPropertyCondition : public SGCondition
34 {
35 public:
36   SGPropertyCondition ( SGPropertyNode *prop_root,
37                         const char * propname  );
38   virtual ~SGPropertyCondition ();
39   virtual bool test () const { return _node->getBoolValue(); }
40 private:
41   SGConstPropertyNode_ptr _node;
42 };
43
44 /**
45  * Condition with constant value
46  *
47  */
48 class SGConstantCondition : public SGCondition
49 {
50 public:
51   SGConstantCondition (bool v) : _value(v) { ; }
52   virtual bool test () const { return _value; }
53 private:
54   bool _value;
55 };
56
57 /**
58  * Condition for a 'not' operator.
59  *
60  * This condition is true only if the child condition is false.
61  */
62 class SGNotCondition : public SGCondition
63 {
64 public:
65   SGNotCondition (SGCondition * condition);
66   virtual ~SGNotCondition ();
67   virtual bool test () const;
68 private:
69   SGSharedPtr<SGCondition> _condition;
70 };
71
72
73 /**
74  * Condition for an 'and' group.
75  *
76  * This condition is true only if all of the conditions
77  * in the group are true.
78  */
79 class SGAndCondition : public SGCondition
80 {
81 public:
82   SGAndCondition ();
83   virtual ~SGAndCondition ();
84   virtual bool test () const;
85                                 // transfer pointer ownership
86   virtual void addCondition (SGCondition * condition);
87 private:
88   std::vector<SGSharedPtr<SGCondition> > _conditions;
89 };
90
91
92 /**
93  * Condition for an 'or' group.
94  *
95  * This condition is true if at least one of the conditions in the
96  * group is true.
97  */
98 class SGOrCondition : public SGCondition
99 {
100 public:
101   SGOrCondition ();
102   virtual ~SGOrCondition ();
103   virtual bool test () const;
104                                 // transfer pointer ownership
105   virtual void addCondition (SGCondition * condition);
106 private:
107   std::vector<SGSharedPtr<SGCondition> > _conditions;
108 };
109
110
111 /**
112  * Abstract base class for property comparison conditions.
113  */
114 class SGComparisonCondition : public SGCondition
115 {
116 public:
117   enum Type {
118     LESS_THAN,
119     GREATER_THAN,
120     EQUALS
121   };
122   SGComparisonCondition (Type type, bool reverse = false);
123   virtual ~SGComparisonCondition ();
124   virtual bool test () const;
125   virtual void setLeftProperty( SGPropertyNode *prop_root,
126                                 const char * propname );
127   virtual void setRightProperty( SGPropertyNode *prop_root,
128                                  const char * propname );
129   // will make a local copy
130   virtual void setLeftValue (const SGPropertyNode * value);
131   virtual void setRightValue (const SGPropertyNode * value);
132   
133   void setLeftDExpression(SGExpressiond* dexp);
134   void setRightDExpression(SGExpressiond* dexp);
135   
136 private:
137   Type _type;
138   bool _reverse;
139   SGPropertyNode_ptr _left_property;
140   SGPropertyNode_ptr _right_property;
141   
142   SGSharedPtr<SGExpressiond> _left_dexp;
143   SGSharedPtr<SGExpressiond> _right_dexp;
144 };
145
146
147 ////////////////////////////////////////////////////////////////////////
148 // Implementation of SGCondition.
149 ////////////////////////////////////////////////////////////////////////
150
151 SGCondition::SGCondition ()
152 {
153 }
154
155 SGCondition::~SGCondition ()
156 {
157 }
158
159
160 \f
161 ////////////////////////////////////////////////////////////////////////
162 // Implementation of SGPropertyCondition.
163 ////////////////////////////////////////////////////////////////////////
164
165 SGPropertyCondition::SGPropertyCondition ( SGPropertyNode *prop_root,
166                                            const char *propname )
167     : _node( prop_root->getNode(propname, true) )
168 {
169 }
170
171 SGPropertyCondition::~SGPropertyCondition ()
172 {
173 }
174
175
176 \f
177 ////////////////////////////////////////////////////////////////////////
178 // Implementation of SGNotCondition.
179 ////////////////////////////////////////////////////////////////////////
180
181 SGNotCondition::SGNotCondition (SGCondition * condition)
182   : _condition(condition)
183 {
184 }
185
186 SGNotCondition::~SGNotCondition ()
187 {
188 }
189
190 bool
191 SGNotCondition::test () const
192 {
193   return !(_condition->test());
194 }
195
196
197 \f
198 ////////////////////////////////////////////////////////////////////////
199 // Implementation of SGAndCondition.
200 ////////////////////////////////////////////////////////////////////////
201
202 SGAndCondition::SGAndCondition ()
203 {
204 }
205
206 SGAndCondition::~SGAndCondition ()
207 {
208 }
209
210 bool
211 SGAndCondition::test () const
212 {
213   int nConditions = _conditions.size();
214   for (int i = 0; i < nConditions; i++) {
215     if (!_conditions[i]->test())
216       return false;
217   }
218   return true;
219 }
220
221 void
222 SGAndCondition::addCondition (SGCondition * condition)
223 {
224   _conditions.push_back(condition);
225 }
226
227
228 \f
229 ////////////////////////////////////////////////////////////////////////
230 // Implementation of SGOrCondition.
231 ////////////////////////////////////////////////////////////////////////
232
233 SGOrCondition::SGOrCondition ()
234 {
235 }
236
237 SGOrCondition::~SGOrCondition ()
238 {
239 }
240
241 bool
242 SGOrCondition::test () const
243 {
244   int nConditions = _conditions.size();
245   for (int i = 0; i < nConditions; i++) {
246     if (_conditions[i]->test())
247       return true;
248   }
249   return false;
250 }
251
252 void
253 SGOrCondition::addCondition (SGCondition * condition)
254 {
255   _conditions.push_back(condition);
256 }
257
258
259 \f
260 ////////////////////////////////////////////////////////////////////////
261 // Implementation of SGComparisonCondition.
262 ////////////////////////////////////////////////////////////////////////
263
264 static int
265 doComparison (const SGPropertyNode * left, const SGPropertyNode *right)
266 {
267   using namespace simgear;
268   switch (left->getType()) {
269   case props::BOOL: {
270     bool v1 = left->getBoolValue();
271     bool v2 = right->getBoolValue();
272     if (v1 < v2)
273       return SGComparisonCondition::LESS_THAN;
274     else if (v1 > v2)
275       return SGComparisonCondition::GREATER_THAN;
276     else
277       return SGComparisonCondition::EQUALS;
278     break;
279   }
280   case props::INT: {
281     int v1 = left->getIntValue();
282     int v2 = right->getIntValue();
283     if (v1 < v2)
284       return SGComparisonCondition::LESS_THAN;
285     else if (v1 > v2)
286       return SGComparisonCondition::GREATER_THAN;
287     else
288       return SGComparisonCondition::EQUALS;
289     break;
290   }
291   case props::LONG: {
292     long v1 = left->getLongValue();
293     long v2 = right->getLongValue();
294     if (v1 < v2)
295       return SGComparisonCondition::LESS_THAN;
296     else if (v1 > v2)
297       return SGComparisonCondition::GREATER_THAN;
298     else
299       return SGComparisonCondition::EQUALS;
300     break;
301   }
302   case props::FLOAT: {
303     float v1 = left->getFloatValue();
304     float v2 = right->getFloatValue();
305     if (v1 < v2)
306       return SGComparisonCondition::LESS_THAN;
307     else if (v1 > v2)
308       return SGComparisonCondition::GREATER_THAN;
309     else
310       return SGComparisonCondition::EQUALS;
311     break;
312   }
313   case props::DOUBLE: {
314     double v1 = left->getDoubleValue();
315     double v2 = right->getDoubleValue();
316     if (v1 < v2)
317       return SGComparisonCondition::LESS_THAN;
318     else if (v1 > v2)
319       return SGComparisonCondition::GREATER_THAN;
320     else
321       return SGComparisonCondition::EQUALS;
322     break;
323   }
324   case props::STRING:
325   case props::NONE:
326   case props::UNSPECIFIED: {
327     string v1 = left->getStringValue();
328     string v2 = right->getStringValue();
329     if (v1 < v2)
330       return SGComparisonCondition::LESS_THAN;
331     else if (v1 > v2)
332       return SGComparisonCondition::GREATER_THAN;
333     else
334       return SGComparisonCondition::EQUALS;
335     break;
336   }
337   default:
338     throw sg_exception("condition: unrecognized node type in comparison");
339   }
340   
341   return 0;
342 }
343
344
345 SGComparisonCondition::SGComparisonCondition (Type type, bool reverse)
346   : _type(type),
347     _reverse(reverse)
348 {
349 }
350
351 SGComparisonCondition::~SGComparisonCondition ()
352 {
353 }
354
355 bool
356 SGComparisonCondition::test () const
357 {
358                                 // Always fail if incompletely specified
359   if (!_left_property || !_right_property)
360     return false;
361
362   // Get LESS_THAN, EQUALS, or GREATER_THAN
363   if (_left_dexp) {
364     _left_property->setDoubleValue(_left_dexp->getValue(NULL));
365   }
366   
367   if (_right_dexp) {
368     _right_property->setDoubleValue(_right_dexp->getValue(NULL));
369   }
370         
371   int cmp = doComparison(_left_property, _right_property);
372   if (!_reverse)
373     return (cmp == _type);
374   else
375     return (cmp != _type);
376 }
377
378 void
379 SGComparisonCondition::setLeftProperty( SGPropertyNode *prop_root,
380                                         const char * propname )
381 {
382   _left_property = prop_root->getNode(propname, true);
383 }
384
385 void
386 SGComparisonCondition::setRightProperty( SGPropertyNode *prop_root,
387                                          const char * propname )
388 {
389   _right_property = prop_root->getNode(propname, true);
390 }
391
392 void
393 SGComparisonCondition::setLeftValue (const SGPropertyNode *node)
394 {
395   _left_property = new SGPropertyNode(*node);
396 }
397
398
399 void
400 SGComparisonCondition::setRightValue (const SGPropertyNode *node)
401 {
402   _right_property = new SGPropertyNode(*node);
403 }
404
405 void
406 SGComparisonCondition::setLeftDExpression(SGExpressiond* dexp)
407 {
408   _left_property = new SGPropertyNode();
409   _left_dexp = dexp;
410 }
411
412 void
413 SGComparisonCondition::setRightDExpression(SGExpressiond* dexp)
414 {
415   _right_property = new SGPropertyNode();
416   _right_dexp = dexp;
417 }\f
418 ////////////////////////////////////////////////////////////////////////
419 // Read a condition and use it if necessary.
420 ////////////////////////////////////////////////////////////////////////
421
422                                 // Forward declaration
423 static SGCondition * readCondition( SGPropertyNode *prop_root,
424                                     const SGPropertyNode *node );
425
426 static SGCondition *
427 readPropertyCondition( SGPropertyNode *prop_root,
428                        const SGPropertyNode *node )
429 {
430   return new SGPropertyCondition( prop_root, node->getStringValue() );
431 }
432
433 static SGCondition *
434 readNotCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
435 {
436   int nChildren = node->nChildren();
437   for (int i = 0; i < nChildren; i++) {
438     const SGPropertyNode * child = node->getChild(i);
439     SGCondition * condition = readCondition(prop_root, child);
440     if (condition != 0)
441       return new SGNotCondition(condition);
442   }
443   SG_LOG(SG_COCKPIT, SG_ALERT, "empty 'not' condition");
444   return 0;
445 }
446
447 static SGCondition *
448 readAndConditions( SGPropertyNode *prop_root, const SGPropertyNode *node )
449 {
450   SGAndCondition * andCondition = new SGAndCondition;
451   int nChildren = node->nChildren();
452   for (int i = 0; i < nChildren; i++) {
453     const SGPropertyNode * child = node->getChild(i);
454     SGCondition * condition = readCondition(prop_root, child);
455     if (condition != 0)
456       andCondition->addCondition(condition);
457   }
458   return andCondition;
459 }
460
461 static SGCondition *
462 readOrConditions( SGPropertyNode *prop_root, const SGPropertyNode *node )
463 {
464   SGOrCondition * orCondition = new SGOrCondition;
465   int nChildren = node->nChildren();
466   for (int i = 0; i < nChildren; i++) {
467     const SGPropertyNode * child = node->getChild(i);
468     SGCondition * condition = readCondition(prop_root, child);
469     if (condition != 0)
470       orCondition->addCondition(condition);
471   }
472   return orCondition;
473 }
474
475 static SGCondition *
476 readComparison( SGPropertyNode *prop_root,
477                 const SGPropertyNode *node,
478                 SGComparisonCondition::Type type,
479                 bool reverse)
480 {
481   SGComparisonCondition * condition = new SGComparisonCondition(type, reverse);
482   if (node->nChildren() != 2) {
483     throw sg_exception("condition: comparison without two children");
484   }
485   
486   const SGPropertyNode* left = node->getChild(0), 
487     *right = node->getChild(1);
488   string leftName(left->getName());
489   if (leftName == "property") {
490     condition->setLeftProperty(prop_root, left->getStringValue());
491   } else if (leftName == "value") {
492     condition->setLeftValue(left);
493   } else if (leftName == "expression") {
494     SGExpressiond* exp = SGReadDoubleExpression(prop_root, left->getChild(0));
495     condition->setLeftDExpression(exp);
496   } else {
497     throw sg_exception("Unknown condition comparison left child:" + leftName);
498   }
499     
500   string rightName(right->getName());
501   if (rightName == "property") {
502     condition->setRightProperty(prop_root, right->getStringValue());
503   } else if (rightName == "value") {
504     condition->setRightValue(right);
505   } else if (rightName == "expression") {
506     SGExpressiond* exp = SGReadDoubleExpression(prop_root, right->getChild(0));
507     condition->setRightDExpression(exp);
508   } else {
509     throw sg_exception("Unknown condition comparison right child:" + rightName);
510   }
511   
512   return condition;
513 }
514
515 static SGCondition *
516 readCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
517 {
518   const string &name = node->getName();
519   if (name == "property")
520     return readPropertyCondition(prop_root, node);
521   else if (name == "not")
522     return readNotCondition(prop_root, node);
523   else if (name == "and")
524     return readAndConditions(prop_root, node);
525   else if (name == "or")
526     return readOrConditions(prop_root, node);
527   else if (name == "less-than")
528     return readComparison(prop_root, node, SGComparisonCondition::LESS_THAN,
529                           false);
530   else if (name == "less-than-equals")
531     return readComparison(prop_root, node, SGComparisonCondition::GREATER_THAN,
532                           true);
533   else if (name == "greater-than")
534     return readComparison(prop_root, node, SGComparisonCondition::GREATER_THAN,
535                           false);
536   else if (name == "greater-than-equals")
537     return readComparison(prop_root, node, SGComparisonCondition::LESS_THAN,
538                           true);
539   else if (name == "equals")
540     return readComparison(prop_root, node, SGComparisonCondition::EQUALS,
541                           false);
542   else if (name == "not-equals")
543     return readComparison(prop_root, node, SGComparisonCondition::EQUALS, true);
544   else if (name == "false") 
545     return new SGConstantCondition(false);
546   else if (name == "true")
547     return new SGConstantCondition(true);
548   else
549     return 0;
550 }
551
552
553 \f
554 ////////////////////////////////////////////////////////////////////////
555 // Implementation of SGConditional.
556 ////////////////////////////////////////////////////////////////////////
557
558 SGConditional::SGConditional ()
559   : _condition (0)
560 {
561 }
562
563 SGConditional::~SGConditional ()
564 {
565 }
566
567 void
568 SGConditional::setCondition (SGCondition * condition)
569 {
570   _condition = condition;
571 }
572
573 bool
574 SGConditional::test () const
575 {
576   return ((_condition == 0) || _condition->test());
577 }
578
579
580 \f
581 // The top-level is always an implicit 'and' group
582 SGCondition *
583 sgReadCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
584 {
585   return readAndConditions(prop_root, node);
586 }
587
588
589 // end of condition.cxx