from DEVS import *
from Simulator import *

from whrandom import randint

import sys

from constant import *
from segment import * 
from car import *
from generator import *
from quadrant import *
from exit import *

class Roundabout(CoupledDEVS):
    def __init__(self):
        CoupledDEVS.__init__(self)
    
        #NORTH=0
        #EAST=1
        #SOUTH=2
        #WEST=3
        #build a roundabout model

        


        #add car generators
        self.NORTH_GEN=self.addSubModel(Generator(2, 18, NORTH, 1))
        self.SOUTH_GEN=self.addSubModel(Generator(2, 18, SOUTH, 3))
        self.WEST_GEN=self.addSubModel(Generator(2, 18, WEST, 4))
        self.EAST_GEN=self.addSubModel(Generator(2, 18, EAST, 2))

        #add road segments
        #segN = Segment(10, "N")
        self.NORTH_SGMT=self.addSubModel(Segment(300, "N"))
        self.SOUTH_SGMT=self.addSubModel(Segment(300, "S"))
        self.WEST_SGMT=self.addSubModel(Segment(300, "W"))
        self.EAST_SGMT=self.addSubModel(Segment(300, "E"))

        #print "***"
        #print `self.NORTH_SGMT`
        #print `segN`
        #sys.exit()

        #add roundabout quadrants
        self.NE_QDT=self.addSubModel(Quadrant(MAXCAPACITY, "NE"))
        self.SE_QDT=self.addSubModel(Quadrant(MAXCAPACITY, "SE"))
        self.NW_QDT=self.addSubModel(Quadrant(MAXCAPACITY, "NW"))
        self.SW_QDT=self.addSubModel(Quadrant(MAXCAPACITY, "SW"))
        
        Segment.quads = [self.NE_QDT, self.SE_QDT, self.NW_QDT, self.SW_QDT]

        #add exits
        self.NORTH_XT=self.addSubModel(Exit(NORTH))
        self.SOUTH_XT=self.addSubModel(Exit(SOUTH))
        self.WEST_XT=self.addSubModel(Exit(WEST))
        self.EAST_XT=self.addSubModel(Exit(EAST))

        #add the relationships between the atomic blocks

        # car generator to road segment
        self.connectPorts(self.SOUTH_GEN.OUT, self.SOUTH_SGMT.IN)
        self.connectPorts(self.EAST_GEN.OUT, self.EAST_SGMT.IN)
        self.connectPorts(self.NORTH_GEN.OUT, self.NORTH_SGMT.IN)
        self.connectPorts(self.WEST_GEN.OUT, self.WEST_SGMT.IN)

        # road segment to roundabout quadrant
        self.connectPorts(self.SOUTH_SGMT.OUT, self.SE_QDT.IN)
        self.connectPorts(self.EAST_SGMT.OUT, self.NE_QDT.IN)
        self.connectPorts(self.NORTH_SGMT.OUT, self.NW_QDT.IN)
        self.connectPorts(self.WEST_SGMT.OUT, self.SW_QDT.IN)

        # South East quadrant to others
        self.connectPorts(self.SE_QDT.EXIT, self.EAST_XT.IN)
        self.connectPorts(self.SE_QDT.FULLFLAG, self.SOUTH_SGMT.RightSeg)
        self.connectPorts(self.SE_QDT.OUT, self.NE_QDT.IN)
        self.connectPorts(self.SE_QDT.EMPTYFLAG, self.EAST_SGMT.LeftSeg)
    
        # North East quadrant to others
        self.connectPorts(self.NE_QDT.EXIT, self.NORTH_XT.IN)
        self.connectPorts(self.NE_QDT.FULLFLAG, self.EAST_SGMT.RightSeg)
        self.connectPorts(self.NE_QDT.OUT, self.NW_QDT.IN)
        self.connectPorts(self.NE_QDT.EMPTYFLAG, self.NORTH_SGMT.LeftSeg)

        # North West quadrant to others
        self.connectPorts(self.NW_QDT.EXIT, self.WEST_XT.IN)
        self.connectPorts(self.NW_QDT.FULLFLAG, self.NORTH_SGMT.RightSeg)
        self.connectPorts(self.NW_QDT.OUT, self.SW_QDT.IN)
        self.connectPorts(self.NW_QDT.EMPTYFLAG, self.WEST_SGMT.LeftSeg)

        # South West quadrant to others
        self.connectPorts(self.SW_QDT.EXIT, self.SOUTH_XT.IN)
        self.connectPorts(self.SW_QDT.FULLFLAG, self.WEST_SGMT.RightSeg)
        self.connectPorts(self.SW_QDT.OUT, self.SE_QDT.IN)
        self.connectPorts(self.SW_QDT.EMPTYFLAG, self.SOUTH_SGMT.LeftSeg)





    

    def select(self, immList):
        print "immList:", immList
        immindex = 0
        maxpri = 0
        for i in range(len(immList)):
            pri = 0
            if immList[i].__class__.__name__ == 'Segment':
                pri = 1
            elif immList[i].__class__.__name__ == 'Quadrant':
                pri = 2
            if pri > maxpri:
                maxpri = pri
                immindex = i
        print "Chose", immindex, "(pri = ", pri, ")"
        return immList[immindex]


