/*------------------------------------------------------------------------------*
 * File Name: FitINIFile.C														*
 * Creation: Sim 04-02-2008														*
 * Purpose: OriginC Source C file												*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	Jasmine 04/03/08 UTILITY_FUNCTION_TO_LOAD_INI_FILE							*
 *------------------------------------------------------------------------------*/
 
////////////////////////////////////////////////////////////////////////////////////
// Including the system header file Origin.h should be sufficient for most Origin
// applications and is recommended. Origin.h includes many of the most common system
// header files and is automatically pre-compiled when Origin runs the first time.
// Programs including Origin.h subsequently compile much more quickly as long as
// the size and number of other included header files is minimized. All NAG header
// files are now included in Origin.h and no longer need be separately included.
//
// Right-click on the line below and select 'Open "Origin.h"' to open the Origin.h
// system header file.
#include <Origin.h>
////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////////
// Include your own header files here.
#include <..\OriginLab\FitINIFile.h>

////////////////////////////////////////////////////////////////////////////////////
// Start your functions here.
/*
struct	PAINIENTRY
{
	LPCTSTR			lpcszKeyName;
	int				nDataType;
};
enum{
	TYPE_INT = 1,
	TYPE_DOUBLE,
	TYPE_STRING,
};
#define		OPAINIENTRY(_Key, _DataType)							{ _Key, (_DataType) },
#define		OPAINIENTRY_END(_Key, _DataType)						{ _Key, (_DataType) }

#define NUM_PARAM_KEY 12
PAINIENTRY s_arrPeakAnalysisParamINI[NUM_PARAM_KEY] = 
{
	OPAINIENTRY("Functions",					TYPE_STRING)
	OPAINIENTRY("Share",						TYPE_INT)
	OPAINIENTRY("Fixed",						TYPE_INT)
	OPAINIENTRY("LowerBounds",					TYPE_DOUBLE)
	OPAINIENTRY("LowerBoundsExclusive",			TYPE_INT)
	OPAINIENTRY("LowerBoundsEnable",			TYPE_INT)
	OPAINIENTRY("UpperBounds",					TYPE_DOUBLE)
	OPAINIENTRY("UpperBoundsExclusive",			TYPE_INT)
	OPAINIENTRY("UpperBoundsEnable",			TYPE_INT)
	OPAINIENTRY("Values",						TYPE_DOUBLE)
	OPAINIENTRY("SignificantDigit",				TYPE_INT)
	/////////////////////////////////////////////////////////////////////////////////////////
	//OPAINIENTRY_END(NULL, 						0)
	OPAINIENTRY_END("", 						0)
};
*/

FitINIFile::FitINIFile(LPCSTR lpcszFilename, BOOL bUseIniPath) // = NULL, TRUE
: INIFile(lpcszFilename, bUseIniPath)
{
}

