#!/usr/bin/python3
import argparse
import logging
import os
import sys
import io
try:
    import dballe
    HAS_DBALLE = True
except ImportError:
    HAS_DBALLE = False

log = logging.getLogger("main")


class CommandError(Exception):
    pass


def setup_logging(args):
    FORMAT = "%(levelname)s: %(message)s"
    if args.verbose:
        logging.basicConfig(level=logging.INFO, stream=sys.stderr, format=FORMAT)
    else:
        logging.basicConfig(level=logging.WARNING, stream=sys.stderr, format=FORMAT)


def get_db(args):
    if not args.url:
        url = os.environ.get("DBA_DB", "")
    else:
        url = args.url

    if not url:
        raise CommandError("Cannot find a database to connect to: --url is not specified and $DBA_DB is not set")

    return dballe.DB.connect(url)


def get_query(args):
    return dict(q.split("=", 1) for q in args.query)


def get_outfd(args, text=False):
    """
from __future__ import unicode_literals
    Get the output file descriptor
    """
    if args.outfile:
        if text:
            return io.open(args.outfile, "wt", encoding="utf-8")
        else:
            return io.open(args.outfile, "wb")
    else:
        if text:
            return io.open(sys.stdout.fileno(), "wt", encoding="utf-8", closefd=False)
        else:
            return io.open(sys.stdout.fileno(), "wb", closefd=False)


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Export data from a DB-All.e database.')
    parser.add_argument("--verbose", action="store_true",
                        help="verbose output")
    parser.add_argument("--url", "--dsn", type=str, metavar="url",
                        help="URL-like database definition, to use for connecting to the DB-All.e database"
                             " (can also be specified in the environment as DBA_DB)")
    parser.add_argument("--user", type=str, metavar="name",
                        help="username to use for connecting to the DB-All.e database")
    parser.add_argument("--pass", type=str, metavar="password", dest="password",
                        help="password to use for connecting to the DB-All.e database")
    parser.add_argument("--outfile", "-o", type=str, metavar="file",
                        help="output file. Default is standard output, if supported")

    subparsers = parser.add_subparsers(dest="format", help="output formats")
    # Use a byte-string for subparser name to avoid seeing u'csv' in output.
    # Remove in python3
    parser_csv = subparsers.add_parser("csv", help="export data as CSV")
    parser_csv.add_argument("query", nargs="*", metavar="key=val",
                            help="DB-All.e query to select data to export")

    parser_gnur = subparsers.add_parser("gnur", help="export data as GNU R workspace")
    parser_gnur.add_argument("query", nargs="*", metavar="key=val",
                             help="DB-All.e query to select data to export")

    parser_bufr = subparsers.add_parser("bufr", help="export data as BUFR")
    parser_bufr.add_argument("query", nargs="*", metavar="key=val",
                             help="DB-All.e query to select data to export")
    parser_bufr.add_argument("--generic", action="store_true",
                             help="export generic BUFR messages")

    parser_crex = subparsers.add_parser("crex", help="export data as CREX")
    parser_crex.add_argument("query", nargs="*", metavar="key=val",
                             help="DB-All.e query to select data to export")
    parser_crex.add_argument("--generic", action="store_true",
                             help="export generic BUFR messages")

    args = parser.parse_args()

    try:
        setup_logging(args)

        if not HAS_DBALLE:
            raise CommandError("This command requires the dballe python module to run")

        db = get_db(args)
        query = get_query(args)

        if args.format == "csv":
            import dballe.dbacsv
            with get_outfd(args, text=True) as fd:
                dballe.dbacsv.export(db, query, fd)
        elif args.format == "bufr":
            if not args.outfile:
                raise CommandError("BUFR output requires --outfile")
            db.export_to_file(query, "BUFR", args.outfile, generic=args.generic)
        elif args.format == "crex":
            if not args.outfile:
                raise CommandError("CREX output requires --outfile")
            db.export_to_file(query, "CREX", args.outfile, generic=args.generic)
        else:
            raise CommandError("Exporter for {} is not available.".format(args.format))

    except CommandError as e:
        log.error("%s", e)
        sys.exit(1)
