//R. Franz
//Energent LLC.
//Santa Ana, CA.

#define setup_use_string

using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

// all variables in unmanaged DLL function need to be managed types in code  i.e. Int32 instead of long

namespace mf_net_wa_sln
{

/*
for nc=2 
HFILES_st="C:/Program Files/NIST/Refprop7/Fluids/R32.fld|C:/Program Files/NIST/Refprop7/Fluids/R125.fld|";
if using HFILES_ch, if terminating '|' is not there, unable to find file for 2nd component
console:  please enter file name   unit 12
*/

	// modified Refdemo.cpp
	// consider changing the names of the variables in this sample (and Refdemo.cpp) to match those in manual.txt
	//      subroutine SETUP (nc,hfiles,hfmix,hrf,ierr,herr)
	//      subroutine SATP (p,x,kph,t,rhol,rhov,xliq,xvap,ierr,herr)

	public class mf_net_wa__refprop
	{
		// Some constants...
		//public const Int32 refpropfluidpathlength=10000;
		public const Int32 refpropfluidpathlength=(refpropcharlength+1)*compsize; //+1 for '|' between file names

		public const Int32 refpropcharlength=255;
		public const Int32 filepathlength=255;
		public const Int32 lengthofreference=3;
		public const Int32 errormessagelength=255;
		public const Int32 compsize=20;

		const string FluidsDirectory=  "c:/Program Files/NIST/RefProp7/fluids/";
		const string MixturesDirectory="c:/Program Files/NIST/RefProp7/mixtures/";
		const string refpropDLL_path=  "c:/Program Files/NIST/RefProp7/Refprop.dll";

		[DllImport(refpropDLL_path, EntryPoint="SETUPdll", SetLastError=true)]
		//ok public static extern void SETUPdll(ref Int32 NumberOfComponents, char[] HFILES, char[] HFMIX, char[] HRF, [In, Out] ref Int32 ierr, [MarshalAs(UnmanagedType.LPArray, SizeConst=errormessagelength)] [In, Out] char[] HERR, Int32 l1, Int32 l2, Int32 l3, Int32 l4);
#if (setup_use_string)
			public static extern void SETUPdll(ref Int32 NumberOfComponents, string HFILES, string HFMIX, string HRF, [In, Out] ref Int32 ierr,  [In, Out] char[] HERR, Int32 l1, Int32 l2, Int32 l3, Int32 l4);
#else
			public static extern void SETUPdll(ref Int32 NumberOfComponents, char[] HFILES, char[] HFMIX, char[] HRF, [In, Out] ref Int32 ierr,  [In, Out] char[] HERR, Int32 l1, Int32 l2, Int32 l3, Int32 l4);
#endif
		
		[DllImport(refpropDLL_path, EntryPoint="SATPdll", SetLastError=true)]
		//ok public static extern void SATPdll(ref double PkPa, double[] X, ref Int32 KPH, [In, Out] ref double TK, [In, Out] ref double RHOF, [In, Out] ref double RHOG, [Out] double[] XLIQ, [Out] double[] XVAP, [In, Out] ref Int32 ierr, [MarshalAs(UnmanagedType.LPArray, SizeConst=errormessagelength)] [In, Out] char[] HERR, Int32 LengthHERR);
		public static extern void SATPdll(ref double PkPa, double[] X, ref Int32 KPH, [In, Out] ref double TK, [In, Out] ref double RHOF, [In, Out] ref double RHOG, [Out] double[] XLIQ, [Out] double[] XVAP, [In, Out] ref Int32 ierr, [In, Out] char[] HERR, Int32 LengthHERR);

