import json
import socket

try:
    from shlex import quote
except ImportError:
    from pipes import quote


def print_dict(d):
    print json.dumps(d, indent=2)


def print_array(a):
    print " ".join((quote(v) for v in a))


def int_arg(arg):
    return int(arg, 0)


class JSONRPCClient(object):
    def __init__(self, addr, port=None, verbose=False):
        self.verbose = verbose
        if addr.startswith('/'):
            self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
            self.sock.connect(addr)
        elif ':' in addr:
            for res in socket.getaddrinfo(addr, port, socket.AF_INET6, socket.SOCK_STREAM, socket.SOL_TCP):
                af, socktype, proto, canonname, sa = res
            self.sock = socket.socket(af, socktype, proto)
            self.sock.connect(sa)
        else:
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.connect((addr, port))

    def __del__(self):
        self.sock.close()

    def call(self, method, params={}, verbose=False):
        req = {}
        req['jsonrpc'] = '2.0'
        req['method'] = method
        req['id'] = 1
        if (params):
            req['params'] = params
        reqstr = json.dumps(req)

        verbose = verbose or self.verbose

        if verbose:
            print("request:")
            print(json.dumps(req, indent=2))

        self.sock.sendall(reqstr)
        buf = ''
        closed = False
        response = {}
        while not closed:
            newdata = self.sock.recv(4096)
            if (newdata == b''):
                closed = True
            buf += newdata
            try:
                response = json.loads(buf)
            except ValueError:
                continue  # incomplete response; keep buffering
            break

        if not response:
            if method == "kill_instance":
                exit(0)
            print "Connection closed with partial response:"
            print buf
            exit(1)

        if 'error' in response:
            print "Got JSON-RPC error response"
            print "request:"
            print_dict(json.loads(reqstr))
            print "response:"
            print_dict(response['error'])
            exit(1)

        if verbose:
            print("response:")
            print(json.dumps(response, indent=2))

        return response['result']