#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

"""
XML utilities used by spec.py
"""

import xml.sax
from xml.sax.handler import ContentHandler


def parse(file):
    doc = Node("root")
    xml.sax.parse(file, Builder(doc))
    return doc


def parse_string(string):
    doc = Node("root")
    xml.sax.parseString(string, Builder(doc))
    return doc


class Node(object):
    def __init__(self, name, attrs=None, text=None, parent=None):
        self.name = name
        self.attrs = attrs
        self.text = text
        self.parent = parent
        self.children = []
        if parent is not None:
            parent.children.append(self)

    def get_bool(self, key, default=False):
        v = self.get(key)
        if v is None:
            return default
        else:
            return bool(int(v))

    def index(self):
        if self.parent:
            return self.parent.children.index(self)
        else:
            return 0

    def has(self, key):
        try:
            self[key]
            return True
        except KeyError:
            return False
        except IndexError:
            return False

    def get(self, key, default=None):
        if self.has(key):
            return self[key]
        else:
            return default

    def __getitem__(self, key):
        if callable(key):
            return list(filter(key, self.children))
        else:
            t = key.__class__
            meth = "__get%s__" % t.__name__
            if hasattr(self, meth):
                return getattr(self, meth)(key)
            else:
                raise KeyError(key)

    def __getstr__(self, name):
        if name[:1] == "@":
            return self.attrs[name[1:]]
        else:
            return self[lambda nd: nd.name == name]

    def __getint__(self, index):
        return self.children[index]

    def __iter__(self):
        return iter(self.children)

    def path(self):
        if self.parent is None:
            return "/%s" % self.name
        else:
            return "%s/%s" % (self.parent.path(), self.name)


class Builder(ContentHandler):
    def __init__(self, start=None):
        ContentHandler.__init__(self)

        self.node = start
        self.types = []

    def __setitem__(self, element, value):
        self.types[element] = value

    def startElement(self, name, attrs):
        self.node = Node(name, attrs, None, self.node)

    def endElement(self, name):
        self.node = self.node.parent

    def characters(self, content):
        if self.node.text is None:
            self.node.text = content
        else:
            self.node.text += content
