#
#
#  $Id: quadrant.py,v 1.1.1.1 2003/03/22 05:15:52 dbelan2 Exp $
#
#  $Log: quadrant.py,v $
#  Revision 1.1.1.1  2003/03/22 05:15:52  dbelan2
#  Initial import of all public_html on www.cs.mcgill.ca.
#
#  Revision 1.11  2001/12/04 18:53:11  hchen19
#  documented.
#
#  Revision 1.10  2001/12/03 19:16:45  hchen19
#  one bug fixed in the intTransition.
#
#  Revision 1.9  2001/12/03 19:08:56  dbelan2
#  Fix bug: roundabout empty and queuing up.
#
#  Revision 1.8  2001/12/03 04:18:54  dbelan2
#  Added name field.
#
#  Revision 1.7  2001/12/03 03:45:41  hchen19
#  more printout.
#
#  Revision 1.6  2001/12/03 03:39:44  hchen19
#  some printout for quadrant added.
#
#  Revision 1.5  2001/12/01 18:35:55  hchen19
#  one bug fixed.
#
#  Revision 1.4  2001/12/01 17:33:35  hchen19
#  Bug fixed in the intTransition() and find some syntax errors.
#
#  Revision 1.3  2001/12/01 04:45:54  hchen19
#  *** empty log message ***
#
#
#
#

from DEVS import *
from Simulator import *

from whrandom import randint
from constant import *

import sys

class Quadrant(AtomicDEVS):
    def __init__(self,MAXCAPACITY, name):
        AtomicDEVS.__init__(self)
        self.maxcap=MAXCAPACITY 
        self.processT=self.maxcap*6  # the time for a car passing through one quadrant of roundabout.
        self.arrivedCars=[]          # cars currently in this quadrant.
        self.leftT=[]	             # the time for each car currently in the quadrant will stay in this quadrant.
        self.timeFlag=None

        self.name = name	     # the quadrant name	
      
        #Declare ports
        self.IN=self.addInPort()   #car will enter from this port either from segment or another quadrant
        self.OUT=self.addOutPort() #car will get out to another quadrant
        self.EXIT=self.addOutPort()#car will exit the roundabout
        self.FULLFLAG=self.addOutPort() #a message will be sent out to indicate whether this quadrant is full or not.
        self.EMPTYFLAG=self.addOutPort()#a message will be sent out to indicate whether this quadrant is empty or not.

        # the first field of the state is to show how many cars in the quadrant
        # the first field of the state is to indicate whether the quadrant is empty or not.
        # the secod field of the state is to indicate whether the quadrant is full or not.
        # the fourth field of the state is to indicate whether an empty or full message already sent.
        self.state=[0,EMPTY,NOTFULL,MSGSENT]

    def extTransition(self):
        print "Before", self   # for debugging
        if not self.state[0]==0:     # if there are currently some cars in the quadrant, update their remaining time
            for i in range(self.state[0]):
                self.leftT[i]=self.leftT[i]-self.elapsed
        
        car=self.peek(self.IN)  # add the car into this quadrant
        self.arrivedCars.append(car)
        self.leftT.append(self.processT)

        if len(self.arrivedCars)==self.maxcap: # if the quadrant is full
            self.state[0]=len(self.arrivedCars)
            self.state[2]=FULL
            self.state[3]=MSGNOTSENT
        elif len(self.arrivedCars)==1: #if the qudarant change from empty to notempty
            self.state[0]=1
            self.state[1]=0
            self.state[3]=MSGNOTSENT
        else:	
            self.state[0]=self.state[0]+1

        print "After",self   # for debugging
        return self.state
   
    def intTransition(self):
        print "Before",self   #for debugging
        if not self.state[3]:	# message 'empty', 'notempty', 'full' or 'notfull' had sent out
            self.state[3]=MSGSENT
        elif not self.state[0]==0:  # a car left this quadrant
            self.state[0]=self.state[0]-1
            self.arrivedCars=self.arrivedCars[1:]
            self.leftT=self.leftT[1:]
            if self.state[0]==0: # the quadrant is empty now
                self.state[1]=EMPTY
                self.state[2]=NOTFULL
                self.state[3]=MSGNOTSENT
            else:
                for i in range(self.state[0]):
                    self.leftT[i]=self.leftT[i]-(self.timeNext-self.timeLast)
                    if self.leftT[i]<0:
                        print "Something wrong with synchronization"

            if self.state[0]==self.maxcap-1: # the quadrant change from 'full' to 'notfull'
                self.state[1]=NOTEMPTY
                self.state[2]=NOTFULL
                self.state[3]=MSGNOTSENT

        else:
            print "Something wrong with synchronization"

        print "After", self  # for debugging
        return self.state
    
    def outputFnc(self):
        if not self.state[3]:  # if a message had not sent out, send it now.
            if self.state[0]==self.maxcap:
                self.poke(self.FULLFLAG, FULL)
            elif self.state[0]>0 and self.state[0]<self.maxcap: #may also be self.state[0]==self.maxcap-1
                self.poke(self.FULLFLAG,NOTFULL)
            elif self.state[0]==1:
                self.poke(self.EMPTYFLAG, NOTEMPTY)
            elif self.state[0]==0:
                self.poke(self.EMPTYFLAG, EMPTY)

            else:
                print "Something wrong"
        else:			# a car left this quadrant
            car=self.arrivedCars[0]
            if car.dest==self.EXIT.outLine[0].hostDEVS.position: # exit the roundabout
                self.poke(self.EXIT, car)
            else:              # go to the next quadrant
                self.poke(self.OUT,car)

    def timeAdvance(self):
        if not self.state[3]: # if a message had not sent out, sent it now
            return 0
        elif self.state[0]==0:  # no message, no car in the quadrant.
            return INFINITY
        else:                   # the first car's remaining time in this quadrant.
            return self.leftT[0]


    def __str__(self):
        s = ">>>>>>>>"
        s += "quadrant: " + self.name + "\n"
        for i in range(len(self.arrivedCars)):
            s += str(self.arrivedCars[i]) + "<" + `self.leftT[i]` + ">\n"
        s += "<<<<<<<<<<"
        return s








