#!/usr/bin/env python2

# Author: Jamie Strandboge <jamie@ubuntu.com>
# Copyright (C) 2012 Canonical Ltd.
#
# This script is distributed under the terms and conditions of the GNU General
# Public License, Version 2 or later. See http://www.gnu.org/copyleft/gpl.html
# for details.

from __future__ import print_function
import cPickle
import optparse
import os
import pprint
import signal
import subprocess
import sys
import tempfile


# TODO: use usn_lib.py
def load_database(db_filename):
    '''Load usn database'''
    print("INFO: Loading %s..." % (db_filename), file=sys.stderr)
    filename = os.path.expanduser(db_filename)
    if not os.path.isfile(filename):
        return {}
    return cPickle.load(open(filename))


def get_norm_db_as_str(db):
    '''Print the db in a normalized format, that can be used to compare'''
    return pprint.pformat(db)


def subprocess_setup():
    # Python installs a SIGPIPE handler by default. This is usually not what
    # non-Python subprocesses expect.
    signal.signal(signal.SIGPIPE, signal.SIG_DFL)


def cmd(command, input=None, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, stdin=None, timeout=None):
    '''Try to execute given command (array) and return its stdout, or return
    a textual error if it failed.'''

    try:
        sp = subprocess.Popen(command, stdin=stdin, stdout=stdout, stderr=stderr, close_fds=True, preexec_fn=subprocess_setup)
    except OSError as e:
        return [127, str(e)]

    out, outerr = sp.communicate(input)
    # Handle redirection of stdout
    if out is None:
        out = ''
    # Handle redirection of stderr
    if outerr is None:
        outerr = ''
    return [sp.returncode, out + outerr]


def diff_db(db1, db2):
    '''Compare two databases'''
    tmpdir = tempfile.mkdtemp(prefix='usndb-tool-')

    fn1 = os.path.join(tmpdir, "db1")
    print("INFO: Formatting %s..." % (os.path.basename(fn1)), file=sys.stderr)
    open(fn1, 'w').write(get_norm_db_as_str(db1))

    fn2 = os.path.join(tmpdir, "db2")
    print("INFO: Formatting %s..." % (os.path.basename(fn2)), file=sys.stderr)
    open(fn2, 'w').write(get_norm_db_as_str(db2))

    print("INFO: diffing %s %s..." % (os.path.basename(fn1), os.path.basename(fn2)), file=sys.stderr)
    rc, report = cmd(['diff', '-u', fn1, fn2])

    os.unlink(fn1)
    os.unlink(fn2)
    os.rmdir(tmpdir)

    return report


#
# main
#
if __name__ == "__main__":
    parser = optparse.OptionParser()
    parser.add_option("--db", help="database file", metavar="FILE")
    parser.add_option("--db2", help="database file", metavar="FILE")
    parser.add_option("--diff", help="Perform diff on files", action='store_true', default=False)
    parser.add_option("--dump", help="Dump the specified db to stdout", action='store_true', default=False)
    (opt, args) = parser.parse_args()

    if not opt.db:
        print("Must specify --db", file=sys.stderr)
        sys.exit(1)
    elif not opt.diff and not opt.dump:
        print("Must specify one of --diff or --dump", file=sys.stderr)
        sys.exit(1)
    elif opt.diff and not opt.db2:
        print("Must specify --db2", file=sys.stderr)
        sys.exit(1)
    elif opt.db and not os.path.isfile(opt.db):
        print("'%s' is not a file" % opt.db, file=sys.stderr)
        sys.exit(1)
    elif opt.db2 and not os.path.isfile(opt.db2):
        print("'%s' is not a file" % opt.db2, file=sys.stderr)
        sys.exit(1)

    db = load_database(opt.db)
    if opt.db2:
        db2 = load_database(opt.db2)

    if opt.diff:
        diff = diff_db(db, db2)
        if diff != "":
            print(diff_db(db, db2))
    elif opt.dump:
        print(get_norm_db_as_str(db))
    else:
        print("Unrecognized command", file=sys.stderr)
        sys.exit(1)
    sys.exit(0)