void FitINIFile::ResetVector()
{
	m_strBFunction.Empty();
	m_vnBPValues.SetSize(0);
	
	m_vsFunctions.SetSize(0);
	m_vnShare.SetSize(0);
	m_vnFixed.SetSize(0);
	m_vdLowerBounds.SetSize(0);
	m_vnLowerBoundsExclusive.SetSize(0);
	m_vnLowerBoundsEnable.SetSize(0);
	m_vdUpperBounds.SetSize(0);
	m_vnUpperBoundsExclusive.SetSize(0);
	m_vnUpperBoundsEnable.SetSize(0);
	m_vdValues.SetSize(0);
	m_vnSignificantDigit.SetSize(0);
}
/*
#define PREFIX_SECTION_PARAM	"Parameter"
#define STR_KEY_FUNCTIONS					"Functions"
#define STR_KEY_SHARE						"Share"
#define STR_KEY_FIXED						"Fixed"
#define STR_KEY_LOWER_BOUNDS				"LowerBounds"
#define STR_KEY_LOWER_BOUNDS_EXCLUSIVE		"LowerBoundsExclusive"
#define STR_KEY_LOWER_BOUNDS_ENABLE			"LowerBoundsEnable"
#define STR_KEY_UPPER_BOUNDS				"UpperBounds"
#define STR_KEY_UPPER_BOUNDS_EXCLUSIVE		"UpperBoundsExclusive"
#define STR_KEY_UPPER_BOUNDS_ENABLE			"UpperBoundsEnable"
#define STR_KEY_VALUES						"Values"
#define STR_KEY_SIGNIFICANT_DIGIT			"SignificantDigit"

#define STR_SECTION_INFO	"Info"
#define STR_KEY_VERSION		"OriginVersion"
#define STR_KEY_NUM_PEAKS	"NumPeaks"


bool FitINIFile::Save(const TreeNode& trINI)
{
	if ( !TreeToVector(trINI) )
		return false;
	
	int nNumPeaks = m_vsFunctions.GetSize();
	ASSERT(m_vsFunctions.GetSize() == nNumPeaks);
	ASSERT(m_vnShare.GetSize() == nNumPeaks);
	ASSERT(m_vnFixed.GetSize() == nNumPeaks);
	ASSERT(m_vdLowerBounds.GetSize() == nNumPeaks);
	ASSERT(m_vnLowerBoundsExclusive.GetSize() == nNumPeaks);
	ASSERT(m_vnLowerBoundsEnable.GetSize() == nNumPeaks);
	ASSERT(m_vdUpperBounds.GetSize() == nNumPeaks);
	ASSERT(m_vnUpperBoundsExclusive.GetSize() == nNumPeaks);
	ASSERT(m_vnUpperBoundsEnable.GetSize() == nNumPeaks);
	ASSERT(m_vdValues.GetSize() == nNumPeaks);
	ASSERT(m_vnSignificantDigit.GetSize() == nNumPeaks);
	
	double dVersion;
	LT_get_var("@V", &dVersion);
	WriteDouble(STR_SECTION_INFO, STR_KEY_VERSION, dVersion);
	WriteInt(STR_SECTION_INFO, STR_KEY_NUM_PEAKS, nNumPeaks);
	
	string strSection;
	for (int ii = 0; ii < nNumPeaks; ii++)
	{
		strSection = PREFIX_SECTION_PARAM + (ii+1);
		WriteString(strSection, STR_KEY_FUNCTIONS, m_vsFunctions[ii]);
		WriteInt(strSection, STR_KEY_SHARE, m_vnShare[ii]);
		WriteInt(strSection, STR_KEY_FIXED, m_vnFixed[ii]);
		WriteDouble(strSection, STR_KEY_LOWER_BOUNDS, m_vdLowerBounds[ii]);
		WriteInt(strSection, STR_KEY_LOWER_BOUNDS_EXCLUSIVE, m_vnLowerBoundsExclusive[ii]);
		WriteInt(strSection, STR_KEY_LOWER_BOUNDS_ENABLE, m_vnLowerBoundsEnable[ii]);
		WriteDouble(strSection, STR_KEY_UPPER_BOUNDS, m_vdUpperBounds[ii]);
		WriteInt(strSection, STR_KEY_UPPER_BOUNDS_EXCLUSIVE, m_vnUpperBoundsExclusive[ii]);
		WriteInt(strSection, STR_KEY_UPPER_BOUNDS_ENABLE, m_vnUpperBoundsEnable[ii]);
		WriteDouble(strSection, STR_KEY_VALUES, m_vdValues[ii]);
		WriteInt(strSection, STR_KEY_SIGNIFICANT_DIGIT, m_vnSignificantDigit[ii]);
	}
	
	return true;
}
*/
bool FitINIFile::Load(TreeNode& trINI)
{
	if ( IsFrom75File() )
		return Load75(trINI);
	
	//int nNumPeaks = ReadInt(STR_SECTION_INFO, STR_KEY_NUM_PEAKS, 0);
	//m_vsFunctions.SetSize(nNumPeaks);
	//m_vnShare.SetSize(nNumPeaks);
	//m_vnFixed.SetSize(nNumPeaks);
	//m_vdLowerBounds.SetSize(nNumPeaks);
	//m_vnLowerBoundsExclusive.SetSize(nNumPeaks);
	//m_vnLowerBoundsEnable.SetSize(nNumPeaks);
	//m_vdUpperBounds.SetSize(nNumPeaks);
	//m_vnUpperBoundsExclusive.SetSize(nNumPeaks);
	//m_vnUpperBoundsEnable.SetSize(nNumPeaks);
	//m_vdValues.SetSize(nNumPeaks);
	//m_vnSignificantDigit.SetSize(nNumPeaks);
	//
	//string strSection;
	//for (int ii = 0; ii < nNumPeaks; ii++)
	//{
		//strSection = PREFIX_SECTION_PARAM + (ii+1);
		//m_vsFunctions[ii] = ReadString(strSection, STR_KEY_FUNCTIONS, "");
		//m_vnShare[ii] = ReadInt(strSection, STR_KEY_SHARE, 0);
		//m_vnFixed[ii] = ReadInt(strSection, STR_KEY_FIXED, 0);
		//m_vdLowerBounds[ii] = ReadDouble(strSection, STR_KEY_LOWER_BOUNDS, NANUM);
		//m_vnLowerBoundsExclusive[ii] = ReadInt(strSection, STR_KEY_LOWER_BOUNDS_EXCLUSIVE, 0);
		//m_vnLowerBoundsEnable[ii] = ReadInt(strSection, STR_KEY_LOWER_BOUNDS_ENABLE, 0);
		//m_vdUpperBounds[ii] = ReadDouble(strSection, STR_KEY_UPPER_BOUNDS, NANUM);
		//m_vnUpperBoundsExclusive[ii] = ReadInt(strSection, STR_KEY_UPPER_BOUNDS_EXCLUSIVE, 0);
		//m_vnUpperBoundsEnable[ii] = ReadInt(strSection, STR_KEY_UPPER_BOUNDS_ENABLE, 0);
		//m_vdValues[ii] = ReadDouble(strSection, STR_KEY_VALUES, NANUM);
		//m_vnSignificantDigit[ii] = ReadInt(strSection, STR_KEY_SIGNIFICANT_DIGIT, 0);
	//}
	//
	//if ( !VectorToTree(trINI) )
		//return false;
	//
	//return true;
	return false;
}

