"""Module for converting xml into dictionary"""

import xml.dom.minidom

class ReadXml:
    """Functions for creating dictionaries from xml"""
    
    def readXml_cacherequest(self, str_xml):
        """Creates a dictionary form an xml string according to the schema
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    		<xsd:include schemaLocation="client.xsd"/>
    		<xsd:element name="cacherequest" type="cache"/>
		    <xsd:complexType name="cache">
  		    <xsd:sequence>
    		    <xsd:element name="destination" type="client" minOccurs="1" maxOccurs="1"/>
    		    <xsd:element name="source" type="client" minOccurs="1" maxOccurs="1"/>
    		    <xsd:element name="count" type="xsd:nonNegativeInteger" minOccurs="1" maxOccurs="1"/>
    		    <xsd:element name="requestid" type="xsd:nonNegativeInteger" minOccurs="1" maxOccurs="1"/>
  		    </xsd:sequence>
		    </xsd:complexType>
		    </xsd:schema>"""
		
        dom = xml.dom.minidom.parseString(str_xml)
        
        destination_dict = self.get_client(dom, 0)
        source_dict = self.get_client(dom, 1)
        count = self.get_data(dom, 'count', 0)
        requestid = self.get_data(dom, 'requestid', 0)
        
        argsOut_dict = {'type':'cacherequest', 'destination':destination_dict, 'source':source_dict, 'count':count, 'requestid':requestid}
        return argsOut_dict
        
    def readXml_cacheresponse(self, str_xml):
        """Creates a dictionary form an xml string according to the schema
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
		    <xsd:include schemaLocation="client.xsd"/>
		    <xsd:element name="cacheresponse" type="cacheres"/>
    		<xsd:complexType name="cacheres">
  		    <xsd:sequence>
    		    <xsd:element name="destination" type="client" minOccurs="1" maxOccurs="1"/>
    		    <xsd:element name="source" type="client" minOccurs="1" maxOccurs="1"/>
    		    <xsd:element name="list" minOccurs="1" maxOccurs="1">
      		    <xsd:complexType>
        		    <xsd:sequence>
          		    <xsd:element name="node" type="client" minOccurs="0" maxOccurs="unbounded"/>
        		    </xsd:sequence>
      		    </xsd:complexType>
    		    </xsd:element>
    		    <xsd:element name="requestid" type="xsd:nonNegativeInteger" minOccurs="1" maxOccurs="1"/>
  		    </xsd:sequence>
    		</xsd:complexType>
    		</xsd:schema>"""
				
        dom = xml.dom.minidom.parseString(str_xml)
        
        destination_dict = self.get_client(dom, 0)
        source_dict = self.get_client(dom, 1)
        requestid = self.get_data(dom, 'requestid', 0)
        
        """nodelist"""
        list_dict = { }
        nodelist = dom.getElementsByTagName('node')
        #print len(nodelist)
        for i in range(len(nodelist)):
            uid = self.get_data(dom, 'uid', i+2)
            ip = self.get_data(dom, 'ip', i+2)
            port = self.get_data(dom, 'port', i+2)
            ipv = self.get_data(dom, 'ipversion', i+2)
            node_dict = {'ip':ip, 'port':port, 'ipversion':ipv}
            list_dict[uid] = node_dict
        
        argsOut_dict = {'type':'cacheresponse', 'destination':destination_dict, 'source':source_dict, 'list':list_dict, 'requestid':requestid}
        return argsOut_dict
            
    def readXml_echorequest(self, str_xml):
        """Creates a dictionary form an xml string according to the schema
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <xsd:include schemaLocation="client.xsd"/>
        <xsd:element name="echorequest" type="echoreq"/>
        <xsd:complexType name="echoreq">
          <xsd:sequence>
            <xsd:element name="destination" type="client" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="source" type="client" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="requestid" type="xsd:nonNegativeInteger" minOccurs="1" maxOccurs="1"/>
          </xsd:sequence>
        </xsd:complexType>
        </xsd:schema>"""
        
        dom = xml.dom.minidom.parseString(str_xml)
        
        destination_dict = self.get_client(dom, 0)
        source_dict = self.get_client(dom, 1)
        requestid = self.get_data(dom, 'requestid', 0)
        
        argsOut_dict = {'type':'echorequest', 'destination':destination_dict, 'source':source_dict, 'requestid':requestid}
        return argsOut_dict
        
    def readXml_echoresponse(self, str_xml):
        """Creates xml according to the schema    
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <xsd:include schemaLocation="client.xsd"/>
        <xsd:element name="echoresponse" type="echores"/>
        <xsd:complexType name="echores">
          <xsd:sequence>
            <xsd:element name="destination" type="client" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="source" type="client" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="requestid" type="xsd:nonNegativeInteger" minOccurs="1" maxOccurs="1"/>
          </xsd:sequence>
        </xsd:complexType>
        </xsd:schema>"""
        
        dom = xml.dom.minidom.parseString(str_xml)
        
        destination_dict = self.get_client(dom, 0)
        source_dict = self.get_client(dom, 1)
        requestid = self.get_data(dom, 'requestid', 0)
        
        argsOut_dict = {'type':'echoresponse', 'destination':destination_dict, 'source':source_dict, 'requestid':requestid}
        return argsOut_dict
        
    def readXml_hello(self, str_xml):
        """Creates xml according to the schema    
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <xsd:include schemaLocation="client.xsd"/>
        <xsd:element name="hello" type="hi"/>
        <xsd:complexType name="hi">
          <xsd:sequence>
            <xsd:element name="destination" type="client" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="source" minOccurs="1" maxOccurs="1">
              <xsd:complexType>
                <xsd:sequence>
                  <xsd:element name="uid" type="xsd:string" minOccurs="1" maxOccurs="1"/>
                  <xsd:element name="ip" type="xsd:string" minOccurs="0" maxOccurs="1"/>
                  <xsd:element name="port" type="xsd:nonNegativeInteger" minOccurs="1" maxOccurs="1"/>
                  <xsd:element name="ipversion" minOccurs="0" maxOccurs="1">
                    <xsd:simpleType>
                      <xsd:restriction base="xsd:nonNegativeInteger">
                        <xsd:enumeration value="4"/>
                        <xsd:enumeration value="6"/>
                      </xsd:restriction>
                    </xsd:simpleType>
                  </xsd:element>
                </xsd:sequence>
              </xsd:complexType>
            </xsd:element>
            <xsd:element name="count" type="xsd:nonNegativeInteger" minOccurs="1" maxOccurs="1"/>
          </xsd:sequence>
        </xsd:complexType>
        </xsd:schema>"""
        
        dom = xml.dom.minidom.parseString(str_xml)
        
        destination_dict = self.get_client(dom, 0)
        source_dict = self.get_client(dom, 1)
        count = self.get_data(dom, 'count', 0)
        
        argsOut_dict = {'type':'hello', 'destination':destination_dict, 'source':source_dict, 'count':count}
        return argsOut_dict
        
    def readXml_pkrequest(self, str_xml):
        """Creates xml according to the schema
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <xsd:include schemaLocation="client.xsd"/>
        <xsd:element name="pkrequest" type="pkreq"/>
        <xsd:complexType name="pkreq">
          <xsd:sequence>
            <xsd:element name="destination" type="client" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="source" type="client" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="requestid" type="xsd:nonNegativeInteger" minOccurs="1" maxOccurs="1"/>
          </xsd:sequence>
        </xsd:complexType>
        </xsd:schema>"""
        
        dom = xml.dom.minidom.parseString(str_xml)
        
        destination_dict = self.get_client(dom, 0)
        source_dict = self.get_client(dom, 1)
        requestid = self.get_data(dom, 'requestid', 0)
        
        argsOut_dict = {'type':'pkrequest', 'destination':destination_dict, 'source':source_dict, 'requestid':requestid}
        return argsOut_dict
        
    def readXml_pkresponse(self, str_xml):
        """Creates xml according to the schema
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <xsd:include schemaLocation="client.xsd"/>
        <xsd:element name="pkresponse" type="pkres"/>
        <xsd:complexType name="pkres">
          <xsd:sequence>
            <xsd:element name="destination" type="client" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="source" type="client" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="publickey" type="xsd:string" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="requestid" type="xsd:nonNegativeInteger" minOccurs="1" maxOccurs="1"/>
          </xsd:sequence>
        </xsd:complexType>
        </xsd:schema>"""
        
        dom = xml.dom.minidom.parseString(str_xml)
        
        destination_dict = self.get_client(dom, 0)
        source_dict = self.get_client(dom, 1)
        publickey = self.get_data(dom, 'publickey', 0)
        requestid = self.get_data(dom, 'requestid', 0)
        
        argsOut_dict = {'type':'pkresponse', 'destination':destination_dict, 'source':source_dict, 'publickey':publickey, 'requestid':requestid}
        return argsOut_dict
        
    def readXml_searchrequest(self, str_xml):
        """Creates xml according to the schema
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <xsd:include schemaLocation="client.xsd"/>
        <xsd:element name="searchrequest" type="search"/>
        <xsd:complexType name="search">
          <xsd:sequence>
            <xsd:element name="destination" type="client" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="source" type="client" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="ttl" default="4" minOccurs="1" maxOccurs="1">
              <xsd:simpleType>
                <xsd:restriction base="xsd:nonNegativeInteger">
                  <xsd:max-inclusive value="255"/>
                </xsd:restriction>
              </xsd:simpleType>
            </xsd:element>
            <xsd:element name="searchfields" minOccurs="1" maxOccurs="1">
              <xsd:complexType>
                <xsd:sequence>
                  <xsd:element name="value" type="xsd:string" minOccurs="1" maxOccurs="unbounded">
                    <xsd:attribute name="field" type="xsd:string" use="required"/>
                  </xsd:element>
                </xsd:sequence>
                <xsd:attribute name="operation" use="optional" default="and">
                  <xsd:simpleType>
                    <xsd:restriction base="xsd:string">
                      <xsd:enumeration value="and"/>
                      <xsd:enumeration value="or"/>
                    </xsd:restriction>
                  </xsd:simpleType>
                </xsd:attribute>
              </xsd:complexType>
            </xsd:element>
            <xsd:element name="requestid" type="xsd:nonNegativeInteger" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="relay" type="client" minOccurs="0" maxOccurs="8"/>
          </xsd:sequence>
        </xsd:complexType>
        </xsd:schema>"""
        
        dom = xml.dom.minidom.parseString(str_xml)
        
        destination_dict = self.get_client(dom, 0)
        source_dict = self.get_client(dom, 1)
        ttl = self.get_data(dom, 'ttl', 0)
        requestid = self.get_data(dom, 'requestid', 0)
        relay = self.get_data(dom, 'relay', 0)
        operation = self.get_attribute(dom, 'searchfields', 'operation', 0)
        
        """searchfields"""
        searchfields_dict = { }
        nodelist = dom.getElementsByTagName('value')
        for i in range(len(nodelist)):
            value = self.get_data(dom, 'value', i)
            field = self.get_attribute(dom, 'value','field',i)
            searchfields_dict[field] = value
        
        argsOut_dict = {'type':'searchrequest', 'destination':destination_dict, 'source':source_dict, 'ttl':ttl, 'searchfields':searchfields_dict, 'operation':operation, 'requestid':requestid, 'relay':relay}
        return argsOut_dict
        
    def readXml_searchresponse(self, str_xml):
        """Creates xml according to the schema
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <xsd:include schemaLocation="client.xsd"/>
        <xsd:element name="searchresponse" type="searchres"/>
        <xsd:complexType name="searchres">
          <xsd:sequence>
            <xsd:element name="destination" type="client" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="source" type="client" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="requestid" type="xsd:nonNegativeInteger" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="searchfields" minOccurs="0" maxOccurs="1">
              <xsd:complexType>
                <xsd:sequence>
                  <xsd:element name="value" type="xsd:string" minOccurs="1" maxOccurs="unbounded">
                    <xsd:attribute name="field" type="xsd:string" use="required"/>
                  </xsd:element>
                </xsd:sequence>
                <xsd:attribute name="operation" use="optional" default="and">	
                  <xsd:simpleType>
                    <xsd:restriction base="xsd:string">
                      <xsd:enmueration value="and"/>
                      <xsd:enmueration value="or"/>
                    </xsd:restriction>
                  </xsd:simpleType>
                </xsd:attribute>
              </xsd:complexType>
            </xsd:element>
            <xsd:element name="foundnode" type="client" minOccurs="0" maxOccurs="unbounded"/>
          </xsd:sequence>
        </xsd:complexType>
        </xsd:schema>"""
        
        dom = xml.dom.minidom.parseString(str_xml)
        
        destination_dict = self.get_client(dom, 0)
        source_dict = self.get_client(dom, 1)
        requestid = self.get_data(dom, 'requestid', 0)
        operation = self.get_attribute(dom, 'searchfields', 'operation', 0)
        
        """searchfields"""
        searchfields_dict = { }
        nodelist = dom.getElementsByTagName('value')
        for i in range(len(nodelist)):
            value = self.get_data(dom, 'value', i)
            field = self.get_attribute(dom, 'value','field',i)
            searchfields_dict[field] = value
        
        """foundnode"""
        foundnode_dict = { }
        nodelist = dom.getElementsByTagName('foundnode')
        for i in range(len(nodelist)):
            uid = self.get_data(dom, 'uid', i+2)
            ip = self.get_data(dom, 'ip', i+2)
            port = self.get_data(dom, 'port', i+2)
            ipv = self.get_data(dom, 'ipversion', i+2)
            node_dict = {'ip':ip, 'port':port, 'ipversion':ipv}
            foundnode_dict[uid] = node_dict
        
        argsOut_dict = {'type':'searchresponse', 'destination':destination_dict, 'source':source_dict, 'requestid':requestid, 'searchfields':searchfields_dict, 'operation':operation, 'foundnode':foundnode_dict}
        return argsOut_dict
        
    def readXml_userdata(self, str_xml):
        """Creates xml according to the schema
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <xsd:include schemaLocation="client.xsd"/>
        <xsd:element name="userdata" type="udata"/>
        <xsd:complexType name="udata">
          <xsd:sequence>
            <xsd:element name="destination" type="client" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="source" type="client" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="data" type="xsd:string" minOccurs="1" maxOccurs="1"/>
          </xsd:sequence>
        </xsd:complexType>
        </xsd:schema>"""
        
        dom = xml.dom.minidom.parseString(str_xml)
        
        destination_dict = self.get_client(dom, 0)
        source_dict = self.get_client(dom, 1)
        data = self.get_data(dom, 'data', 0)
        
        argsOut_dict = {'type':'userdata', 'destination':destination_dict, 'source':source_dict, 'data':data}
        return argsOut_dict
        
    def get_data(self, dom, tagname, number):
        """returns data of an element"""
        nodelist = dom.getElementsByTagName(tagname)
        if nodelist:
            node = nodelist[number]
            node.normalize( )
            if node.childNodes:
                self.node = node.firstChild.data.strip( )
                return self.node
            else:
                return ""
        else:
            return ""
    
    def get_client(self, dom, number):
        """returns a dictionary containing client data"""
        uid = self.get_data(dom, 'uid', number)
        ip = self.get_data(dom, 'ip', number)
        port = self.get_data(dom, 'port', number)
        ipv = self.get_data(dom, 'ipversion', number)
        return {'uid':uid, 'ip':ip, 'port':port, 'ipversion':ipv}
    
    def get_attribute(self, dom, tagname, attrname, number):
        """returns attribute of an element"""
        nodelist = dom.getElementsByTagName(tagname)
        node = nodelist[number]
        return node.getAttribute(attrname).strip( )
    
    def incoming(self, str_xml):
        """Dispatches incoming xml to the according functions"""
        try:
            dom = xml.dom.minidom.parseString(str_xml)
            function = getattr(self, 'readXml_' + dom.documentElement.nodeName)
            return function(str_xml)
        except AttributeError:
            raise NotImplementedError
