from __future__ import generators
from SimPy.Simulation  import *
#from SimPy.Monitor import *
from random import Random
from SimGUI import *

class Source(Process):
    """ Source generates customers randomly"""
    def __init__(self,seed=333):
        Process.__init__(self)
        self.SEED = seed

    def generate(self,number,interval):       
        rv = Random(self.SEED)
        for i in range(number):
            c = Customer(name = "Customer%02d"%(i,))
            activate(c,c.visit(timeInBank=12.0))
            t = rv.expovariate(1.0/interval)
            yield hold,self,t

def NoInSystem(R):
    """ The number of customers in the resource R
    in waitQ and active Q"""
    return (len(R.waitQ)+len(R.activeQ))

class Customer(Process):
    """ Customer arrives, is served and leaves """
    def __init__(self,name):
        Process.__init__(self)
        self.name = name
        
    def visit(self,timeInBank=0):       
        arrive=now()
        Qlength = [NoInSystem(counter[i]) for i in range(Nc)]
        ##print "%7.4f %s: Here I am. %s   "%(now(),self.name,Qlength)
        for i in range(Nc):
            if Qlength[i] ==0 or Qlength[i]==min(Qlength): join =i ; break
        yield request,self,counter[join]
        wait=now()-arrive
        waitMonitor.observe(wait,t=now())                                 #Lmond
        ##print "%7.4f %s: Waited %6.3f"%(now(),self.name,wait)
        tib = counterRV.expovariate(1.0/timeInBank)
        yield hold,self,tib
        yield release,self,counter[join]
        serviceMonitor.observe(now()-arrive,t=now())
        if trace:
            gui.writeConsole("Customer leaves at %.1d"%now())
        ##print "%7.4f %s: Finished    "%(now(),self.name)

def model():
    global Nc,counter,counterRV,waitMonitor,serviceMonitor,trace,lastLeave,noRunYet
    counterRV = Random(params["counterseed"])
    sourceseed = params["sourceseed"]
    nrRuns=params["nrRuns"]
    lastLeave=0
    gui.noRunYet=True
    for runNr in range(nrRuns):
        gui.noRunYet=False
        trace=params["trace"]
        if trace:
            gui.writeConsole(text='\n** Run %s'%(runNr+1))
        Nc = 2
        counter = [Resource(name="Clerk0"),Resource(name="Clerk1")]
        waitMonitor = Monitor(name='Waiting Times')
        waitMonitor.xlab='Time'
        waitMonitor.ylab='Customer waiting time'
        serviceMonitor = Monitor(name='Service Times')
        serviceMonitor.xlab='Time'
        serviceMonitor.ylab='Total service time = wait+service'
        initialize()
        source = Source(seed = sourceseed)
        activate(source,source.generate(params["numberCustomers"],params["interval"]),0.0)
        simulate(until=params['endtime'])
        lastLeave+=now()
    gui.writeConsole("%s simulation run(s) completed\n"%nrRuns)
    gui.writeConsole("Parameters:\n%s"%params)
def statistics():
    if gui.noRunYet:
        showwarning(title='SimPy warning',message="Run simulation first -- no data available.")
        return
    aver=lastLeave/params['nrRuns']
    gui.writeConsole(text="Average time for %s customers to get through bank: %.1f\n(%s runs)\n"\
                      %(params['numberCustomers'],aver,params['nrRuns']))

__doc__="""
Modified bank11.py (from Bank Tutorial) with GUI.

Model: Simulate customers arriving
at random, using a Source, requesting service
from two counters each with their own queue
random servicetime.

Uses Monitor objects to record waiting times
and total service times."""

def showAuthors():
    gui.showTextBox(text="Tony Vignaux\nKlaus Muller",title="Author information")
class MyGUI(SimGUI):
    def __init__(self,win,**p):
        SimGUI.__init__(self,win,**p)
        self.help.add_command(label="Author(s)",
                              command=showAuthors,underline=0)
        self.edit.add_command(label="Run simulation",
                              command=model,underline=0)
        self.view.add_command(label="Statistics",
                              command=statistics,underline=0)
    def findMonitors(self):
        self._monitors=[]
        globs=globals()
        for k in globs.keys():
            a =globs[k]
            if isinstance(a,Monitor):
                self._monitors.append(a)
                print a,type(a)

p={"endtime":2000,
   "sourceseed":1133,
   "counterseed":3939393,
   "numberCustomers":50,
   "interval":10.0,
   "trace":0,
   "nrRuns":1}
params=Parameters(p)
gui=MyGUI(root,title="SimPy GUI example",doc=__doc__)
root.mainloop()