int FitINIFile::GetItemNums(const StringArray& saItems, LPCSTR lpcszItemPrefix)
{
	int nNums = 0;
	string strItem;
	do
	{
		strItem = lpcszItemPrefix;
		strItem += (++nNums);
	}while (saItems.Find(strItem) >= 0);
	--nNums;
	
	return nNums;
}

#define STR_SECTION75_PEAKPARAMETERS			"PEAKPARAMETERS"

#define STR_KEY75_BL_FUNC						"BFUNC"
#define PREFIX_KEY75_BP_VALUES					"BP"

#define STR_KEY75_NUM_PEAKS						"NUMPEAKS"
#define PREFIX_KEY75_FUNCTIONS					"PEAKTYPE"
#define PREFIX_KEY75_PEAK_NO					"PN"
//#define PREFIX_KEY75_SHARE						""
#define PREFIX_KEY75_VAR						"V"
#define PREFIX_KEY75_LOWER_BOUNDS				"LB"
//#define PREFIX_KEY75_LOWER_BOUNDS_EXCLUSIVE		""
#define PREFIX_KEY75_LOWER_BOUNDS_ENABLE		"LBON"
#define PREFIX_KEY75_UPPER_BOUNDS				"UB"
//#define PREFIX_KEY75_UPPER_BOUNDS_EXCLUSIVE		""
#define PREFIX_KEY75_UPPER_BOUNDS_ENABLE		"UBON"
#define PREFIX_KEY75_VALUES						"P"
//#define PREFIX_KEY75_SIGNIFICANT_DIGIT			""

bool FitINIFile::Load75(TreeNode& trINI)
{
	ResetVector();
	
	string strSection = STR_SECTION75_PEAKPARAMETERS;
	string strKey;
	
	StringArray saKeys;
	GetKeyNames(saKeys, strSection);
	
	strKey = STR_KEY75_BL_FUNC;
	m_strBFunction = ReadString(strSection, strKey, "");
	int nNumBaselinePeaks = GetItemNums(saKeys, PREFIX_KEY75_BP_VALUES);
	for (int nBaselinePeakNo = 1; nBaselinePeakNo <= nNumBaselinePeaks; nBaselinePeakNo++)
	{
		strKey = PREFIX_KEY75_BP_VALUES + nBaselinePeakNo;
		m_vnBPValues.Add(ReadDouble(strSection, strKey, NANUM));
	}	

	int nNumPeaks = ReadInt(STR_SECTION75_PEAKPARAMETERS, STR_KEY75_NUM_PEAKS, 0);
	for (int nPeakNo = 1; nPeakNo <= nNumPeaks; nPeakNo++)
	{
		strKey = PREFIX_KEY75_FUNCTIONS + nPeakNo;
		m_vsFunctions.Add(ReadString(strSection, strKey, ""));
		
		string strKeyPeakNoPrefix = PREFIX_KEY75_PEAK_NO + nPeakNo;
		
		string strTmp = strKeyPeakNoPrefix + PREFIX_KEY75_VALUES;
		int nNumParams = GetItemNums(saKeys, strTmp);
		for (int nParamNo = 1; nParamNo <= nNumParams; nParamNo++)
		{
			strKey = strKeyPeakNoPrefix + PREFIX_KEY75_VALUES + nParamNo;
			m_vdValues.Add(ReadDouble(strSection, strKey, NANUM));

			strKey = strKeyPeakNoPrefix + PREFIX_KEY75_UPPER_BOUNDS_ENABLE + nParamNo;
			m_vnUpperBoundsEnable.Add(ReadInt(strSection, strKey, 0));
			
			strKey = strKeyPeakNoPrefix + PREFIX_KEY75_UPPER_BOUNDS + nParamNo;
			m_vdUpperBounds.Add(ReadDouble(strSection, strKey, NANUM));
			
			strKey = strKeyPeakNoPrefix + PREFIX_KEY75_LOWER_BOUNDS_ENABLE + nParamNo;
			m_vnLowerBoundsEnable.Add(ReadInt(strSection, strKey, 0));
			
			strKey = strKeyPeakNoPrefix + PREFIX_KEY75_LOWER_BOUNDS + nParamNo;
			m_vdLowerBounds.Add(ReadDouble(strSection, strKey, NANUM));

			strKey = strKeyPeakNoPrefix + PREFIX_KEY75_VAR + nParamNo;
			m_vnFixed.Add(ReadInt(strSection, strKey, 0)? 0 : 1); // fix <==> not variable
		}
	}
	
	if ( !VectorToTree(trINI) )
		return false;
	
	return true;
}

