#! /usr/bin/python

# Program at end of class on Thursday, 18 April

__author__="J Dean Brock"

import threading
import sys

def doUpdate(sharedInfo, key, myNum):
    siLock = sharedInfo['lock']
    siVals = sharedInfo['value']
    siLock.acquire()
    if key in siVals:
        rendezvousPt = siVals[key]
        del siVals[key]       # The other guy still has a reference
        retVal  = rendezvousPt['value'] + myNum
        rendezvousPt['value'] = retVal
        keyLock = rendezvousPt['cond']
        keyLock.notify()      # Start the other guy
    else:
        keyCond = threading.Condition(siLock)
        rendezvousPt = {'value': myNum, 'cond': keyCond }
        siVals[key] = rendezvousPt
        keyCond.wait()        # ZZZZZZZZ
        retVal = rendezvousPt['value']
    siLock.release()
    return retVal

class counter(threading.Thread):
    def __init__(self, countUp, sharedInfo, myName):
        threading.Thread.__init__(self)
        self.countUp = countUp
        self.sharedInfo = sharedInfo
        self.niceName = myName
    def run(self):
        myCountDown = self.countUp-1
        while (myCountDown >= 0):
            key = 'rum' + str(myCountDown%100).zfill(2)
            myMark = self.niceName
            myNum=myMark[-1]
            retV=doUpdate(self.sharedInfo, key, myNum)
            response = 'Return to '+myMark+' for '+str(key)+' is '+str(retV)+'\n'
            print response,
            myCountDown = myCountDown - 1

def RunEm(numThreads=10):
    if numThreads>10:
        numThreads=10
    numIncs = 100/numThreads
    print "Run with ", numThreads, " threads doing ", numIncs, " inits"
    shLock = threading.Lock()
    shVals = {}
    shInfo = {'value': shVals, 'lock': shLock}
    tList = []
    for x in range(numThreads):
        newThread = counter(numIncs, shInfo, 'T' + str(x).zfill(3))
        newThread.start()
        tList.append(newThread)
    for t in tList:
        t.join()
    tWinner = {}
    print "Value of shared variables are: "
    sillyList = shVals.keys()        # To deal with Python differences
    sillyList.sort()
    for key in sillyList:
        print "  ", key, "->", shVals[key]
        kSplit = shVals[key].split()[1]
        if (kSplit in tWinner):
            tWinner[kSplit] += 1
        else:
            tWinner[kSplit] = 1
    print "And the winnners are ..."
    sillyList = tWinner.keys()
    sillyList.sort()
    for key in sillyList:
        print key, ":  ", tWinner[key]

        

if __name__ == "__main__":
    arg = 100
    if len(sys.argv) > 1:
        arg=int(sys.argv[1])
    RunEm(arg)

