#!/usr/bin/env python
# -*- coding: utf-8 -*-

import readline
from restshlib.restshlib import RestSHLib
import getpass
import base64
import sys
import cmd
import shlex
import traceback

DEBUG = False

HELP_TEXT = '''Usage: command [<command-option>...]

Cliente commands:
  set <header|setting> <key> <value>
  unset <header|setting> <key>
  show <headers|settings>
  prompt <new-prompt>
  login <username>
  baseurl <host>
  help [<command>]

Rest actions:
  get <url>
  post <url> <data>
  put <url> <data>
  delete <url>
'''

class RestSH(cmd.Cmd, object):
    restshlib = None
    baseurl = "no-host"
    login = "no-user"
    prompt = ""
    cfg_prompt = "%(login)s@%(baseurl)s|restsh> "

    def __init__(self, *args, **kwargs):
        self.restshlib = RestSHLib()
        self.prompt = self.cfg_prompt % {"login": self.login, "baseurl": self.baseurl}
        super(RestSH, self).__init__(*args, **kwargs)

    def postcmd(self, stop, line):
        self.prompt = self.cfg_prompt % {"login": self.login, "baseurl": self.baseurl}

    def _print_response(self, response):
        if self.restshlib.settings.get('print_request', "1") in ["1","yes","true"]:
            print "Request:"
            print "  url: %s" % (unicode(response.request.full_url))
            print "  data: %s" % (unicode(response.request.data))
            print "  headers:"
            for header in response.request.headers.iteritems():
                print "    %s: %s" % (unicode(header[0]), unicode(header[1]))
        if self.restshlib.settings.get('print_body', "1") in ["1","yes","true"]:
            print "Response body:"
            print response.text
        if self.restshlib.settings.get('print_headers', "1") in ["1","yes","true"]:
            print "Response headers:"
            for header in response.headers.iteritems():
                print "  %s: %s" % (header[0], header[1])
        if self.restshlib.settings.get('print_status', "1") in ["1","yes","true"]:
            print "Status Code: %s" % (unicode(response.status_code))

    def do_help(self, params):
        '''Show help information. Example: help set'''
        if params:
            super(RestSH, self).do_help(params)
        else:
            print HELP_TEXT

    def do_quit(self, params):
        '''Quit restsh'''
        sys.exit()

    def do_EOF(self, params):
        '''Quit restsh'''
        sys.exit()

    def do_set(self, params):
        '''Set headers and settings variables. Example: set settings auth_method digest'''
        args = shlex.split(params)
        if len(args) != 3:
            raise Exception("Invalid number of parameters")
        else:
            (typ, key, value) = args
        if typ == "header":
            self.restshlib.set_header(key, value)
        elif typ == "setting":
            self.restshlib.set_setting(key, value)
        else:
            raise Exception("Invalid type of variables")

    def do_unset(self, params):
        '''Unset headers and settings variables. Example: unset settings auth_method'''
        args = shlex.split(params)
        if len(args) != 2:
            raise Exception("Invalid number of parameters")
        else:
            (typ, key) = args
        if typ == "header":
            self.restshlib.unset_header(key)
        elif typ == "setting":
            self.restshlib.unset_setting(key)
        else:
            raise Exception("Invalid type of variables")

    def do_show(self, params):
        '''Show headers and settings variables. Example: show settings'''
        args = shlex.split(params)
        if len(args) != 1:
            raise Exception("Invalid number of parameters")
        else:
            (typ,) = args
        if typ == "headers":
            for header in self.restshlib.headers.iteritems():
                print "%s: %s" % (header[0], header[1])
        elif typ == "settings":
            for setting in self.restshlib.settings.iteritems():
                print "%s: %s" % (setting[0], setting[1])
        else:
            raise Exception("Invalid type of variables")

    def do_baseurl(self, params):
        '''Set the base url for all requests. Example: baseurl http://testserver.com/api'''
        args = shlex.split(params)
        if len(args) != 1:
            raise Exception("Invalid number of parameters")
        else:
            (baseurl,) = args
        self.baseurl = baseurl
        self.restshlib.set_base_url(self.baseurl)

    def do_login(self, params):
        '''Set HTTP AUTH login username and password. Example: login myusername'''
        args = shlex.split(params)
        if len(args) != 1:
            raise Exception("Invalid number of parameters")
        else:
            (username,) = args
        self.login = username
        password = getpass.getpass('Password: ')
        self.restshlib.set_auth(self.login, password, self.restshlib.settings.get('auth_method', 'basic'))

    def do_get(self, params):
        '''Send get request. Example: get /url'''
        args = shlex.split(params)
        if len(args) != 1:
            raise Exception("Invalid number of parameters")
        else:
            (url,) = args
        response = self.restshlib.get(url)
        self._print_response(response)

    def do_post(self, params):
        '''Send post request. Example: post /url key=value test=test'''
        args = shlex.split(params)
        if len(args) < 1:
            raise Exception("Invalid number of parameters")
        else:
            url = args[0]
            data = {}
            for arg in args[1:]:
                arg_split = arg.split("=")
                if len(arg_split) != 2:
                    raise Exception("Invalid data format")
                data[arg_split[0]] = arg_split[1]
        response = self.restshlib.post(url, data)
        self._print_response(response)

    def do_put(self, params):
        '''Send put request. Example: put /url key=value test=test'''
        args = shlex.split(params)
        if len(args) < 1:
            raise Exception("Invalid number of parameters")
        else:
            url = args[0]
            data = {}
            for arg in args[1:]:
                arg_split = arg.split("=")
                if len(arg_split) != 2:
                    raise Exception("Invalid data format")
                data[arg_split[0]] = arg_split[1]
        response = self.restshlib.put(url, data)
        self._print_response(response)

    def do_delete(self, params):
        '''Send delete request. Example: delete /url'''
        args = shlex.split(params)
        if len(args) != 1:
            raise Exception("Invalid number of parameters")
        else:
            (url,) = args
        response = self.restshlib.delete(url)
        self._print_response(response)

    def do_prompt(self, params):
        '''Change restsh prompt. Example: prompt "restsh> "'''
        args = shlex.split(params)
        if len(args) != 1:
            raise Exception("Invalid number of parameters")
        else:
            (prompt,) = args
        self.cfg_prompt = prompt

if __name__=='__main__':
    restsh = RestSH()
    if len(sys.argv) == 2:
        restsh.do_baseurl(sys.argv[1])
        restsh.postcmd(None, None)
    elif len(sys.argv) > 2:
        print "ERROR: invalid parameters"
        print "Usage: %s [<baseurl>]" % (sys.argv[0])
        sys.exit(1)

    while True:
        try:
            restsh.cmdloop()
        except Exception as e:
            if DEBUG:
                exc_type, exc_value, exc_traceback = sys.exc_info()
                print "*** print_tb:"
                traceback.print_tb(exc_traceback, file=sys.stdout)
            print "ERROR: %s " % str(e)
