/*  CSci 658, Software Language Engineering
    Stackable Trait Test
 H. Conrad Cunninghampr
*/

// IntQueue root abstract class
abstract class IntQueue {
  def get(): Int
  def put(x: Int)
}


import scala.collection.mutable.ArrayBuffer

// IntQueue concrete class using an ArrayBuffer
class BasicIntQueue extends IntQueue {
  private val buf = new ArrayBuffer[Int]

  def get() = buf.remove(0)
  def put(x: Int) { buf += x }

  // provide a convenient string display form
  override def toString = "IntQueue(" + buf.mkString(",") + ")"
}


/*  Trait Doubling extends IntQueue, hence can only be mixed in to a
    class that also extends IntQueue.  Note the super call to the
    abstract method get in IntQueue.  This trait must be mixed in
    after Incrementing a class or trait that gives a concrete
    definition to put.
*/
 
trait Doubling extends IntQueue {
  abstract override def put(x: Int) { super.put(2*x) }
}

// MyQueue mixes Doubling into BasicIntQueue
class MyQueue extends BasicIntQueue with Doubling


/*  Trait Incrementing extends IntQueue, hence can only be mixed in to
    a class that also extends IntQueue.  Note the super call to the
    abstract method put in IntQueue.  This trait must be mixed in
    after a class or trait that gives a concrete definition to put.
*/
 
trait Incrementing extends IntQueue {
  abstract override def put(x: Int) { super.put(x+1) }
}


/*  Trait Incrementing extends IntQueue, hence can only be mixed in to
    a class that also extends IntQueue.  Note the super call to the
    abstract method put in IntQueue.  This trait must be mixed in
    after a class or trait that gives a concrete definition to put.
*/
 
trait Filtering extends IntQueue {
  abstract override def put(x: Int) {
    if (x >= 0) super.put(x)
  }
}


object StackableTest {

 def main(args: Array[String]) {

    println("\nBegin execution of StackableTest.\n")

    var q = new BasicIntQueue
    println("q         = new BasicIntQueue")
    println("q         : " + q)
    q.put(10)
    println("q.put(10) : " + q)
    q.put(20)
    println("q.put(20) : " + q)
    var x = q.get()
    println("q.get()   = " + x)
    x = q.get()
    println("q.get()   = " + x)
    println("q         : " + q)
    q.put(-1); q.put(0); q.put(1)
    println("q.put(-1); q.put(0); q.put(1)")
    println("q         : " + q)
    q.get()
    println

    // Mixing in Doubling
    q = new MyQueue
    println("q         = new MyQueue (mixes in Doubling)")
    println("q         : " + q)
    q.put(10)
    println("q.put(10) : " + q)
    q.put(20)
    println("q.put(20) : " + q)
    x = q.get()
    println("q.get()   = " + x)
    x = q.get()
    println("q.get()   = " + x)
    println("q         : " + q)
    q.put(-1); q.put(0); q.put(1)
    println("q.put(-1); q.put(0); q.put(1)")
    println("q         : " + q)
    q.get()
    println

    // Still mixing in Doubling
    q = new BasicIntQueue with Doubling
    println("q         = new BasicIntQueue with Doubling")
    println("q         : " + q)
    q.put(10)
    println("q.put(10) : " + q)
    q.put(20)
    println("q.put(20) : " + q)
    x = q.get()
    println("q.get()   = " + x)
    x = q.get()
    println("q.get()   = " + x)
    println("q         : " + q)
    q.put(-1); q.put(0); q.put(1)
    println("q.put(-1); q.put(0); q.put(1)")
    println("q         : " + q)
    q.get()
    println

    // Mixing in Incrementing then Filtering
    q = new BasicIntQueue with Incrementing with Filtering
   println(
     "q         = new BasicIntQueue with Incrementing with Filtering")
    println("q         : " + q)
    q.put(10)
    println("q.put(10) : " + q)
    q.put(20)
    println("q.put(20) : " + q)
    x = q.get()
    println("q.get()   = " + x)
    x = q.get()
    println("q.get()   = " + x)
    println("q         : " + q)
    q.put(-1); q.put(0); q.put(1)
    println("q.put(-1); q.put(0); q.put(1)")
    println("q         : " + q)
    q.get()
    println

    // Mixing in Filtering then Incrementing
    q = new BasicIntQueue with Filtering with Incrementing
   println(
     "q         = new BasicIntQueue with Filtering with Incrementing")
    println("q         : " + q)
    q.put(10)
    println("q.put(10) : " + q)
    q.put(20)
    println("q.put(20) : " + q)
    x = q.get()
    println("q.get()   = " + x)
    x = q.get()
    println("q.get()   = " + x)
    println("q         : " + q)
    q.put(-1); q.put(0); q.put(1)
    println("q.put(-1); q.put(0); q.put(1)")
    println("q         : " + q)
    q.get()
    println

    println("\nEnd execution of StackableTest.\n")

 }
}

