### A MODULE/CLASS THAT MODELS A BANK ACCOUNT ###############

# The global variable, the money in the account:
account = 100       # we'll start at 1d0....
#PREMISES FOR ATTACHED PROOF, IF ANY: 
# (account == 100)
# the global invariant (sometimes called the _class invariant_):
"""{ globalinvOK  account >= 0  }"""  # this property must stay true forever
#PREMISES FOR NEXT LINE: 
# (account >= 0)

# A real account maintains a log of all the transactions:
log = [0+100]    # log  is an array (list) that grows.  Here, it has one entry.
#PREMISES FOR ATTACHED PROOF, IF ANY: 
# (log == [(0 + 100)])
# (account >= 0)
#PREMISES FOR NEXT LINE: 
# (log == [(0 + 100)])
# (account >= 0)

# There is another global invariant: the  balance  is correct!
###  """{ globalinv   account == summation of  i: 0..log(len-1), log[i] }"""

# We can use  def  clauses, explained in Chapter 3, and arrays,
# explained in Chapter 6, to state and prove this property.


def deposit(howmuch) :
    """deposit adds  howmuch  to  account"""
    """{ pre  howmuch >= 0 
         post  True }"""
    global account, log
    #PREMISES FOR NEXT LINE: 
    # (howmuch >= 0)
    # (account >= 0)
    """{ 1.OK  account >= 0    premise # the globalinv holds on entry
         2.OK  howmuch >= 0    premise  # the function's precondition
         3.OK  account >= 0 and howmuch >= 0  andi 1 2
    }"""
    #PREMISES FOR NEXT LINE: 
    # ((account >= 0) and (howmuch >= 0))
    account = account + howmuch
    #PREMISES FOR ATTACHED PROOF, IF ANY: 
    # (account == (account_old + howmuch))
    # ((account_old >= 0) and (howmuch >= 0))
    """{ 1.OK account == account_old + howmuch    premise
         2.OK account_old >= 0  and  howmuch >= 0    premise 
         3.OK account >= 0                         algebra 1 2
    }"""
    #PREMISES FOR NEXT LINE: 
    # (account >= 0)
    log.append(0+howmuch)   # record the transaction in the log
    #PREMISES FOR ATTACHED PROOF, IF ANY: 
    # (log[(len(log) - 1)] == (0 + howmuch))
    # (len(log) == (len(log_old) + 1))
    # (account >= 0)
    #PREMISES FOR NEXT LINE: 
    # (log[(len(log) - 1)] == (0 + howmuch))
    # (account >= 0)
    # POSTCONDITION AND ALL GLOBAL INVARIANTS VERIFIED AT END OF FUNCTION
#PREMISES FOR NEXT LINE: 
# (log == [(0 + 100)])
# (account >= 0)

    # We must prove the global invariants are preserved at the exit.


def withdraw(howmuch) :
    """withdraw  removes  howmuch  from  account"""
    """{ pre  howmuch >= 0 
         post  True }""" 
    global account, log
    #PREMISES FOR NEXT LINE: 
    # (howmuch >= 0)
    # (account >= 0)
    # the same premises hold here like in  deposit
    if  howmuch <= account :
        #PREMISES FOR THEN-ARM: 
        # (howmuch <= account)
        # (howmuch >= 0)
        # (account >= 0)
        # now we know that  howmuch <= account :
        account = account - howmuch
        #PREMISES FOR ATTACHED PROOF, IF ANY: 
        # (account == (account_old - howmuch))
        # (howmuch <= account_old)
        # (howmuch >= 0)
        # (account_old >= 0)
        """{ 1.OK account == account_old - howmuch    premise
             2.OK  howmuch <= account_old            premise
             3.OK  account >= 0                     algebra 1 2
        }"""
        #PREMISES FOR NEXT LINE: 
        # (account >= 0)
        log.append(0-howmuch)  # record the transaction in the log
        #PREMISES FOR ATTACHED PROOF, IF ANY: 
        # (log[(len(log) - 1)] == (0 - howmuch))
        # (len(log) == (len(log_old) + 1))
        # (account >= 0)
        #PREMISES FOR NEXT LINE: 
        # (log[(len(log) - 1)] == (0 - howmuch))
        # (account >= 0)

    else :
        #PREMISES FOR ELSE-ARM: 
        # not (howmuch <= account)
        # (howmuch >= 0)
        # (account >= 0)
        """{ 1.OK not(howmuch <= account)     premise
             2.OK  account >= 0               premise  # the invariant
        }"""
        #PREMISES FOR NEXT LINE: 
        # (account >= 0)
        pass
        #PREMISES FOR NEXT LINE: 
        # (account >= 0)
        """{ 1.OK account >= 0                premise }"""
        #PREMISES FOR NEXT LINE: 
        # (account >= 0)
    #PREMISES FOR NEXT LINE: 
    # (account >= 0)
    # (howmuch >= 0)
    # END IF
    """{ 1.OK account >= 0                     premise }"""
    #PREMISES FOR NEXT LINE: 
    # (account >= 0)
    # POSTCONDITION AND ALL GLOBAL INVARIANTS VERIFIED AT END OF FUNCTION
#PREMISES FOR NEXT LINE: 
# (log == [(0 + 100)])
# (account >= 0)
    # We reprove the global invariants here.