/* Binary Tree Traversal Framework
   Top-level framework
   H. Conrad Cunningham
   Version #1: 15 October 2008
   Version #2: 29 April 2010   Separate each level into a separate file

This program is a relatively straightforward translation into Scala of
the non-generic Java code for the Binary Tree Traversal framework
described in the paper:

  H. C. Cunningham, Y. Liu, and C. Zhang. Using classic problems to
  teach Java framework design, Science of Computer Programming,
  Special Issue on Principles and Practice of Programming in Java
  (PPPJ 2004), Vol. 59, No. 1-2, pp. 147-169, January 2006. 
  doi: 10.10.16/j.scico.2005.07.009.

This Scala version uses a singleton object to replace the application
of the Singleton pattern in the Java version.  However, it does not
attempt to take advantage of other enhanced features of Scala.  For
example, this code just uses Scala traits to define the signatures of
the interfaces and does not use generics to avoid casting within
applications.

123456789012345678901234567890123456789012345678901234567890123456789012345678
*/


/* Class BinTree a Binary Tree base class structured for the role
   Component base class in the Composite design pattern.  It also has
   the role of Element in the Visitor design pattern.
*/

abstract class BinTree {
  // mutators
  def setValue(nv: Any)     { }
  def setLeft (nl: BinTree) { }       
  def setRight(nr: BinTree) { }

  // accept Visitor object
  def accept(vis: BinTreeVisitor) 

  //accessors
  def getValue: Any     = null 
  def getLeft:  BinTree = null
  def getRight: BinTree = null
}


/* Class Node is a binary tree node with a value and left and right
   subtrees.  This has the role of Composite subclass in the Composite
   design pattern and role of a ConcreteElement class in the Visitor
   pattern.
*/

class Node(v: Any, l: BinTree, r: BinTree) extends BinTree {

  // attributes
  private var nodeVal = v
  private var left    = l
  private var right   = r
 
  // mutators
  override def setValue(nv: Any)     { nodeVal = nv    }
  override def setLeft (nl: BinTree) { left    = nl    }
  override def setRight(nr: BinTree) { right   = nr    }

  // accept Visitor object
  def accept(vis: BinTreeVisitor)    { vis.visit(this) }

  // accessors
  override def getValue = nodeVal
  override def getLeft  = left 
  override def getRight = right

  // redefine toString to aid in testing
  override def toString = "Node(" + l + "(" + nodeVal + ")" + r + ")"
}


/* Singleton object NilTree represents an empty binary tree node.
   This has the role of a Leaf subclass in the Composite design 
   pattern and ConcreteElement class in the Visitor pattern.  
*/

object NilTree extends BinTree {
  def accept(v: BinTreeVisitor) { v.visit(this) }  // accept Visitor
  override def toString = "NilTree"
}


/* The BinTreeVisitor trait defines the Binary Tree Visitor
   interface. This interface has the Visitor base role in the Visitor
   design pattern.  Implementations of this interface are tightly
   coupled with the BinTree Composite hierarchy.  Implementations are
   expected to do their own traversals of the BinTree
   structure.
*/

abstract trait BinTreeVisitor {
  def visit(t: Node)
  def visit(t: NilTree.type)
}
