#!/usr/bin/python
# coding: utf-8
from __future__ import absolute_import
from __future__ import print_function
from __future__ import division
from __future__ import unicode_literals
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.dsn:
        dsn = os.environ.get("DBA_DB", "")
    else:
        dsn = args.dsn

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

    elif dballe.DB.is_url(dsn):
        return dballe.DB.connect_from_url(dsn)
    else:
        return dballe.DB.connect(dsn, args.user, args.password)

def get_query(args):
    query = dballe.Record()
    for q in args.query:
        query.set_from_string(q)
    return query

def get_outfd(args, text=False):
    """
    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("--dsn", type=str, metavar="dsn",
                        help="DSN, or 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(b"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(b"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(b"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(b"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 == "gnur":
            if not args.outfile:
                raise CommandError("cannot export R data to standard output: please use --outfile")
            import dballe.rconvert
            import dballe.volnd
            idx = (dballe.volnd.AnaIndex(), \
                dballe.volnd.DateTimeIndex(), \
                dballe.volnd.LevelIndex(), \
                dballe.volnd.TimeRangeIndex(), \
                dballe.volnd.NetworkIndex())
            res = dballe.volnd.read(db.query_data(query), idx)
            dballe.rconvert.volnd_save_to_r(res, args.outfile)
        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)
