#!/usr/bin/python

import SocketServer
from threading import Thread
from SimpleXMLRPCServer import SimpleXMLRPCServer,SimpleXMLRPCRequestHandler
try:
    from SimpleXMLRPCServer import SimpleXMLRPCDispatcher
except ImportError:
    pass
import xmlrpclib
import select
import socket
import urllib
import os
from types import *

from queue import QueueEntry
from BitQueue import version,BindException
import policy
from i18n import *

def encode_binary(data):
    return xmlrpclib.Binary(data)

def decode_binary(bin):
    return bin.data

def xml_escape(o,escape=urllib.quote):
    to = type(o)
    if to in StringTypes:
        o = escape(o)
    elif to == TupleType:
        o = tuple([xml_escape(i,escape) for i in list(o)])
    elif to == ListType:
        o = [xml_escape(i,escape) for i in o]
    elif to == DictType:
        n = {}
        for key in o.keys():
            n[key] = xml_escape(o[key],escape)
        o = n
    return o

def xml_unescape(o,unescape=urllib.unquote):
    return xml_escape(o,unescape)

class CommandResponse:
    def __init__(self,result='',error=None):
        self.result = result
        if not result and not error and not error is None:
            import traceback
            self.error = ''.join(traceback.format_stack()[:-1])
        self.error = error or ''

    def getreply(self):
        return self.result

    def geterror(self):
        if hasattr(self.error,'has_key') and self.error.has_key('msg'):
            return self.error.get('msg','')
        return self.error

    def encode(self):
        return {'reply':xml_escape(self.result),
                'error':xml_escape(self.error)}

    def decode(self,dict):
        self.result = xml_unescape(dict.get('reply',''))
        self.error = xml_unescape(dict.get('error',''))

class XMLRPCServer(SimpleXMLRPCServer,SocketServer.ThreadingMixIn,Thread):

    allow_reuse_address = 1

    def __init__(self,RequestHandlerClass,manager):
        Thread.__init__(self)
        self.manager = manager
        self.policy = policy.get_policy()
        self._quit = 0
        addr = self.policy(policy.XMLRPC_IP), \
               self.policy(policy.XMLRPC_PORT)
        try:
            SimpleXMLRPCServer.__init__(self,addr,RequestHandlerClass,
                                        logRequests=0)
        except Exception,why:
            raise BindException,'%s:%d: %s' % (addr+(str(why),))
        self.register_instance(self.manager)

    def get_request(self):
        while not self._quit:
            try:
                ifds,ofds,efds = select.select([self],[],[],10)
            except:
                ifds,ofds,efds = [],[],[]
            if len(ifds) > 0:
                return self.socket.accept()
        return None

    def run(self):
        while not self._quit:
            try:
                self.handle_request()
            except TypeError:
                pass
        print 'xmlrpc stopped'

    def stop(self):
        self._quit = 1
        self.server_close()

class XMLRPCRequestHandler(SimpleXMLRPCRequestHandler):

    def setup(self):
        SimpleXMLRPCRequestHandler.setup(self)
        self.manager = self.server.manager
        self.policy = self.server.policy
        self.id = self.policy(policy.XMLRPC_ID).split(',')

    def _dispatch(self,method,params):
        params = xml_unescape(params)
        if len(params) < 1 or not params[0] in self.id:
            raise Exception('unauthorized')
        if hasattr(SimpleXMLRPCRequestHandler,'_dispatch'):
            dispatch = SimpleXMLRPCRequestHandler._dispatch
            instance = self
        else:
            dispatch = SimpleXMLRPCDispatcher._dispatch
            instance = self.server
        res = dispatch(instance,method,params[1:])
        if isinstance(res,CommandResponse):
            res = res.encode()
        return res

class _Method:
    def __init__(self,send,name,id=''):
        self.__send = send
        self.__name = name
        self.__id = id

    def __getattr__(self,name):
        return _Method(self.__send,"%s.%s" % (self.__name,name),self.__id)

    def __call__(self,*args):
        dict = self.__send(self.__name,(self.__id,)+args)
        res = CommandResponse()
        res.decode(dict)
        return res

class XMLRPCRequest(xmlrpclib.ServerProxy):
    def __init__(self, addr, id, transport=None, encoding='iso-8859-1', verbose=0):
        self.addr = addr
        self.__id = id
        uri = 'http://%s:%d' % self.addr
        # establish a "logical" server connection

        # get the url
        import urllib
        type, uri = urllib.splittype(uri)
        if type not in ("http", "https"):
            raise IOError, "unsupported XML-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

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

        params = xml_escape(params)
        request = xmlrpclib.dumps(params, methodname, encoding=self.__encoding)

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

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

        return response

    def __getattr__(self,name):
        return _Method(self.__request,name,self.__id)

if __name__ == '__main__':
    rpc = XMLRPCRequest(('127.0.0.1',19413),'xmlrpcbt')
    print rpc.listMethods()
