# CODE THAT KEEPS TRACK OF THE COINS IN A TOY BANK:

# module DimesBank {

# fields in module:
dimes = 0
#PREMISES FOR ATTACHED PROOF, IF ANY: 
# (dimes == 0)
#PREMISES FOR NEXT LINE: 
# (dimes == 0)
money = 0
#PREMISES FOR ATTACHED PROOF, IF ANY: 
# (money == 0)
# (dimes == 0)
# we want the module to maintain true this invariant property:
"""{ globalinvOK  money == dimes * 10  }"""
#PREMISES FOR NEXT LINE: 
# (money == (dimes * 10))

# the checker  verifies that the invariant holds true HERE, on initialization.

# the method/function below can use the invariant, and the function
# must ensure that the invariant holds on exit:
def handleCoinInsertion(howmany) :
    """handles the insertion of  howmany  dimes into the bank:"""
    """{ pre   howmany >= 0 
         post  True        # the function enforces the invariant, that's it.
    }"""
    global dimes, money
    #PREMISES FOR NEXT LINE: 
    # (howmany >= 0)
    # (money == (dimes * 10))
    # we can introduce the invariant as a premise as needed:
    """{ 1.OK  money == dimes * 10      premise   }"""
    #PREMISES FOR NEXT LINE: 
    # (money == (dimes * 10))
    dimes = dimes + howmany
    #PREMISES FOR ATTACHED PROOF, IF ANY: 
    # (dimes == (dimes_old + howmany))
    # (money == (dimes_old * 10))
    """{ 1.OK  money == dimes_old * 10                premise
         2.OK  dimes == dimes_old + howmany           premise
         4.OK  money + (howmany * 10) == dimes * 10   algebra  1 2
    }"""
    #PREMISES FOR NEXT LINE: 
    # ((money + (howmany * 10)) == (dimes * 10))
    # invariant is broken here, but the next command restores it:
    money = money + (howmany * 10)
    #PREMISES FOR ATTACHED PROOF, IF ANY: 
    # (money == (money_old + (howmany * 10)))
    # ((money_old + (howmany * 10)) == (dimes * 10))
    """{ 1.OK  money_old + (howmany * 10) == dimes * 10    premise
         2.OK  money == money_old + (howmany * 10)         premise
         3.OK  money == dimes * 10                         subst 2 1 
    }"""
    #PREMISES FOR NEXT LINE: 
    # (money == (dimes * 10))
    # POSTCONDITION AND ALL GLOBAL INVARIANTS VERIFIED AT END OF FUNCTION
#PREMISES FOR NEXT LINE: 
# (money == (dimes * 10))
    # the checker verifies here that the invariant is true again.
    
# } END MODULE


# the following would be in a component that imports (uses) the module:

# throughout every line of the following code, the invariant is holding true:
coins = readInt("press button and insert your coins!")
#PREMISES FOR ATTACHED PROOF, IF ANY: 
# True
# (money == (dimes * 10))
#PREMISES FOR NEXT LINE: 
# (money == (dimes * 10))
assert coins > 0
#PREMISES FOR NEXT LINE: 
# (coins > 0)
# (money == (dimes * 10))
novar = handleCoinInsertion(coins)
#PREMISES FOR ATTACHED PROOF, IF ANY: 
# True
# (coins > 0)
# (money_old == (dimes_old * 10))
#PREMISES FOR NEXT LINE: 
# (coins > 0)
print money
#PREMISES FOR NEXT LINE: 
# (coins > 0)