#!/usr/bin/env python
# -*- coding:utf-8 -*-

import os
import re
import sys
import logging
import shutil
import datetime
import yaml
import optparse

try:
    import caliper.common as common
except ImportError:
    import common

from caliper.server.build import build
from caliper.server.run import run
from caliper.server.parser_process import parser_log
from caliper.server.score import score
from caliper.server.score import write_results
from caliper.server.shared.settings import settings
from caliper.server.shared import caliper_path
from caliper.server.shared import send_mails
from caliper.server import summary
from caliper.server.parser_process import normalize
from caliper.server.shared.caliper_path import folder_ope as Folder
from caliper.server.upload import upload
from caliper.server.hosts import host_factory


def build_all_tests(test_node, remote_host,c_option, f_option, sections):
    try:
        result = build.build_for_target(test_node, remote_host, c_option, f_option, clear, sections)
    except Exception, e:
        raise
    return result

def run_caliper(test_node, f_option, sections, run_case_list, num):
    try:
        logging.debug("begining to run Caliper")
        result = run.run_caliper_tests(test_node, f_option, c_option, sections, run_case_list, num)
    except Exception:
        print e
        logging.info("There is wrong when running Caliper")
        raise
    else:
        return result

def parser_caliper_logs(sections, run_case_list):
    try:
        logging.debug("begining to Parse Caliper Logs")
        result = parser_log.parser_caliper_tests(sections, run_case_list)
    except Exception, e:
        print e
        logging.info("There is wrong when parsing Caliper")
        raise
    else:
        return result

def optional_arg(arg_default):
    '''
    parser.add_option
    :param arg_default: arg default value
    :return: if no value return arg_default else return value
    '''
    def func(option, opt_str, value, parser):
        if parser.rargs and not parser.rargs[0].startswith('-'):
            val = parser.rargs[0]
            parser.rargs.pop(0)
        else:
            val = arg_default
        setattr(parser.values, option.dest, val)

    return func