M=Roundabout()
S=Simulator(M)
endtime=800
S.simulate(endtime)
print '***************Performace Metrics**************************'
print 'The average queue length of north segment is ', M.NORTH_SGMT.getAvgUse(endtime)
print 'The average queue length of south segment is ', M.SOUTH_SGMT.getAvgUse(endtime)
print 'The average queue length of west segment is ', M.WEST_SGMT.getAvgUse(endtime)
print 'The average queue length of east segment is ', M.EAST_SGMT.getAvgUse(endtime)

print 'The transition time of car that exiting to the north is: '
print M.NORTH_XT.state 
print 'The transition time of car that exiting to the south is: '
print M.SOUTH_XT.state
print 'The transition time of car that exiting to the west is: '
print M.WEST_XT.state
print 'The transition time of car that exiting to the east is: '
print M.EAST_XT.state






# compute and print queue time avg
exits = [('North', M.NORTH_XT.state), ('South', M.SOUTH_XT.state), \
         ('West', M.WEST_XT.state), ('East', M.EAST_XT.state)]



for i in [1, 2]:
    if i == 1:
        print "Avg transit time"
    elif i == 2:
        print "Avg queue time of cars in exit DEVS"
    totalSum = 0.0
    totalEntries = 0
    for exit in exits:
        sum = 0.0
        n = len(exit[1])
        totalEntries += n
        print exit[0],   # name
        for info in exit[1]:
            sum += info[i]
        totalSum += sum
        print ": avg is",
        if n == 0:
            print 0
        else:
            print sum / n
    print "Over all cars that exited",
    if totalEntries == 0:
        print 0
    else:
        print totalSum / totalEntries
    print "*************"




## the following just put the qtime and transit time into files for plotting 
start=310
end=610
interval=20

total=[]
count=[]
for i in range((end-start)/interval):
    count.append(0)
    total.append(0)


qstart=0
qend=260
qinterval=20
qtime=[]
for i in range((qend-qstart)/20):
    qtime.append(0)

q=M.NORTH_XT.state
for i in range(len(q)):
    x, y, z=q[i]
    j=int((y-start)/20)
    count[j]=count[j]+1
    total[j]=total[j]+1
    k=int((z-qstart)/20)
    qtime[k]=qtime[k]+1
f=open('transitionNorth', "w")
for k in range(len(count)):
    x=start+interval/2+interval*k
    f.write(`x`+'\t'+`count[k]`+'\n')
f.close()

for i in range((end-start)/interval):
    count[i]=0
q=M.SOUTH_XT.state
for i in range(len(q)):
    x, y, z=q[i]
    j=int((y-start)/20)
    count[j]=count[j]+1
    total[j]=total[j]+1
    k=int((z-qstart)/20)
    qtime[k]=qtime[k]+1
f=open('transitionSouth', "w")
for k in range(len(count)):
    x=start+interval/2+interval*k
    f.write(`x`+'\t'+`count[k]`+'\n')
f.close()

for i in range((end-start)/interval):
    count[i]=0
q=M.EAST_XT.state
for i in range(len(q)):
    x, y, z=q[i]
    j=int((y-start)/20)
    count[j]=count[j]+1
    total[j]=total[j]+1
    k=int((z-qstart)/20)
    qtime[k]=qtime[k]+1
f=open('transitionEast', "w")
for k in range(len(count)):
    x=start+interval/2+interval*k
    f.write(`x`+'\t'+`count[k]`+'\n')
f.close()

for i in range((end-start)/interval):
    count[i]=0
q=M.WEST_XT.state
for i in range(len(q)):
    x, y, z=q[i]
    j=int((y-start)/20)
    count[j]=count[j]+1
    total[j]=total[j]+1
    k=int((z-qstart)/20)
    qtime[k]=qtime[k]+1
f=open('transitionWest', "w")
for k in range(len(count)):
    x=start+interval/2+interval*k
    f.write(`x`+'\t'+`count[k]`+'\n')
f.close()


f=open('transitionTotal', "w")
for k in range(len(count)):
    x=start+interval/2+interval*k
    f.write(`x`+'\t'+`total[k]`+'\n')
f.close()

f=open('qwaitingTime',"w")
for k in range(len(qtime)):
    x=qstart+qinterval/2+qinterval*k
    f.write(`x`+'\t'+`qtime[k]`+'\n')
f.close()
















