#!/usr/bin/env python

#Copyright (c) 2010, Chris Hall <chris.hall@mod10.net>
#All rights reserved.

#Redistribution and use in source and binary forms, with or without modification,
#are permitted provided that the following conditions are met:

#* Redistributions of source code must retain the above copyright notice,
#this list of conditions and the following disclaimer.
#* Redistributions in binary form must reproduce the above copyright notice,
#this list of conditions and the following disclaimer in the documentation
#and/or other materials provided with the distribution.

#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
#DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
#ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
#(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

from xml.dom import minidom
from xml.dom import Node

def format(text):
        doc = minidom.parseString(text)
        root = doc.childNodes[0]
        return root.toprettyxml(indent='  ')

def formatXML(doc, encoding=None):
        root = doc.childNodes[0]
        return root.toprettyxml(indent='  ', encoding=encoding)

def _patch_minidom():
        minidom.Text.writexml = _writexml_text
        minidom.Element.writexml = _writexml_element
        minidom.Node.toprettyxml = _toprettyxml_node

def _collapse(node):
        for child in node.childNodes:
                if child.nodeType == Node.TEXT_NODE and len(child.data.strip()) == 0:
                        child.data = ''
                else:
                        _collapse(child)

def _writexml_text(self, writer, indent="", addindent="", newl=""):
        minidom._write_data(writer, "%s"%(self.data.strip()))

def _writexml_element(self, writer, indent="", addindent="", newl=""):
        # indent = current indentation
        # addindent = indentation to add to higher levels
        # newl = newline string
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
                writer.write(" %s=\"" % a_name)
                minidom._write_data(writer, attrs[a_name].value)
                writer.write("\"")
        if self.childNodes:
                if self.childNodes[0].nodeType == Node.TEXT_NODE and len(self.childNodes[0].data) > 0:
                        writer.write(">")
                else:
                        writer.write(">%s"%(newl))
                for node in self.childNodes:
                        node.writexml(writer,indent+addindent,addindent,newl)
                if self.childNodes[-1].nodeType == Node.TEXT_NODE and len(self.childNodes[0].data) > 0:
                        writer.write("</%s>%s" % (self.tagName,newl))
                else:
                        writer.write("%s</%s>%s" % (indent,self.tagName,newl))
        else:
                writer.write("/>%s"%(newl))

def _toprettyxml_node(self, indent="\t", newl="\n", encoding = None):
        _collapse(self)
        # indent = the indentation string to prepend, per level
        # newl = the newline string to append
        writer = minidom._get_StringIO()
        if encoding is not None:
                import codecs
                # Can't use codecs.getwriter to preserve 2.0 compatibility
                writer = codecs.lookup(encoding)[3](writer)
        if self.nodeType == Node.DOCUMENT_NODE:
                # Can pass encoding only to document, to put it into XML header
                self.writexml(writer, "", indent, newl, encoding)
        else:
                self.writexml(writer, "", indent, newl)
        return writer.getvalue()

_patch_minidom()
