# L-14 MCS 275 Fri 10 Feb 2017 : classtree.py
"""
The class Tree defines an ordered binary tree:
all elements at the left of the data at each node
are smaller and all elements at the right branch
are larger than the data at the node.
While a Node is never None, a tree can be empty.
The class offers methods to list all nodes in
preorder, inorder, or postorder.
"""

from classnode import Node

class Tree(object):
    """
    Defines a ordered binary tree.
    """
    def __init__(self):
        """
        Returns an empty tree.
        """
        self._root = None

    def add(self, item):
        """
        Adds an item to the tree.
        """
        if self._root is None:
            self._root = Node(item)
        else:
            self._root.insert(item)

    def show(self, node, k):
        """
        Returns a string to display a tree,
        for the current node and level k.
        """
        result = (k-1)*"|  "
        if k > 0:
            result = result + "|->"
        result = result + str(node) + "\n"
        if node.left() is not None:
            result += self.show(node.left(), k+1)
        if node.right() is not None:
            result += self.show(node.right(), k+1)
        return result

    def __str__(self):
        """
        Returns the string representation.
        """
        if self._root is None:
            return ''
        else:
            result = self.show(self._root, 0)
            return result[0:len(result)-1]

    def __repr__(self):
        """
        The representation is the string representation.
        """
        return str(self)

    def inorder_nodes(self, node):
        """
        Returns a list by traversing nodes in inorder.
        """
        result = []
        if node.left() is not None:
            result = self.inorder_nodes(node.left())
        result.append(node.value())
        if node.right() is not None:
            result += self.inorder_nodes(node.right())
        return result

    def inorder(self):
        """
        Returns the data as a list in inorder.
        """
        if self._root is None:
            return []
        else:
            return self.inorder_nodes(self._root)

    def preorder_nodes(self, node):
        """
        Returns a list by traversing nodes in preorder.
        """
        result = [node.value()]
        if node.left() is not None:
            result += self.preorder_nodes(node.left())
        if node.right() is not None:
            result += self.preorder_nodes(node.right())
        return result

    def preorder(self):
        """
        Returns the data as a list in preorder.
        """
        if self._root is None:
            return []
        else:
            return self.preorder_nodes(self._root)

    def postorder_nodes(self, node):
        """
        Returns a list by traversing nodes in postorder.
        """
        result = []
        if node.left() is not None:
            result += self.postorder_nodes(node.left())
        if node.right() is not None:
            result += self.postorder_nodes(node.right())
        result.append(node.value())
        return result

    def postorder(self):
        """
        Returns a list in postorder.
        """
        if self._root is None:
            return []
        else:
            return self.postorder_nodes(self._root)

def main():
    """
    uses a tree to store strings
    """
    tree = Tree()
    tree.add("here")
    tree.add("comes")
    tree.add("the")
    tree.add("best")
    tree.add("part")
    tree.add("we")
    tree.add("have")
    print(tree)
    print(tree.preorder())
    print(tree.inorder())
    print(tree.postorder())

if __name__ == "__main__":
    main()