#define STR_SECTION_INFO	"Info"
#define STR_KEY_VERSION		"OriginVersion"
bool FitINIFile::IsFrom75File()
{
	double dVersion = ReadDouble(STR_SECTION_INFO, STR_KEY_VERSION, 7.5);
	if ( dVersion < 8.0 )
		return true;

	return false;
}

bool FitINIFile::TreeToVector(const TreeNode& trINI)
{
	if ( !trINI )
		return false;
	
	TreeNode trBaseline = trINI.Baseline;
	if ( !trBaseline )
		return false;
	
	TreeNode trParameters = trINI.Parameters;
	if ( !trParameters )
		return false;
		
	m_strBFunction = trBaseline.Function.strVal;
	m_vnBPValues = trBaseline.Values.dVals;
	
	m_vsFunctions = trParameters.Functions.strVals;
	m_vnShare = trParameters.Share.nVals;
	m_vnFixed = trParameters.Fixed.nVals;
	m_vdLowerBounds = trParameters.LowerBounds.dVals;
	m_vnLowerBoundsExclusive = trParameters.LowerBoundsExclusive.nVals;
	m_vnLowerBoundsEnable = trParameters.LowerBoundsEnable.nVals;
	m_vdUpperBounds = trParameters.UpperBounds.dVals;
	m_vnUpperBoundsExclusive = trParameters.UpperBoundsExclusive.nVals;
	m_vnUpperBoundsEnable = trParameters.UpperBoundsEnable.nVals;
	m_vdValues = trParameters.Values.dVals;
	m_vnSignificantDigit = trParameters.SignificantDigit.nVals;
	
	return true;
}
bool FitINIFile::VectorToTree(TreeNode& trINI)
{
	if ( !trINI )
		return false;
	
	TreeNode trBaseline = tree_check_get_node(trINI, "Baseline");
	TreeNode trParameters = tree_check_get_node(trINI, "Parameters");
	
	trBaseline.Function.strVal = m_strBFunction;
	trBaseline.Values.dVals = m_vnBPValues;
	
	trParameters.Functions.strVals = m_vsFunctions;
	trParameters.Share.nVals = m_vnShare;
	trParameters.Fixed.nVals = m_vnFixed;
	trParameters.LowerBounds.dVals = m_vdLowerBounds;
	trParameters.LowerBoundsExclusive.nVals = m_vnLowerBoundsExclusive;
	trParameters.LowerBoundsEnable.nVals = m_vnLowerBoundsEnable;
	trParameters.UpperBounds.dVals = m_vdUpperBounds;
	trParameters.UpperBoundsExclusive.nVals = m_vnUpperBoundsExclusive;
	trParameters.UpperBoundsEnable.nVals = m_vnUpperBoundsEnable;
	trParameters.Values.dVals = m_vdValues;
	trParameters.SignificantDigit.nVals = m_vnSignificantDigit;
	
	return true;
}


///Jasmine 04/03/08 UTILITY_FUNCTION_TO_LOAD_INI_FILE
bool fit_ini_file_load_setting(LPCSTR lpcszFilename, TreeNode& trSetting, BOOL bUseIniPath = TRUE)
{
	if(!trSetting)
		return false;
	
	FitINIFile iniFile(lpcszFilename, bUseIniPath);
	
	return iniFile.Load(trSetting);
	
}
///End UTILITY_FUNCTION_TO_LOAD_INI_FILE