/*  Engr 691-6, Special Topics, Software Language Engineering
    Survey DSL in Scala Experimentation
    H. Conrad Cunningham
    10 March 2009, 10 April 2009

123456789012345678901234567890123456789012345678901234567890123456789012345678

In this code, I am experimenting with a few Scala constructs to see
what might be useful in reimplementing my Ruby code for the Survey DSL
in Scala.

*/

import scala.collection.mutable._

//  Declarations to support use of implicit parameters
class QuestionOptions(val opts: Map[Symbol,Any])
  
object DSLDefaults {
  implicit val questionOptions = 
    new QuestionOptions(Map[Symbol,Any]('numresp -> 1))
}

import DSLDefaults._


// Base class for Object Scoping implementation of DSL.  This also
// uses closures as the grouping mechanism for nested statements.

abstract class DSL {

  /* In a full implementation, this class implements a parser for the
     Survey DSL.  It will enforce syntactic restrictions build an
     extensive semantic model (abstract syntax tree).  The question's
     conditions and actions and the response's actions are functions
     whose evaluation are deferred until the second pass.
  */

  protected var actionList : List[() => Unit] = Nil

  def processDSL // put the DSL code here in subclass

  // The use of the implicit parameter does not seem to be good
  // syntactically here.  I probably should use a mechanism like another
  // subcommend in closure.
  def question(text: String)(body: => Unit)
              (implicit qopts: QuestionOptions) {
    // build question node, store text and execute closure which groups 
    // the responses
    println("Question with text:  " + text)
    for (opt <- qopts.opts) println(opt)

    body  // execute question block in DSL
  }

  def response(text: String) {
    println("Response with just text:  " + text)
    // build response node, store text and null action
  }

  // Alternative to doing two kinds of responses might be to have a
  // separate coomand associated this this to introduct the optional
  // closure (maybe a chain).

  def responseAct(text: String)(action: => Unit) {
    println("Response with text:  " + text)
    // build response node, store text and deferred action
    actionList = actionList ::: List(() => action)
  }

  def cond(test: => Boolean) {
    println(test)
    actionList = actionList ::: List(() => {test; println("Condition")})
  }

  def action(act: => Unit) {
    println(act)
    actionList = actionList ::: List(() => act)
  }

  // An experiment using symbols, hashes, and varargs.
  def optionsMap(args: (Symbol,Any)*): Map[Symbol,Any] = 
    Map[Symbol,Any](args: _*)
}


object ExpDSL extends DSL {

  // Declarations of variables used in DSL actions and conditions
  private var x: Int     = 0
  private var y: Boolean = false

  // Procedure to hold DSL statements
  override def processDSL {

    question("Number 1") {

      cond { x == 0 }

      responseAct("Item a") { 
        println("Executing Item a body")
        x = 1
      }

      responseAct("Item b") { 
        println("Executing Item b body")
        y = true
      }

      response("Item c")

      action { println("action!")}
    }
    ( optionsMap('numresp -> 2, 'z -> "x") )  // optional argument

  }  // end procedure to hold DSL program

  def main(args: Array[String]) {
    println("Test beginning")
    processDSL
    println("Testing deferred response actions")
    actionList.map(_.apply)
    println("Test ending with x = " + x + " and y = " + y)
  }

}
