'''
Created on Jan 5, 2011
Modified on May 25, 2012
@author:  = Dilum Bandara
@version:  = 0.2
@copyright:  = Copyright(c) 2011, Dilum Bandara
@contact:  = dilumb@engr.colostate.edu
@license:  = GPL
'''

class DES:
    '''
    Discrete event simulation engine
    '''
    def __init__(self):
        self._event_list = []
        self.now = 0.0


    def __del__(self):
        self._event_list = []


    def addEvent(self, start_time, event_type, nid, data, sort = True):
        '''
        Add an event to waiting event list
        @param start_time: Event start time
        @param event_type: Type of event
        @param nid: Node responsible for event
        @param data: Data associated with event
        @param sort: Do events need to be sorted
        '''
        new_event = [start_time, event_type, nid, data]
        if sort == True: #Sort according to time
            if len(self._event_list) == 0: 
                self._event_list.append(new_event)
                return
            start = 0 
            end = len(self._event_list) - 1
            idx = -1
            while True:
                mid = (start + end)/2
                if start_time > self._event_list[mid][0]: start = mid + 1
                else: end = mid -1
                if start > end:
                    idx = start 
                    break
                elif (self._event_list[mid][0] <= start_time) and \
                    (self._event_list[mid + 1][0] > start_time):
                    idx = mid + 1
                    break            
            self._event_list.insert(idx, new_event)
            return
#            for i in range(len(self._event_list)):  #Search for proper position
#                if self._event_list[i][0] > start_time:
#                    self._event_list.insert(i, new_event)
#                    return
#            #Fist or last item
#            self._event_list.append(new_event)
        else: #If input is already sorted
            self._event_list.append(new_event)
            return


    def removeEvent(self, start_time, event_type, nid, subQuery = None):
        '''
        Remove given event from event list 
        @param start_time: Event start time
        @param event_type: Event type
        @param nid: Node responsible for event
        @param subQuery: Sub-query associated with event 
        '''
        if len(self._event_list) == 0:
            print 'Error: Event list already empty.'
            return
        else :
            for i in range(len(self._event_list)):  #Search for proper position
                if self._event_list[i][0] == start_time and \
                    self._event_list[i][1] == event_type and \
                    self._event_list[i][2] == nid:
                    if subQuery == None:
                        del self._event_list[i]
                        return
                    else:
                        if subQuery == self._event_list[i][3][0]:
                            del self._event_list[i]
                            return
                if self._event_list[i][0] > start_time: break
            print 'Error: No such event in event list', start_time
            return


    def getNextEvent(self):
        '''
        Get next event from list
        @return: Next event in cronological order. Has format 
        [start_time, event_type, nid, data]
        '''        
        if len(self._event_list) > 0:
            self.now = self._event_list[0][0]
            return self._event_list.pop(0)
        else :
            return self._event_list