/*  CSci 658, Software Language Engineering
    Direct Test of State Machine Semantic Model
    (Semantic Model for Secret Panel DSL Examples)
    H. Conrad Cunningham

1234567890123456789012345678901234567890123456789012345678901234567890

2009-04-13: (V1) Original
2009-05-13: (V1a)  Removed CommandChannel class since now separate.
2018-02-01: (V1b) Updated comments. Created compile script

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 chapter "An Introductory Example" of his book
Domain-Specific Languages.

*/


/*  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.")
  }
}
