import unittest
import collections


class TestLayer(unittest.TestCase):

    # ------
    # Glyphs
    # ------

    def getLayer_glyphs(self):
        layer, _ = self.objectGenerator("layer")
        for name in "ABCD":
            layer.newGlyph(name)
        return layer

    def test_len(self):
        layer = self.getLayer_glyphs()
        self.assertEqual(
            len(layer),
            4
        )

    def _testInsertGlyph(self, setGlyphName=True):
        layer, _ = self.objectGenerator("layer")
        glyph, _ = self.objectGenerator("glyph")
        pen = glyph.getPen()
        pen.moveTo((100, 0))
        pen.lineTo((100, 500))
        pen.lineTo((500, 500))
        pen.closePath()
        glyph.width = 600
        if setGlyphName:
            glyph.name = "test"
        layer["test"] = glyph
        self.assertTrue("test" in layer)
        self.assertEqual(
            layer["test"].bounds,
            glyph.bounds
        )

    def test_set_glyph(self):
        self._testInsertGlyph(setGlyphName=True)

    def test_set_glyph_with_name_None(self):
        self._testInsertGlyph(setGlyphName=False)

    def test_get_glyph_in_font(self):
        layer = self.getLayer_glyphs()
        self.assertEqual(
            layer["A"].name,
            "A"
        )

    def test_get_glyph_not_in_font(self):
        layer = self.getLayer_glyphs()
        with self.assertRaises(KeyError):
            layer["E"]

    # ----
    # Hash
    # ----

    def test_hash_object_self(self):
        layer_one = self.getLayer_glyphs()
        self.assertEqual(
            hash(layer_one),
            hash(layer_one)
        )

    def test_hash_object_other(self):
        layer_one = self.getLayer_glyphs()
        layer_two = self.getLayer_glyphs()
        self.assertNotEqual(
            hash(layer_one),
            hash(layer_two)
        )

    def test_hash_object_self_variable_assignment(self):
        layer_one = self.getLayer_glyphs()
        a = layer_one
        self.assertEqual(
            hash(layer_one),
            hash(a)
        )

    def test_hash_object_other_variable_assignment(self):
        layer_one = self.getLayer_glyphs()
        layer_two = self.getLayer_glyphs()
        a = layer_one
        self.assertNotEqual(
            hash(layer_two),
            hash(a)
        )

    def test_is_hashable(self):
        layer_one = self.getLayer_glyphs()
        self.assertTrue(
            isinstance(layer_one, collections.abc.Hashable)
        )

    # --------
    # Equality
    # --------

    def test_object_equal_self(self):
        layer_one = self.getLayer_glyphs()
        self.assertEqual(
            layer_one,
            layer_one
        )

    def test_object_not_equal_other(self):
        layer_one = self.getLayer_glyphs()
        layer_two = self.getLayer_glyphs()
        self.assertNotEqual(
            layer_one,
            layer_two
        )

    def test_object_equal_self_variable_assignment(self):
        layer_one = self.getLayer_glyphs()
        a = layer_one
        self.assertEqual(
            layer_one,
            a
        )

    def test_object_not_equal_self_variable_assignment(self):
        layer_one = self.getLayer_glyphs()
        layer_two = self.getLayer_glyphs()
        a = layer_one
        self.assertNotEqual(
            layer_two,
            a
        )

    # ---------
    # Selection
    # ---------

    def test_selected_true(self):
        layer = self.getLayer_glyphs()
        try:
            layer.selected = False
        except NotImplementedError:
            return
        layer.selected = True
        self.assertEqual(
            layer.selected,
            True
        )

    def test_selected_false(self):
        layer = self.getLayer_glyphs()
        try:
            layer.selected = False
        except NotImplementedError:
            return
        self.assertEqual(
            layer.selected,
            False
        )

    # Glyphs

    def test_selectedGlyphs_default(self):
        layer = self.getLayer_glyphs()
        try:
            layer.selected = False
        except NotImplementedError:
            return
        self.assertEqual(
            layer.selectedGlyphs,
            ()
        )

    def test_selectedGlyphs_setSubObject(self):
        layer = self.getLayer_glyphs()
        try:
            layer.selected = False
        except NotImplementedError:
            return
        glyph1 = layer["A"]
        glyph2 = layer["B"]
        glyph1.selected = True
        glyph2.selected = True
        self.assertEqual(
            tuple(sorted(layer.selectedGlyphs, key=lambda glyph: glyph.name)),
            (glyph1, glyph2)
        )

    def test_selectedGlyphs_setFilledList(self):
        layer = self.getLayer_glyphs()
        try:
            layer.selected = False
        except NotImplementedError:
            return
        glyph3 = layer["C"]
        glyph4 = layer["D"]
        layer.selectedGlyphs = [glyph3, glyph4]
        self.assertEqual(
            tuple(sorted(layer.selectedGlyphs, key=lambda glyph: glyph.name)),
            (glyph3, glyph4)
        )

    def test_selectedGlyphs_setEmptyList(self):
        layer = self.getLayer_glyphs()
        try:
            layer.selected = False
        except NotImplementedError:
            return
        glyph1 = layer["A"]
        glyph1.selected = True
        layer.selectedGlyphs = []
        self.assertEqual(
            layer.selectedGlyphs,
            ()
        )

    # Glyph Names

    def test_selectedGlyphNames_default(self):
        layer = self.getLayer_glyphs()
        try:
            layer.selected = False
        except NotImplementedError:
            return
        self.assertEqual(
            layer.selectedGlyphs,
            ()
        )

    def test_selectedGlyphNames_setSubObject(self):
        layer = self.getLayer_glyphs()
        try:
            layer.selected = False
        except NotImplementedError:
            return
        glyph1 = layer["A"]
        glyph2 = layer["B"]
        glyph1.selected = True
        glyph2.selected = True
        self.assertEqual(
            tuple(sorted(layer.selectedGlyphNames)),
            ("A", "B")
        )

    def test_selectedGlyphNames_setFilledList(self):
        layer = self.getLayer_glyphs()
        try:
            layer.selected = False
        except NotImplementedError:
            return
        layer.selectedGlyphNames = ["C", "D"]
        self.assertEqual(
            tuple(sorted(layer.selectedGlyphNames)),
            ("C", "D")
        )

    def test_selectedGlyphNames_setEmptyList(self):
        layer = self.getLayer_glyphs()
        try:
            layer.selected = False
        except NotImplementedError:
            return
        glyph1 = layer["A"]
        glyph1.selected = True
        layer.selectedGlyphNames = []
        self.assertEqual(
            layer.selectedGlyphNames,
            ()
        )
