#!/usr/bin/python2
# -*- coding: utf-8 -*-
#
# Copyright 2016 Nandaja Varma <nvarma@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.


import argparse
import os
import shutil
import subprocess
import sys
import time
from collections import OrderedDict
from gdeploylib import *
from gdeploycore import call_core_functions
from platform import dist
from pkg_resources import get_distribution

helpers = Helpers()

def parse_arguments(args=None):
    '''
    This method uses argparser to parse the command line inputs
    to the gdeploy script
    '''
    usage = 'gdeploy [-h] [-v] [-vv] [-k] -c CONFIG_FILE'
    parser = argparse.ArgumentParser(usage=usage)
    parser.add_argument('--version',
                        action='version',
                        version='%(prog)s ' +
                        get_distribution('gdeploy').version)
    parser.add_argument('-c', dest='config_file',
                        help="Configuration file",
                        type=argparse.FileType('rt'))
    parser.add_argument('-k', dest='keep',
                        action='store_true',
                        help="Keep the generated ansible utility files")
    parser.add_argument('--trace', dest='trace',
                        action='store_true',
                        help="Turn on the trace messages in logs")
    parser.add_argument('-vv', dest='verbose',
                        action='store_true',
                        help="verbose mode")
    parser.add_argument('--addfeature', dest='feature_name',
                        help="Add new feature to gdeploy")

    try:
        args = parser.parse_args(args=args)
    except IOError as msg:
        parser.error(str(msg))
    if not args.config_file:
        if not args.feature_name:
            parser.print_help()
            try:
                Global.logger.error("Invalid usage")
            except:
                pass
            return None
        else:
            add_feature(args.feature_name)
            return None
    return args

def check_ansible_installation():
    # On RHEL6 machines complain if ansible is not installed. We do not handle
    # dependencies in spec file, since ansible is not shipped with RHEL6.

    dist_type = dist()
    op_system = dist_type[0]
    if op_system != 'redhat':
        Global.logger.info("A non-redhat Operating System is detected. No further checks will be executed")
        return
    major_vers = dist_type[1].split('.')[0]

    # gdeploy currently is supported only on RHEL6 or above
    if int(major_vers) < 6:
        msg = "Error: gdeploy is supported only on RHEL6 or above"
        print msg
        Global.logger.error(msg)
        helpers.cleanup_and_quit()

    if major_vers == '6':
        pkg = subprocess.Popen(["rpm", "-qa", "ansible"],
                               stdout=subprocess.PIPE).communicate()[0]
        msg =  "Please install Ansible(version >= 2.2) to use gdeploy."
        if pkg == '':           # Ansible not installed
            print "Error: " + msg
            Global.logger.error(msg)
            helpers.cleanup_and_quit()
        else:                   # Extraxt ansible version
            if Global.trace:
                Global.logger.info("Found package: %s"%pkg)
            ansible_version = pkg.split('-')[1]
            major_version = int(ansible_version[0])
            minor_version = int(ansible_version[2])
            if major_version < 2 or (major_version == 2 and minor_version < 2):
                print "Error: " + msg
                Global.logger.error(msg)
                helpers.cleanup_and_quit()
    return

def init_global_values(args):
    global helpers
    sections_list = []
    Global.config = helpers.read_config(args.config_file.name)
    Global.verbose = '-vv' if args.verbose else ''
    Global.keep = args.keep
    Global.trace = args.trace

    for sec in  Global.config._sections:
        sections = helpers.parse_patterns(sec)
        for each in sections:
            sections_list.append((each,
                dict(Global.config._sections[sec])))
    Global.sections = OrderedDict(sections_list)
    if Global.trace:
        Global.logger.info("Initialised global variables.")

def create_files_and_dirs():
    global helpers
    '''
    Create required directories for all the configuration data to go in.
    '''
    helpers.mk_dir(Global.group_vars_dir)
    if Global.trace:
        Global.logger.info("Created group_vars directory: %s"%
                           Global.group_vars_dir)
    helpers.touch_file(Global.group_file)
    if Global.trace:
        Global.logger.info("Created group file: %s"%Global.group_file)
    helpers.mk_dir(Global.host_vars_dir)
    if Global.trace:
        Global.logger.info("Created host_vars directory: %s"%
                           Global.host_vars_dir)

def create_playbooks_in_local():
    '''
    Templates directory in this codebase's repo will be moved to
    /var/tmp/playbooks
    '''
    global helpers
    playbooks_path_pkg = '/usr/share/gdeploy/playbooks'
    playbooks_env_var = os.getenv('GDEPLOY_TEMPLATES')
    # Is environment variable GDEPLOY_TEMPLATES set
    if playbooks_env_var:
        if Global.trace:
            Global.logger.info("Environment variable GDEPLOY_TEMPLATES "
                               "is set to: %s"% playbooks_env_var)
        playbooks_dir = helpers.get_file_dir_path(playbooks_env_var,
                                                  'playbooks')
    # Or assumes the templates are present as a part of ansible installation
    else:
        playbooks_dir = playbooks_path_pkg

    Global.logger.info("Playbook directory for the run: %s"%playbooks_dir)

    if not os.path.isdir(playbooks_dir):
        msg = "Playbook files not found.\n\n" \
            "Gdeploy looks inside the directory %s or \n" \
            "wants the environment varible GDEPLOY_TEMPLATES set."\
             % (playbooks_path_pkg)
        print "Error: " + msg
        Global.logger.error(msg.strip('\n\t\r'))
        if Global.trace:
            Global.logger.info("Cleaning up the process and quitting.")
        helpers.cleanup_and_quit()
    helpers.copy_files(playbooks_dir)

def main(arg):
    Global.logger.info("\n\n")
    Global.logger.info("**** gdeploy run started with options %s ****"%arg)
    Global.logger.info("For complete CLI log, set log_path in "\
                       "/etc/ansible/ansible.cfg")
    args = parse_arguments(arg)
    if args:
        init_global_values(args)
        check_ansible_installation()
        create_files_and_dirs()
        helpers.get_hostnames()
        # Log the hosts here, helper.get_hostnames is called from
        # multiple functions
        Global.logger.info("gdeploy hosts: %s"%Global.hosts)
        create_playbooks_in_local()
        call_core_functions()
        call_features()
        if Global.trace:
            Global.logger.info("Retrieving hostnames and the feature directory.")
        helpers.cleanup_and_quit(0)
        if Global.trace:
            Global.logger.info("Run was successful, cleaning up and quitting.")
    else:
        Global.logger.info("Error while parsing the config file.")

if __name__ == '__main__':
    log_event()
    main(sys.argv[1:])
