#!/usr/bin/env python

import sys
import argparse
import os
import unittest2 as unittest
from ruamel import yaml

from smacha.util import Tester

import rospy
import rospkg
import rostest


ROS_TEMPLATES_DIR = '../src/smacha_ros/templates'
TEMPLATES_DIR = 'smacha_templates/smacha_test_examples'

WRITE_OUTPUT_FILES = False
OUTPUT_PY_DIR = '/tmp/smacha/smacha_test_examples/smacha_generated_py'
OUTPUT_YML_DIR = '/tmp/smacha/smacha_test_examples/smacha_generated_scripts'
CONF_FILE = 'test_examples_config.yml'
DEBUG_LEVEL = 1
CONF_DICT = {}

class TestGenerate(Tester):
    """Tester class for general unit testing of various SMACHA tool
    functionalities.

    The tests run by this class are performed by generating code using SMACHA
    scripts and templates and comparing the generated output code to the
    expected code from hand-written code samples.

    This includes testing both SMACHA YAML scripts generated by, e.g. the
    :func:`smacha.parser.contain` and :func:`smacha.parser.extract` methods,
    and Python code generated by the :func:`smacha.generator.run` method.
    """

    def __init__(self, *args, **kwargs):
        # Set Tester member variables
        self.set_write_output_files(WRITE_OUTPUT_FILES)
        self.set_output_py_dir(OUTPUT_PY_DIR)
        self.set_output_yml_dir(OUTPUT_YML_DIR)
        self.set_debug_level(DEBUG_LEVEL)

        # Store the base path
        self._base_path = os.path.dirname(os.path.abspath(__file__))

        # Call the parent constructor
        super(TestGenerate, self).__init__(
            *args,
            script_dirs=[os.path.join(self._base_path, 'smacha_scripts/smacha_test_examples')],
            template_dirs=[
                os.path.join(self._base_path, ROS_TEMPLATES_DIR),
                os.path.join(self._base_path, TEMPLATES_DIR)
                ],
            **kwargs)


    def test_generate(self):
        """Test generating against baseline files"""
        for test_case in CONF_DICT['TEST_GENERATE']:
            with self.subTest(test_case=test_case):
                test_params = test_case.values()[0]
                script_file = test_params['script']
                baseline = test_params['baseline']
                with open(os.path.join(self._base_path, 'smacha_test_examples/{}'.format(baseline))) as original_file:
                    generated_code = self._strip_uuids(self._generate(os.path.join(self._base_path, 'smacha_scripts/smacha_test_examples/{}'.format(script_file))))
                    original_code = original_file.read()
                self.assertTrue(self._compare(generated_code, original_code, file_a='generated', file_b='original'))


if __name__=="__main__":
    # Read the configuration file before parsing arguments,
    try:
        base_path = os.path.dirname(os.path.abspath(__file__))
        conf_file_loc = os.path.join(base_path, CONF_FILE)
        f = open(conf_file_loc)
        CONF_DICT = yaml.load(f)
    except Exception as e:
        print('Failed to read the configuration file. See error:\n{}'.format(e))
        exit()

    if CONF_DICT.has_key('WRITE_OUTPUT_FILES'):
        WRITE_OUTPUT_FILES = CONF_DICT['WRITE_OUTPUT_FILES']
    if CONF_DICT.has_key('OUTPUT_PY_DIR'):
        OUTPUT_PY_DIR = CONF_DICT['OUTPUT_PY_DIR']
    if CONF_DICT.has_key('OUTPUT_YML_DIR'):
        OUTPUT_YML_DIR = CONF_DICT['OUTPUT_YML_DIR']
    if CONF_DICT.has_key('DEBUG_LEVEL'):
        DEBUG_LEVEL = CONF_DICT['DEBUG_LEVEL']

    rospy.init_node('test_smacha_ros_generate',log_level=rospy.DEBUG)
    rostest.rosrun('smacha_ros', 'test_smacha_ros_generate', TestGenerate)