Add median* condition

The median condition determines the median value from a configured group
of properties and checks that against a defined condition to determine
whether or not the callback is called.

*Note: When 2 properties are used with the median condition, the
property determined to be the max is used instead of the average of the
2 properties. This is for providing a "worst case" median value.

An example would be to create a group consisting of multiple ambient
sensors where the median value from these ambient sensors would be used
to shutdown the system if above a given temperature.

i.e.)

- name: median temps
  description: >
    'If this condition passes the median ambient temperature
    is too high(>= 45C). Shut the system down.'
  class: condition
  condition: median
  paths: ambient sensors
  properties: ambient temp
  callback: ambient log and shutdown
  op: '>='
  bound: 45000
  oneshot: true

Tested:
    A defined median condition is generated according to the
MedianCondition class
    The MedianCondition class produces a single median value from a
group of property values
    Median value used against the given operation to determine if
callback is called or not

Change-Id: Icd53e1a6e30a263b7706a935f040eea97dcc2414
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/src/pdmgen.py b/src/pdmgen.py
index c4184fc..963c7b3 100755
--- a/src/pdmgen.py
+++ b/src/pdmgen.py
@@ -768,6 +768,33 @@
             indent=indent)
 
 
+class MedianCondition(Condition, Renderer):
+    '''Handle the median condition config file directive.'''
+
+    def __init__(self, *a, **kw):
+        self.op = kw.pop('op')
+        self.bound = kw.pop('bound')
+        self.oneshot = TrivialArgument(
+            type='boolean',
+            value=kw.pop('oneshot', False))
+        super(MedianCondition, self).__init__(**kw)
+
+    def setup(self, objs):
+        '''Resolve type.'''
+
+        super(MedianCondition, self).setup(objs)
+        self.bound = TrivialArgument(
+            type=self.type,
+            value=self.bound)
+
+    def construct(self, loader, indent):
+        return self.render(
+            loader,
+            'median.mako.cpp',
+            c=self,
+            indent=indent)
+
+
 class Journal(Callback, Renderer):
     '''Handle the journal callback config file directive.'''
 
@@ -1110,6 +1137,7 @@
             },
             'condition': {
                 'count': CountCondition,
+                'median': MedianCondition,
             },
         }