import inspect
import logging
import new
import os
import string
import sys
import tempfile
import time
# pylint: disable=E0611
from autotest.cli import job
from autotest.client.shared import logging_config

virt_test_dir = "/usr/local/autotest/client/tests/virt"
sys.path.insert(0, virt_test_dir)
from autotest.client.tests.virt.virttest import utils_koji

logging_config.LoggingConfig().configure_logging(verbose=True)


class site_job(job.job):
    pass


class site_job_create(job.job_create):

    """
    Adds job manipulation including installing packages from brew
    """

    op_action = 'create'

    def __init__(self):
        super(site_job_create, self).__init__()
        self.parser.add_option('-T', '--template', action='store_true',
                               help='Control file is actually a template')
        self.parser.add_option('-x', '--extra-cartesian-config',
                               action='append',
                               help='Add extra configuration to the cartesian '
                               'config file')
        self.parser.add_option('--timestamp', action='store_true',
                               help='Add a timestamp to the name of the job')
        self.parser.add_option('--koji-arch', default='x86_64',
                               help='Default architecture for packages '
                               'that will be fetched from koji build. '
                               'This will be combined with "noarch".'
                               'This option is used to help to validate '
                               'packages from the job submitting machine.')
        self.parser.add_option('--koji-tag', help='Sets a default koji tag '
                               'for koji packages specified with --koji-pkg')
        self.parser.add_option('--koji-pkg', action='append',
                               help='Packages to add to host installation '
                               'based on koji build. This options may be '
                               'specified multiple times.')
        self.koji_client = None

    def parse(self):
        '''
        Parse options.

        If any brew options is specified, instantiate KojiDownloader
        '''
        (self.command_line_options,
         self.command_line_leftover) = super(site_job_create, self).parse()

        #
        # creating the new control file
        #
        if (self.command_line_options.template and
                self.command_line_options.control_file):
            generated_control_file = self._generate_control_file()
            self.data['control_file'] = open(generated_control_file).read()

        if self.command_line_options.koji_pkg:
            if self.koji_client is None:
                self.koji_client = utils_koji.KojiClient()

        return (self.command_line_options, self.command_line_leftover)

    def _process_options(self):
        '''
        Process all options given on command line
        '''
        all_options_valid = True

        self._set_koji_tag()
        if not self._check_koji_packages():
            all_options_valid = False

        return all_options_valid

    def _set_koji_tag(self):
        '''
        Sets the default koji tag.

        Configuration item on file is: koji_tag
        '''
        if self.command_line_options.koji_tag is not None:
            utils_koji.set_default_koji_tag(self.command_line_options.koji_tag)

    def _check_koji_packages(self):
        '''
        Check if packages specification are valid and exist on koji/brew

        Configuration item on file is: koji_pkgs
        '''
        all_packages_found = True
        if self.command_line_options.koji_pkg is not None:
            logging.debug('Checking koji packages specification')
            for pkg_spec_text in self.command_line_options.koji_pkg:
                pkg_spec = utils_koji.KojiPkgSpec(pkg_spec_text)

                if not (pkg_spec.is_valid() and
                        self.koji_client.is_pkg_valid(pkg_spec)):
                    logging.error('Koji package spec is not valid, skipping: '
                                  '%s' % pkg_spec)
                    all_packages_found = False
                else:
                    rpms = self.koji_client.get_pkg_rpm_info(
                        pkg_spec,
                        self.command_line_options.koji_arch)
                    for subpackage in pkg_spec.subpackages:
                        if subpackage not in [rpm['name'] for rpm in rpms]:
                            logging.error('Package specified but not found in '
                                          'koji: %s' % subpackage)
                            all_packages_found = False

                    rpms = ", ".join(rpm['nvr'] for rpm in rpms)
                    logging.debug('Koji package spec is valid')
                    logging.debug('Koji packages to be fetched and installed: '
                                  '%s' % rpms)

        return all_packages_found

    def _generate_job_config(self):
        '''
        Converts all options given on the command line to config file syntax
        '''
        extra = []
        if self.command_line_options.extra_cartesian_config:
            extra += self.command_line_options.extra_cartesian_config

        if self.command_line_options.koji_tag:
            extra.append("koji_tag = %s" % self.command_line_options.koji_tag)

        if self.command_line_options.koji_pkg:
            koji_pkgs = []
            for koji_pkg in self.command_line_options.koji_pkg:
                koji_pkgs.append('"%s"' % koji_pkg)
            extra.append("koji_pkgs = [%s]" % ', '.join(koji_pkgs))

        # add quotes...
        extra = ["'%s'" % e for e in extra]
        # ... and return as string that will be eval'd as a Python list
        return "[%s]" % ', '.join(extra)

    def _generate_control_file(self):
        '''
        Generates a controle file from a template
        '''
        custom_job_cfg = self._generate_job_config()
        input_file = self.command_line_options.control_file
        logging.debug('Generating control file from template: %s' % input_file)
        template = string.Template(open(input_file).read())
        output_fd, path = tempfile.mkstemp(prefix='atest_control_', dir='/tmp')
        logging.debug('Generated control file to be saved at: %s' % path)
        parameters_dict = {"custom_job_cfg": custom_job_cfg}
        control_file_text = template.substitute(parameters_dict)
        os.write(output_fd, control_file_text)
        os.close(output_fd)
        return path

    def execute(self):
        if not self._process_options():
            self.generic_error('Some command line options validation failed. '
                               'Aborting job creation.')
            return

        #
        # add timestamp to the jobname
        #
        if self.command_line_options.timestamp:
            logging.debug("Adding timestamp to jobname")
            timestamp = time.strftime(" %Y-%m-%d %H:%M:%S", time.localtime())
            self.jobname += timestamp
            self.data['name'] = self.jobname

        execute_results = super(site_job_create, self).execute()
        self.output(execute_results)


for cls in [getattr(job, n) for n in dir(job) if not n.startswith("_")]:
    if not inspect.isclass(cls):
        continue
    cls_name = cls.__name__
    site_cls_name = 'site_' + cls_name
    if hasattr(sys.modules[__name__], site_cls_name):
        continue
    bases = (site_job, cls)
    members = {'__doc__': cls.__doc__}
    site_cls = new.classobj(site_cls_name, bases, members)
    setattr(sys.modules[__name__], site_cls_name, site_cls)
