#!/usr/bin/python
import glob
import logging
import os
import shutil
import sys

try:
    import autotest.common as common  # pylint: disable=W0611
except ImportError:
    import common  # pylint: disable=W0611
from autotest.client.shared.settings import settings
from autotest.client.shared import logging_manager, logging_config
from autotest.client import utils
from autotest.frontend import optparser
from autotest.frontend import setup_django_environment  # pylint: disable=W0611
from autotest.frontend.tko import models_utils as tko_models_utils
from autotest.frontend.afe import models_utils as afe_models_utils

ERROR_NO_RESULTS_AVAILABLE = 1
ERROR_WRONG_INPUT = 2
ERROR_USER_ABORT = 3


class DeleteJobLoggingConfig(logging_config.LoggingConfig):

    """
    Used with the sole purpose of providing convenient logging setup
    for this program.
    """

    def configure_logging(self, results_dir=None, verbose=False):
        super(DeleteJobLoggingConfig, self).configure_logging(use_console=True,
                                                              verbose=verbose)


def get_results_dir():
    results_dir = ""
    results_dir_list = []
    tko_dir_relative = os.path.dirname(os.path.abspath(sys.argv[0]))
    results_dir_relative = os.path.abspath(os.path.join(tko_dir_relative, '..',
                                                        'results'))

    top_path = settings.get_value('COMMON', 'autotest_top_path',
                                  default='/usr/local/autotest')
    results_dir_absolute = os.path.abspath(os.path.join(top_path, 'results'))

    if results_dir_absolute == results_dir_relative:
        results_dir_list = [results_dir_absolute]
    else:
        results_dir_list = [results_dir_absolute, results_dir_relative]

    for d in results_dir_list:
        if glob.glob(os.path.join(d, '*')):
            results_dir = d
            break

    if not results_dir:
        logging.error("No results available under %s", results_dir_list)
        sys.exit(ERROR_NO_RESULTS_AVAILABLE)

    return results_dir


def get_tags_by_range(jobid_range):
    jobs = tko_models_utils.jobs_get_by_tag_range(jobid_range)
    return [job.tag for job in jobs]


def get_tags_list(option):
    tag_list = []
    if option.isdigit():
        tag_list = get_tags_by_range([int(option)])
    else:
        range = option.split("-")
        if len(range) != 2:
            logging.error("Wrong range format, expected int-int string")
            sys.exit(ERROR_WRONG_INPUT)
        try:
            inf = int(range[0])
            sup = int(range[1])
        except ValueError:
            logging.error("Wrong range format, expected int-int string")
            sys.exit(ERROR_WRONG_INPUT)
        if not sup > inf:
            logging.error("Job range has to be an increasing sequence")
            sys.exit(ERROR_WRONG_INPUT)
        range = xrange(int(range[0]), int(range[1]) + 1)
        tag_list = get_tags_by_range(range)

    return tag_list


class OptionParser(optparser.OptionParser):

    def __init__(self):
        optparser.OptionParser.__init__(self, usage="%prog [options]")
        self.add_option("-r", action="store", type="string",
                        dest="range",
                        default="",
                        help="range of jobs you want to delete. ex: 1-100")
        self.add_option("-t", action="store", type="string",
                        dest="tag",
                        default="",
                        help=("specific job tag you want to delete. ex: "
                              "112-autotest/test.foobar.com"))
        self.add_option("--dry-run", action="store_true",
                        dest="dry_run",
                        default=False,
                        help=("Just simulate deletion"))
        self.add_option("-y", action="store_true",
                        dest="auto",
                        default=False,
                        help=("Don't ask for confirmation before deleting"))


def delete_job_full(tag):
    tko_job = tko_models_utils.job_get_by_tag(tag)

    if tko_job is None:
        logging.error('Job tag "%s" does not exist in database', tag)
        return

    if tko_job.afe_job_id is None:
        logging.debug('TKO job has no AFE job associated')
        afe_job = None
    else:
        logging.debug('Job sent via AFE, deleting AFE job "%s"',
                      tko_job.afe_job_id)
        afe_job = afe_models_utils.job_get_by_id(tko_job.afe_job_id)
        if afe_job is None:
            logging.warn('AFE job referenced but not found')

        if options.dry_run:
            return

        logging.info("Deleting job tag %s" % tag)
        if afe_job is not None:
            deleted = afe_models_utils.job_delete_by_id(afe_job.id)
            if not deleted:
                logging.error("Failed while deleting AFE job")

        deleted = tko_models_utils.job_delete_by_tag(tag)
        if not deleted:
            logging.error("Failed while deleting TKO job")


if __name__ == '__main__':
    logging_manager.configure_logging(DeleteJobLoggingConfig(), verbose=True)
    parser = OptionParser()
    options, args = parser.parse_args()
    if args:
        parser.print_help()
        sys.exit(ERROR_WRONG_INPUT)

    if not options:
        parser.print_help()
        sys.exit(ERROR_WRONG_INPUT)

    if not options.range and not options.tag:
        parser.print_help()
        sys.exit(ERROR_WRONG_INPUT)

    if options.range:
        tag_list = get_tags_list(options.range)

    elif options.tag:
        tag_list = [options.tag]

    logging.info("The following job tags were selected/found:")
    for tag in tag_list:
        logging.info("    %s" % tag)
    answer = utils.ask("Do you want to delete them?", auto=options.auto)

    if answer == 'y':
        for tag in tag_list:
            try:
                delete_job_full(tag)
            except Exception, detail:
                logging.error("Could not delete job tag %s: %s",
                              tag, detail)
                logging.error("It is likely that you tried to "
                              "delete a job that was already queued")
                logging.error("Please abort the job before trying again")

            results_dir = get_results_dir()
            parent_tagdir = os.path.dirname(tag)
            if not parent_tagdir:
                parent_tagdir = tag
            results_dir = os.path.abspath(os.path.join(results_dir,
                                                       parent_tagdir))
            if not os.path.isdir(results_dir):
                logging.error("Job directory %s does not exist" % results_dir)
            else:
                logging.info("Deleting job directory %s" % results_dir)
                if not options.dry_run:
                    shutil.rmtree(results_dir)
    else:
        logging.info("Aborting...")
        sys.exit(ERROR_USER_ABORT)
