# Copyright (c) 2012 Mitch Garnaat http://garnaat.org/
# Copyright (c) 2012 Amazon.com, Inc. or its affiliates.
# All Rights Reserved
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish, dis-
# tribute, sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject to the fol-
# lowing conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#

import xml.sax


def pythonize_name(name, sep='_'):
    s = ''
    if name[0].isupper:
        s = name[0].lower()
    for c in name[1:]:
        if c.isupper():
            s += sep + c.lower()
        else:
            s += c
    return s


class XmlHandler(xml.sax.ContentHandler):

    def __init__(self, root_node, connection):
        self.connection = connection
        self.nodes = [('root', root_node)]
        self.current_text = ''

    def startElement(self, name, attrs):
        self.current_text = ''
        t = self.nodes[-1][1].startElement(name, attrs, self.connection)
        if t != None:
            if isinstance(t, tuple):
                self.nodes.append(t)
            else:
                self.nodes.append((name, t))

    def endElement(self, name):
        self.nodes[-1][1].endElement(name, self.current_text, self.connection)
        if self.nodes[-1][0] == name:
            self.nodes.pop()
        self.current_text = ''

    def characters(self, content):
        self.current_text += content

    def parse(self, s):
        xml.sax.parseString(s, self)


class Element(dict):

    def __init__(self, connection=None, element_name=None,
                 stack=None, parent=None, list_marker=None,
                 item_marker=None, pythonize_name=False):
        dict.__init__(self)
        self.connection = connection
        self.element_name = element_name
        self.list_marker = list_marker or ['Set']
        self.item_marker = item_marker or ['member', 'item']
        if stack is None:
            self.stack = []
        else:
            self.stack = stack
        self.pythonize_name = pythonize_name
        self.parent = parent

    def __getattr__(self, key):
        if key in self:
            return self[key]
        for k in self:
            e = self[k]
            if isinstance(e, Element):
                try:
                    return getattr(e, key)
                except AttributeError:
                    pass
        raise AttributeError

    def get_name(self, name):
        if self.pythonize_name:
            name = pythonize_name(name)
        return name

    def startElement(self, name, attrs, connection):
        self.stack.append(name)
        for lm in self.list_marker:
            if name.endswith(lm):
                l = ListElement(self.connection, name, self.list_marker,
                                self.item_marker, self.pythonize_name)
                self[self.get_name(name)] = l
                return l
        if len(self.stack) > 0:
            element_name = self.stack[-1]
            e = Element(self.connection, element_name, self.stack, self,
                        self.list_marker, self.item_marker,
                        self.pythonize_name)
            self[self.get_name(element_name)] = e
            return (element_name, e)
        else:
            return None

    def endElement(self, name, value, connection):
        if len(self.stack) > 0:
            self.stack.pop()
        value = value.strip()
        if value:
            if isinstance(self.parent, Element):
                self.parent[self.get_name(name)] = value
            elif isinstance(self.parent, ListElement):
                self.parent.append(value)


class ListElement(list):

    def __init__(self, connection=None, element_name=None,
                 list_marker=['Set'], item_marker=('member', 'item'),
                 pythonize_name=False):
        list.__init__(self)
        self.connection = connection
        self.element_name = element_name
        self.list_marker = list_marker
        self.item_marker = item_marker
        self.pythonize_name = pythonize_name

    def get_name(self, name):
        if self.pythonize_name:
            name = utils.pythonize_name(name)
        return name

    def startElement(self, name, attrs, connection):
        for lm in self.list_marker:
            if name.endswith(lm):
                l = ListElement(self.connection, name,
                                self.list_marker, self.item_marker,
                                self.pythonize_name)
                setattr(self, self.get_name(name), l)
                return l
        if name in self.item_marker:
            e = Element(self.connection, name, parent=self,
                        list_marker=self.list_marker,
                        item_marker=self.item_marker,
                        pythonize_name=self.pythonize_name)
            self.append(e)
            return e
        else:
            return None

    def endElement(self, name, value, connection):
        if name == self.element_name:
            if len(self) > 0:
                empty = []
                for e in self:
                    if isinstance(e, Element):
                        if len(e) == 0:
                            empty.append(e)
                for e in empty:
                    self.remove(e)
        else:
            setattr(self, self.get_name(name), value)
