from requests import Session
from functools import wraps
import logging
import getopt
import sys
import json

class ApiError(Exception):
    pass

def status_ok(f):
    @wraps(f)
    def wrapper(self, *args, **kwds):
        r = f(self, *args, **kwds)
        if r.status_code != 200:
            raise ApiError(str(r.status_code))
        return r
    return wrapper


class Api():
    def __init__(self, root):
        self.root = root
        self.api_root = root
        self.session = Session()
        self.result = None

    def http(self, f, url, data=None, json=None, params=None):
        if f in ['post', 'POST']:
            self.result = self.session.post(url, data=data, json=json)
        elif f in ['put', 'PUT']:
            self.result = self.session.put(url, data=data, json=json)
        elif f in ['get', 'GET']:
            self.result = self.session.get(url, params=params)
        elif f in ['delete', 'DELETE']:
            self.result = self.session.delete(url, params=params)
        else:
            return None
        logging.debug("request  headers: %s", self.result.request.headers)
        logging.debug("response headers: %s", self.result.headers)
        return self.result

    @status_ok
    def api_call(self, f, root, json=None,  data=None, params=None):
        return self.http(f, self.api_root + root, data, json, params)

    def login(self, username, password):
        self.http('post', self.api_root + '/api/login', json={'user': username, 'password': password})

    def logout(self):
        self.http('post', self.api_root + '/api/logout')

if __name__ == "__main__":
    try:
        opts, args = getopt.getopt(sys.argv[1:],
                                   "l:o:h:u:p:H",
                                   ["loglevel=", "output=", "host=", "user=", "pass="])
    except getopt.GetoptError as err:
        # print help information and exit:
        print str(err)  # will print something like "option -a not recognized"
        sys.exit(2)


    loglevel = logging.ERROR
    output = None
    user = 'admin'
    passwd = 'admin'
    root = None
    show_headers = False
    for o, a in opts:
        if o in ("-l", "--loglevel"):
            if a == 'ERROR':
                loglevel = logging.ERROR
            elif a == 'WARNING':
                loglevel = logging.WARNING
            elif a == 'DEBUG':
                loglevel = logging.DEBUG
        elif o in ("-o", "--output"):
            output = a
        elif o in ("-h", "--host"):
            root = 'http://' + a
        elif o in ("-u", "--user"):
            user = a
        elif o in ("-p", "--pass"):
            passwd = a
        elif o in ("-H"):
            show_headers = True
        else:
            assert False, "unhandled option"

    logging.basicConfig(level=loglevel,
                        filename=output,
                        filemode='w')

    if root is None:
        print "spotbox_api -h hostip api_route args"

    def do_cmd(args):
        if len(args) < 2:
            print "missing cmd and route"
            return

        cmd = args[0]
        route = args[1]
        if len(args) > 2:
            params = json.loads(args[2])
        else:
            params = None
        try:
            if cmd in ['get', 'delete']:
                api.api_call(cmd, route, params=params)
            elif cmd in ['put', 'post']:
                api.api_call(cmd, route, json=params)

            print "request URL:"
            print api.api_root + api.result.request.path_url

            if show_headers:
                print "\nrequest  headers:"
                print api.result.request.headers

                print "\nresponse headers:"
                print api.result.headers

            print "\nresponse:"
            print api.result.text

        except Exception as e:
            print "Failed call", str(e)

    api = Api(root)
    if len(args) == 0:
        running = True
        while running:
            cmd = raw_input("> ")
            try:
                args = cmd.split()
                if len(cmd) > 0:
                    if len(args) == 1 and args[0] in ('quit', 'exit'):
                        break
                    if len(args) > 2:
                        args = [args[0], args[1], ' '.join(args[2:])]
                    do_cmd(args)
            except Exception, e:
                print "ERROR:", str(e)

    elif len(args) >= 2:
        api.login(user, passwd)
        do_cmd(args)
        api.logout()
    else:
        print "spotbox_api -h hostip api_route args"

    logging.shutdown()
