"""
JSON AMP dialect.

This is a *huge* hack.
"""
from json import dumps, loads
from twisted.internet import defer, protocol
from twisted.protocols import amp, basic
from txampext import exposed


def _objectHook(obj):
    """
    An object hook for type hinting.
    """
    try:
        for name, newType in obj.pop("__type__").iteritems():
            assert type(newType) is list
            assert newType[0] == "str"
            obj[name] = [s.encode("utf-8") for s in obj[name]]
    except KeyError:
        pass

    return obj


def _default(obj):
    try:
        return list(obj)
    except TypeError:
        return obj.isoformat()


class JSONAMPDialectReceiver(basic.NetstringReceiver):
    """
    JSON AMP dialect speaking protocol.
    """
    def __init__(self, amp):
        self._amp = amp


    def stringReceived(self, string):
        request = loads(string, object_hook=_objectHook)

        identifier = request.pop("_ask")
        # DISGUSTING IMPLEMENTATION DETAIL EXPLOITING HACK
        src = self._amp.boxReceiver.locator
        responder = src.locateResponder(request.pop("_command"))
        responderFunction = responder.func_closure[1].cell_contents
        command = responder.func_closure[2].cell_contents

        for key, ampType in command.arguments:
            ampClass = ampType.__class__

            if ampClass is exposed.ExposedResponderLocator:
                request[key] = self._amp
                continue

            transformer = _ampTypeMap.get(ampClass)
            if transformer is not None:
                request[key] = transformer(request[key])

        d = defer.maybeDeferred(responderFunction, **request)

        def _wrapAnswer(response):
            """
            Wrap the answer and return the response.
            """
            response["_answer"] = identifier
            return response

        def _report(failure):
            """
            Encode the error.
            """
            key = failure.trap(*command.allErrors)
            response = {
                "_error_code": command.allErrors[key],
                "_error_description": str(failure.value),
                "_error": identifier
            }
            return response

        d.addCallbacks(_wrapAnswer, _report)

        @d.addCallback
        def writeResponse(response):
            encoded = dumps(response, default=_default)
            self.transport.write(encoded)


    def connectionLost(self, reason):
        """
        Tells the box receiver to stop receiving boxes.
        """
        self._amp.boxReceiver.stopReceivingBoxes(reason)
        return basic.NetstringReceiver.connectionLost(self, reason)



_ampTypeMap = {
    amp.String: lambda u: u.encode("utf-8")
}



class JSONAMPDialectFactory(protocol.Factory):
    """
    A factory for JSON AMP dialects.
    """
    def __init__(self, ampFactory):
        self._ampFactory = ampFactory


    def buildProtocol(self, addr):
        """
        Builds a bridge and associates it with an AMP protocol instance.
        """
        ampProto = self._ampFactory.buildProtocol(addr)
        return JSONAMPDialectReceiver(ampProto)

@@ -194,349 +194,8 @@
 d%0A%0A%0A
-def _objectHook(obj):%0A    %22%22%22%0A    An object hook for type hinting.%0A    %22%22%22%0A    try:%0A        for name, newType in obj.pop(%22__type__%22).iteritems():%0A            assert type(newType) is list%0A            assert newType%5B0%5D == %22str%22%0A            obj%5Bname%5D = %5Bs.encode(%22utf-8%22) for s in obj%5Bname%5D%5D%0A    except KeyError:%0A        pass%0A%0A    return obj%0A%0A%0A
 def 
@@ -209,16 +209,16 @@
 t(obj):%0A
+
     try:
@@ -298,16 +298,17 @@
 mat()%0A%0A%0A
+%0A
 class JS
@@ -503,16 +503,16 @@
 tring):%0A
+
         
@@ -537,33 +537,8 @@
 ring
-, object_hook=_objectHook
 )%0A%0A 

Remove the object hook (because its stupid)