		// Definitions of the Refprop types  from Refdemo.cpp
/*		typedef void (__stdcall *fp_SETUPDLLTYPE)(long&,char*,char*,char*,long&,char*,long,long,long,long);
		typedef void (__stdcall *fp_INFOdllTYPE)(long&,double&,double&,double&,double&,double&,double&,double&,double&,double&,double&);
		typedef void (__stdcall *fp_SATdllTYPE)(double&,double*,long&,double&,double&,double&,double*,double*,long&,char*, long);
		typedef void (__stdcall *fp_ENTROENTHALdllTYPE)(double&,double&,double*,double&);
		typedef void (__stdcall *fp_TDPFLSHdllTYPE)(double&,double&,double*,double&,double&,double&,double*,double*,double&,double&,double&,double&,double&,double&,double&,long&,char*, long);
		typedef void (__stdcall *fp_DEHSFLSHdllTYPE)(double&,double&,double*,double&,double&,double&,double&,double*,double*,double&,double&,double&,double&,double&,double&,long&,char*, long);
		typedef void (__stdcall *fp_TQHFLSHdllTYPE)(double&,double&,double*,long&,double&,double&,double&,double&,double*,double*,double&,double&,double&,double&,double&,double&,long&,char*, long);
		typedef void (__stdcall *fp_MASSMOLEFRACTIONdllTYPE)(double*,double*,double&);
		typedef void (__stdcall *fp_CRITPdllTYPE)(double*,double&,double&,double&,long&,char*, long);
		typedef void (__stdcall *fp_PSFL1dllTYPE)(double&,double&,double*,long&,double&,double&,long&,char*, long);
		typedef void (__stdcall *fp_TPRHOdllTYPE)(double&,double&,double*,long&,long&,double&,long&,char* HERR, long LengthHERR);
		typedef void (__stdcall *fp_PRESSdllTYPE)(double&,double&,double*,double&);
		typedef void (__stdcall *fp_GIBBSdllTYPE)(double&,double&,double*,double&,double& GR);
		typedef void (__stdcall *fp_CVCPdllTYPE)(double&,double&,double*,double&,double&);
		typedef void (__stdcall *fp_THERMdllTYPE)(double&,double&,double*,double&,double&,double&,double&,double&,double&,double&,double&);
		typedef void (__stdcall *fp_THERM2dllTYPE)(double&,double&,double*,double&,double&,double&,double&,double&,double&,double&,double&,double&,double&,double&,double&,double&,double&,double&,double&,double&,double&,double&,double&,double&,double&);
		typedef void (__stdcall *fp_TRNPRPdllTYPE)(double&,double&,double*,double&,double&,long&,char*, long);
		typedef void (__stdcall *fp_2IVdllTYPE)(double&,double&,double*,double&);
		typedef void (__stdcall *fp_LIMITXdllTYPE)(char*,double&,double&,double&,double*,double&,double&,double&,double&,long&,char*,long,long);
		typedef void (__stdcall *fp_SETKTVdllTYPE)(long&,long&,char*,double&,char*,long&,char*,long,long,long);
		typedef void (__stdcall *fp_GETKTVdllTYPE)(long&,long&,char*,double&,char*,char*,char*,char*,long ln1,long ln2,long ln3,long ln4,long ln5);
		typedef void (__stdcall *fp_GETFIJdllTYPE)(char*,char*,char*,char*,long,long,long);

		// Definition of pointers to the Refprop functions...
		void (__stdcall *SETUPdll)(long& NumberOfComponents, char* HFILES, char* HFMIX, char* HRF, long& ierr, char* HERR, long l1, long l2,long l3,long l4);
		void (__stdcall *INFOdll)(long& icomp, double& wm,double& ttp,double& tnbp,double& tc,double& pc,double& dc,double& zc,double& acf,double& dip,double& rgas);
		void (__stdcall *SATTdll)(double& TK,double* X, long& KPH, double& PkPa, double& RHOF, double& RHOG, double* XLIQ, double* XVAP,long& ierr, char* HERR, long LengthHERR);
		void (__stdcall *SATPdll)(double& PkPa,double* X, long& KPH, double& TK, double& RHOF, double& RHOG, double* XLIQ, double* XVAP,long& ierr, char* HERR, long LengthHERR);
		void (__stdcall *ENTROdll)( double& TK,double& RHOMOLL,double* X, double& SJMOLK);
		void (__stdcall *ENTHALdll)(double& TK,double& RHOMOLL,double* X, double& HJMOL);
		void (__stdcall *TDFLSHdll)(double&,double&,double*,double&,double&,double&,double*,double*,double&,double&,double&,double&,double&,double&,double&,long&,char*, long);
		void (__stdcall *TPFLSHdll)(double&,double&,double*,double&,double&,double&,double*,double*,double&,double&,double&,double&,double&,double&,double&,long&,char*, long);
		void (__stdcall *PDFLSHdll)(double&,double&,double*,double&,double&,double&,double*,double*,double&,double&,double&,double&,double&,double&,double&,long&,char*, long);
		void (__stdcall *DSFLSHdll)(double& RHOMOLL,double& SJMOLK, double* Z,double& TK,     double& PKPA,   double& RHOFMOL,double& RHOGMOL,double* X,double* Y, double& QUAL,double& UJMOL,double& HJMOL, double& CV,double& CP,double& W,long& ierr, char* HERR, long LengthHERR);
		void (__stdcall *DEFLSHdll)(double& RHOMOLL,double& UJMOL,  double* Z,double& TK,     double& PKPA,   double& RHOFMOL,double& RHOGMOL,double* X,double* Y, double& QUAL,double& HJMOL,double& SJMOL, double& CV,double& CP,double& W,long& ierr, char* HERR, long LengthHERR);
		void (__stdcall *PEFLSHdll)(double& PKPA,   double& UJMOL,  double* Z,double& TK,     double& RHOMOL, double& RHOFMOL,double& RHOGMOL,double* X,double* Y, double& QUAL,double& HJMOL,double& SJMOLK,double& CV,double& CP,double& W,long& ierr, char* HERR, long LengthHERR);
		void (__stdcall *DHFLSHdll)(double& RHOMOLL,double& HJMOL,  double* Z,double& TK,     double& PKPA,   double& RHOFMOL,double& RHOGMOL,double* X,double* Y, double& QUAL,double& UJMOL,double& SJMOLK,double& CV,double& CP,double& W,long& ierr, char* HERR, long LengthHERR);
		void (__stdcall *PHFLSHdll)(double& PKPA,   double& HJMOL,  double* Z,double& TK,     double& RHOMOL, double& RHOFMOL,double& RHOGMOL,double* X,double* Y, double& QUAL,double& UJMOL,double& SJMOLK,double& CV,double& CP,double& W,long& ierr, char* HERR, long LengthHERR);
		void (__stdcall *PSFLSHdll)(double& PKPA,   double& SJMOLK, double* Z,double& TK,     double& RHOMOL, double& RHOFMOL,double& RHOGMOL,double* X,double* Y, double& QUAL,double& UJMOL,double& HJMOL, double& CV,double& CP,double& W,long& ierr, char* HERR, long LengthHERR);
		void (__stdcall *THFLSHdll)(double& TK,     double& HJMOL,  double* Z,long& kr, double& PKPA,double& RHOMOL,double& RHOFMOL,double& RHOGMOL,double* X,double* Y, double& QUAL,  double& U,    double& SJMOLK,double& CV,double& CP,double& W,long& ierr, char* HERR, long LengthHERR);
		void (__stdcall *PQFLSHdll)(double& PKPA,   double& QUAL,   double* Z,long& kq, double& TK,  double& RHOMOL,double& RHOFMOL,double& RHOGMOL,double* X,double* Y, double& UJMOL, double& HJMOL,double& SJMOLK,double& CV,double& CP,double& W,long& ierr, char* HERR, long LengthHERR);
		void (__stdcall *TQFLSHdll)(double& TK,     double& QUAL,   double* Z,long& kq, double& PKPA,double& RHOMOL,double& RHOFMOL,double& RHOGMOL,double* X,double* Y, double& UJMOL, double& HJMOL,double& SJMOLK,double& CV,double& CP,double& W,long& ierr, char* HERR, long LengthHERR);
		void (__stdcall *XMASSdll)(double* X,       double* XKG,double& WMOL);
		void (__stdcall *XMOLEdll)(double* X,       double* XKG,double& WMOL);
		void (__stdcall *CRITPdll)(double* X,       double& TCRIT,  double& PCRIT,double& RHOCRIT, long& ierr,char* HERR, long LengthHERR);
		void (__stdcall *PSFL1dll)(double& PKPA,    double& SJMOLK, double* Z,  long& KPH,   double& TK,  double& RHOMOL,long& ierr,char* HERR, long LengthHERR);
		void (__stdcall *TPRHOdll)(double& TK,double& PKPA,double* X,long& KPH,long& KGUESS, double& RHO, long& ierr,char* HERR, long LengthHERR);
		void (__stdcall *PRESSdll)(double& TK,      double& RHOMOLL,double* X, double& PKPA);
		void (__stdcall *GIBBSdll)(double& TK,      double& RHOMOLL,double* X, double& AR,      double& GR);
		void (__stdcall *CVCPdll)(double& TK,      double& RHOMOLL,double* X, double& CVJMOLK, double& CPJMOLK);
		void (__stdcall *THERMdll)(double& TK,      double& RHOMOLL,double* X, double& PKPA,  double& UJMOL,double& HJMOL,double& SJMOLK, double& CVJMOLK, double& CPJMOLK, double& GAMMAMS, double& HJTKKPA);
		void (__stdcall *THERM2dll)(double& TK,      double& RHOMOLL,double* X, double& PKPA,  double& UJMOL,double& HJMOL,double& SJMOLK, double& CVJMOLK, double& CPJMOLK, double& OMEGA, double& Z, double& HJTKKPA,double& aH,double& G,double& xkappa,double& beta,double& dPdD,double& d2PdD2,double& dPdT,double& dDdT,double& dDdP,double& spare1,double& spare2,double& spare3,double& spare4);
		void (__stdcall *TRNPRPdll)(double& TK,      double& RHOMOLL,double* X, double& ETA,   double& TCX,  long& ierr,char* herr, long LengthHERR);

		void (__stdcall *DHDTdll)(double& TK,      double& RHOMOLL,double* X, double& dHdT);
		void (__stdcall *DPDDdll)(double& TK,      double& RHOMOLL,double* X, double& DPDRHO);
		void (__stdcall *DPDD2dll)(double& TK,      double& RHOMOLL,double* X, double& DP2DD2);
		void (__stdcall *DPDTdll)(double& TK,      double& RHOMOLL,double* X, double& DPT);
		void (__stdcall *DDDPdll)(double& TK,      double& RHOMOLL,double* X, double& DRHODP);
		void (__stdcall *DDDTdll)(double& TK,      double& RHOMOLL,double* X, double& DRHODT);
		void (__stdcall *FGCTYdll)(double& TK,      double& RHOMOLL,double* X, double& FUGACITY);// The following ifdef block is the standard way of creating macros which make exporting
		void (__stdcall *LIMITXdll)(char* htyp,double& TinK,double& rhoin_Mol,double& PinkPa, double* X, double& TminK, double& TmaxK, double& rhomaxMol,double& PmaxkPa, long& ierr,char* herr,long lnhtyp,long lnherr);
		void (__stdcall *SETKTVdll)(long& icomp, long& jcomp, char* hmodij,double& fij,char* hfmix,long& ierr,char* herr,long Lengthhmodij,long Lengthhfmix,long LengthHERR);
		void (__stdcall *GETKTVdll)(long& icomp, long& jcomp,char* hmodij,double& fij,char*  hfmix,char* hfij,char* hbinp,char* hmxrul,long ln1,long ln2,long ln3,long ln4,long ln5);
		void (__stdcall *GETFIJdll)(char* hmodij,char* fij,char* hfij,char* hmxrul,long ln1,long ln2,long ln3);
*/

		
		double[] x; //[compsize]={0};
		Int32 nc,ierr;
		char[] HFILES_ch, HRF_ch, HERR_ch, HFMIX_ch;
		string HFILES_st, HRF_st,          HFMIX_st;  //HERR_st unable to return HERR as string

