#!/usr/bin/env python
# Copyright (c) 2014, Marcus Breese
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
#   list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice, this
#   list of conditions and the following disclaimer in the documentation and/or
#   other materials provided with the distribution.
#
# * Neither the names of the authors nor contributors may not be used to endorse or
#   promote products derived from this software without specific prior written
#   permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


import sys
import os

try:
    import tabql
except:
    sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..'))
    import tabql


def usage(msg=None):
    if msg:
        sys.stderr.write('ERROR: %s\n' % msg)

    sys.stdout.write('''\

[tabql] - an interface for using SQLite with tab-delimited files.

Usage: tabql {opts} {db files} SQL-QUERY

Database file definition:
    -tab {table-name:}filename.txt
    -csv {table-name:}filename.csv (Planned for future)

    In either case, the given file will be available to query by the given
    table name. By default, the tables will be named tbl1, tbl2, etc... As
    a special case, if there is only one input file, it will be named 'tbl'.
    You can mix and match -tab and -csv.

    Each column will be named c1, c2, c3, etc... if the file is missing a
    header (configured below). Column types will be auto-determined by
    SQLite.

    stdin may be used as an input if the filename is set as '-' (default if
    no -tab or -csv option is given). Note: stdin may not be used if -i is
    set.

    Source files may also be gzip compressed.

Options:
    -db filename.db    Use filename.db as the name of the SQLite database. If
                       this option is used, the temporary DB will NOT be
                       deleted on exit. If you set the filename to be
                       ':memory:', then the DB will be kept entirely in RAM.
                       (default: use a temporary file that is deleted on exit)

    -noheader          The file has no header

    -headercomment     The header is the last commented line

    -i                 Start an interactive SQLite session
                       (default if no query is given)

    -t tmpdir          Store the temporary DB file in tmpdir
                       (default: $TMPDIR or /tmp)

    -f                 Force overwriting an existing file
''')

    sys.exit(1)


if __name__ == '__main__':
    fnames = []
    dbfname = None
    noheader = False
    headercomment = False
    interactive = False
    tmpdir = None
    force = False
    verbose = False
    query = []

    last = None

    for arg in sys.argv[1:]:
        if last == '-tab' or last == '-csv':
            if ':' in arg:
                tablename = arg.split(':', 1)[0]
                fname = os.path.expanduser(arg.split(':', 1)[0])
            else:
                tablename = 'tbl%s' % (len(fnames) + 1) 
                fname = os.path.expanduser(arg)

            if fname == '-' or os.path.exists(fname):
                fnames.append((last, tablename, fname))
            else:
                usage("Missing input file: %s" % arg)

            last = None
        elif last == '-db':
            dbfname = os.path.expanduser(arg)
            last = None
        elif last == '-t':
            if not os.path.isdir(arg):
                usage("Invalid temporary directory: %s" % arg)
            tmpdir = arg
            last = None
        elif arg == '-h':
            usage()
        elif arg == '-f':
            force = True
        elif arg == '-headercomment':
            headercomment = True
        elif arg == '-noheader':
            noheader = True
        elif arg == '-i':
            interactive = True
        elif arg == '-v':
            verbose = True
        elif arg in ['-db', '-tab' ,'-t', '-csv']:
            last = arg
        else:
            query.append(arg)

    if dbfname and os.path.exists(dbfname):
        if not force:
            usage("Database file: %s already exists!" % arg)
        else:
            os.unlink(dbfname)


    if not fnames:
        fnames.append(('-tab', 'tbl', '-'))
    elif len(fnames) == 1 and fnames[0][1] == 'tbl1':
        fnames = [(fnames[0][0], 'tbl', fnames[0][2])]

    for ftype, tname, fname in fnames:
        if fname == '-' and interactive:
            usage("Interactive mode can not be used when the data is read from stdin")

    db = tabql.TabQL(fnames, dbfname, noheader, headercomment, tmpdir, verbose)

    if query:
        header = False
        for colnames, row in db.execute(' '.join(query)):
            if not header:
                sys.stdout.write('%s\n' % '\t'.join(colnames))
                header = True

            sys.stdout.write('%s\n' % '\t'.join([str(x) for x in row]))


    if interactive:
        # subprocess doesn't work right when opening sqlite3
        os.system('sqlite3 %s' % tabql.dbfname)

    db.close()
