import numpy as np

class MinMaxFrequencyDetector():
    def __init__(self):
        self.timeWindowMin    = 0.5
        self.tempAmplitudeMin = 0.5
        self.bufferSize       = 7
        self.bufferPeriodSize = 4

        self.paramMaxTemp = 100.0
        self.paramMinTemp = -100.0

        self.isFoundedTmin = False
        self.isFoundedTmax = False
        self.timeTmin = 0.0
        self.timeTmax = 0.0
        self.tempTmin = self.paramMaxTemp
        self.tempTmax = self.paramMinTemp

        self.counterTminBuffer = 0
        self.counterTmaxBuffer = 0

        self.tempBuffer = [0.0] * self.bufferSize
        self.timeBuffer = [0.0] * self.bufferSize

        self.timeTminBuffer = [0.0] * self.bufferPeriodSize
        self.timeTmaxBuffer = [0.0] * self.bufferPeriodSize
        self.tempTminBuffer = [0.0] * self.bufferPeriodSize
        self.tempTmaxBuffer = [0.0] * self.bufferPeriodSize

        self.hasAmplitudeChanged = False

        self.isTheFirstSample = True

        self.averagePeriodTmin = 7.5
        self.averagePeriodTmax = 7.5

    def getIsSignalTmin(self, waitTimeMax , numberCycless):
        numberCycles = numberCycless
        #Saturate the numberCycles if user enters a value greater than the bufferPeriodSize:
        if (numberCycles > (self.bufferPeriodSize-1)):
            numberCycles = (self.bufferPeriodSize-1)
        #If the stored samples are less than total capacity of the bufferPeriodSize, then there is no signal. Condition happens only at the beggining
        if(self.counterTminBuffer < self.bufferPeriodSize):
            return False
        #If the difference between the time now and the time when the last Tmin was detected is large enough, then there is no signal:
        if((self.timeBuffer[0] - self.timeTminBuffer[0]) > waitTimeMax):
            return False
        #If any of the last periods is large enough, then there is no signal. This is used for filtering false positive signal detection:
        for i in range(numberCycles):
            if((self.timeTminBuffer[i] - self.timeTminBuffer[i+1]) > waitTimeMax):
                return False
        #If in the previous conditions were not satisfied, then there is signal:
        return True



    def getPeriodTminSec(self):
        return self.averagePeriodTmin
    

    def pushNewSample(self, time, temp):
        if (self.isTheFirstSample):
            self.isTheFirstSample = False
            for n in range(self.bufferSize):
                self.tempBuffer[n] = temp
                self.timeBuffer[n] = time
            return

        for n in range(self.bufferSize-1,0,-1):
            self.tempBuffer[n] = self.tempBuffer[n-1]
            self.timeBuffer[n] = self.timeBuffer[n-1]
        
        self.tempBuffer[0] = temp
        self.timeBuffer[0] = time

        if ((self.tempBuffer[0] > self.tempBuffer[self.bufferSize-2]) and (self.isFoundedTmin==False)):
            if (self.tempBuffer[self.bufferSize-2] < self.tempTmin):
                self.tempTmin = self.tempBuffer[self.bufferSize - 2]
            else:
                self.hasAmplitudeChanged = True
                self.isFoundedTmin = True
                
                self.tempTmin = self.tempBuffer[self.bufferSize-1]
                self.timeTmin = self.timeBuffer[self.bufferSize-1]
                
                self.isFoundedTmax = False
                self.tempTmax = self.paramMinTemp

                
                if (self.counterTminBuffer < self.bufferPeriodSize):
                    self.counterTminBuffer += 1
                
                for n in range(self.bufferPeriodSize-1,0,-1):
                    self.timeTminBuffer[n] = self.timeTminBuffer[n-1]
                    self.tempTminBuffer[n] = self.tempTminBuffer[n-1]

                self.timeTminBuffer[0] = self.timeTmin
                self.tempTminBuffer[0] = self.tempTmin
                
                if (self.counterTminBuffer > 1):
                    averageAux = 0
                    for n in range(self.counterTminBuffer-1):
                        averageAux += (self.timeTminBuffer[n] - self.timeTminBuffer[n+1])
                    self.averagePeriodTmin = averageAux/(self.counterTminBuffer-1)
        
        elif ((self.tempBuffer[0] <= self.tempBuffer[self.bufferSize-2]) and (self.isFoundedTmax == False)):
            if (self.tempBuffer[self.bufferSize-2] > self.tempTmax):
                self.tempTmax = self.tempBuffer[self.bufferSize-2]
            else:
                self.tempTmax = self.tempBuffer[self.bufferSize-1]
                self.timeTmax = self.timeBuffer[self.bufferSize-1]
                if (((self.timeTmax - self.timeTmin) > self.timeWindowMin) and (np.abs(self.tempTmax - self.tempTmin) > self.tempAmplitudeMin)):
                    self.hasAmplitudeChanged = True
                    self.isFoundedTmax = True
                    
                    self.tempTmax = self.tempBuffer[self.bufferSize-1]
                    self.timeTmax = self.timeBuffer[self.bufferSize-1]
                    
                    self.isFoundedTmin = False
                    self.tempTmin = self.paramMaxTemp

                    if (self.counterTmaxBuffer < self.bufferPeriodSize):
                        self.counterTmaxBuffer += 1
                    
                    for n in range(self.bufferPeriodSize-1, 0,-1):
                        self.timeTmaxBuffer[n] = self.timeTmaxBuffer[n-1]
                        self.tempTmaxBuffer[n] = self.tempTmaxBuffer[n-1]
                    
                    self.timeTmaxBuffer[0] = self.timeTmax
                    self.tempTmaxBuffer[0] = self.tempTmax
                    
                    if (self.counterTmaxBuffer > 1):
                        averageAux = 0
                        for n in range(self.counterTmaxBuffer-1):
                            averageAux += (self.timeTmaxBuffer[n] - self.timeTmaxBuffer[n+1])
                        self.averagePeriodTmax = averageAux/(self.counterTmaxBuffer-1)
