from __future__ import print_function, unicode_literals, division

import unittest
import os
import re

from subprocess import check_output
from tempfile import mkdtemp

from pyrouge import Rouge155
from pyrouge.utils.file_utils import str_from_file, xml_equal


module_path = os.path.dirname(__file__)
os.chdir(module_path)
add_data_path = lambda p: os.path.join('data', p)
check_output_clean = lambda c: check_output(c).decode("UTF-8").strip()


class PyrougeTest(unittest.TestCase):

    def test_paths(self):
        rouge = Rouge155()

        def get_home_from_settings():
            with open(rouge.settings_file) as f:
                for line in f.readlines():
                    if line.startswith("home_dir"):
                        rouge_home = line.split("=")[1].strip()
            return rouge_home

        self.assertEqual(rouge.home_dir, get_home_from_settings())
        self.assertTrue(os.path.exists(rouge.bin_path))
        self.assertTrue(os.path.exists(rouge.data_dir))

        wrong_path = "/nonexisting/path/rewafafkljaerearjafankwe3"
        with self.assertRaises(Exception) as context:
            rouge.system_dir = wrong_path
        self.assertEqual(
            str(context.exception),
            "Cannot set {} directory because the path {} does not "
            "exist.".format("system", wrong_path))
        right_path = add_data_path("systems")
        rouge.system_dir = right_path
        self.assertEqual(rouge.system_dir, right_path)

        with self.assertRaises(Exception) as context:
            rouge.model_dir = wrong_path
        self.assertEqual(
            str(context.exception),
            "Cannot set {} directory because the path {} does not "
            "exist.".format("model", wrong_path))
        right_path = add_data_path("models")
        rouge.model_dir = right_path
        self.assertEqual(rouge.model_dir, right_path)

    def test_wrong_system_pattern(self):
        wrong_regexp = "adfdas454fd"
        rouge = Rouge155()
        rouge.system_dir = add_data_path("systems")
        rouge.model_dir = add_data_path("models")
        #rouge.system_filename_pattern = "SL.P.10.R.11.SL062003-(\d+).html"
        rouge.system_filename_pattern = wrong_regexp
        rouge.model_filename_pattern = "SL.P.10.R.[A-D].SL062003-#ID#.html"
        with self.assertRaises(Exception) as context:
            rouge.evaluate()
        self.assertEqual(
            str(context.exception),
            "Did not find any files matching the pattern {} in the system "
            "summaries directory {}.".format(wrong_regexp, rouge.system_dir))

    def test_wrong_model_pattern(self):
        rouge = Rouge155()
        rouge.system_dir = add_data_path("systems")
        rouge.model_dir = add_data_path("models_plain")
        rouge.system_filename_pattern = "SL.P.10.R.11.SL062003-(\d+).html"
        rouge.model_filename_pattern = "SL.P.10.R.[A-D].SL062003-#ID#.html"
        with self.assertRaises(Exception) as context:
            rouge.evaluate()
        match_string = (
            r"Could not find any model summaries for the system "
            r"summary with ID " + "(\d+)" + r". Specified model filename "
            r"pattern was: " + re.escape(rouge.model_filename_pattern))
        try:
            assert_regex = self.assertRegex
        except AttributeError:
            assert_regex = self.assertRegexpMatches
        assert_regex(str(context.exception), re.compile(match_string))

    def test_text_conversion(self):
        rouge = Rouge155()
        text = str_from_file(add_data_path("spl_test_doc"))
        html = rouge.convert_text_to_rouge_format(text, "D00000.M.100.A.C")
        target = str_from_file(add_data_path("spl_test_doc.html"))
        self.assertEqual(html, target)

    # only run this test if BeautifulSoup is installed
    try:
        from bs4 import BeautifulSoup

        def test_get_plain_text(self):
            input_dir = add_data_path("SL2003_models_rouge_format")
            output_dir = mkdtemp()
            target_dir = add_data_path("SL2003_models_plain_text")
            command = (
                "pyrouge_convert_rouge_format_to_plain_text "
                "-i {} -o {}".format(input_dir, output_dir))
            check_output(command.split())
            filenames = os.listdir(input_dir)
            for filename in filenames:
                output_file = os.path.join(output_dir, filename)
                output = str_from_file(output_file)
                target_file = os.path.join(target_dir, filename)
                target = str_from_file(target_file)
                self.assertEqual(output, target)
    except ImportError:
        pass

    def test_convert_summaries(self):
        input_dir = add_data_path("SL2003_models_plain_text")
        output_dir = mkdtemp()
        target_dir = add_data_path("SL2003_models_rouge_format")
        command = (
            "pyrouge_convert_plain_text_to_rouge_format -i {} -o {}".format(
                input_dir, output_dir))
        check_output(command.split())
        filenames = os.listdir(input_dir)
        for filename in filenames:
            output_file = os.path.join(output_dir, filename)
            output = str_from_file(output_file)
            target_file = os.path.join(target_dir, filename)
            target = str_from_file(target_file)
            filename = filename.replace(".html", "")
            target = target.replace(filename, "dummy title")
            self.assertEqual(output, target, filename)

    def test_config_file(self):
        rouge = Rouge155()
        rouge.system_dir = add_data_path("systems")
        rouge.model_dir = add_data_path("models")
        rouge.system_filename_pattern = "SL.P.10.R.11.SL062003-(\d+).html"
        rouge.model_filename_pattern = "SL.P.10.R.[A-D].SL062003-#ID#.html"
        rouge.config_file = add_data_path("config_test.xml")
        rouge.write_config(system_id=11)
        self.assertTrue(xml_equal(
            rouge.config_file,
            add_data_path("ROUGE-test_11.xml")))
        os.remove(rouge.config_file)

    def test_evaluation(self):
        rouge = Rouge155()
        rouge.system_dir = add_data_path("systems")
        rouge.model_dir = add_data_path("models")
        rouge.system_filename_pattern = "SL.P.10.R.11.SL062003-(\d+).html"
        rouge.model_filename_pattern = "SL.P.10.R.[A-D].SL062003-#ID#.html"
        pyrouge_output = rouge.evaluate(system_id=11).strip()
        rouge_command = (
            "{bin} -e {data} -c 95 -2 -1 -U -r 1000 -n 4 -w 1.2 "
            "-a -m {xml}".format(
                bin=rouge.bin_path,
                data=rouge.data_dir,
                xml=add_data_path("ROUGE-test_11.xml")))
        orig_rouge_output = check_output_clean(rouge_command.split())
        self.assertEqual(pyrouge_output, orig_rouge_output)

    def test_rouge_for_plain_text(self):
        model_dir = add_data_path("models_plain")
        system_dir = add_data_path("systems_plain")
        pyrouge_command = (
            "pyrouge_evaluate_plain_text_files -m {} -s {} -sfp "
            "D(\d+).M.100.T.A -mfp D#ID#.M.100.T.[A-Z] -id 1".format(
                model_dir, system_dir))
        pyrouge_output = check_output_clean(pyrouge_command.split())
        rouge = Rouge155()
        config_file = add_data_path("config_test2.xml")
        rouge_command = (
            "{bin} -e {data} -c 95 -2 -1 -U -r 1000 -n 4 -w 1.2 "
            "-a -m {xml}".format(
                bin=rouge.bin_path,
                data=rouge.data_dir,
                xml=config_file))
        orig_rouge_output = check_output_clean(rouge_command.split())
        self.assertEqual(pyrouge_output, orig_rouge_output)

    def test_write_config(self):
        system_dir = add_data_path("systems")
        model_dir = add_data_path("models")
        system_filename_pattern = "SL.P.10.R.11.SL062003-(\d+).html"
        model_filename_pattern = "SL.P.10.R.[A-D].SL062003-#ID#.html"
        config_file = os.path.join(mkdtemp(), "config_test.xml")
        command = (
            "pyrouge_write_config_file -m {m} -s {s} "
            "-mfp {mfp} -sfp {sfp} -c {c}".format(
                m=model_dir, s=system_dir,
                mfp=model_filename_pattern, sfp=system_filename_pattern,
                c=config_file))
        check_output(command.split())
        target_xml = add_data_path("config_test.xml")
        print(config_file, target_xml)
        self.assertTrue(xml_equal(config_file, target_xml))

    def test_options(self):
        rouge = Rouge155()
        model_dir = add_data_path("models_plain")
        system_dir = add_data_path("systems_plain")
        config_file = add_data_path("config_test2.xml")
        command_part1 = (
            "pyrouge_evaluate_plain_text_files -m {} -s {} -sfp "
            "D(\d+).M.100.T.A -mfp D#ID#.M.100.T.[A-Z] -id 1 -rargs".format(
                model_dir, system_dir))

        command_part2 = [
            "\"-e {data} -c 90 -2 -1 -U -r 1000 -n 2 -w 1.2 "
            "-a -m {xml}\"".format(
                data=rouge.data_dir, xml=config_file)]

        pyrouge_command = command_part1.split() + command_part2
        pyrouge_output = check_output_clean(pyrouge_command)
        rouge_command = (
            "{bin} -e {data} -c 90 -2 -1 -U -r 1000 -n 2 -w 1.2 "
            "-a -m {xml}".format(
                bin=rouge.bin_path, data=rouge.data_dir, xml=config_file))
        orig_rouge_output = check_output_clean(rouge_command.split())
        self.assertEqual(pyrouge_output, orig_rouge_output)


def main():
    unittest.main()

if __name__ == "__main__":
    main()
