#!/usr/bin/python3.6
import os
import pwd
import sys
from typing import Optional

from retrace.argparser import ArgumentParser
from retrace.retrace import (log_debug,
                             log_error,
                             log_warn,
                             KernelVer,
                             RetraceTask,
                             RetraceWorkerError)
from retrace.config import Config

CONFIG = Config()

if __name__ == "__main__":
    cmdline_parser = ArgumentParser(description="Execute a retrace job")
    cmdline_parser.add_argument("task_id", type=int, help="Task ID (%s/<task_id>) must exist" % CONFIG["SaveDir"])
    cmdline_parser.add_argument("--restart", action="store_true", default=False,
                                help="Restart the task if it has already been processed")
    cmdline_parser.add_argument("--foreground", action="store_true", default=False, help="Do not fork to background")
    cmdline_parser.add_argument("--kernelver", default=None,
                                help="Kernel version (e.g. 2.6.32-287.el6), also needs --arch")
    cmdline_parser.add_argument("--arch", help="Architecture")
    cmdline = cmdline_parser.parse_args()

    log = cmdline._log

    if not os.environ.get("RETRACE_SERVER_TESTING") and \
            pwd.getpwnam("retrace").pw_uid != os.getuid():
        sys.stderr.write("Please use 'retrace-server-task' to restart or create a new task\n")
        sys.exit(1)

    # do not use logging yet - we need the task
    if cmdline.kernelver and not cmdline.arch:
        sys.stderr.write("You also need to specify architecture when overriding kernel version\n")
        sys.exit(1)

    try:
        task = RetraceTask(cmdline.task_id)
    except Exception:
        sys.stderr.write("Task '%d' does not exist\n" % cmdline.task_id)
        sys.exit(1)

    if task.has_status():
        if not cmdline.restart:
            sys.stderr.write("%s has already been executed for task %d\n" % (sys.argv[0], cmdline.task_id))
            sys.stdout.write("You can use --restart option if you really want to restart the task\n")
            sys.exit(1)

        task.reset()

    worker = task.create_worker()
    worker.begin_logging()

    if not cmdline.foreground:
        try:
            pid = os.fork()
        except OSError:
            log_error("Unable to fork")
            worker._fail()

        # parent - kill
        if pid != 0:
            sys.exit(0)

        try:
            os.setpgrp()
        except Exception as ex:
            log_warn("Failed to detach from process group: %s" % str(ex))

    kernelver: Optional[KernelVer] = None
    if cmdline.kernelver is not None:
        try:
            kernelver = KernelVer(cmdline.kernelver)
            if cmdline.arch:
                kernelver.arch = cmdline.arch
            log_debug("Using kernel version from command line: %s" % kernelver)
        except Exception as ex:
            log_warn(str(ex))

    try:
        worker.start(kernelver=kernelver, arch=cmdline.arch)
    except RetraceWorkerError as ex:
        sys.exit(ex.errorcode)
