import subprocess
import re
import os
import numpy as np
import matplotlib.pyplot as plt
import math
import fileinput
import time
import matplotlib.ticker as tickers
import matplotlib as mpl
from matplotlib.ticker import MultipleLocator,FormatStrFormatter,MaxNLocator
import codecs
import sys


#-------------------------------------------------------------------------------------------------------
def run_CellProblem(executable, parset, gridLevel, gamma, mu1,lambda1, rho1, alpha, beta, theta, material_prestrain_imp, outputPath, write_materialFunctions, write_prestrainFunctions, write_VTK,write_L2Error ,write_IntegralMean, write_LOG ):
    print('----- RUN Cell-Problem ----')
    processList = []
    LOGFILE = "Cell-Problem_output.log"
    print('LOGFILE:',LOGFILE)
    print('executable:',executable)
    print('parset:',parset)

    # test = {5,5}
    # test = '5 5'
    # levels = [gridLevel, gridLevel]
    # print(listToString(gridLevel))
        # start_time = time.time()
    if write_LOG:
        p = subprocess.Popen(executable + parset
                                        # + " -numLevels " + str(str(gridLevel) + "  " + str(gridLevel))
                                        # + " -numLevels " + str(4) + " " + str(4)
                                        # + " -numLevels " + {listToString(gridLevel)}
                                        # + " -numLevels " + " " + test
                                        # + " -gamma " + str(gamma)
                                        # + " -mu1 " + str(mu1)
                                        # + " -lambda1 " + str(lambda1)
                                        # + " -alpha " + str(alpha)
                                        # + " -beta " + str(beta)
                                        # + " -theta " + str(theta)
                                        + " -material_prestrain_imp " + str(material_prestrain_imp)
                                        + " -write_materialFunctions " + str(write_materialFunctions)
                                        + " -write_prestrainFunctions " + str(write_prestrainFunctions)
                                        + " -write_VTK " + str(write_VTK)
                                        + " -write_L2Error " + str(write_L2Error)
                                        + " -write_IntegralMean" + str(write_IntegralMean)
                                        + " -outputPath " + str(outputPath)
                                        + " | tee " + LOGFILE, shell=True)

    else:
        p = subprocess.Popen(executable + parset
                                        # + " -numLevels " + str(gridLevel) + " " + str(gridLevel)
                                        # + " -gamma " + str(gamma)
                                        # + " -mu1 " + str(mu1)
                                        # + " -lambda1 " + str(lambda1)
                                        # + " -alpha " + str(alpha)
                                        # + " -beta " + str(beta)
                                        # + " -theta " + str(theta)
                                        + " -material_prestrain_imp " + str(material_prestrain_imp)
                                        + " -write_materialFunctions " + str(write_materialFunctions)
                                        + " -write_prestrainFunctions " + str(write_prestrainFunctions)
                                        + " -write_VTK " + str(write_VTK)
                                        + " -write_L2Error " + str(write_L2Error)
                                        + " -write_IntegralMean" + str(write_IntegralMean)
                                        + " -outputPath " + str(outputPath), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, shell=True )  # surpress Logging

    p.wait() # wait

    # print("--- %s seconds ---" % (time.time() - start_time))
    # print('------FINISHED PROGRAM on level:' + str(gridLevel))
    processList.append(p)
    ###Wait for all simulation subprocesses before proceeding
    exit_codes = [p.wait() for p in processList]

    return

#-------------------------------------------------------------------------------------------------------
def ReadEffectiveQuantities(QFilePath = os.path.dirname(os.getcwd()) + '/outputs/QMatrix.txt', BFilePath = os.path.dirname(os.getcwd())+ '/outputs/BMatrix.txt'):
    # Read Output Matrices (effective quantities)
    # From Cell-Problem output Files : ../outputs/Qmatrix.txt , ../outputs/Bmatrix.txt
    # -- Read Matrix Qhom
    X = []
    # with codecs.open(path + '/outputs/QMatrix.txt', encoding='utf-8-sig') as f:
    with codecs.open(QFilePath, encoding='utf-8-sig') as f:
        for line in f:
            s = line.split()
            X.append([float(s[i]) for i in range(len(s))])
    Q = np.array([[X[0][2], X[1][2], X[2][2]],
                  [X[3][2], X[4][2], X[5][2]],
                  [X[6][2], X[7][2], X[8][2]] ])

    # -- Read Beff (as Vector)
    X = []
    # with codecs.open(path + '/outputs/BMatrix.txt', encoding='utf-8-sig') as f:
    with codecs.open(BFilePath, encoding='utf-8-sig') as f:
        for line in f:
            s = line.split()
            X.append([float(s[i]) for i in range(len(s))])
    B = np.array([X[0][2], X[1][2], X[2][2]])
    return Q, B


# Function to convert a list to string
def listToString(s):
    # initialize an empty string
    str1 = " "
    # return string
    # return (str1.join(str(s)))
    return (str1.join(str(e) for e in s))


def SetParametersCellProblem(mu_,lambda_,rho_,alpha,beta,theta,gamma,gridLevel, ParsetFilePath = os.path.dirname(os.getcwd()) +"/inputs/cellsolver.parset"):
    print('----set Parameters -----')
    with open(ParsetFilePath, 'r') as file:
        filedata = file.read()
    filedata = re.sub('(?m)^numLevels\s?=.*','numLevels='+str(gridLevel)+' '+str(gridLevel) ,filedata)
    filedata = re.sub('(?m)^alpha\s?=.*','alpha='+str(alpha),filedata)
    filedata = re.sub('(?m)^beta\s?=.*','beta='+str(beta),filedata)
    filedata = re.sub('(?m)^theta\s?=.*','theta='+str(theta),filedata)
    filedata = re.sub('(?m)^gamma\s?=.*','gamma='+str(gamma),filedata)
    filedata = re.sub('(?m)^mu\s?=.*','mu='+listToString(mu_),filedata)
    filedata = re.sub('(?m)^lambda\s?=.*','lambda='+listToString(lambda_),filedata)
    filedata = re.sub('(?m)^rho\s?=.*','rho='+listToString(rho_),filedata)
    filedata = re.sub('(?m)^mu1\s?=.*','mu1='+str(mu_[0]),filedata)
    filedata = re.sub('(?m)^rho1\s?=.*','rho1='+str(rho_[0]),filedata)
    filedata = re.sub('(?m)^lambda1\s?=.*','lambda1='+str(lambda_[0]),filedata)
    f = open(ParsetFilePath,'w')
    f.write(filedata)
    f.close()

#-------------------------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------------------------