#!/usr/bin/env python
"""Tron Control

Part of the command line interface to the tron daemon. Provides the interface
to controlling jobs and runs.
"""

import datetime
import logging
import optparse
import sys
import urlparse

import tron
from tron.commands import cmd_utils
from tron.commands.cmd_utils import ExitCode
from tron.commands import client


COMMAND_HELP = (
    ('start',           'Start the selected job, job run, action, or service'),
    ('cancel',          'Cancel the selected job run'),
    ('disable',         'Disable selected job and cancel any outstanding runs'),
    ('enable',          'Enable the selected job and schedule the next run'),
    ('disableall',      'Disable all jobs'),
    ('enableall',       'Enable all jobs'),
    ('fail',            'Mark an UNKNOWN job as having failed'),
    ('success',         'Mark an UNKNOWN job as having succeeded'),
    ('skip',            'Skip a failed action, runs dependent actions.'),
    ('stop',            'Stop the service or action run (SIGTERM)'),
    ('kill',            'Force kill the service or action run (SIGKILL)'),
)


log = logging.getLogger('tronctl')


class TronCtlOptionParser(optparse.OptionParser):
    def format_epilog(self, formatter):
        # We want to include some extra helpful info
        result = [formatter.format_heading("Commands")]
        formatter.indent()
        for cmd_name, desc in COMMAND_HELP:
            text = ''.join((cmd_name.ljust(20), desc.ljust(40)))
            result.append(formatter._format_text(text))
            result.append('\n')

        result.append('\n')
        return ''.join(result)


def parse_date(option, opt_str, value, parser):
    parser.values.run_date = datetime.datetime.strptime(value, "%Y-%m-%d")


def parse_options():
    usage = "usage: %prog [options] <command> [<job | job run | action>]"
    parser = cmd_utils.build_option_parser(
                usage, parser_class=TronCtlOptionParser)

    parser.add_option("--run-date", action="callback", callback=parse_date,
                      type="string", dest="run_date",
                      help="For job starts, what should run date be set to")

    options, args = parser.parse_args(sys.argv)
    if len(args) < 2:
        parser.error("Missing command")

    return options, args[1:]


def edit(options, command, uri):
    data = {'command': command}
    if command == "start" and options.run_date:
        data['run_time'] = str(options.run_date)

    uri = urlparse.urljoin(options.server, uri)
    response = client.request(uri, data=data)

    if response.error:
        return

    print response.content['result']
    return True


def control_objects(options, command, object_identifiers):
    tron_client = client.Client(options.server)
    url_index = tron_client.index()
    for identifier in object_identifiers:
        try:
            tron_id = client.get_object_type_from_identifier(
                url_index, identifier)
        except ValueError, e:
            raise SystemExit("Error: %s" % e)

        yield edit(options, command, tron_id.url)


def main():
    """run tronctl"""
    options, args = parse_options()
    cmd_utils.setup_logging(options)
    cmd_utils.load_config(options)

    command = args.pop(0)
    if not args:
        # our only non-object commands are for enabling and disabling jobs, so
        # just direct those commands here
        if not edit(options, command, client.get_job_url('')):
            sys.exit(ExitCode.fail)
    else:
        if not all(control_objects(options, command, args)):
            sys.exit(ExitCode.fail)


if __name__ == '__main__':
    main()
