# -*- coding: utf-8 -*-

"""
This program calls the Agyo REST webservices to perform all the needs for the b2b invoice system

Needs:

 Virtualenv with python 2.7 and zeep package installed

Params:

 -w --url           url to invoke
 -f --function      GET|POST
 -j --json          input json file
 -o --output        output json file
 -u --unsafe        disable ssl verification over https
 -v --verbose       write some messages to log file

The result of the script is written in json format, to the output file.

Other 2 files are written by the program:
- error log, with the same file name of the output json file with the extension .err
- output log, with the same file name of the output json file with the extension .log

"""

import requests
from requests.exceptions import HTTPError
from requests.exceptions import SSLError
from requests.structures import CaseInsensitiveDict
import datetime
import sys
import json


class Log:
    def __init__(self, flog, ferr):
        self.flog = flog
        self.ferr = ferr

    def message(self, message):
        with open(self.flog, 'a') as f:
            f.write("%s: %s\n" % (datetime.datetime.now(), message))

    def error(self, error):
        with open(self.ferr, 'a') as f:
            f.write("%s: %s\n" % (datetime.datetime.now(), error))
        self.message(error)


def errlog(msg):
    print >> sys.stderr, "%s" % (msg,)


def option_parsing():
    from optparse import OptionParser

    usage = "usage: %prog [options] argument"
    parser = OptionParser(usage=usage)
    parser.add_option("-u", "--url", dest="url", action="store", type="string",
                      help="url to invoke [REQUIRED]")
    parser.add_option("--header", dest="header", action="store", default=None, type="string",
                      help="header text file")
    parser.add_option("-f", "--function", dest="func", action="store", type="string",
                      help="requested function (GET|POST|GET_RAW|PATCH) [REQUIRED]")
    parser.add_option("-j", "--json", dest="json", action="store", default=None, type="string",
                      help="input data in json format")
    parser.add_option("-o", "--output", dest="output", action="store", type="string",
                      help="output file name [REQUIRED]")
    parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False,
                      help="display verbose output")
    parser.add_option("--unsafe", action="store_false", dest="safe", default=True,
                      help="disable ssl cert verification")
    opz, args = parser.parse_args()
    if not opz.url:
        parser.error("-u param is required; try -h")
    if not opz.func:
        parser.error("-f param is required; try -h")
    if not opz.output:
        parser.error("-o param is required; try -h")
    return opz


def call_the_service(url, header, func, ifile, ofile, safe, verbose):
    flog = ofile.rsplit('.', 1)[0] + ".log"
    ferr = ofile.rsplit('.', 1)[0] + ".err"
    logger = Log(flog, ferr)
    # carica headers dal file di testo passato
    if header is not None:
        try:
            with open(header) as f:
                if verbose:
                    logger.message("Reading headers data from %s" % header)
                heads = json.load(f)
        except IOError as e:
            logger.error("%s %s" % (e.strerror, e.filename))
            sys.exit(1)
    else:
        heads = None
    # carica dati request da file json passato
    if ifile is not None:
        try:
            with open(ifile) as f:
                if verbose:
                    logger.message("Reading json input data from %s" % ifile)
                data = json.load(f)
        except IOError as e:
            logger.error("%s %s" % (e.strerror, e.filename))
            sys.exit(1)
    else:
        data = json.dumps('{}')
    # consuma servizio
    try:
        headers = CaseInsensitiveDict()
        # headers["Content-Type"] = "application/json"
        if heads is not None:
            headers.update(heads)
        if verbose:
            logger.message("Sent %s request to %s. See %s for request headers and %s for request params."
                           % (func, url, header, ifile))
        if func == "POST":
            resp = requests.post(url, headers=headers, json=data, verify=safe)
            # open(ofile, 'w').write(resp.content)
            open(ofile, 'w').write(json.dumps(json.loads(resp.content), indent=0))
        if func == "GET":
            resp = requests.get(url, headers=headers, params=data, verify=safe)
            open(ofile, 'w').write(json.dumps(json.loads(resp.content), indent=0))
        if func == "GET_RAW":
            resp = requests.get(url, headers=headers, params=data, verify=safe)
            open(ofile, 'w').write(resp.content)
        if func == "PATCH":
            resp = requests.patch(url, headers=headers, params=data, verify=safe)
            open(ofile, 'w').write(json.dumps(json.loads(resp.content), indent=0))
        if verbose:
            logger.message("See %s for result." % (ofile))
        sys.exit(0)
    except SSLError:
        logger.error("SSL cert error. Try --unsafe option (at your own risk).")
        sys.exit(3)
    except HTTPError as e:
        logger.error("HTTPError: %s." % e.message)
        sys.exit(4)
    except Exception as e:
        logger.error(e.__class__)
        sys.exit(5)


if __name__ == "__main__":
    options = option_parsing()
    call_the_service(url=options.url,
                     header=options.header,
                     func=options.func,
                     ifile=options.json,
                     ofile=options.output,
                     safe=options.safe,
                     verbose=options.verbose)
