import os, platform, sys
from models.kempers01 import Kempers01
from pycThermopack.pyctp import cubic, extended_csp, cpa, pcsaft, saftvrmie
import pandas as pd
import numpy as np
from datetime import datetime

ROOT_PATH = os.path.dirname(os.path.abspath(__file__))
DATA_PATH = ROOT_PATH + '/data/benchmark'

class BenchmarkRunner:
    def __init__(self, mode='cov', points=50, version=None):
        verify = input('Initialising BenchmarkRunner with mode :'+mode+', points : ' + str(points)+'. "Y" to continiue.')
        if verify != 'Y':
            exit(0)

        self.points = points
        self.mode = mode
        self.model = Kempers01
        self.model_name = 'Kempers01'

        if version is None:
            # Make output dir for this benchmark run
            i = 0
            while os.path.isdir(ROOT_PATH + '/output/benchmark/V' + str(i)):
                i += 1

            self.outdir = ROOT_PATH + '/output/benchmark/V' + str(i)
            self.outpath = self.outdir + '/' + mode
            os.mkdir(self.outdir)
            os.mkdir(self.outpath)


            # Write a little meta file to the output dir
            with open(self.outdir+'/meta.txt', 'w') as file:
                tags = ['Date', 'Model', 'Mode']
                vals = [datetime.now().strftime("%d/%m/%Y %H:%M:%S"), self.model_name, mode]
                for tag, val in zip(tags, vals):
                    file.write(tag + ' : ' + str(val) + '\n')

                file.write('\nContains runs for :\n')
        else:
            self.outdir = ROOT_PATH + '/output/benchmark/V' + str(version)
            self.outpath = self.outdir + '/'+mode
            if os.path.isdir(self.outpath):
                print('This BenchmarkRunner instance may overwrite files in', self.outpath)
                verify = input("'Y' to verify")
                if verify != 'Y':
                    exit(0)

                with open(self.outdir + '/meta.txt', 'a') as file:
                    file.write('\n#########################\n')
                    tags = ['Date', 'Model', 'Mode']
                    vals = [datetime.now().strftime("%d/%m/%Y %H:%M:%S"), self.model_name, mode]
                    for tag, val in zip(tags, vals):
                        file.write(tag + ' : ' + str(val) + '\n')

                    file.write('\nContains runs for :\n')
            else:
                os.mkdir(self.outpath)


    def update_meta(self, filename):
        with open(self.outdir + '/meta.txt', 'a') as file:
            file.write(filename +', '+ self.mode + '\n')

    def data_298(self, filename, comps):
        data = pd.read_excel(DATA_PATH + '/298_files/' + filename + '_298.xlsx')
        x_data = data['c']
        x_axis = np.linspace(min(x_data), max(x_data), self.points)

        eos_list = ['VdW', 'SRK', 'PR', 'PT', 'SW', 'PC-SAFT', 'SPUNG']
        data = {'Components': comps, 'Temp': 298, 'Pres': 1e5, 'x_'+comps.split(',')[0]: x_axis}

        eos = cubic.cubic()
        eos.init(comps, 'VdW')
        model = self.model(comps, eos, temp=298, pres=1e5)

        for i, eos_key in enumerate(eos_list[:-2]):
            eos = cubic.cubic()
            eos.init(comps, eos_key)
            model.set_eos(eos)
            data[eos_key] = model.get_soret_comp(x_axis, mode=self.mode)[0]

        eos = pcsaft.pcsaft()
        eos.init(comps)
        model = self.model(comps, eos, temp=298)
        data['PC-SAFT'] = model.get_soret_comp(x_axis, mode=self.mode)[0]

        eos = extended_csp.ext_csp()
        eos.init(comps, 'SRK', 'Classic', 'vdW', 'NIST_MEOS', 'C3')
        model = self.model(comps, eos, temp=298)
        data['SPUNG'] = model.get_soret_comp(x_axis, mode=self.mode)[0]

        df = pd.DataFrame(data)
        save_path = self.outpath+'/298_files/'+filename+'.csv'
        df.to_csv(save_path)
        print('Saved :', save_path)
        self.update_meta(filename)


    def run_298(self):
        os.mkdir(self.outpath+'/298_files')
        solute_names = ['benzene', 'toluene']
        solvent_names = ['_hexane', '_heptane']
        solvent_codes = [',NC6', ',NC7']

        comp_codes = ['BENZENE', 'TOLU']
        compnames = ['benzene', 'toluene']

        for i in range(2):
            for j in range(2):
                self.data_298(solute_names[i] + solvent_names[j], comp_codes[i] + solvent_codes[j])

    def n_alkanes(self):
        os.mkdir(self.outpath+'/n_alkanes')
        mixtures = ['NC10,NC5', 'NC12,NC6', 'NC12,NC7', 'NC12,NC8']

        eos_list = ['VdW', 'SRK', 'PR', 'PT', 'SW', 'PC-SAFT', 'SPUNG']

        for comps in mixtures:
            comp1, comp2 = comps.split(',')

            data = pd.read_excel(DATA_PATH + '/n-alkanes/' + comp1 + '_' + comp2 + '_298K.xlsx')
            x1_list = data['c']

            x_axis = np.linspace(min(x1_list), max(x1_list), self.points)

            data = {'Components': comp2+','+comp1, 'Temp': 298, 'Pres': 1e5, 'x_'+comp2 : x_axis}
            for i, eos_key in enumerate(eos_list[:-2]):
                print('n-alkanes : ', eos_key, comps)
                eos = cubic.cubic()
                eos.init(comps, eos_key)
                model = self.model(comps, eos, temp=298)
                data[eos_key] = model.get_soret_comp(x_axis, mode=self.mode)[1]

            eos = pcsaft.pcsaft()
            eos.init(comps)
            model = self.model(comps, eos, temp=298)
            data['PC-SAFT'] = model.get_soret_comp(x_axis, mode=self.mode)[1]

            eos = extended_csp.ext_csp()
            eos.init(comps, 'SRK', 'Classic', 'vdW', 'NIST_MEOS', 'C3')
            model = self.model(comps, eos, temp=298)
            data['SPUNG'] = model.get_soret_comp(x_axis, mode=self.mode)[1]

            df = pd.DataFrame(data)
            save_path = self.outpath + '/n_alkanes/' + comp1 + '_' + comp2 + '.csv'
            df.to_csv(save_path)
            print('Saved :', save_path)
            self.update_meta(comp1+'_'+comp2)

    def cold_gas(self):
        comps = 'C1,AR'
        T = 88

        data = pd.read_excel(DATA_PATH + '/cold_gases/AR_C1_' + str(T) + 'K.xlsx')
        x_list = data['c']
        soret_list = data['ST']

        x_axis = np.linspace(min(x_list), max(x_list), self.points)

        eos_list = ['VdW', 'SRK', 'PR', 'PT', 'SW']
        data = {'Components': 'AR,C1', 'Temp': 88, 'Pres': 1e5, 'x_Ar' : x_axis}
        for i, eos_key in enumerate(eos_list):
            print('Cold gas :', eos_key)
            eos = cubic.cubic()
            eos.init(comps, eos_key)
            model = self.model(comps, eos, temp=T)
            data[eos_key] = model.get_soret_comp(1 - x_axis, mode=self.mode)[1]

        eos = extended_csp.ext_csp()
        print('Cold gas :', 'SPUNG')
        eos.init(comps, 'SRK', 'Classic', 'vdW', 'NIST_MEOS', 'C3')
        model = self.model(comps, eos, temp=88)
        data['SPUNG'] = model.get_soret_comp(x_axis, mode=self.mode)[1]

        eos = saftvrmie.saftvrmie()
        print('Cold gas :', 'SAFT-VR-MIE')
        eos.init(comps)
        model = self.model(comps, eos, temp=88)
        data['SAFT-VR-MIE'] = model.get_soret_comp(x_axis, mode=self.mode)[1]

        df = pd.DataFrame(data)

        save_path = self.outpath + '/AR_C1.csv'
        df.to_csv(save_path)
        print('Saved', save_path)
        self.update_meta('AR_C1')

    def etoh_h2o_T(self, eos, eos_name):
        if not os.path.isdir(self.outpath + '/ethanol_water'):
            os.mkdir(self.outpath + '/ethanol_water')

        save_path = self.outpath + '/ethanol_water/temp_'+ eos_name + '.csv'

        # Get data
        data = pd.read_csv(DATA_PATH + '/ethanol_water.csv', na_values='NaN')
        temp_list = [int(x) for x in data.columns[1:]]
        cons_list = data['c']

        comps = 'ETOH,H2O'
        temp_ax = np.linspace(min(temp_list), max(temp_list), self.points) + 273
        data = {'Components': 'EtOH,H2O', 'Temp': temp_ax, 'EOS' : eos_name,  'Pres': 1e5}

        # Because experimental data are given with weight fraction ethanol
        # So must convert to mole fractions to use model
        M_h2o = 18.02
        M_etoh = 46.07

        # Run model
        for c in cons_list:
            x_etoh = (c / M_etoh) / ((c / M_etoh) + ((1 - c) / M_h2o))
            x_h2o = 1 - x_etoh
            model = self.model(comps, eos, x=[x_etoh, x_h2o])
            data[c] = model.get_soret_temp(temp_ax, mode=self.mode)[0]

        df = pd.DataFrame(data)
        df.to_csv(save_path)
        print('Saved :', save_path + '.png')
        self.update_meta('EtOH_H2O_T_'+eos_name)

    def etoh_h2o_c(self, eos, eos_name):
        if not os.path.isdir(self.outpath + '/ethanol_water'):
            os.mkdir(self.outpath + '/ethanol_water')

        save_path = self.outpath + '/ethanol_water/cons_'+ eos_name +'.csv'
        # Get data
        data = pd.read_csv(DATA_PATH + '/ethanol_water.csv', na_values='NaN')
        temp_list = [int(x) for x in data.columns[1:]]
        cons_list = data['c']

        comps = 'ETOH,H2O'

        M_h2o = 18.02
        M_etoh = 46.07

        w_etoh_ax = np.linspace(min(cons_list), max(cons_list), self.points)
        w_h20_ax = 1 - w_etoh_ax

        data = {'Comment': 'Soret coefficient of water',
                'Components': 'EtOH,H2O',
                'Pres': 1e5,
                'EOS' : eos_name,
                'w_EtOH' : w_etoh_ax}

        x_etoh_ax = (w_etoh_ax / M_etoh) / ((w_etoh_ax / M_etoh) + (w_h20_ax / M_h2o))

        for T in temp_list:
            model = self.model(comps, eos, temp=T + 273)
            data[T] = model.get_soret_comp(x_etoh_ax, mode=self.mode)[1]

        df = pd.DataFrame(data)
        df.to_csv(save_path)
        print('Saved :', save_path)
        self.update_meta('EtOH_H2O_c_'+eos_name)

if __name__ == '__main__':
    print('Running')
    benchmark = BenchmarkRunner(mode='com', version=3)
    benchmark.run_298()
    benchmark.n_alkanes()
    benchmark.cold_gas()

    eos = cpa.cpa()
    eos.init('ETOH,H2O')
    benchmark.etoh_h2o_c(eos, 'CPA')
    benchmark.etoh_h2o_T(eos, 'CPA')

    eos = pcsaft.pcsaft()
    eos.init('ETOH,H2O')
    benchmark.etoh_h2o_c(eos, 'PC-SAFT')
    benchmark.etoh_h2o_T(eos, 'PC-SAFT')

    print('\nBenchmarking finished sucsessfully.\nOutput files saved to', benchmark.outpath)