import unittest
import types

import core.theme
import core.event
import core.widget


class theme(unittest.TestCase):
    def setUp(self):
        core.event.clear()
        self.invalidThemeName = "this-theme-does-not-exist"
        self.validThemeName = "default"
        self.defaultsTheme = {"defaults": {"fg": "red", "bg": "black"}}
        self.cycleTheme = {
            "cycle": [
                {"fg": "red", "bg": "black"},
                {"fg": "black", "bg": "red"},
                {"fg": "white", "bg": "blue"},
            ]
        }
        self.colorTheme = {"colors": [{"red": "#ff0000", "blue": "#0000ff"}]}
        self.walTheme = {"colors": ["wal"]}
        self.cycleValueTheme = {"defaults": {"fg": ["red", "green", "blue"]}}
        self.stateTheme = {"warning": {"fg": "yellow"}, "critical": {"fg": "red"}}

    def test_invalid_theme(self):
        with self.assertRaises(RuntimeError):
            core.theme.Theme(self.invalidThemeName)

    def test_valid_theme(self):
        theme = core.theme.Theme(self.validThemeName)
        self.assertEqual(self.validThemeName, theme.name)

    def test_defaults(self):
        theme = core.theme.Theme(raw_data=self.defaultsTheme)
        self.assertEqual(self.defaultsTheme["defaults"]["fg"], theme.get("fg"))
        self.assertEqual(self.defaultsTheme["defaults"]["bg"], theme.get("bg"))

    def test_cycle(self):
        theme = core.theme.Theme(raw_data=self.cycleTheme)
        self.assertEqual(None, theme.get("prev-bg"))
        self.assertEqual(self.cycleTheme["cycle"][0]["fg"], theme.get("fg"))
        self.assertEqual(self.cycleTheme["cycle"][0]["bg"], theme.get("bg"))
        core.event.trigger("next-widget")
        self.assertEqual(self.cycleTheme["cycle"][0]["bg"], theme.get("bg", "previous"))
        core.event.trigger("next-widget")
        self.assertEqual(self.cycleTheme["cycle"][2]["fg"], theme.get("fg"))
        self.assertEqual(self.cycleTheme["cycle"][2]["bg"], theme.get("bg"))

        with unittest.mock.patch("core.output.sys.stdout"):
            core.event.trigger("draw")
            self.assertEqual(self.cycleTheme["cycle"][0]["fg"], theme.get("fg"))
            self.assertEqual(self.cycleTheme["cycle"][0]["bg"], theme.get("bg"))

    def test_custom_iconset(self):
        theme = core.theme.Theme(raw_data=self.defaultsTheme)
        self.assertNotEqual("aaa", theme.get("padding"))
        theme = core.theme.Theme(
            raw_data=self.defaultsTheme, iconset={"defaults": {"padding": "aaa"}}
        )
        self.assertEqual("aaa", theme.get("padding"))

    def test_colors(self):
        theme = core.theme.Theme(raw_data=self.defaultsTheme)
        self.assertEqual({}, theme.keywords())
        theme = core.theme.Theme(raw_data=self.colorTheme)
        self.assertEqual(self.colorTheme["colors"][0], theme.keywords())

    def test_wal_colors(self):
        with unittest.mock.patch("core.theme.io") as io:
            with unittest.mock.patch("core.theme.os") as os:
                os.path.isfile.return_value = True
                io.open.return_value = unittest.mock.MagicMock()
                io.open.return_value.__enter__.return_value.read.return_value = """
                    { "colors": { "red": "#ff0000" } }
                """

                theme = core.theme.Theme(raw_data=self.walTheme)
                self.assertEqual({"red": "#ff0000"}, theme.keywords())

    def test_wal_special(self):
        with unittest.mock.patch("core.theme.io") as io:
            with unittest.mock.patch("core.theme.os") as os:
                os.path.isfile.return_value = True
                io.open.return_value.__enter__.return_value.read.return_value = """
                    { "special": { "background": "#ff0000" } }
                """

                theme = core.theme.Theme(raw_data=self.walTheme)
                self.assertEqual({"background": "#ff0000"}, theme.keywords())

    def test_cycle_value(self):
        widget = core.widget.Widget()
        expected = self.cycleValueTheme["defaults"]["fg"]
        theme = core.theme.Theme(raw_data=self.cycleValueTheme)

        for i in range(0, len(expected) * 3):
            self.assertEqual(expected[i % len(expected)], theme.get("fg", widget))
            self.assertEqual(
                expected[i % len(expected)], theme.get("fg", widget)
            )  # ensure multiple invocations are OK
            core.event.trigger("draw")

    def test_state(self):
        widget = core.widget.Widget()
        theme = core.theme.Theme(raw_data=self.stateTheme)

        self.assertEqual(None, theme.get("fg", widget))

        widget.state = types.MethodType(lambda self: ["warning"], widget)
        self.assertEqual(self.stateTheme["warning"]["fg"], theme.get("fg", widget))

        widget.state = types.MethodType(lambda self: ["critical"], widget)
        self.assertEqual(self.stateTheme["critical"]["fg"], theme.get("fg", widget))


# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4