# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# by Greg Hazel

import xmlrpclib
from xmlrpclib2 import *
from BTL import ebrpc

old_PyCurlTransport = PyCurlTransport
class PyCurlTransport(old_PyCurlTransport):

    def set_connection_params(self, h):
        h.add_header('User-Agent', "ebrpclib.py/1.0")
        h.add_header('Connection', "Keep-Alive")
        h.add_header('Content-Type', "application/octet-stream")
    
    def _parse_response(self, response):
        # read response from input file/socket, and parse it
        return ebrpc.loads(response.getvalue())[0]

# --------------------------------------------------------------------
# request dispatcher

class _Method:
    # some magic to bind an EB-RPC method to an RPC server.
    # supports "nested" methods (e.g. examples.getStateName)
    def __init__(self, send, name):
        self.__send = send
        self.__name = name
    def __getattr__(self, name):
        return _Method(self.__send, "%s.%s" % (self.__name, name))
    def __call__(self, *args, **kwargs):
        args = (args, kwargs)
        return self.__send(self.__name, args)
    # ARG! prevent repr(_Method()) from submiting an RPC call!
    def __repr__(self):
        return "<%s instance at 0x%08X>" % (self.__class__, id(self))


# Double underscore is BAD!
class EBRPC_ServerProxy(xmlrpclib.ServerProxy):
    """uri [,options] -> a logical connection to an EB-RPC server

    uri is the connection point on the server, given as
    scheme://host/target.

    The standard implementation always supports the "http" scheme.  If
    SSL socket support is available (Python 2.0), it also supports
    "https".

    If the target part and the slash preceding it are both omitted,
    "/RPC2" is assumed.

    The following options can be given as keyword arguments:

        transport: a transport factory
        encoding: the request encoding (default is UTF-8)

    All 8-bit strings passed to the server proxy are assumed to use
    the given encoding.
    """

    def __init__(self, uri, transport=None, encoding=None, verbose=0,
                 allow_none=0):
        # establish a "logical" server connection

        # get the url
        import urllib
        type, uri = urllib.splittype(uri)
        if type not in ("http", "https"):
            raise IOError, "unsupported EB-RPC protocol"
        self.__host, self.__handler = urllib.splithost(uri)
        if not self.__handler:
            self.__handler = "/RPC2"

        if transport is None:
            if type == "https":
                transport = xmlrpclib.SafeTransport()
            else:
                transport = xmlrpclib.Transport()
        self.__transport = transport

        self.__encoding = encoding
        self.__verbose = verbose
        self.__allow_none = allow_none

    def __request(self, methodname, params):
        # call a method on the remote server

        request = ebrpc.dumps(params, methodname, encoding=self.__encoding,
                              allow_none=self.__allow_none)

        response = self.__transport.request(
            self.__host,
            self.__handler,
            request,
            verbose=self.__verbose
            )

        if len(response) == 1:
            response = response[0]

        return response

    def __repr__(self):
        return (
            "<ServerProxy for %s%s>" %
            (self.__host, self.__handler)
            )

    __str__ = __repr__

    def __getattr__(self, name):
        # magic method dispatcher
        return _Method(self.__request, name)
    
def new_server_proxy(url, max_connects=None, timeout=None):
    c = cache_set.get_cache(PyCURL_Cache, url, max_per_cache=max_connects)
    t = PyCurlTransport(c, max_connects=max_connects, timeout=timeout)
    return EBRPC_ServerProxy(url, transport=t)

ServerProxy = new_server_proxy