from lxml import etree as ET

import vytree

NODE_ELEMENT = "node"
TAG_NODE_ELEMENT = "tagNode"
LEAF_NODE_ELEMENT = "leafNode"
NAME_CONSTRAINT_ELEMENT = "nameConstraint"
VALUE_CONSTRAINT_ELEMENT = "valueConstraint"
HELP_STRING_ELEMENT = "helpString"
VALUE_HELP_STRING_ELEMENT = "valueHelpString"

NODE_NAME_ATTRIBUTE = "name"
TYPE_ATTRIBUTE = "type"
CONSTRAINT_ATTRIBUTE = "constraint"
DESCRIPTION_ATTRIBUTE = "description"

class ReferenceTreeLoader(object):
    def __init__(self, xml_source):
        self.__xml_tree = ET.parse(xml_source)
        self.__xml_root = self.__xml_tree.getroot()
        
    def load(self, reference_tree):
        self._walk_xml_node(self.__xml_root, reference_tree)

    def _walk_xml_leaf_node(self, node, reference_node):
        print "Adding leaf node %s" % node.tag

    def _walk_xml_node(self, xml_node, reference_node):
        for xml_child in xml_node:
            # <tagNode> can not contain another <tagNode>, but we do not reflect it here
            # because it's already expressed in the RELAX-NG XML grammar
            if (xml_child.tag == NODE_ELEMENT) or (xml_child.tag == TAG_NODE_ELEMENT):
                next_reference_node = reference_node.insert_child([xml_child.attrib[NODE_NAME_ATTRIBUTE]])
                self._walk_xml_node(xml_child, next_reference_node)
            elif xml_child.tag == NAME_CONSTRAINT_ELEMENT:
                # Blind faith here again, type= attribute is required by the grammar
                name_type = xml_child.attrib[TYPE_ATTRIBUTE]

                # constraint= arribute is optional, needs a check
                name_constraint = None
                if CONSTRAINT_ATTRIBUTE in xml_child.attrib:
                    name_constraint = xml_child.attrib[CONSTRAINT_ATTRIBUTE]

                reference_node.set_name_constraint(name_type, name_constraint)
            elif xml_child.tag == HELP_STRING_ELEMENT:
                help_string = xml_child.attrib[DESCRIPTION_ATTRIBUTE]
                reference_node.set_help_string(help_string)
            elif xml_child.tag == LEAF_NODE_ELEMENT:
                next_reference_node = reference_node.insert_child([xml_child.attrib[NODE_NAME_ATTRIBUTE]])
                self._walk_xml_leaf_node(xml_child, next_reference_node)


@@ -416,16 +416,42 @@
 ription%22
+%0AVALUE_ATTRIBUTE = %22value%22
 %0A%0Aclass 
@@ -512,16 +512,23 @@
 l_source
+, types
 ):%0A     
@@ -621,16 +621,45 @@
 troot()%0A
+        self.__types = types%0A
         
@@ -791,16 +791,20 @@
 e(self, 
+xml_
 node, re
@@ -830,46 +830,1671 @@
     
-print %22Adding leaf node %25s%22 %25 node.tag
+for xml_child in xml_node:%0A            if xml_child.tag == HELP_STRING_ELEMENT:%0A                help_string = xml_child.attrib%5BDESCRIPTION_ATTRIBUTE%5D%0A                reference_node.set_help_string(help_string)%0A            elif xml_child.tag == VALUE_CONSTRAINT_ELEMENT:%0A                value_type = xml_child.attrib%5BTYPE_ATTRIBUTE%5D%0A                value_constraint = None%0A                if CONSTRAINT_ATTRIBUTE in xml_child.attrib:%0A                    value_constraint = xml_child.attrib%5BCONSTRAINT_ATTRIBUTE%5D%0A                reference_node.add_value_constraint(value_type, value_constraint)%0A            elif xml_child.tag == VALUE_HELP_STRING_ELEMENT:%0A                # A lot of blind faith: the point is that %3CvalueHelpString%3E%0A                # can have either value= attribute or type= and constaint= attributes%0A                help_string = xml_child.attrib%5BDESCRIPTION_ATTRIBUTE%5D%0A                value_type = None%0A                value_constraint = None%0A                value = None%0A%0A                if TYPE_ATTRIBUTE in xml_child.attrib:%0A                    value_type = xml_child.attrib%5BTYPE_ATTRIBUTE%5D%0A                if CONSTRAINT_ATTRIBUTE in xml_child.attrib:%0A                    value_constraint = xml_child.attrib%5BCONSTRAINT_ATTRIBUTE%5D%0A                if VALUE_ATTRIBUTE in xml_child.attrib:%0A                    value = xml_child.attrib%5BVALUE_ATTRIBUTE%5D%0A%0A                format = None%0A                if value_type is not None:%0A                    format = self.__types%5Bvalue_type%5D.get_format_string(value_constraint)%0A                else:%0A                    format = value%0A%0A                reference_node.add_value_help_string(format, help_string)
 %0A%0A  

Add leaf node loading support to the ReferenceTreeLoader.