# Path: twyg/config.py
# class Properties(object):
#     """ Class for managing configuration properties. """
# 
#     def __init__(self, properties, defaults, config, extra_prop_warning=True):
#         """
#         Load and parse the default config file ``default`` and merge it
#         with the configuration ``config`` (defaults will be
#         overwritten).
# 
#         The ``properties`` dict contains the list of allowed properties
#         where the key is the name of the property and the value a
#         two-element tuple of which the first element is the class of the
#         property and the second element the property's extra parameters
#         (note that some property types have mandatory extra parameters,
#         e.g. ArrayProperty). For example:
# 
#         {
#             'fontName':  (StringProperty, {}),
#             'fontSizes': (ArrayProperty,  {'type': NumberProperty})
#         }
# 
#         Warn on property names that are not listed in the ``properties``
#         dict if ``extra_prop_warning`` is True.
#         """
# 
#         c = loaddefaults(defaults)
#         c.update(config)
#         config = c
# 
#         # Build properties dictionary
#         self._properties = {}
#         for name, prop_params in properties.iteritems():
#             # The first parameter is the property class, the second the
#             # optional constructor parameters
#             prop_class, opts = prop_params
#             self._properties[name] = prop_class(name, **opts)
# 
#         for name, prop in self._properties.iteritems():
#             if name not in config:
#                 raise ConfigError("Missing property: '%s'" % name)
#             e = parse_expr(config[name])
# #            print '>>>', name, ':', e
#             prop.expr = e
#             prop.name = name
# 
#         if extra_prop_warning:
#             self._warn_extra_props(config)
# 
#     def _warn_extra_props(self, config):
#         extra_props = set(config.keys()) - set(self._properties.keys())
#         for p in extra_props:
#             token = config[p][0]
#             #TODO make displaying warnings optional? print to stdout?
#             print >>sys.stderr, (
#                 "Warning: Unknown property '%s' in configuration "
#                 "file '%s' on line %s" % (p, token.file, token.line))
# 
#     def eval(self, name, scope=None, vars={}):
#         """ Evaluate the value of a property.
# 
#         ``name`` is the name of the property, ``scope`` the object in
#         whose context the property is to be evaluated and ``vars``
#         contains a dict of variable name and value pairs that will be
#         injected into the evaluation scope.
#         """
# 
#         if name not in self._properties:
#             # TODO more detailed error message
#             raise AttributeError("Property '%s' does not exist" % name)
# 
#         p = self._properties[name]
#         if scope:
#             for propname, varname in scope.property_mappings.iteritems():
#                 if hasattr(scope, propname):
#                     vars[varname] = getattr(scope, propname)
#                 # TODO triggered by 'basecolor' -- why?
# #                else:
# #                    raise ConfigError("Variable '%s' is not evaluated "
# #                                      "at this point" % (varname))
# 
#         return p.eval(vars)
# 
# class NumberProperty(Property):
#     def __init__(self, name, min=None, max=None):
#         super(NumberProperty, self).__init__(name)
#         self.min = min
#         self.max = max
# 
#     def _validate(self):
#         if type(self.value) not in (int, float):
#             raise ConfigError("Property '%s' must evaluate to a number"
#                               % self.name, self.expr)
# 
#         if self.min and self.value < self.min:
#             raise ConfigError(
#                 "Number property '%s' must have a value greater "
#                 "than %s" % (self.name, self.min), self.expr)
# 
#         if self.max and self.value > self.max:
#             raise ConfigError("Number property '%s' must have a value less "
#                               "than %s" % (self.name, self.max), self.expr)
# 
# class BooleanProperty(Property):
#     def eval(self, vars):
#         vars = {'no': 0, 'off': 0, 'false': 0, 'yes': 1, 'on': 1, 'true': 1}
#         n = eval_expr(self.expr, vars)
# 
#         if type(n) not in (int, float):
#             raise ConfigError(
#                 ("Boolean property '%s' must evaluate to a numeric value"
#                  % self.name), self.expr)
# 
#         self.value = True if n > 0.0 else False
#         return self.value
# 
# Path: twyg/tree.py
# class Direction(object):
#     Top, Right, Bottom, Left = range(4)
# 
# def opposite_dir(d):
#     if d == Direction.Bottom:
#         return Direction.Top
#     if d == Direction.Right:
#         return Direction.Left
#     if d == Direction.Top:
#         return Direction.Bottom
#     if d == Direction.Left:
#         return Direction.Right
#     else:
#         raise ValueError, 'Invalid direction: %s' % d
# 
# Path: twyg/geomutils.py
# def halfcircle(cx, y1, y2, rfactor, dir, y):
#     dir = -dir
#     dy = float(y2 - y1)
#     r = dy / 2
#     cy = (y1 + y2) / 2.
#     r *= rfactor
#     xcorr = dir * math.sqrt(r * r - pow(y1 - cy, 2))
#     return cx - dir * math.sqrt(r * r - pow(y - cy, 2)) + xcorr


import math, os, sys
from twyg.config import Properties, NumberProperty, BooleanProperty
from twyg.tree import Direction, opposite_dir
from twyg.geomutils import halfcircle





