"""
$URL: svn+ssh://sting.mems-exchange.org/repos/trunk/DurusWorks/qpy/quoted.py $
$Id: quoted.py 33799 2011-05-11 10:58:28Z 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.
    Supports positional and named arguments, including attribute access,
    as required by the string format() method.
    """
    __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 __getattr__(self, name):
        return _quote_wrap(getattr(self.value, name))

    def keys(self):
        return list(self.value.keys())

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 __html__(self):
        """
        Returns this xml instance.  Included for compatibility with
        other software packages that have designated this method to
        return html that needs no more quoting.
        """
        return self

    def format(self, *args, **kwargs):
        quoted_args = tuple([_quote_wrap(arg) for arg in args])
        quoted_kwargs = _xml_quote_wrapper(kwargs)
        return xml(unicode_str.format(self, *quoted_args, **quoted_kwargs))

    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']