		public mf_net_wa__refprop()
		{
			// Now use the functions.

			// Refprop variables that need to be defined
			//
			// nc = Number of components in the mixture
			// x[NumberOfComponentsInMixtures] = Mole fraction of each component
			// ierr =  An integer flag defining an error
			// HFILES[] = a character array defining the fluids in a mixture
			// HRF[] = a character array denoting the reference state
			// HERR[] = a character array for storing a string - Error message
			// HFMIX[] a character array defining the path to the mixture file

			x=new double[compsize];
			HFILES_ch=new char[refpropfluidpathlength+1];
			HRF_ch=new char[lengthofreference+1];
			HERR_ch=new char[errormessagelength+1];
			HFMIX_ch=new char[refpropcharlength+1];

			nc = 1;
			x[0] = 1.0;

			//    Set HFILES to the path of the R134a.fld file.  Terminate with '\0'
			//    Set HFMIX to the path of the HMX.BNC file.  Terminate with '\0'
			//    Set HRF to a reference...DEF in this case.  Terminate with '\0'
			//    Set HERR to a default error..."ok" for now.  Terminate with '\0'

			// Note, the directory will likely be different on other machines
			HFILES_st="C:\\Program Files\\NIST\\Refprop7\\Fluids\\R134a.fld";
			//HFILES_st="C:\\Program Files\\Refprop7\\Fluids\\R134a.fld"; // trigger error
			HFMIX_st= "C:\\Program Files\\NIST\\Refprop7\\Fluids\\HMX.BNC";
			HRF_st="DEF";
			//overwritten by dll HERR_st="Ok";

			// Call SETUPdll to initialize global variables in Refprop
#if (setup_use_string)
			SETUPdll(ref nc, HFILES_st, HFMIX_st, HRF_st, ref ierr, HERR_ch,
				refpropfluidpathlength,refpropcharlength,
				lengthofreference,errormessagelength);
#else
			convert_string_to_charArray(HFILES_st, HFILES_ch);
			convert_string_to_charArray(HFMIX_st, HFMIX_ch);
			convert_string_to_charArray(HRF_st, HRF_ch);
			//convert_string_to_charArray(HERR_st, HERR_ch);

//		public static extern void SETUPdll(ref Int32 NumberOfComponents, char[] HFILES, char[] HFMIX, char[] HRF, [In, Out] ref Int32 ierr, [MarshalAs(UnmanagedType.LPArray, SizeConst=errormessagelength)] [In, Out] char[] HERR, Int32 l1, Int32 l2, Int32 l3, Int32 l4);
			SETUPdll(ref nc, HFILES_ch, HFMIX_ch, HRF_ch, ref ierr, HERR_ch,
				refpropfluidpathlength,refpropcharlength,
				lengthofreference,errormessagelength);
#endif

			if (ierr != 0) 
			{
				CheckStatus(ierr, HERR_ch, "SETUPdll");
			}

			// Create variables that are to be
			// (a) Used to call the SATPdll function
			// (b) Returned by the SATPdll function

			double[] XLIQ=new double[compsize]; //={0.0};
			double[] XVAP=new double[compsize]; //={0.0};
			// Some values...
			double PkPa,TK,RHOF,RHOG;
			Int32 KPH;

			KPH = 2;    // Vapor
			PkPa = 101.325;

			TK=0.0; // else unassigned, declared as ref in function
			RHOF=0.0;
			RHOG=0.0;

//		public static extern void SATPdll(ref double PkPa, double[] X, ref Int32 KPH, [In, Out] ref double TK, [In, Out] ref double RHOF, [In, Out] ref double RHOG, [Out] double[] XLIQ, [Out] double[] XVAP, [In, Out] ref Int32 ierr, [MarshalAs(UnmanagedType.LPArray, SizeConst=errormessagelength)] [In, Out] char[] HERR, Int32 LengthHERR);
			SATPdll(ref PkPa,x,ref KPH,ref TK,ref RHOF,ref RHOG,XLIQ,XVAP,ref ierr,HERR_ch,errormessagelength);
			// Answers from the Refprop interface program, to check results
			if (ierr != 0) 
			{
				CheckStatus(ierr, HERR_ch, "SATPdll");
			}
			MessageBox.Show(String.Format("sat p {0} t {1} rhoL {2} rhoV {3}", PkPa, TK, RHOF,RHOG));

			// Tsat(101.325) = 247.08 K
			// rhof = 13.493. mol/m^3
			// rhog = 0.051533 mol/m^3

			// Now try a mixture...say R410a
		
			nc = 2;
			x[0] = 0.69762;
			x[1] = 0.30238;
			//    Set HFILES to the mixture of R32 and R125.  Terminate with '\0'

			HFILES_st="C:/Program Files/NIST/Refprop7/Fluids/R32.fld|C:/Program Files/NIST/Refprop7/Fluids/R125.fld|";
			//HFILES_st="C:/Program Files/NIST/Refprop7/Fluids/R32.fld|C:/Program Files/NIST/Refprop7/Fluids/R125.fld"; 
			//  above missing '|' (can trigger error) when using char[] HFILES_ch, console: please enter file name   unit 12
			HFMIX_st= "C:/Program Files/NIST/Refprop7/Fluids/HMX.BNC";
			HRF_st="DEF";
			//overwritten by dll HERR_st="Ok";

#if (setup_use_string)
			SETUPdll(ref nc, HFILES_st, HFMIX_st, HRF_st, ref ierr, HERR_ch,
				refpropfluidpathlength,refpropcharlength,
				lengthofreference,errormessagelength);
#else
			convert_string_to_charArray(HFILES_st, HFILES_ch);
			convert_string_to_charArray(HFMIX_st, HFMIX_ch);
			convert_string_to_charArray(HRF_st, HRF_ch);
			//convert_string_to_charArray(HERR_st, HERR_ch);

			SETUPdll(ref nc, HFILES_ch, HFMIX_ch, HRF_ch, ref ierr, HERR_ch,
				refpropfluidpathlength,refpropcharlength,
				lengthofreference,errormessagelength);
#endif

			if (ierr != 0) 
			{
				CheckStatus(ierr, HERR_ch, "SETUPdll");
			}

			SATPdll(ref PkPa,x,ref KPH,ref TK,ref RHOF,ref RHOG,XLIQ,XVAP,ref ierr,HERR_ch,errormessagelength);
			if (ierr != 0) 
			{
				CheckStatus(ierr, HERR_ch, "SATPdll");
			}
			MessageBox.Show(String.Format("sat p {0} t {1} rhoL {2} rhoV {3}", PkPa, TK, RHOF,RHOG));
			// For vapor (KPH = 2)
			// Tsat(101.325) =  221.74 K
			// rhof =  18.594 mol/m^3  actually 18.213
			// rhog =  0.057501 mol/m^3
		}
		~mf_net_wa__refprop() 
		{
		}

		void convert_string_to_charArray(string s, char[] c) 
		{
			int i;
			if (s.Length+1>c.Length) 
			{
				MessageBox.Show(String.Format("string Length {0} +1 > char Length {1} ", s.Length, c.Length));
				Application.Exit();
			}
			for (i=0; i<s.Length; i++) 
			{
				c[i]=s[i];
			}
			c[i]='\0';
		}

		public bool CheckStatus(Int32 ierr, char[] err_msg, String RoutineName) 
		{
			string text;
			bool fatal;

			text=new string(err_msg);

			//Int32 sugCap=12*80;  
			//StringBuilder msg=new StringBuilder("Status "+status+" returned by "+RoutineName+'\n', sugCap);
			//msg.Append("error   "+text+'\n');
			
			fatal=true;
			//if ierr!=0 should throw an exception, particularly if ierr>0
			MessageBox.Show(text);
			return fatal;
		}
	}
}