#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from __future__ import print_function

import sys
import os
import locale
import argparse
import urllib
import urllib2
import logging
import logging.handlers

import mini_buildd.misc
import mini_buildd.setup
import mini_buildd.api

LOG = logging.getLogger("mini_buildd")
mini_buildd.misc.setup_console_logging(logging.DEBUG)

PARSER = argparse.ArgumentParser(prog="mini-buildd-tool",
                                 description="mini-buildd user tool.",
                                 formatter_class=argparse.ArgumentDefaultsHelpFormatter)

PARSER.add_argument('--version', action='version', version=mini_buildd.__version__)
PARSER.add_argument("-v", "--verbose", dest="verbosity", action='count', default=0,
                    help="lower log level. Give twice for max logs")
PARSER.add_argument("-q", "--quiet", dest="terseness", action='count', default=0,
                    help="tighten log level. Give twice for min logs")
PARSER.add_argument("-H", "--host", action='store', default="localhost:8066",
                    help="mini-buildd host (http port)")
PARSER.add_argument("-O", "--output", action='store', default="plain",
                    help="output type: 'html', 'plain' or 'python'")
PARSER.add_argument("-C", "--clear-creds", action='store_true',
                    help="clear credentials cache")

def print_daemon_messages(headers):
    "Output daemon messages to stderr"
    msgs_header = "x-mini-buildd-message"
    for msg in [v for k, v in headers.items() if msgs_header == k[:len(msgs_header)]]:
        print("Daemon message: {m}".format(m=mini_buildd.misc.b642u(msg)), file=sys.stderr)

def cmd_call(args):
    # Construct base URL form host argument
    base_url = "http://{h}".format(h=args.host)

    # Log in if required by this call
    if mini_buildd.api.COMMANDS[args.command].LOGIN:
        mini_buildd.misc.web_login(
            base_url,
            CREDS_CACHE)

    # Compute api call parameters
    http_args = {}
    for k in [k for k in args.__dict__.keys() if k not in ["terseness", "verbosity", "host", "clear_creds", "login", "func"]]:
        http_args[k] = args.__dict__[k]

    # Confirm if required by this call
    if mini_buildd.api.COMMANDS[args.command].CONFIRM:
        if not http_args["confirm"]:
            http_args["confirm"] = raw_input("Repeat command name to confirm: ")
        if not http_args["confirm"]:
            raise Exception("{c}: Not confirmed, skipped.".format(c=args.command))

    # Do the api call
    call_url = "{b}/mini_buildd/api?{a}".format(b=base_url, a=urllib.urlencode(http_args))
    LOG.info("API call URL: {u}".format(u=call_url))
    response = urllib2.urlopen(call_url)

    # Output daemon messages to stderr
    print_daemon_messages(response.headers)

    # Output result to stdout
    result = response.read()
    if sys.stdout.isatty() and http_args["output"] == "plain":
        # On plain output to a tty, try to encode to the preferred locale
        encoding = response.headers["content-type"].partition("charset=")[2]
        sys.stdout.write(unicode(result, encoding if encoding else "UTF-8").encode(locale.getpreferredencoding()))
    else:
        sys.stdout.write(result)


SUBPARSERS = PARSER.add_subparsers()

for cmd, cmd_cls in mini_buildd.api.COMMANDS.items():
    cmd_parser = SUBPARSERS.add_parser(cmd, help=cmd_cls.__doc__)
    for cmd_args, cmd_kvargs in cmd_cls.ARGUMENTS:
        cmd_parser.add_argument(*cmd_args, **cmd_kvargs)

    if cmd_cls.CONFIRM:
        cmd_parser.add_argument("--confirm", action='store', default="", metavar="COMMAND",
                                help="this command needs user confirmation; this option allows to force-bypass that, by explicitly repeating the command")

    cmd_parser.set_defaults(func=cmd_call,
                            command=cmd,
                            login=cmd_cls.LOGIN)

# Parse and run
ARGS = PARSER.parse_args()
LOG.setLevel(logging.WARNING - (10 * (min(2, ARGS.verbosity) - min(2, ARGS.terseness))))

if LOG.getEffectiveLevel() <= logging.DEBUG:
    mini_buildd.setup.DEBUG = ["exception"]

try:
    CREDS_CACHE = mini_buildd.misc.CredsCache(os.path.join(os.getenv("HOME"), ".mini-buildd-tool.credentials"))
    if ARGS.clear_creds:
        CREDS_CACHE.clear()
    ARGS.func(ARGS)
except urllib2.HTTPError as e:
    print_daemon_messages(e.headers)
    mini_buildd.setup.log_exception(LOG, ARGS.host, e)
    sys.exit(1)
except Exception as e:
    mini_buildd.setup.log_exception(LOG, "{h}".format(h=ARGS.host), e)
    sys.exit(2)
