# -*- coding: utf-8 -*-

import os
import os.path
from StringIO import StringIO
from time import time

__all__ = ['Parser', 'IncrementalParser', 'DispatchParser']

import xml.dom as xd
import xml.dom.minidom as xdm
import xml.sax as xs
import xml.sax.handler as xsh
import xml.sax.saxutils as xss
from xml.sax.saxutils import quoteattr, escape, unescape

from bridge import Element, ENCODING, Attribute, PI, Comment, Document
from bridge.common import ANY_NAMESPACE

class Parser(object):
    def __init__(self):
        self.buffer = []
        
    def __deserialize_fragment(self, current, parent):
        if current.attributes:
            for key in iter(current.attributes.keys()):
                attr = current.attributes[key]
                Attribute(attr.localName, attr.value,
                          attr.prefix, attr.namespaceURI, parent)

        children_num = len(current.childNodes)
        children = iter(current.childNodes)
        for child in children:
            nt = child.nodeType
            if nt == xd.Node.TEXT_NODE:
                data = escape(child.data)
                if children_num == 1:
                    parent.xml_text = data
                else:
                    parent.xml_children.append(data)
            elif nt == xd.Node.CDATA_SECTION_NODE:
                parent.as_cdata = True
                data = child.data
                if children_num == 1:
                    parent.xml_text = data
                else:
                    parent.xml_children.append(data)
            elif nt == xd.Node.COMMENT_NODE:
                Comment(data=unicode(child.data), parent=parent)
            elif nt == xd.Node.PROCESSING_INSTRUCTION_NODE:
                PI(target=unicode(child.target), data=unicode(child.data), parent=parent)
            elif nt == xd.Node.ELEMENT_NODE:
                element = Element(name=child.localName, prefix=child.prefix,
                                  namespace=child.namespaceURI, parent=parent)

                self.__deserialize_fragment(child, element)

    def __qname(self, name, prefix=None):
        if prefix:
            return "%s:%s" % (prefix, nam
e)
        return name
    
    def __attrs(self, node):
        for attr_ns, attr_name in iter(node.xml_attributes):
            if attr_ns == xd.XMLNS_NAMESPACE and attr_name == 'xmlns':
                continue
            attr = node.xml_attributes[(attr_ns, attr_name)]
            ns = attr.xml_ns
            pref
ix = attr.xml_prefix
            name = attr.xml_name
            yield ns, name, prefix, attr.xml_text or ''

    def __append_namespace(self, prefix, ns):
        if prefix:
            self.buffer.append(' xmlns:%s="%s"' % (prefix, ns))
        elif ns is not None:
            self.buffer.append(' xmlns="%s"' % (ns, ))
            
    def __build_ns_map(self, ns_map, element):
        for child in element.xml_children:
            if isinstance(child, Element):
                if child.xml_ns not in ns_map:
                    ns_map[child.xml_prefix] = child.xml_ns
                for attr_ns, attr_name in child.xml_attributes:
                    if attr_ns not in ns_map:
                        ns_map[attr_ns] = child.xml_attributes[(attr_ns, attr_name)].xml_prefix

    def __is_known(self, ns_map, prefix, ns):
        if prefix in ns_map and ns_map[prefix] == ns:
            return True

        ns_map[prefix] = ns
        return False

    def __append_text(self, text, as_cdata):
        if as_cdata:
            self.buffer.append('<![CDATA[')
        self.buffer.append(text)
        if as_cdata:
            self.buffer.append(']]>')
                    
    def __serialize_element(self, element, parent_ns_map=None):
        for child in iter(element.xml_children):
            if isinstance(child, basestring):
                child = child.strip().strip('\n').strip('\r\n')
                if not child:
                    continue
                self.__append_text(child, element.as_cdata)
            elif isinstance(child, Element):
                ns_map = {}
                ns_map.update(parent_ns_map or {})
                prefix = ns = name = None
                if child.xml_prefix:
                    prefix = child.xml_prefix
                if child.xml_ns:
                    ns = child.xml_ns
        
                name = child.xml_name
                qname = self.__qname(name, prefix=prefix)
                
                self.buffer.append('<%s' % qname)
                if not self.__is_known(ns_map, prefix, ns):
                    self.__append_namespace(prefix, ns)

                for ns, name, prefix, value in self.__attrs(child):
                    if ns is None:
                        pass
                    elif ns == xd.XML_NAMESPACE:
                        name = 'xml:%s' % name
                    elif ns == xd.XMLNS_NAMESPACE:
                        if not self.__is_known(ns_map, name, value):
                            self.__append_namespace(name, value)
                        continue
                    else:
                        name = '%s:%s' % (prefix, name)
                        if not self.__is_known(ns_map, prefix, ns):
                            self.__append_namespace(prefix, ns)
                        
                    self.buffer.append(' %s=%s' % (name, quoteattr(value)))

                if child.xml_text or child.xml_children:
                    self.buffer.append('>')
                
                    if child.xml_text:
                        self.__append_text(child.xml_text, child.as_cdata)

                    if child.xml_children:
                        self.__serialize_element(child, ns_map)

                    self.buffer.append('</%s>' % (qname, ))
                else:
                    self.buffer.append(' />')
            elif isinstance(child, Comment):
                self.buffer.append('<!--%s-->\n' % (child.data,))
            elif isinstance(child, PI):
                self.buffer.append('<?%s %s?>\n' % (child.target, child.data))


    def serialize(self, document, indent=False, encoding=ENCODING, prefixes=None, omit_declaration=False):
        if not isinstance(document, Document):
            root = document
            document = Document()
            document.xml_children.append(root)

        self.__serialize_element(document)

        if not omit_declaration:
            self.buffer.insert(0, '<?xml version="1.0" encoding="%s"?>%s' % (encoding, os.linesep))
            
        content = ''.join(self.buffer)
        self.buffer = []
        if indent:
            return content.rstrip(os.linesep).encode(encoding)

        return content.encode(encoding)

    def deserialize(self, source, prefixes=None, strict=False):
        doc = None
        if isinstance(source, basestring):
            if os.path.exists(source):
                doc = xdm.parse(source)
            else:
                doc = xdm.parseString(source)
        elif hasattr(source, 'read'):
            doc = xdm.parse(source)

        document = Document()

        self.__deserialize_fragment(doc, document)
        
        if doc:
            try:
                doc.unlink()
            except KeyError:
                pass
            
        return document

import xml.sax as xs
import xml.sax.saxutils as xss
from xml.parsers import expat
try:
    import cStringIO as StringIO
except ImportError:
    import StringIO
from time import time

class IncrementalHandler(xss.XMLGenerator):
    def __init__(self, out, encoding=ENCODING):
        xss.XMLGenerator.__init__(self, out, encoding) 
        self._root = Document()
        self._current_el = self._root
        self._current_level = 0
        self._as_cdata = False

    def reset(self):
        if self._root:
            self._root.forget()
            self._root = None
        if self._current_el:
            self._current_el.forget()
            self._current_el = None
        self._root = Document()
        self._current_el = self._root
        self._current_level = 0

    def startDocument(self):
        self._root = Document()
        self._current_el = self._root
       