import random
class Maquina:
    def __init__(self, nMaquina, nPiezas, algoritmo):
        self._ejecucion = []
        self._nMaquina=nMaquina

        self._libre=True

        self._tiempoEjecucionFase=0
        self._tiempoActual = 0

        self._candidatos=[]

        self._faseActualMaquina=[]

        self._FasesEjecutadasLista=[]
        self._FasesEjecutadasHisto=[]
        self._algoritmo=algoritmo
        self._piezasEspera = {}
        for i in range(nPiezas):
            self._piezasEspera[i+1]=False
    def getFases(self):
        return  self._FasesEjecutadasHisto
    def getEjecucion(self):
        return self._ejecucion
    def getNmaquina(self):
        return self._nMaquina
    def getTiempoMaquina(self):
        return self._tiempoActual
    def getCandidatos(self):
        return self._candidatos
    def setEjecucion(self, nPieza):
        if nPieza != 0:
            self._ejecucion.append(nPieza)
        else:
            self._ejecucion.append(0)

    def esLibre(self):
        faseEliminada=self._faseActualMaquina
        if len(self._faseActualMaquina) > 0:
            if self._libre==False:
                diferenciaTiempo = self._tiempoActual - self._tiempoEjecucionFase
                if diferenciaTiempo==self._faseActualMaquina[0].get_tiempoRequerido():
                    self._piezasEspera[self._faseActualMaquina[0].get_nPieza()]=False
                    self._libre=True
                    if self._faseActualMaquina[0] in self._candidatos:
                        self._FasesEjecutadasHisto[-1].set_TiempoSalida(self._tiempoActual)
                        self._candidatos.remove(self._faseActualMaquina[0])
                        self._faseActualMaquina=[]
                        return faseEliminada
        return []
                        #self._tiempoEjecucionFase=self._tiempoActual
    def guardaFaseCandidata(self, fase):
        self._candidatos.append(fase)
        self._piezasEspera[fase.get_nPieza()]=True
    """def resetTiempoEjecucionProceso(self):
        self._tiempoEjecucionProceso = 0"""

    def PiezaEntradaEspera(self, nPieza):
        return self._piezasEspera[nPieza]
    def SetTiempo(self):
        self._tiempoActual+=0.5
        if len(self._faseActualMaquina) > 0:
            self._FasesEjecutadasHisto.append(self._faseActualMaquina[0])
        else:
            self._FasesEjecutadasHisto.append(0)
    def ejecutarFase(self, tamanosCola):
        #self.esLibre()
        if len(self._candidatos) >0 and self._libre==True:
            if self._algoritmo == "spt":
                self.spt()
            elif self._algoritmo=="llp":
                self.llp()
            elif self._algoritmo=="fifo":
                self.fifo()
            elif self._algoritmo== "mayortiempo":
                self.mayorTiempoOperacionesRestantes()
            elif self._algoritmo=="aleatorio":
                self.aleatorio()
            elif self._algoritmo=="mayorvalor":
                self.mayorValor()
            elif self._algoritmo=="edd":
                self.edd()
            elif self._algoritmo == "winq":
                self.winq(tamanosCola)
            self._libre =False
            if len(self._faseActualMaquina) > 0:
                self._FasesEjecutadasLista.append(self._faseActualMaquina[0])
    def spt(self):


        for candidato in self._candidatos:


            if len(self._faseActualMaquina) == 0:
                self._faseActualMaquina=[candidato]
                self._tiempoEjecucionFase = self._tiempoActual
                candidato.set_TiempoEntrada(self._tiempoActual)
            elif self._faseActualMaquina[0].get_tiempoRequerido() > candidato.get_tiempoRequerido():
                self._faseActualMaquina = [candidato]
                self._tiempoEjecucionFase = self._tiempoActual
                candidato.set_TiempoEntrada(self._tiempoActual)

    def llp(self):
        for candidato in self._candidatos:


            if len(self._faseActualMaquina) == 0:
                self._faseActualMaquina=[candidato]
                self._tiempoEjecucionFase = self._tiempoActual
                candidato.set_TiempoEntrada(self._tiempoActual)
            elif self._faseActualMaquina[0].get_tiempoRequerido() < candidato.get_tiempoRequerido():
                self._faseActualMaquina = [candidato]
                self._tiempoEjecucionFase = self._tiempoActual
                candidato.set_TiempoEntrada(self._tiempoActual)

    def mayorTiempoOperacionesRestantes(self):
        for candidato in self._candidatos:

            if len(self._faseActualMaquina) == 0:
                self._faseActualMaquina = [candidato]
                self._tiempoEjecucionFase = self._tiempoActual
                candidato.set_TiempoEntrada(self._tiempoActual)
            elif self._faseActualMaquina[0].get_tiempoOperacionalRestante() < candidato.get_tiempoOperacionalRestante():
                self._faseActualMaquina = [candidato]
                self._tiempoEjecucionFase = self._tiempoActual
                candidato.set_TiempoEntrada(self._tiempoActual)
    def mayorValor(self):
        for candidato in self._candidatos:

            if len(self._faseActualMaquina) == 0:
                self._faseActualMaquina = [candidato]
                self._tiempoEjecucionFase = self._tiempoActual
                candidato.set_TiempoEntrada(self._tiempoActual)
            elif self._faseActualMaquina[0].getValor()< candidato.getValor():
                self._faseActualMaquina = [candidato]
                self._tiempoEjecucionFase = self._tiempoActual
                candidato.set_TiempoEntrada(self._tiempoActual)
    def edd(self):
        for candidato in self._candidatos:

            if len(self._faseActualMaquina) == 0:
                self._faseActualMaquina = [candidato]
                self._tiempoEjecucionFase = self._tiempoActual
                candidato.set_TiempoEntrada(self._tiempoActual)
            elif self._faseActualMaquina[0].getTiempoEsperado() > candidato.getTiempoEsperado():
                self._faseActualMaquina = [candidato]
                self._tiempoEjecucionFase = self._tiempoActual
                candidato.set_TiempoEntrada(self._tiempoActual)


    def winq(self, tamanosCola):
        for candidato in self._candidatos:
            colaSigCand=tamanosCola[candidato.getTiempoSig()-1]

            if len(self._faseActualMaquina) == 0:
                self._faseActualMaquina = [candidato]
                self._tiempoEjecucionFase = self._tiempoActual
                candidato.set_TiempoEntrada(self._tiempoActual)
                colaSigAnt = tamanosCola[self._faseActualMaquina[0].getTiempoSig() - 1]
            elif colaSigAnt > colaSigCand:
                self._faseActualMaquina = [candidato]
                self._tiempoEjecucionFase = self._tiempoActual
                candidato.set_TiempoEntrada(self._tiempoActual)
                colaSigAnt = tamanosCola[self._faseActualMaquina[0].getTiempoSig() - 1]

    def fifo(self):
        self._faseActualMaquina = [self._candidatos[0]]
        self._tiempoEjecucionFase = self._tiempoActual
        self._candidatos[0].set_TiempoEntrada(self._tiempoActual)

    def aleatorio(self):
        self._faseActualMaquina = [random.choice(self._candidatos)]
        self._tiempoEjecucionFase = self._tiempoActual
        self._faseActualMaquina[0].set_TiempoEntrada(self._tiempoActual)

