"""Create mockups of stuff.

    The idea is that eval(mockup(obj1)) == eval(mockup(obj2))
    is mostly equivalent to obj1==obj2.

    For containers, such as lists, dicts, sets, all components are
    'reprified'. For simple builtin types, it's the type itself, with the exception that all
    integers are normalized to longs. For other types, repr() is used.

    >>> mockup("abc")
    'abc'

    >>> mockup(range(5))
    [0, 1, 2, 3, 4]

    >>> import sys
    >>> d=mockup({"a": [type(1), type("s")], "b": set([Ellipsis])})
    >>> d["a"]
    ["<type 'int'>", "<type 'str'>"]
    >>> d["b"]
    set(['Ellipsis'])

    >>> from django.utils.datastructures import MultiValueDict
    >>> md = mockup(MultiValueDict({"a": [type(1), type("s")], "b": set([Ellipsis])}))
    >>> md
    MultiValueDict({'a': ["<type 'int'>", "<type 'str'>"], 'b': set(['Ellipsis'])})
    >>> md.getlist("a")
    ["<type 'int'>", "<type 'str'>"]
    >>> md["a"]
    "<type 'str'>"
"""

import types, re
from Cookie import BaseCookie
from django.utils.datastructures import MultiValueDict
from django.db.models.query import QuerySet
from django.forms import FormWrapper
from django.http import HttpResponse
from django.template.context import Context




# ignore these keys in context objects
context_ignore = ["LANGUAGES","LANGUAGE_CODE", "LANGUAGE_BIDI","sql_queries", "context", "debug", "perms", "MAILADMIN_ROOTURL", "AUTH_ROOTURL"]

# regulare expression, this is replaced in a repr() of unknown objects
mockup_others_re = re.compile(r" object at 0x[0-f]+>$")



def mockup(src):
    """returns a "mockup" for testing purposes. This is the main dispatcher.
    """
    return _dispatch.get(type(src), mockup_others)(src)

def mockup_others(src):
    """dispatches objects"""
    if isinstance(src, QuerySet):
        return mockup_list(src)
    elif isinstance(src, MultiValueDict):
        return mockup_multi_value_dict(src)
    elif isinstance(src, FormWrapper):
        return mockup_dict(src.__dict__)
    elif isinstance(src, BaseCookie):
        return mockup_cookie(src)
    elif isinstance(src, HttpResponse):
        return mockup_response(src)
    elif isinstance(src, Context):
        return mockup_context(src)
    else:
        return mockup_others_re.sub(" object>",repr(src))


def mockup_response(response):
    data = dict(status_code=response.status_code,
                cookies=response.cookies)
    if response.has_header("Location"):
        data["location"]=response["Location"]
    return mockup_dict(data)

def mockup_context(context):
    result = {}
    for d in context:
        result.update(d)
    for k in context_ignore:
        if k in result:
            del result[k]
        if "csrfmiddlewaretoken" in result:
            result["csrfmiddlewaretoken"] = "self.csrfmiddlewaretoken"
    return mockup_dict(result)


def identity(src):
    return src

def mockup_tuple(src):
    return tuple([mockup(x) for x in src])

def mockup_list(src):
    return [mockup(x) for x in src]

def mockup_dict(src):
    return dict([(k, mockup(v)) for k,v in src.iteritems()])

def mockup_multi_value_dict(src):
    return MultiValueDictMockup(dict([(k, mockup(v)) for k,v in src.lists()]))

def mockup_set(src):
    return set([mockup(x) for x in src])

def mockup_cookie(src):
    return CookieMockup(src)

class CookieMockup(object):
    def __init__(self, src):
        self.cookie = src
    def __repr__(self):
        return "%s(%r)" % (self.cookie.__class__.__name__, self.cookie.output([], header=""))

class MultiValueDictMockup(MultiValueDict):
    def __repr__(self):
        return "MultiValueDict(%s)" % dict.__repr__(self)

_dispatch = {
    types.IntType: identity,
    types.LongType: identity,
    types.StringType: identity,
    types.UnicodeType: identity,
    types.BooleanType: identity,
    types.FloatType: identity,
    types.NoneType: identity,
    types.TupleType: mockup_tuple,
    types.ListType: mockup_list,
    types.DictionaryType: mockup_dict,
    type(set()): mockup_set,
}


def _test():
    import doctest
    doctest.testmod()

if __name__ == "__main__":
    _test()