class Layout(object):

    def __init__(self, config):
        properties = {

# Path: twyg/config.py
# class Properties(object):
#     """ Class for managing configuration properties. """
# 
#     def __init__(self, properties, defaults, config, extra_prop_warning=True):
#         """
#         Load and parse the default config file ``default`` and merge it
#         with the configuration ``config`` (defaults will be
#         overwritten).
# 
#         The ``properties`` dict contains the list of allowed properties
#         where the key is the name of the property and the value a
#         two-element tuple of which the first element is the class of the
#         property and the second element the property's extra parameters
#         (note that some property types have mandatory extra parameters,
#         e.g. ArrayProperty). For example:
# 
#         {
#             'fontName':  (StringProperty, {}),
#             'fontSizes': (ArrayProperty,  {'type': NumberProperty})
#         }
# 
#         Warn on property names that are not listed in the ``properties``
#         dict if ``extra_prop_warning`` is True.
#         """
# 
#         c = loaddefaults(defaults)
#         c.update(config)
#         config = c
# 
#         # Build properties dictionary
#         self._properties = {}
#         for name, prop_params in properties.iteritems():
#             # The first parameter is the property class, the second the
#             # optional constructor parameters
#             prop_class, opts = prop_params
#             self._properties[name] = prop_class(name, **opts)
# 
#         for name, prop in self._properties.iteritems():
#             if name not in config:
#                 raise ConfigError("Missing property: '%s'" % name)
#             e = parse_expr(config[name])
# #            print '>>>', name, ':', e
#             prop.expr = e
#             prop.name = name
# 
#         if extra_prop_warning:
#             self._warn_extra_props(config)
# 
#     def _warn_extra_props(self, config):
#         extra_props = set(config.keys()) - set(self._properties.keys())
#         for p in extra_props:
#             token = config[p][0]
#             #TODO make displaying warnings optional? print to stdout?
#             print >>sys.stderr, (
#                 "Warning: Unknown property '%s' in configuration "
#                 "file '%s' on line %s" % (p, token.file, token.line))
# 
#     def eval(self, name, scope=None, vars={}):
#         """ Evaluate the value of a property.
# 
#         ``name`` is the name of the property, ``scope`` the object in
#         whose context the property is to be evaluated and ``vars``
#         contains a dict of variable name and value pairs that will be
#         injected into the evaluation scope.
#         """
# 
#         if name not in self._properties:
#             # TODO more detailed error message
#             raise AttributeError("Property '%s' does not exist" % name)
# 
#         p = self._properties[name]
#         if scope:
#             for propname, varname in scope.property_mappings.iteritems():
#                 if hasattr(scope, propname):
#                     vars[varname] = getattr(scope, propname)
#                 # TODO triggered by 'basecolor' -- why?
# #                else:
# #                    raise ConfigError("Variable '%s' is not evaluated "
# #                                      "at this point" % (varname))
# 
#         return p.eval(vars)
# 
# class NumberProperty(Property):
#     def __init__(self, name, min=None, max=None):
#         super(NumberProperty, self).__init__(name)
#         self.min = min
#         self.max = max
# 
#     def _validate(self):
#         if type(self.value) not in (int, float):
#             raise ConfigError("Property '%s' must evaluate to a number"
#                               % self.name, self.expr)
# 
#         if self.min and self.value < self.min:
#             raise ConfigError(
#                 "Number property '%s' must have a value greater "
#                 "than %s" % (self.name, self.min), self.expr)
# 
#         if self.max and self.value > self.max:
#             raise ConfigError("Number property '%s' must have a value less "
#                               "than %s" % (self.name, self.max), self.expr)
# 
# class BooleanProperty(Property):
#     def eval(self, vars):
#         vars = {'no': 0, 'off': 0, 'false': 0, 'yes': 1, 'on': 1, 'true': 1}
#         n = eval_expr(self.expr, vars)
# 
#         if type(n) not in (int, float):
#             raise ConfigError(
#                 ("Boolean property '%s' must evaluate to a numeric value"
#                  % self.name), self.expr)
# 
#         self.value = True if n > 0.0 else False
#         return self.value
# 
# Path: twyg/tree.py
# class Direction(object):
#     Top, Right, Bottom, Left = range(4)
# 
# def opposite_dir(d):
#     if d == Direction.Bottom:
#         return Direction.Top
#     if d == Direction.Right:
#         return Direction.Left
#     if d == Direction.Top:
#         return Direction.Bottom
#     if d == Direction.Left:
#         return Direction.Right
#     else:
#         raise ValueError, 'Invalid direction: %s' % d
# 
# Path: twyg/geomutils.py
# def halfcircle(cx, y1, y2, rfactor, dir, y):
#     dir = -dir
#     dy = float(y2 - y1)
#     r = dy / 2
#     cy = (y1 + y2) / 2.
#     r *= rfactor
#     xcorr = dir * math.sqrt(r * r - pow(y1 - cy, 2))
#     return cx - dir * math.sqrt(r * r - pow(y - cy, 2)) + xcorr


# Path: twyg/layout.py
import math, os, sys
from twyg.config import Properties, NumberProperty, BooleanProperty
from twyg.tree import Direction, opposite_dir
from twyg.geomutils import halfcircle





class Layout(object):

    def __init__(self, config):
        properties = {

            'horizontalBalance':       (NumberProperty,  {}),
