#!/usr/bin/env python

from imp import find_module
import os
import os.path
import sys
from textwrap import dedent
from argparse import ArgumentParser
from unittest.loader import TestLoader
from unittest.runner import TextTestRunner


# list autopilot depends here, with the form:
# ('python module name', 'ubuntu package name'),
DEPENDS = [
    ('compizconfig', 'python-compizconfig'),
    ('dbus', 'python-dbus'),
    ('gobject', 'python-gobject'),
    ('gtk', 'python-gtk2'),
    ('ibus', 'python-ibus'),
    ('junitxml', 'python-junitxml'),
    ('testscenarios', 'python-testscenarios'),
    ('testtools', 'python-testtools'),
    ('xdg', 'python-xdg'),
    ('Xlib', 'python-xlib'),
]


def check_depends():
    """Check for required dependancies, and print a helpful message if any are
    missing.

    If all required modules are present, return True, False otherwise.
    """
    missing = []
    for module_name, package_name in DEPENDS:
        try:
            find_module(module_name)
        except ImportError:
            missing.append(package_name)
    if missing:
        print dedent("""\
            You are missing one or more packages required to run autopilot. They
            are:

            %s

            Please install these packages and re-run this script.
            """ % (' '.join(missing))
            )
        return False
    return True


def ensure_autopilot_is_importable():
    """Patch sys.path with the local autopilot directory if it's not already
    importable.
    """
    try:
        find_module("autopilot")
    except ImportError:
        ap_dir = os.path.join(os.path.dirname(__file__),
            "../tests/autopilot")
        ap_dir = os.path.realpath(ap_dir)
        sys.path.append(ap_dir)
        print "Patching sys.path to include local autopilot folder '%s'\n" % ap_dir


def parse_arguments():
    """Parse command-line arguments, and return an argparse arguments object."""
    parser = ArgumentParser(description="Autopilot test-runner")
    subparsers = parser.add_subparsers(help='Run modes', dest="mode")

    parser_run = subparsers.add_parser('run', help="Run autopilot tests")
    parser_run.add_argument('-o', "--output", required=False,
        help='Write test result report to file. Defaults to stdout')
    parser_run.add_argument('-f', "--format", choices=['text', 'xml'], default='text',
        required=False, help='Specify desired output format. Default is "text".')
    parser_run.add_argument('-r', '--record', action='store_true', default=False,
        required=False, help="Record failing tests. Required 'recordmydesktop' app to be installed. Videos \
        are stored in /tmp/autopilot.")
    parser_run.add_argument("-rd", "--record-directory", required=False,
        default="/tmp/autopilot", type=str, help="Directory to put recorded tests (only if -r) specified.")
    parser_run.add_argument("test", nargs="*", help="Specify tests to run, as listed by the 'list' command")


    parser_list = subparsers.add_parser('list', help="List autopilot tests")
    args = parser.parse_args()

    return args


def list_tests():
    """Print a list of tests we find inside autopilot.tests."""
    num_tests = 0
    from testtools import iterate_tests
    loader = TestLoader()
    test_suite = loader.discover('autopilot.tests')
    print "Listing all autopilot tests:"
    print
    for test in iterate_tests(test_suite):
        has_scenarios = hasattr(test, "scenarios")
        if has_scenarios:
            num_tests += len(test.scenarios)
            print " *%d %s" % (len(test.scenarios), test.id())
        else:
            num_tests += 1
            print test.id()
    print "\n %d total tests." % (num_tests)


def run_tests(args):
    """Run tests, using input from `args`."""
    import junitxml
    import autopilot.globals

    if args.record:
        autopilot.globals.video_recording_enabled = True
        autopilot.globals.video_record_directory = args.record_directory

    loader = TestLoader()
    if args.test:
        test_suite = loader.loadTestsFromNames(args.test)
    else:
        test_suite = loader.discover('autopilot.tests')

    if args.output == None:
        results_stream = sys.stdout
    else:
        try:
            path = os.path.dirname(args.output)
            if path != '' and not os.path.exists(path):
                os.makedirs(path)
            results_stream = open(args.output, 'w')
        except:
            results_stream = sys.stdout
    if args.format == "xml":
        result = junitxml.JUnitXmlResult(results_stream)
        result.startTestRun()
        test_suite.run(result)
        result.stopTestRun()
        results_stream.close()
        if not result.wasSuccessful:
            exit(1)
    elif args.format == "text":
        runner = TextTestRunner(stream=results_stream)
        success = runner.run(test_suite).wasSuccessful()
        if not success:
            exit(1)

def main():
    args = parse_arguments()
    if args.mode == 'list':
        list_tests()
    elif args.mode == 'run':
        run_tests(args)

if __name__ == "__main__":
    if not check_depends():
        exit(1)
    ensure_autopilot_is_importable()
    main()
