/** Coffee Machine example
 *  
 *  inspired by the Coffee Machine example in the Telelogic TAU Tutorial
 *  
 *  Gregor v. Bochmann, December 2008 */

// there is at least one problems in this specification:
// After coinElse, the controller may go into the BROKEN state after returning the coin; and there it will loop. 
//      Note: The behavior for the interaction returnChange is non-deterministic.
// This is shown by TEST1 which checks whether a given interaction sequence can be realized: 
//    there are two possible execution paths in the coffee machine: one is correct (leading to the STOP) and one deadlocks (see drawing).
// This is also shown by the progress check on USERVIEW.

CONTROLLER = (coin[5] -> PAIDFIVE | coin[10] -> PAIDTEN
             | coinElse -> returnChange -> BROKEN | coinElse -> returnChange -> CONTROLLER),
BROKEN = ({coin[5], coin[10], coinElse} -> returnChange -> BROKEN), 

PAIDFIVE = (tea -> MAKETEA | coffee -> returnChange -> CONTROLLER),
PAIDTEN = (tea -> returnCoin[5] -> MAKETEA | coffee -> MAKECOFFEE),
MAKETEA = (fillWater -> waterOK -> heatWater -> warm -> cupOfTea -> CONTROLLER),
MAKECOFFEE = (fillWater -> waterOK -> fillCoffee -> coffeeOK -> heatWater -> warm -> cupOfCoffee -> CONTROLLER).

HARDWARE = (fillWater -> waterOK -> HARDWARE | heatWater -> warm -> HARDWARE | fillCoffee -> PREPARECOFFEE),
PREPARECOFFEE = (coffeeOK -> HARDWARE). 

// faulty hardware : may loose a "coffeeOK" message
// PREPARECOFFEE = (coffeeOK -> HARDWARE | looseMessage -> HARDWARE).

// faulty hardware : when adding coffee, may repeat a loop an arbitrary number of times before providing the "coffeeOK" message
// PREPARECOFFEE = (coffeeOK -> HARDWARE | tryToFix -> LOOP), LOOP = (tryToFix -> LOOP | coffeeOK -> HARDWARE).

// faulty hardware : when adding coffee, may get into a loop where it stays forever
// PREPARECOFFEE = (coffeeOK -> HARDWARE | tryToFix -> LOOP), LOOP = (tryToFix -> LOOP).


// ||COFFEEMACHINE = (CONTROLLER || HARDWARE).

set UserAlphabet = {coin[5], coin[10], coinElse, tea, coffee, returnChange, returnCoin[5], cupOfTea, cupOfCoffee}

||USERVIEW =  (CONTROLLER || HARDWARE) @ UserAlphabet.

TESTCASE1 = (coinElse -> returnChange -> coin[5] -> tea -> cupOfTea -> STOP) + UserAlphabet.
||TEST1 = (USERVIEW || TESTCASE1).

property SAFENESS = (tea -> cupOfTea -> SAFENESS | coffee -> cupOfCoffee -> SAFENESS).
||SAFETYCHECK = (USERVIEW || SAFENESS).

progress SOME = {tea}