if __name__=="__main__":
    parser = optparse.OptionParser()
    parser.add_option("-v", "--version", action="store_true", dest="version", default=False, help="display version")
    parser.add_option("-a", "--all", action="store_true", dest="all", default=False, help="run all")
    parser.add_option('-b', '--build', action='callback', callback=optional_arg('all_build'), dest='build',
                      help="select to incrementally build the selected test tools")
    parser.add_option('-r', '--run', action='callback', callback=optional_arg('all_run'), dest='run',
                      help="select to run the selected test tools")
    parser.add_option("-q", "--cleanbuild", action="store_true",
            dest="cleanbuild", help="select to clean build the selected tools")
    parser.add_option("-p", "--parse", action="store_true", dest="parse", default=False,
                        help="select to Parse the selected test tools")
    parser.add_option("-s", "--score", action="store_true", dest="score", default=False,
                        help="select to Score the selected test tools")
    parser.add_option("-u", "--upload", action="store_true", dest="upload", default=False,
            help="select the webpage to upload")
    parser.add_option("-e", "--email", action="store_true", dest="send_email",
            default=False, help="Select to send mail to the receivers or not")
    parser.add_option( "-f", "--folder", action="store", dest="folder",
            default="", help="assign a folder to store the results")
    parser.add_option("-l", "--benchmarklist", action="store_true", dest="benchmarklist", default=False,
                        help="display support benchmark list")
    parser.add_option("-d", "--debug", action="store_true", dest="debug", default=False,help="debug mode")
    parser.add_option("-m", "--message", action="store", dest="message",default="", help="add a message for test")
    parser.add_option("-t", "--times", action="store", dest="times", default="", help="test times")
    parser.add_option("-n", "--node", action="store", dest="node", default="", help="Select testnode to run test")
    parser.add_option("-c", "--concurrent", action="store_true", dest="concurrent", default=False,
                        help="concurrent test")

    (options, args) = parser.parse_args()
    start_time = datetime.datetime.now()

    if options.debug:
        logging.basicConfig(level=logging.DEBUG)
    else:
        logging.basicConfig(level=logging.INFO)

    if options.version:
        version = common.VERSION
        print version
        sys.exit()
    config_files = os.path.join(caliper_path.config_files.config_dir, 'cases_config.json')
    fp = open(config_files, 'r')
    tool_list = []
    case_list = yaml.load(fp.read())
    dimension_list = {}
    for dimension in case_list:
        dimension_list[dimension] = []
        for i in range(len(case_list[dimension])):
            for tool in case_list[dimension][i]:
                dimension_list[dimension].append(tool)

    if options.benchmarklist:
        for dimen in dimension_list:
            print dimen + ':'
            for tool in dimension_list[dimen]:
                print '    '+tool
        sys.exit()

    f_option = 0
    if options.folder:
        f_option = 1
        caliper_path.folder_ope.workspace = options.folder
        caliper_path.folder_ope.set_up_path()
        from caliper.server.shared.caliper_path import folder_ope as FOLDER
        if os.path.exists(FOLDER.caliper_log_file):
            fp = open(FOLDER.caliper_log_file,'a+')
            fp.write("re-execution with -f .It may be execution of all the tools or some specific tools as specified in the config file \n")
            fp.close()
    if not os.path.exists(caliper_path.folder_ope.workspace):
        try:
            os.makedirs(caliper_path.folder_ope.workspace)
        except Exception as e:
            print e
            sys.exit(1)

    # get config file
    caliper_path.config_files.name = caliper_path.folder_ope.workspace
    caliper_path.config_files.setup_path()
    if not os.path.exists(caliper_path.folder_ope.workspace + "/config"):
        shutil.copytree(caliper_path.caliper_config_file, caliper_path.folder_ope.workspace + "/config")

    settings.set_config_files(os.path.join(
        caliper_path.config_files.config_dir,
        'project_config.cfg'
    ))

    # create test dir
    caliper_path.create_dir()
    remote_host = host_factory.get_remote_host()
    num = 0
    if options.times:
        num = int(options.times)
    test_node = ''
    if options.node:
        test_node = options.node
    else:
        test_node = caliper_path.sections[0]

    c_option = 0
    if options.concurrent:
        c_option = 1

    clear = 0
    if options.cleanbuild:
        clear = 1

    if options.message:
        message_file = Folder.caliper_message_file
        mp = open(message_file, 'a+')
        mp.write(options.message)
        mp.close()

    if options.all:
        sections, run_case_list = settings.get_run_sections(c_option, dimension_list, 'all')
        settings.push_ssh_key()
        # build
        result1 = build_all_tests(test_node, remote_host, c_option, f_option, sections)
        # run
        result2 = run_caliper(test_node, f_option, sections, run_case_list, num)

        # parser
        try:
            result2 = parser_caliper_logs(sections, run_case_list)
            if result2:
               sys.exit()
            result2 = score.compute_caliper_logs(sections, run_case_list,1)
        except Exception:
            raise

        # score
        try:
            result2 = score.compute_caliper_logs(sections, run_case_list,2)
            # if intermediate:
            #     parser_caliper(remote_host)
        except Exception as e:
            print e
            pass

        end_time = datetime.datetime.now()
        interval = end_time - start_time
        try:
            summary_path = os.path.join(caliper_path.folder_ope.workspace, 'output', 'results_summary.log')
            json_file = os.path.join(caliper_path.folder_ope.workspace, "output", "results", "json",
                                     'hardwareinfo.json')
            summary.output_summary_info(json_file, summary_path, interval.seconds)
        except Exception, e:
            logging.info(e)
            pass

        # upload
        try:
            # filter all the test cases to get only the common test cases passed in all the plaforms. other test cases marked as INVALID.
            flag = write_results.yaml_filter(Folder.yaml_dir)

            # Reads one value from all the plaforms and then compares this values with each other to rank them. This is done for all the values in the yaml files. These new values are writed to _score_post.yaml.
            write_results.normalize_caliper()

            # computes the score i.e TOTAL_SCORE in the form of 100% for each section in the newly generated _post.yaml and _post.json files. _post.yaml file is to be used for image creation and _post.json file is to be used for table creation in HTML report.
            normalize.normalise()
        except Exception as e:
            print e
        try:
            upload.upload_url(caliper_path.folder_ope.workspace)
        except:
            pass

    if options.build or options.run:
        settings.push_ssh_key()
        if options.build:
            sections, run_case_list = settings.get_run_sections(c_option, dimension_list, options.build)
            result1 = build_all_tests(test_node, remote_host, c_option, f_option, sections)

        if options.run:
            sections, run_case_list = settings.get_run_sections(c_option, dimension_list, options.run)
            result2 = run_caliper(test_node, f_option, sections, run_case_list, num)

    if options.parse:
        if options.run:
            sections, run_case_list = settings.get_run_sections(c_option, dimension_list, options.run)
        else:
            sections, run_case_list = settings.get_run_sections(c_option, dimension_list, 'all')
        try:
            result2 = parser_caliper_logs(sections, run_case_list)
            if result2:
               sys.exit()
            result2 = score.compute_caliper_logs(sections, run_case_list,1)
        except Exception:
            raise

    if options.score:
        if options.run:
            sections, run_case_list = settings.get_run_sections(c_option, dimension_list, options.run)
        else:
            sections, run_case_list = settings.get_run_sections(c_option, dimension_list, 'all')
        try:
            result2 = score.compute_caliper_logs(sections, run_case_list,2)
            # if intermediate:
            #     parser_caliper(remote_host)
        except Exception as e:
            print e
            pass

    if options.upload:
        end_time = datetime.datetime.now()
        interval = end_time - start_time
        try:
            summary_path = os.path.join(caliper_path.folder_ope.workspace, 'output', 'results_summary.log')
            json_file = os.path.join(caliper_path.folder_ope.workspace, "output", "results", "json",
                                     'hardwareinfo.json')
            summary.output_summary_info(json_file, summary_path, interval.seconds)
        except Exception, e:
            logging.info(e)
            pass
        try:
            # filter all the test cases to get only the common test cases passed in all the plaforms. other test cases marked as INVALID.
            flag = write_results.yaml_filter(Folder.yaml_dir)

            # Reads one value from all the plaforms and then compares this values with each other to rank them. This is done for all the values in the yaml files. These new values are writed to _score_post.yaml.
            write_results.normalize_caliper()

            # computes the score i.e TOTAL_SCORE in the form of 100% for each section in the newly generated _post.yaml and _post.json files. _post.yaml file is to be used for image creation and _post.json file is to be used for table creation in HTML report.

            normalize.normalise()
        except Exception as e:
            print e
        try:
            upload.upload_url(caliper_path.folder_ope.workspace)
        except:
            pass
    result_name = caliper_path.folder_ope.workspace.split(os.sep)[-1] + '.zip'
    result_path = caliper_path.CALIPER_REPORT_HOME
    if options.upload and options.send_email:
        result_path = os.path.join(result_path, result_name)
        if os.path.exists(result_path):
            send_mails.send_mails(result_path)
            print("\n'%s file has been sent, please check the mail\n" % result_name)
            sys.exit()
        if not os.path.exists(result_path):
            try:
                os.makedirs(caliper_path.folder_ope.workspace)
            except Exception as e:
                print("\nCan't able to send the mail as '%s' file is not created\n" % result_name)
                sys.exit()



    if options.folder and options.send_email:
        result_path = os.path.join(caliper_path.folder_ope.workspace, caliper_path.folder_ope.name,
                                   'results_summary.log')
        if os.path.exists(result_path):
             send_mails.send_mails(result_path)
             print("\n'results_summary.log' file has been sent, please check the mail\n")
             sys.exit()
        if not os.path.exists(result_path):
            try:
                os.makedirs(caliper_path.folder_ope.workspace)
            except Exception as e:
                print("\nCan't able to send the mail as 'results_summary.log' file is not present\n ")
                sys.exit()

    if not options.folder and options.send_email:
        result_path = os.path.join(caliper_path.folder_ope.workspace, caliper_path.folder_ope.name,
                                   'results_summary.log')
        if os.path.exists(result_path):
            send_mails.send_mails(result_path)
            print("\n'results_summary.log' file has been sent , please check the mail\n")
            sys.exit()
        if not os.path.exists(result_path):
            try:
                os.makedirs(caliper_path.folder_ope.workspace)
            except Exception as e:
                print("\n Can't able to send the mail as 'results_summary.log' file is not present\n ")
                sys.exit()

    if not options.upload and options.send_email:
        current_path = os.getcwd()
        flag = 0
        for root, _, files in sorted(os.walk(current_path)):
            for name in files:
                if re.search(result_name, name):
                    result_path = os.path.join(root, name)
                    flag = 1
                    break
            if flag == 1:
                break
        if os.path.exists(result_path):
            send_mails.send_mails(result_path)

