from abc import abstractmethod
from rna.pattern.composite import Component, Leaf, Composite


def test_basics():
    composite = Composite()
    assert composite.parent is None

    leaf = Leaf()
    assert leaf.parent is None


class MyLeaf(Leaf):
    def operation(self) -> str:
        return "Leaf"


class MyComposite(Composite):
    def operation(self) -> str:
        results = []
        for child in self._children:
            results.append(child.operation())
        return f"Branch({'+'.join(results)})"


def test_composite_pattern():
    # Test the behavior of the Composite pattern implementation
    simple = MyLeaf()
    assert simple.operation() == "Leaf"

    tree = MyComposite()
    branch1 = MyComposite()
    leaf1 = MyLeaf()
    leaf2 = MyLeaf()
    branch1.add(leaf1)
    branch1.add(leaf2)
    branch2 = MyComposite()
    leaf3 = MyLeaf()
    branch2.add(leaf3)
    tree.add(branch1)
    tree.add(branch2)

    assert tree.operation() == "Branch(Branch(Leaf+Leaf)+Branch(Leaf))"

    tree.add(simple)
    assert tree.operation() == "Branch(Branch(Leaf+Leaf)+Branch(Leaf)+Leaf)"

    # deconstruct
    assert len(tree._children) == 3
    assert len(branch1._children) == 2
    branch1.remove(leaf1)
    assert len(branch1._children) == 1
    branch1.remove(leaf2)
    assert len(branch1._children) == 0
    assert len(tree._children) == 3
    tree.remove(branch1)
    assert len(tree._children) == 2
    tree.remove(simple)
    assert len(tree._children) == 1
    tree.remove(branch2)
    assert len(tree._children) == 0


class Graphic(Component):
    @abstractmethod
    def render(self) -> None:
        pass


class CompositeGraphic(Graphic.Composite):
    def render(self):
        for child in self._children:
            child.render()


class Ellipse(Graphic.Leaf):
    def __init__(self, name):
        self.name = name
        super().__init__()

    def render(self):
        print("Ellipse", self.name)


def test_auto_generated_composite_leaf_classes():
    ellipse1 = Ellipse("1")
    ellipse2 = Ellipse("2")
    ellipse3 = Ellipse("3")
    ellipse4 = Ellipse("4")
    graphic1 = CompositeGraphic()
    graphic2 = CompositeGraphic()
    graphic1.add(ellipse1)
    graphic1.add(ellipse2)
    graphic1.add(ellipse3)
    graphic2.add(ellipse4)
    graphic = CompositeGraphic()
    graphic.add(graphic1)
    graphic.add(graphic2)

    assert graphic.render() is None
