#-------------------------------------------------------------------------------
# Name:          Experiment Manager
# Purpose:       Creates a list of experiments (flowrates dependent on inlet concentration and residence time) which are performend. 
#                The list is extended when the optimal experimental design in Matlab is used.
# Authors:       Leon H, Jonathan G, Eric N
#
# Last Version:  16.09.2022
# Copyright:     (c) Institute of Technical Biocatalysis TUHH
# Licence:       GNU GPL-v3 
#-------------------------------------------------------------------------------
from InputManager_2022_05_24 import InputManager

class ExperimentManager:
    def __init__(self,InputManager) -> None:
        
        self.InputManager = InputManager
        self.AdminValues = self.InputManager.getAdminValues()
        self.startValues = self.InputManager.getStartValues()
        self.RunParameters = self.InputManager.getAllRunParameters()
        self.PumpMode = self.InputManager.getPumpMode()

        # TODO: implement generally for everything?
        if self.PumpMode == 1:
            self.nPumps = 1
        elif self.PumpMode == 2:
            self.nPumps = 2
        elif self.PumpMode == 3:
            self.nPumps = 4
            
        self.ListExperiments = []

        self.timePassed = 0

        #self.createBaseStep()
        #self.createStartingExperiments()
        #self.createBaseStep()

    def getExperiments(self):
        return self.ListExperiments

    def addNewExperiment(self,resTime,targetS1 = [],targetS3 = []):
        self.ListExperiments.append(self.createNewExperiment(resTime,targetS1,targetS3))

    def addStep(self,resTime,targetS1 = [],targetS3 = []):
        self.ListExperiments.append(self.createStepExperiment(resTime,targetS1,targetS3))

    def createExperimentBase(self):
        tempExperiment = {}
        tempExperiment['Name'] = self.startValues.Name
        tempExperiment['isStep'] = False
        tempExperiment['Done'] = False
        tempExperiment['FigureAbs'] = None
        tempExperiment['FigureCnv'] = None
        tempExperiment['temperatures'] = []
        tempExperiment['flowRates'] = []
        tempExperiment['Flags'] = []

        return tempExperiment
    
    def createNewExperiment(self,resTime,targetS1 = [],targetS3 = []):
        ''' for both Mode 1 and 2 '''

        tempExperiment = self.createExperimentBase()
        tempExperiment['ResidenceTime'] = resTime

        if self.PumpMode == 1:
            tempExperiment['TotalFlowrate'] = self.startValues.ReactorVolume/resTime
            tempExperiment['StockConc'] = self.startValues.StartConcentration
            tempExperiment['GenFileName'] = '_'.join((self.startValues.Name,str(int(resTime))))

        elif self.PumpMode == 2:            
            tempExperiment['TargetConcentrationS1'] = targetS1
            tempExperiment['TotalFlowrate'] = self.startValues.ReactorVolume/resTime
            
            tempExperiment['GenFileName'] = '_'.join((self.startValues.Name,str(int(resTime)),str(targetS1)))

        elif self.PumpMode == 3:
            tempExperiment['TargetConcentrationS1'] = targetS1
            tempExperiment['TargetConcentrationS3'] = targetS3            
            tempExperiment['TotalFlowrate'] = self.startValues.ReactorVolume/resTime
            
            tempExperiment['GenFileName'] = '_'.join((self.startValues.Name,str(int(resTime)),str(targetS1),str(targetS3)))

        return tempExperiment

    def calcFlowrates(self,experiment):
        ''' calculates the flowrates, depending on the stock concentrations and the NAD-decay '''

        cNAD = 1/2*(2*self.startValues.ConcentrationS1-self.timePassed*self.AdminValues.DecayRate)
        print('Current concentration: %f mmol/l'%(cNAD))
        if self.PumpMode == 2:
            experiment['FlowrateS1'] = experiment['TotalFlowrate']*experiment['TargetConcentrationS1']/(cNAD)
            experiment['FlowrateS2'] = experiment['TotalFlowrate']-experiment['FlowrateS1']

        elif self.PumpMode == 3:
            experiment['FlowrateS1'] = experiment['TotalFlowrate']*experiment['TargetConcentrationS1']/(cNAD)
            experiment['FlowrateS3'] = experiment['TotalFlowrate']*experiment['TargetConcentrationS3']/self.startValues.ConcentrationS3
            experiment['FlowrateS2'] = 0.5*(experiment['TotalFlowrate']-experiment['FlowrateS1']-experiment['FlowrateS3'])
            experiment['FlowrateS4'] = experiment['FlowrateS2']
        pass

    def createStepExperiment(self,resTime,targetS1 = None,targetS3 = None):
        if targetS1 is None:
            targetS1 = 0
        if targetS3 is None:
            targetS3 = 0
        tempExperiment = self.createExperimentBase()
        tempExperiment['isStep'] = True
        tempExperiment['TargetConcentrationS1'] = 0.1
        tempExperiment['TargetConcentrationS3'] = 0
        self.startValues.ConcentrationS1
        # set ResidenceTime so that Experiment will run for 0.5min+ResTime+StepMaxDelay
        tempExperiment['ResidenceTime'] = resTime
        tempExperiment['Step'] = {}

        tempExperiment['Step']['ResidenceTime'] = self.AdminValues.StepResTime
        for i in range(self.nPumps):
            tempExperiment['FlowrateS%i'%(i+1)] = 0
        # tempExperiment['FlowrateS2'] = self.startValues.ReactorVolume/self.AdminValues.StepResTime
        tempExperiment['FlowrateS2'] = 0.1
        tempExperiment['TotalFlowrate'] = tempExperiment['FlowrateS2']

        '''
        mix = targetS1/self.startValues.ConcentrationS1
        tempExperiment['Step']['FlowrateS1'] = self.startValues.ReactorVolume/self.AdminValues.StepResTime*mix
        tempExperiment['Step']['FlowrateS2'] = self.startValues.ReactorVolume/self.AdminValues.StepResTime*(1-mix)
        '''
        tempExperiment['Step']['FlowrateS1'] = 0.5
        tempExperiment['Step']['FlowrateS2'] = 0.1
        for i in range(2,self.nPumps):
            tempExperiment['Step']['FlowrateS%i'%(i+1)] = 0
        tempExperiment['Step']['TotalFlowrate'] = tempExperiment['Step']['FlowrateS1'] + tempExperiment['Step']['FlowrateS2']

        tempExperiment['GenFileName'] = '_'.join(('Step',str(self.startValues.ReactorVolume),str(self.AdminValues.StepResTime),str(self.AdminValues.StepMaxDelay)))

        return tempExperiment

    def createStartingExperiments(self):

        if self.PumpMode == 1:
            for i in range(self.RunParameters.shape[0]):
                tempResTime = self.RunParameters.iloc[i]['ResTimes']
                self.addNewExperiment(tempResTime)
        elif self.PumpMode == 2:
            for i in range(self.RunParameters.shape[0]):
                tempResTime = self.RunParameters.iloc[i]['ResTimes']
                tempTarget1 = self.RunParameters.iloc[i]['TargetConcentrationS1']
                self.addNewExperiment(tempResTime,tempTarget1)
        elif self.PumpMode == 3:
            for i in range(self.RunParameters.shape[0]):
                tempResTime = self.RunParameters.iloc[i]['ResTimes']
                tempTarget1 = self.RunParameters.iloc[i]['TargetConcentrationS1']
                tempTarget3 = self.RunParameters.iloc[i]['TargetConcentrationS3']
                self.addNewExperiment(tempResTime,tempTarget1,tempTarget3)
        #print(self.ListExperiments)
        print('ListOfexperiments Done')
        
    def createBaseStep(self):
        resTime = (3+1/12+self.AdminValues.StepResTime*self.AdminValues.StepMaxDelay)/self.AdminValues.TimeSecurity
        targetS1 = self.startValues.ConcentrationS1/2
        self.addStep(resTime,targetS1)

    def setTimePassed(self,timePassed):
        self.timePassed = timePassed