/*  CSci 658, Software Language Engineering
    Frog Dynamic Composition Example
    H. Conrad Cunningham

1234567890123456789012345678901234567890123456789012345678901234567890

2010-03-09: (V1) Scala reimplementation
2018-02-13: (V1a) Reformat. Check compilation.

This program is a Scala reimplementation of the Java Frog dynamic
composition example from chapter 10 of Budd's
Understanding Object-Oriented Progamming with Java.

In Budd's Java example "growUp" is a side-effecting function, which
this instructor considers bad design.  Thus, the "growUp" method is
replaced by pure function "grownUp" and the increment is moved to the
"grow" method.

This version also adds a companion object for Frog and the constant
metamorphosisAge to replace the constant 24.

*/

class Frog {
  private var behavior: FrogBehavior =
    new TadpoleBehavior // note type of var

  def grow { 
    if (behavior.grownUp)
      behavior = new AdultFrogBehavior 
    behavior.grow // behavior does actual work 
    behavior.swim 
  } 
}

object Frog {
  val metamorphosisAge = 24 
}

abstract class FrogBehavior {     
  def grow 
  def swim
  def grownUp: Boolean = false // changed Java name from "growUp"
} 

class TadpoleBehavior extends FrogBehavior {    
  private var age: Int = 1 // changed initialization from Java
                           // because increment moved from
                           // "grownUp" to "grow"

  def grow { println("Tadpole growing at age " + age); age += 1 }
  def swim { println("Tadpole swimming.") } 

  override def grownUp: Boolean = (age > Frog.metamorphosisAge) 
    // moved increment of age to grow to make this a pure function
    // introduced symbolic name for age for metamorphosis
} 

class AdultFrogBehavior extends FrogBehavior {
  def grow = { println("AdultFrog growing.") } 
  def swim = { println("AdultFrog swimming.") } 
} 

object FrogTest {

  // Main method for testing
  def main(args: Array[String]) {

    println("Frog program beginning.")
    val frog = new Frog

    for (i <- 0 to 100)
      frog.grow

    println("Frog program ending.")
  }
}
