#include "NGCal.h"
#include "Therm.h"
#include "Detail.h"
#include "math.h"
static Therm *ptTherm;
static Detail *ptDetail;

int NGCal_Init(NGParSTRUCT *ptNGPar) {

	ptDetail = Detail_Construct();
	if (NULL == ptDetail) {
		return MEMORY_ALLOCATION_ERROR;
	}


	ptTherm = (Therm *) malloc(sizeof(Therm));
	Therm_Init(ptTherm);
	if (NULL == ptTherm) {
		return MEMORY_ALLOCATION_ERROR;
	}

	return NGCal_NGCal;
}

int NGCal_UnInit(void) {
	if (ptDetail) free(ptDetail);
	if (ptTherm) free(ptTherm);
	return 0;
}

double SOS(NGParSTRUCT *ptNGPar) {
	if (NULL == ptDetail || NULL == ptTherm) {
		NGCal_UnInit();
		NGCal_Init(ptNGPar);
	}
	Therm_Run(ptTherm, ptNGPar, ptDetail);
	ptNGPar->dCstar = 0.0;
	return ptNGPar->dSOS;
}

double Crit(NGParSTRUCT *ptNGPar, double dPlenumVelocity) {
	if (NULL == ptDetail || NULL == ptTherm) {
		NGCal_UnInit();
		if (NGCal_NGCal != NGCal_Init(ptNGPar)) {
			ptNGPar->lStatus = MEMORY_ALLOCATION_ERROR;
			return 0.0;
		}
	}


	Therm_Run(ptTherm, ptNGPar, ptDetail);

	double DH = (ptNGPar->dSOS * ptNGPar->dSOS - dPlenumVelocity * dPlenumVelocity) / 2.0;
	double S = ptNGPar->dS;
	double H = ptNGPar->dH;
	double R = ptNGPar->dRhof;
	double P = ptNGPar->dPf;
	double Z = ptNGPar->dZf;
	double T = ptNGPar->dTf;
	// DDH = 10.0;
	for (int i = 1; i < MAX_NUM_OF_ITERATIONS; i++) {
		double tolerance = 1.0;
		Therm_HS_Mode(ptTherm, ptNGPar, ptDetail, H - DH, S, 1);
		Therm_Run(ptTherm, ptNGPar, ptDetail);
		double DDH = DH;
		DH = (ptNGPar->dSOS * ptNGPar->dSOS - dPlenumVelocity * dPlenumVelocity) / 2.0;
		if (fabs(DDH - DH) < tolerance) break;
	}
	ptNGPar->dCstar = (ptNGPar->dRhof * ptNGPar->dSOS) / sqrt(R * P * Z);
	ptNGPar->dPf = P;
	ptNGPar->dTf = T;
	Therm_Run(ptTherm, ptNGPar, ptDetail);
	Detail_dhvMol(ptDetail,ptNGPar);
	return ptNGPar->dCstar;
}

double Cperf(const NGParSTRUCT *ptNGPar) {
	double k = ptNGPar->dKappa;
	double root = 2.0 / (k + 1.0);
	double exponent = (k + 1.0) / (k - 1.0);
	return (sqrt(k * pow(root, exponent)));
}

double CRi(const NGParSTRUCT *ptNGPar) {
	return (Cperf(ptNGPar) / sqrt(ptNGPar->dZf));
}
