#!/usr/bin/python3
#
#  V elementárním řešení bylo nešikovné, že implementace operátorů byla
#  roztroušená po celém programu, takže přidat nový operátor vyžadovalo
#  projít celý program.
#
#  Zde ukazujeme, jak oddělit implementaci operátorů do samostatných tříd
#  (odvozených od nějaké společné třídy Node).
#

class Node:

    def eval(self):
        raise NotImplementedError()


class NumNode(Node):

    def __init__(self, x):
        self.value = x

    def __str__(self):
        return str(self.value)

    def eval(self):
        return self.value


class AddNode(Node):

    def __init__(self, left, right):
        self.left = left
        self.right = right

    def __str__(self):
        return '(' + str(self.left) + '+' + str(self.right) + ')'

    def eval(self):
        return self.left.eval() + self.right.eval()


class SubNode(Node):

    def __init__(self, left, right):
        self.left = left
        self.right = right

    def __str__(self):
        return '(' + str(self.left) + '-' + str(self.right) + ')'

    def eval(self):
        return self.left.eval() - self.right.eval()


class MulNode(Node):

    def __init__(self, left, right):
        self.left = left
        self.right = right

    def __str__(self):
        return '(' + str(self.left) + '*' + str(self.right) + ')'

    def eval(self):
        return self.left.eval() * self.right.eval()


class DivNode(Node):

    def __init__(self, left, right):
        self.left = left
        self.right = right

    def __str__(self):
        return '(' + str(self.left) + '/' + str(self.right) + ')'

    def eval(self):
        return self.left.eval() // self.right.eval()


x = AddNode(MulNode(NumNode(3), NumNode(4)), SubNode(NumNode(5), NumNode(6)))
print(x)
print(x.eval())