/*  Engr 691-6, Special Topics, Software Language Engineering
    Fowler's State Machine Model for the Secret Panel DSL Examples
    Testing the Semantic Model
    H. C. Cunningham
    Version 1:  13 April 2009
    Version 1a: 13 May 2009   Removed CommandChannel class since now separate.

123456789012345678901234567890123456789012345678901234567890123456789012345678

This is a Scala reimplementation of Martin Fowler's configuration test
of his State Machine semantic model (for the Secret Panel Controller)
given in the "An Introductory Example" section of his DSL book work in
progress http://www.martinfowler.com/dslwip/intro.html.

*/


/*  Do some limited testing of the State Machine Semantic model. 

    Much of the hardcoded test here is the configuration example code 
    from Fowler's book.  
*/

object StateMachineTest {

  def main(args: Array[String]) {
    println("\nState Machine test beginning.\n")

    // Beginning of Folwer's example configuration code
    val doorClosed  = Event("doorClosed",  'D1CL)
    val drawOpened  = Event("drawOpened",  'D2OP)
    val lightOn     = Event("lightOn",     'L1ON)
    val doorOpened  = Event("doorOpened",  'D1OP)
    val panelClosed = Event("panelClosed", 'PNCL)

    val unlockPanelCmd = Command("unlockPanel", 'PNUL)
    val lockPanelCmd   = Command("lockPanel",   'PNLK)
    val lockDoorCmd    = Command("lockDoor",    'D1LK)
    val unlockDoorCmd  = Command("unlockDoor",  'D1UL)

    val idle                 = new State("idle")
    val activeState          = new State("active")
    val waitingForLightState = new State("waitingForLight")
    val waitingForDrawState  = new State("waitingForDraw")
    val unlockedPanelState   = new State("unlockedPanel")

    val machine = new StateMachine(idle)

    idle.addTransition(doorClosed, activeState)
    idle.addAction(unlockDoorCmd)
    idle.addAction(lockPanelCmd)
    idle.setMachine(machine)

    activeState.addTransition(drawOpened, waitingForLightState)
    activeState.addTransition(lightOn, waitingForDrawState)
    activeState.setMachine(machine)

    waitingForLightState.addTransition(lightOn, unlockedPanelState)
    waitingForLightState.setMachine(machine)

    waitingForDrawState.addTransition(drawOpened, unlockedPanelState)
    waitingForDrawState.setMachine(machine)

    unlockedPanelState.addAction(unlockPanelCmd)
    unlockedPanelState.addTransition(panelClosed, idle)
    unlockedPanelState.addAction(lockDoorCmd)
    unlockedPanelState.setMachine(machine)

    machine.addResetEvents(doorOpened)

    // End of Fowler's example configuration code

    // Try the execution of the model
    val commandsChannel = new CommandChannel
    val control = new Controller(machine,commandsChannel)

    println(control.toString)

    control.handle('D1CL)
    control.handle('L1ON)
    control.handle('D2OP)
    control.handle('PNCL)

    println("Commands output:  " + commandsChannel.getOutput)

    println("\nState Machine test ending.")
  }
}
