# L-11 MCS 275 Fri 8 Feb 2008 : classtree.py

# object oriented implementation of a binary tree

class Node:
   """
   defines a node in a binary tree
   """
   def __init__(self,data):
      """
      returns a node with data
      """
      self._left = None
      self._data = data
      self._right = None

   def value(self):
      """
      returns data at the node
      """
      return self._data

   def __str__(self):
      """
      data at node represented as string
      """
      return str(self._data)

class Tree:
   """
   defines a binary tree
   """
   def __init__(self):
      """
      returns an empty tree
      """
      self._root = None

   def add(self,n):
      """
      adds the number in the tree
      """
      if self._root is None:
         self._root = Node(n)
      else:
         self.insert(self._root,n)

   def insert(self,nd,n):
      """
      inserts n to the node 
      """
      if n < nd.value():
         if nd._left is None:
            nd._left = Node(n)
         else:
            self.insert(nd._left,n)
      else:
         if nd._right is None:
            nd._right = Node(n)
         else:
            self.insert(nd._right,n)

   def show(self,nd,k):
      """
      returns a string to display a tree,
      for current node nd and level k
      """
      s = (k-1)*"|  "
      if k > 0: s = s + "|->"
      s = s + str(nd) + "\n"
      if not nd._left is None:
         s = s + self.show(nd._left,k+1)
      if not nd._right is None:
         s = s + self.show(nd._right,k+1)
      return s

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

   def __repr__(self):
      """
      prints the string representation
      """
      print str(self)
      return ""

   def preorderNodes(self,nd):
      """
      returns a list by traversing nodes in preorder 
      """
      L = []
      if not nd._left is None:
         L = self.preorderNodes(nd._left)
      L.append(nd.value())
      if not nd._right is None:
         L = L + self.preorderNodes(nd._right)
      return L

   def preorder(self):
      """
      returns a list in preorder
      """
      if self._root is None:
         return [] 
      else:
         return self.preorderNodes(self._root)

   def inorderNodes(self,nd):
      """
      returns a list by traversing nodes in inorder 
      """
      L = [nd.value()]
      if not nd._left is None:
         L = L + self.inorderNodes(nd._left)
      if not nd._right is None:
         L = L + self.inorderNodes(nd._right)
      return L

   def inorder(self):
      """
      returns a list in inorder
      """
      if self._root is None:
         return [] 
      else:
         return self.inorderNodes(self._root)

   def postorderNodes(self,nd):
      """
      returns a list by traversing nodes in postorder 
      """
      L = []
      if not nd._right is None:
         L = self.postorderNodes(nd._right)
      L.append(nd.value())
      if not nd._left is None:
         L = L + self.postorderNodes(nd._left)
      return L

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

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

if __name__ == "__main__" : main()
