"""This module contains the Proxy class.

Although the Proxy class has a simple API, the module as a whole is quite 
confusing.  Here are the logical entities involved:

proxy client - This is the client of the proxy.
proxied host - This is the host being proxied.
proxy - This is the proxy as a whole.

The proxy itself is devided into three parts:

proxy server - This is the server portion of the proxy.  It listens for 
connections from proxy clients.

proxy server backend - this is backend of the proxy server.  it handles a 
connection from a proxy client.

proxied host client - This is the portion of the proxy that connects to the 
proxied host.

Notice that proxy server backend and proxied host client are similar in that 
they each have a single connection.  In fact, I call them peers.

Consider the following usage scenario.  The proxy client wishes to connect to 
the proxied host.  The proxy client connects to the proxy server.  The proxy
server creates a proxy server backend.  The proxy server backend start the 
creation of a proxy host client.  If everything is successful, the proxy client
can send data to the proxy server backend.  The proxy server backend forwards
the data to the proxy host client.  The proxy host client forwards the data
to the proxied host.  The data flow above can be generalized to the following:
A proxy server backend or proxied host client receives data, fowards it to 
its peer, who fowards it to its associated proxied host or proxy client 
respectively.

The API is simple in that the user only has to worry about instantiating the 
Proxy class, catching socket.error exceptions, and calling asyncore.loop.
By the way, due to the way the code flows, the Proxy class is actually just a
pseudonym for the ProxyServer class.

Concerning line endings, the standard is "\r\n", but we need to be prepared to
receive "\n" as well.  Hence, look for "\n", and if there's a "\r" in front of
it, that's fine too.

"""

import asyncore
from asynchat import async_chat
import socket
from cStringIO import StringIO


class ProxyServer(asyncore.dispatcher):

    """This is the server portion of the proxy.  
    
    It listens for connections from proxy clients.  It is also the entry point
    into this module.  Thus it goes by the pseudonym Proxy.

    The following private variables are used: 

    _proxiedHost, _proxiedPort - These are host and port that are being 
    proxied.

    _encrypt, _decrypt - These are the encrypt and decrypt functions to use.
    
    """

    def __init__(self, proxiedHost, proxiedPort, listeningPort, encrypt, 
        decrypt):
        """Start listening on listeningPort."""
        LISTEN = 5
        self._proxiedHost = proxiedHost
        self._proxiedPort = proxiedPort
        self._encrypt = encrypt
        self._decrypt = decrypt
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.bind(("", listeningPort))
        self.listen(LISTEN)

    def handle_accept(self):
        """Accept a connection.
        
        Create a _ProxyServerBackend and a _ProxiedHostClient.  Let the
        _ProxiedHostClient instance take over processing since we now need to
        connect to the proxied host.

        """
        (socket, address) = self.accept()
        proxiedHostClient = _ProxiedHostClient(self, self._decrypt)
        proxyServerBackend = _ProxyServerBackend(socket, self._encrypt, 
                proxiedHostClient )
        proxiedHostClient.peer = proxyServerBackend 

Proxy = ProxyServer


class _Peer(async_chat):

    """This is the base class for _ProxyServerBackend and _ProxiedHostClient.

    It provides common behavior concerning data flow.

    The following attributes are provided:

    peer - This is the peer of this _Peer.  Remember that instances of
    _ProxyServerBackend and _ProxiedHostClient are peers of each other.
    
    The following private variables are used: 

    _translator - Apply this to the data before transfering the data to this
    _Peer's peer.

    _buf - This is a StringIO buffer for incoming data.
    
    """

    def __init__(self, socket, translator, peer):
        """Initialize the async_chat class."""
        async_chat.__init__(self, socket)
        self.set_terminator("\n")
        self.shutdown = False
        self.peer = peer
        self._translator = translator
        self._buf = StringIO()

    def collect_incoming_data(self, data):
        """Just buffer the data."""
        self._buf.write(data)

    def found_terminator(self):
        """Forward _translator(_buf) to peer and reset _buf."""
        line = self._translator(self._buf.getvalue() + "\n")
        self.peer.push(line)
        self._buf = StringIO()


class _ProxyServerBackend(_Peer):

    """This is backend of the proxy server.

    It handles a connection from a proxy client.

    It turns out that the baseclass is doing all the work.  However, I'll keep
    this class just in case I end up needing to do something here.  More 
    importantly, it's helpful to maintain the terminology.

    """

    pass


class _ProxiedHostClient(_Peer):

    """This is the portion of the proxy that connects to the proxied host."""

    def __init__(self, proxyServer, translator):
        """Start a connection to the proxied host."""
        _Peer.__init__(self, None, translator, None)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect((proxyServer._proxiedHost, proxyServer._proxiedPort))

    def handle_connect(self):
        """Do nothing.  This must be defined."""
        pass
