"""
$URL: svn+ssh://svn.mems-exchange.org/repos/trunk/qpy/quoted.py $
$Id: quoted.py 31195 2008-10-04 19:09:10Z dbinger $
"""
import sys

if not sys.version.startswith('3'):
    from __builtin__ import unicode, basestring, long # for checker.
    unicode_str = unicode
    number_classes = (int, long, float)
    string = basestring
else:
    number_classes = (int, float)
    string = str
    unicode_str = str

def xml_quote(x):
    """(x:anything) -> xml
    """
    if isinstance(x, xml):
        return x
    if x is None:
        return xml()
    if type(x) is unicode_str:
        s = x
    elif isinstance(x, string):
        s = unicode_str(x, 'utf-8')
    else:
        s = unicode_str(x)
    s = s.replace("&", "&amp;")
    s = s.replace("<", "&lt;")
    s = s.replace(">", "&gt;")
    s = s.replace('"', "&quot;")
    s = s.replace("'", "&#39;") # &apos; is not HTML.
    return xml(s)

class _xml_quote_wrapper (object):
    """
    Not for outside code.
    For values that are used as arguments to the % operator, this allows
    str(value) and repr(value), if called as part of the formatting, to
    produce quoted results.
    """
    __slots__ = ['value']

    def __init__(self, value):
        self.value = value

    def __str__(self):
        return xml_quote(self.value)

    def __repr__(self):
        return xml_quote(repr(self.value))

    def __getitem__(self, key):
        return _quote_wrap(self.value[key])

def _quote_wrap(x):
    """(x) -> _xml_quote_wrapper | x
    Not for outside code.
    Return a value v for which str(v) and repr(v) will produce quoted strings,
    or, if x is a dict, for which str(v[key]) and repr(v[key]) will produce
    quoted strings.
    """
    if isinstance(x, number_classes):
        return x
    else:
        return _xml_quote_wrapper(x)

class xml (unicode_str):
    """
    This subclass of str is designated as needing no more xml quoting.
    """
    __slots__ = []

    def __new__(klass, string=None, encoding=sys.getdefaultencoding(), 
        errors='strict'):
        if string is None:
            return xml('')
        elif isinstance(string, unicode_str):
            string = string.encode('utf-8')
            encoding = 'utf-8'
        return unicode_str.__new__(klass, string, encoding, errors)

    def __add__(self, other):
        """(other) -> xml
        """
        return xml(unicode_str.__add__(self, xml_quote(other)))

    def __radd__(self, other):
        """(other:str) -> xml
        """
        if isinstance(other, string):
            return xml(unicode_str.__add__(xml_quote(other), self))
        else:
            return NotImplemented

    def __mul__(self, other):
        """(other) -> xml
        """
        return xml(unicode_str.__mul__(self, other))

    def __rmul__(self, other):
        """(other) -> xml
        """
        return xml(unicode_str.__mul__(self, other))

    def __mod__(self, other):
        """(other) -> xml
        """
        if isinstance(other, tuple):
            target = tuple(_quote_wrap(item) for item in other)
        else:
            target = _quote_wrap(other)
        return xml(unicode_str.__mod__(self, target))

    def join(self, items):
        """(items) -> xml
        """
        return xml(unicode_str.join(self, (xml_quote(item) for item in items)))

join_xml = xml().join
xml.quote = staticmethod(xml_quote)

def join_str(args):
    return ''.join(unicode_str(arg) for arg in args if arg is not None)

__all__ = ['xml', 'join_xml', 'join_str', 'xml_quote']
