#!/usr/bin/env python

###############################################################################
# (c) Copyright 2016 CERN                                                     #
#                                                                             #
# This software is distributed under the terms of the GNU General Public      #
# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
#                                                                             #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization  #
# or submit itself to any jurisdiction.                                       #
###############################################################################
'''
Command line client that interfaces to the Installer class

:author: Stefan-Gabriel CHITIC
'''
from __future__ import print_function

import logging
import optparse
import sys
import traceback

import os

from lbCVMFSTools.Injector import injector
from lbCVMFSTools.Scheduler import Scheduler
from lbCVMFSTools.TaskHandlerInterface import TaskHandlerInterface
from lbCVMFSTools.TaskHandlers.NightliesInstallTask.NightliesInstallTask \
    import NightliesInstallTask
from lbCVMFSTools.TransactionHandlers.CVMFSTransactionHandler.\
    CVMFSTranscationHandler import CVMFSTransactionHandler
from lbCVMFSTools.TransactionHandlerInterface import \
    TransactionHandlerInterface
from lbCVMFSTools.TaskHandlers.NightliesInstallTask.Utils import PathManager


# Class for known install exceptions
###############################################################################


class CVMFSNightliesInstallException(Exception):
    """ Custom exception for cvmfs-install

    :param msg: the exception message
    """

    def __init__(self, msg):
        """ Constructor for the exception """
        # super(CVMFSNightliesInstallException, self).__init__(msg)
        Exception.__init__(self, msg)


# Classes and method for command line parsing
###############################################################################


class CVMFSNightliesInstallOptionParser(optparse.OptionParser):
    """ Custom OptionParser to intercept the errors and rethrow
    them as CVMFSNightliesInstallException """

    def error(self, msg):
        """
        Arguments parsing error message exception handler

        :param msg: the message of the exception
        :return: Raises CVMFSNightliesInstallException with the exception
        message
        """
        raise CVMFSNightliesInstallException("Error parsing arguments: " +
                                             str(msg))

    def exit(self, status=0, msg=None):
        """
        Arguments parsing error message exception handler

        :param status: the status of the application
        :param msg: the message of the exception
        :return: Raises CVMFSNightliesInstallException with the exception
        message
        """
        raise CVMFSNightliesInstallException("Error parsing arguments: " +
                                             str(msg))


class CVMFSNightliesInstallClient(object):
    """ Main class for the tool """

    def __init__(self, arguments=None, prog="CVMFSNightliesInstall"):
        """ Common setup for both clients """
        self.log = logging.getLogger(__name__)
        self.arguments = arguments
        self.installer = None
        self.prog = prog
        self.dry_run = None
        self.workspace = None
        self.installArea = None

        parser = CVMFSNightliesInstallOptionParser(usage=usage(self.prog))
        parser.add_option('--dry-run',
                          dest="dryrun",
                          default=False,
                          action="store_true",
                          help="Only print the command that will be run")
        parser.add_option('--workspace',
                          dest="workspace",
                          default=None,
                          action="store",
                          help="Sets a custom workspace. The default is the "
                               "user $HOME directory")
        parser.add_option('--installarea',
                          dest="installArea",
                          default=None,
                          action="store",
                          help="Sets a custom install area. The default is"
                               "/cvmfs")
        self.parser = parser

    def main(self):
        """ Main method for the ancestor:
        call parse and run in sequence

        :returns: the return code of the call
        """
        rc = 0
        try:
            opts, args = self.parser.parse_args(self.arguments)
            if len(args) != 1:
                raise CVMFSNightliesInstallException("Repo name needs to be"
                                                     " provided")
            self.reponame = args[0]
            if opts.dryrun:
                self.dry_run = True

            if opts.workspace:
                self.workspace = opts.workspace
            else:
                raise CVMFSNightliesInstallException("Workspace are needs "
                                                     "to be provided")
            if opts.installArea:
                self.installArea = opts.installArea
            else:
                raise CVMFSNightliesInstallException("Installation area are "
                                                     "needs to be provided")
            if self.workspace or self.installArea:
                pathManager = PathManager(workspace=self.workspace,
                                          installArea=self.installArea)
                injector.provide_instance(PathManager, pathManager)

            transactionHandler = CVMFSTransactionHandler(
                self.reponame,
                dry_run=self.dry_run)
            taskHandler = NightliesInstallTask(dry_run=self.dry_run)
            injector.provide_instance(TransactionHandlerInterface,
                                      transactionHandler)
            injector.provide_instance(TaskHandlerInterface, taskHandler)

            # Getting the function to be invoked
            self.run(opts, args)

        except CVMFSNightliesInstallException as lie:
            print("ERROR: " + str(lie), file=sys.stderr)
            self.parser.print_help()
            rc = 1
        except:
            print("Exception in lb-install:", file=sys.stderr)
            print('-'*60, file=sys.stderr)
            traceback.print_exc(file=sys.stderr)
            print('-'*60, file=sys.stderr)
            rc = 1
        return rc

    def run(self, opts, args):
        """ Main method for the command

        :param opts: The option list
        :param args: The arguments list
        """
        # Parsing first argument to check the mode
        Scheduler()


# Usage for the script
###############################################################################
def usage(cmd):
    """ Prints out how to use the script...

    :param cmd: the command executed
    """
    cmd = os.path.basename(cmd)
    return """\n%(cmd)s repo_name -  installs nighlties builds on CVMFS'

""" % {"cmd": cmd}


def CVMFSNightliesInstall(prog="CVMFSNightliesInstall"):
    """
    Default caller for command line CVMFSNightliesInstall client
    :param configType: the configuration used
    :param prog: the name of the executable
    """
    logging.basicConfig(format="%(levelname)-8s: %(asctime)s %(message)s")
    logging.getLogger().setLevel(logging.WARNING)
    sys.exit(CVMFSNightliesInstallClient(prog=prog).main())

# Main just chooses the client and starts it
if __name__ == "__main__":
    CVMFSNightliesInstall()
