def agenda_prox_evento(tipo,tempo_atual,cliente_id,taxa_de_chegada,taxa_de_servico,probabilidade,tipo_evento):
    if tipo==CHEGADA:
        tempo_ate_prox_chegada = gera_amostra_exponencial(taxa_de_chegada)
        return (tempo_atual+tempo_ate_prox_chegada,tipo,tipo_evento,cliente_id,tempo_ate_prox_chegada,tempo_atual)
    elif tipo==PARTIDA:
        tempo_de_servico = 1.0/taxa_de_servico
        return (tempo_atual+tempo_de_servico,tipo,tipo_evento,cliente_id,tempo_de_servico,tempo_atual)
	def test_media_exp(self):
		taxa=0.1
		amostras = []
		for i in range(0,10000):
			amostra = utils_controller.gera_amostra_exponencial(taxa)
			amostras.append(amostra)
		media = utils_controller.media(amostras)
		#Faz o arredondamento
		media = round(media,0)
		self.assertEqual(media,10.0)
	def test_media(self):
		taxa=0.1
		amostras = []
		for i in range(0,10000):
			amostra = utils_controller.gera_amostra_exponencial(taxa)
			amostras.append(amostra)
		media = reduce(lambda x,y: x+y , amostras) / len(amostras)*1.0
		#Faz o arredondamento
		media = round(media,0)
		print media
		self.assertEqual(media,10)
def agenda_prox_evento(tipo,tempo_atual,cliente_id,taxa_de_chegada,taxa_de_servico,probabilidade,tipo_distribuicao):
    
    if tipo==CHEGADA:
        #Calcula tempo ate proxima chegada do cliente_id
        if tipo_distribuicao==EXPONENCIAL:
            tempo_ate_prox_chegada = gera_amostra_exponencial(taxa_de_chegada)
        elif tipo_distribuicao==DETERMINISTICA:
            tempo_ate_prox_chegada = 1/taxa_de_chegada
        elif tipo_distribuicao==UNIFORME:
            tempo_ate_prox_chegada = gera_amostra_uniforme(5,15)
        return (tempo_atual+tempo_ate_prox_chegada,CHEGADA,cliente_id,tempo_ate_prox_chegada,tempo_atual)
    elif tipo==PARTIDA:
        #Calcula tempo de servico do cliente_id
        if tipo_distribuicao==EXPONENCIAL:
            tempo_de_servico = 1.0/taxa_de_servico
        elif tipo_distribuicao==DETERMINISTICA:
            tempo_de_servico = 1.0/taxa_de_servico
        elif tipo_distribuicao==UNIFORME:
            tempo_de_servico = gera_amostra_exponencial(taxa_de_servico)

        return (tempo_atual+tempo_de_servico,PARTIDA,cliente_id,tempo_de_servico,tempo_atual)
def simulador(lbda, mi, p, tipo_dist,limite):
    
    #Inicializar variáveis de estado
    
    area = 0.0
    N = 0 #Numero de clientes no sistema
    A = 0 #Numero de atendimentos finalizados
    C = 0 #Numero de clientes que chegaram ate agora    
    b = 0.0 #Soma do período ocupado
    tb = 0 #Ultima vez que o periodo esteve ocupado
    
    #Inicializar lista de eventos
    #ev = my_events() 
    tempo_inicial = 0.0
    chegada_sistema_vazio = 0.0
    buffer_chegadas = []
    buffer_exp = []
    primeira_chegada = agenda_prox_evento(tipo=CHEGADA,tempo_atual=tempo_inicial, cliente_id=C, taxa_de_chegada=lbda,taxa_de_servico=mi,probabilidade=p, tipo_distribuicao=tipo_dist)
    ev = [primeira_chegada]
        
    #Processar lista de eventos
    i=1
    temp_chegada_antiga = 0.0
    while A<limite: #Enquanto criterio de parada nao for satisfeito
        ev_atual = heappop(ev) #Retira o proximo evento da heap        
        
        if ev_atual[TIPO]==CHEGADA:
            #tempo_entre_chegadas = ev_atual[TEMPO] - ev_atual[TEMPO_ATUAL]
            tempo_entre_chegadas = ev_atual[TEMPO_DE_SERVICO]
            tempo_exp = gera_amostra_exponencial(lbda)
            buffer_chegadas.append(tempo_entre_chegadas)
            buffer_exp.append(tempo_exp)
            
            #print ev_atual[TEMPO]
            
            area = area + N *(ev_atual[TEMPO]-ev_atual[TEMPO_ATUAL])
            
            if N==0:
                chegada_sistema_vazio+=1.0
            
            #Atualizo variáveis de estado
            N = N + 1    
            C = C + 1
            
            proxima_chegada = agenda_prox_evento(CHEGADA,ev_atual[TEMPO],cliente_id=C,taxa_de_chegada=lbda,taxa_de_servico=mi,probabilidade=p, tipo_distribuicao=tipo_dist)
            heappush(ev, proxima_chegada)
            
            #Se este é o primeiro             
            if N == 1:
                
                tb = ev_atual[TEMPO];
                
                proxima_partida = agenda_prox_evento(PARTIDA,ev_atual[TEMPO],ev_atual[ID],taxa_de_chegada=lbda,taxa_de_servico=mi,probabilidade=p, tipo_distribuicao=tipo_dist)
                
                heappush(ev,proxima_partida)
        elif ev_atual[TIPO]==PARTIDA :
            area = area + N *(ev_atual[TEMPO]-ev_atual[TEMPO_ATUAL])
            
            #Atualizo variáveis de estado
            valor = random.random()
            if(valor>(1-p)):
                #print "Retornou pra fila"
                A = A + 1
            else:
                N = N - 1
                A = A + 1
                #Se ainda tem alguém na fila            
            if N > 0:
                    #Agenda a próxima partida
                proxima_partida = agenda_prox_evento(PARTIDA,ev_atual[TEMPO],cliente_id=A,taxa_de_chegada=lbda,taxa_de_servico=mi,probabilidade=p, tipo_distribuicao=tipo_dist)
                heappush(ev,proxima_partida)
            else:
                b = b + ev_atual[TEMPO] - tb    
                
    u = b / ev_atual[TEMPO]
    fracao_chegadas_vazio = chegada_sistema_vazio/limite
    return (area/ev_atual[TEMPO_ATUAL],u,fracao_chegadas_vazio,buffer_chegadas,buffer_exp)