/*------------------------------------------------------------------------------*
 * File Name: FFWFuncBodyPage.h		 											*
 * Creation: 																	*
 * Purpose: OriginC Source C file												*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	Jasmine 06/21/10 ORG-343 QUICK_CHECK_FUNCTION_BODY							*
 *	Folger 06/24/10 ORG-390-S3 CHANGE_DO_IT_TO_EVALUATE							*
 *	Folger 06/24/10 ORG-390-P1 FUNCTION_BODY_GONE_WHEN_EDIT_FUNCTION_OF_EQUATION_TYPE
 *	Folger 06/24/10 ORG-390-P4 SHOW_CONSTANTS_IN_EVALUATION_PAGE				*
 *	Folger 06/25/10 ORG-390-P2 SAVE_USER_CHANGED_IN_FIT_FUNCTION_WIZARD_INTO_FDF*
 *	Folger 07/06/10 ORG-432-S13 CENTRALIZE_FUNCTION_BODY_PAGE_RESOURCES			*
 *	Bill 07/15/2010 ORG-576-S1 MOVE_TO_NEXT_ROW_IF_USER_PRESS_ENTER             *
 *	Jasmine 07/29/10 ORG-591-P7 FINSH_EVENT_IS_TOO_LATE_SO_DISABLE_ONCE_FIND_ERROR
 *	Jasminie 07/30/10 ORG-591-P7 PRECOMPILE_FILE_MAKE_COMPILE_CHECKING_FAIL		*
 *	Jasmine 08/02/10 ORG-591-P7 DETECH_EXTERNAL_DLL_SOURCE						*
 *	Jasmine 08/10/10 ORG-745-P4 ALLOW_EXTERNAL_DLL_HAS_EMPTY_ANNOTATION			*
 *	Folger 08/11/10 ORG-756-P3 BETTER_CHECKING_FOR_VALID_EQUATIONS				*
 *	Folger 08/16/10 ORG-756-P1-P2 BETTER_ERROR_CHECKING_FOR_FITTING_FUNCTION_LT_EVALUATION
 *------------------------------------------------------------------------------*/

/*------------------------------------------------------------------------------*
 this file contains six classes:
 	1. FFWEquationPageBase
 	|-2. FFWOCFunctionPage
 	|-3. FFWExternalDLLPage
 	|-4. FFWExpressionPage
 	|-5. FFWMultiEquationPage
 	|-6. FFWLabtalkPage
 *------------------------------------------------------------------------------*/ 
 
#ifndef _FFW_FUNC_BODY_PAGE_H
#define _FFW_FUNC_BODY_PAGE_H

#include "FunctionMgr.h"//for FFWOCFunctionPage
#include "FFWParamControls.h"

/*------------------------------------------------------------------------------*
 * FFWEquationPageBase	 														*
 *------------------------------------------------------------------------------*/
enum{ FFW_PARAM_TAB, FFW_CONST_TAB};

///Sophy 7/5/2010 ORG-432-S12 CHECK_EQUATION_PARAMS_SETTINGS
enum {
	FFW_EQUATION_OK = 0,
	FFW_EQUATION_INVALID_PARAMS,
	FFW_EQUATION_INVALID_CONTANT,
	FFW_EQUATION_INVALID_INDEPS,
	FFW_EQUATION_COMPILE_ERROR,
	FFW_EQUATION_PEAK_ATTRIB_ERROR,
	FFW_EQUATION_TOO_MANY_INDEPS,	///Sophy 7/7/2010 ORG-432-S14 WARNING_MSG_WHEN_EVALUATE_WITH_TOO_MANY_INDEPS
	FFW_EQUATION_EMPTY_FORMULA,		///Sophy 7/8/2010 ORG-518-P2 IMPROVE_ERR_MSG_FOR_QUICK_CHECK
	FFW_EQUATION_EMPTY_DLL,			///Jasmine 08/02/10 ORG-591-P7 DETECH_EXTERNAL_DLL_SOURCE
};
///end CHECK_EQUATION_PARAMS_SETTINGS

#define	TRIM_STR(_Str)	_Str.TrimLeft(), _Str.TrimRight();	///Sophy 7/8/2010 ORG-518-P3 TRIM_PARAM_VALUE_AND_CONSTANT_BEFORE_SAVE

class FFWEquationPageBase : public FFWPageBase
{
public:
	FFWEquationPageBase(int nID = 0) : FFWPageBase(nID){}

	virtual BOOL OnInitPage();

	BOOL 	OnEvaluateClick(Control ctrl);
	
	void  	OnAfterEditParaControl(Control flxControl, int nRow, int nCol);
	
	BOOL 	OnTabChange(Control ctrl);
	
	bool	InitGridConstant();
	bool	InitGridParam();
	bool	InitTabControls();
	
	//virtual
	BOOL	OnNext();///Sophy 7/5/2010 ORG-432-S12 CHECK_EQUATION_PARAMS_SETTINGS

protected:
	virtual bool 	UpdateTreeToPageGUI(const TreeNode& trFunction);
	virtual bool 	UpdatePageGUIToTree(TreeNode& trFunction);
	virtual string	GetPageHintsName(bool bNextPage = false);///Jasmine 06/25/10 ORG390-P5 MOVE_FFW_HINTS_TO_TXT
	
	bool 			evaluateDependentVar();
	
	/// Hong 07/01/10 ORG-432 FFW_NEW_GUI_DESIGN
	int				getIndepVarsVal(vector& vv);
	/// end FFW_NEW_GUI_DESIGN
	
	///Sophy 7/5/2010 ORG-432-S12 CHECK_EQUATION_PARAMS_SETTINGS
	int				CheckEquation(string& strErrMsg);
	///end CHECK_EQUATION_PARAMS_SETTINGS

	
protected:
	FFWParamSetting 		m_FFWParamGrid;
	FFWConstantSetting 		m_gridConstant;
	TabControl				m_tabParameter;
	
	Control					m_controlDependVar;
	//Control					m_controlIndependVar;
	//Control					m_controlParam;

	Edit					m_editEquation;

};

virtual BOOL FFWEquationPageBase::OnInitPage()
{	
	/// Hong 07/01/10 ORG-432 FFW_NEW_GUI_DESIGN
	m_controlDependVar = GetItem(IDC_FIT_FUNC_DEPEND_VAR);
	/// end FFW_NEW_GUI_DESIGN

	if ( !InitGridConstant() || !InitGridParam() || !InitTabControls() )
		return FALSE;
	                 
	m_editEquation	= GetItem(IDC_FIT_FUNC_FUNCTION_BODY_EDIT);

	BitmapRadioButton btnEvaluate = GetItem(FFW_EVALUATE_BTN);
	vector<string> vsTips(1);
	vsTips[0] = _L("Evaluate");
	btnEvaluate.Init(1, IDB_APPLY_BTN, 16, vsTips);
	
	FFWPageBase::OnInitPage();
	
	return TRUE;
}

BOOL FFWEquationPageBase:: OnEvaluateClick(Control ctrl){return evaluateDependentVar();}

void  FFWEquationPageBase::OnAfterEditParaControl(Control flxControl, int nRow, int nCol)
{
	if (NLPARAMGRIDCOLTYPE_NAME == nCol)
	{
		vector<string> vsNames;

		m_FFWParamGrid.GetColValues(NLPARAMGRIDCOLTYPE_NAME, vsNames);

		string strNew = vsNames[nRow];

		vsNames.RemoveAt(nRow);
		vsNames.RemoveAt(0);

		if ( vsNames.Find(strNew) != -1)
		{
			string strErrMsg;

			strErrMsg.Format(_L("The parameter %s already exists"), strNew);

			MessageBox(strErrMsg, STR_ERROR, MB_OK);

			string strDummy("");

			m_FFWParamGrid.SetCell(nRow, nCol, strDummy);			
		}
	}

	m_FFWParamGrid.OnAfterEdit(flxControl, nRow, nCol);
}

BOOL FFWEquationPageBase::OnTabChange(Control ctrl)
{
	bool bParamTab = FFW_PARAM_TAB == m_tabParameter.GetCurSel();
	m_FFWParamGrid.SetVisible(bParamTab);
	m_gridConstant.SetVisible(!bParamTab);
	return TRUE;
}

bool FFWEquationPageBase::InitGridParam()
{
	m_FFWParamGrid.Init(IDC_FIT_FUNC_PARAM_GRID, *this, "junk");
	
	m_FFWParamGrid.ShowGroup(0);
	
	return true;
}

bool FFWEquationPageBase::InitGridConstant()
{
	m_gridConstant.Init(IDC_FIT_FUNC_CONSTANT_GRID, *this);
	return true;
}

bool FFWEquationPageBase::InitTabControls()
{
	m_tabParameter = GetItem(IDC_FIT_FUNC_PARAM_TAB);
	if(!m_tabParameter)
		return false;
	
	m_tabParameter.InsertItem(FFW_PARAM_TAB, _L("Parameters"));
	m_tabParameter.InsertItem(FFW_CONST_TAB, _L("Constants"));
	
	RECT rTab;
	m_tabParameter.GetWindowRect(&rTab);
	ScreenToClient(&rTab);
	m_tabParameter.AdjustRect(FALSE, &rTab);
	
	m_FFWParamGrid.MoveWindow(rTab);
	m_gridConstant.MoveWindow(rTab);

	OnTabChange(m_tabParameter);
	
	return true;
}

virtual bool FFWEquationPageBase::UpdateTreeToPageGUI(const TreeNode& trFunction)
{
	//parameter
	/// Bill 07/02/2010 ORG-432-P2 HIDE_PEAK_ATTRIBUTES_IF_NOT_PEAK_FUNCTION
	bool bPeakFunction = FuncOrganizer().IsPeak(m_pHolder->m_trFunction);
	m_FFWParamGrid.HideCol(NLPARAMGRIDCOLTYPE_PEAK_ATTRIBUTE, !bPeakFunction);
	/// End HIDE_PEAK_ATTRIBUTES_IF_NOT_PEAK_FUNCTION

	m_FFWParamGrid.SetTree(m_pHolder->m_trFunction);
	m_FFWParamGrid.ResizeCols();

	//constant
	vector<string> vsVariables;
	vector<string> vsValues;
 	int nCount = FuncOrganizer().GetConstants(m_pHolder->m_trFunction, vsVariables, vsValues);
	m_gridConstant.Update(vsVariables, vsValues);
	m_gridConstant.ResizeCols();
	
	//function body
	if(m_editEquation)
	{
		/// Bill 07/05/2010 ORG-478-P4 FIXED_LINE_BREAK_ISSUE
		//m_editEquation.Text = FuncOrganizer().GetFormula(trFunction);
		string strFuncBody = FuncOrganizer().GetFormula(trFunction);
		StringToEditText(strFuncBody, m_editEquation);
		/// End FIXED_LINE_BREAK_ISSUE
	}

	//evaluate controls
	char ch = ',';
	string strIndepNames = FuncOrganizer().GetIndependVars(trFunction, ch);
	vector<string> vsNames;
	int nNames = strIndepNames.GetTokens(vsNames, ch);
	
	ch = ';';
	string strIndepVars = FuncOrganizer().GetIndependVarsWithValue(trFunction, ch);	
	vector vValues;
	FuncOrganizer().ParseIndependVarsValue(vValues, trFunction, strIndepVars, ch);
	
	int nMaxNum = 4;
	vector<int> vnLabels = {IDC_FIT_FUNC_INDEPEND_VAR1, IDC_FIT_FUNC_INDEPEND_VAR2, IDC_FIT_FUNC_INDEPEND_VAR3, IDC_FIT_FUNC_INDEPEND_VAR4};
	vector<int> vnEdits = {IDC_FIT_FUNC_INDEPEND_VAR_VALUE1, IDC_FIT_FUNC_INDEPEND_VAR_VALUE2, IDC_FIT_FUNC_INDEPEND_VAR_VALUE3, IDC_FIT_FUNC_INDEPEND_VAR_VALUE4};
	ASSERT( nMaxNum == vnLabels.GetSize() && nMaxNum == vnEdits.GetSize() );
	for(int ii = 0; ii < nMaxNum; ii++)
	{
		Control label 	= GetItem( vnLabels[ii] );
		Control edit	= GetItem( vnEdits[ii] );
		if(ii < nNames)
		{
			label.Text = vsNames[ii] + " = ";
			if( ii < vValues.GetSize() )
				edit.Text = ftoa( vValues[ii] );
			label.Visible = edit.Visible = true;
		}
		else
		{
			label.Visible = edit.Visible = false;
		}
	}
	
	return true;
}

virtual bool FFWEquationPageBase::UpdatePageGUIToTree(TreeNode& trFunction)
{
	//parameter
	m_FFWParamGrid.GetTree(trFunction);
	
	//constant
	vector<string> vsVariables, vsValues;
	m_gridConstant.GetColValues(CONSTANT_VARIABLE_COLUMN, vsVariables);
	m_gridConstant.GetColValues(CONSTANT_VALUE_COLUMN, vsValues);

	vsVariables.RemoveAt(0);
	vsValues.RemoveAt(0);
	for (int ii = vsVariables.GetSize() - 1 ; ii >= 0 ; --ii)
		if ( vsVariables[ii] == "")
		{
			vsVariables.RemoveAt(ii);
			vsValues.RemoveAt(ii);
		}
	FuncOrganizer().SetConstants(vsVariables, vsValues, trFunction);
	
	//function body
	string strFormula = m_editEquation ? m_editEquation.Text : "";
	FuncOrganizer().SetFormula(strFormula, trFunction);
	
	//evaluate controls
	///------ Folger 06/25/10 ORG-390-P2 SAVE_USER_CHANGED_IN_FIT_FUNCTION_WIZARD_INTO_FDF
	FuncOrganizer().ClearQuickCheck(trFunction);
	/// Hong 07/01/10 ORG-432 FFW_NEW_GUI_DESIGN
	//FuncOrganizer().SetQuickCheck(trFunction, m_controlIndependVar ? m_controlIndependVar.Text : "");
	//FuncOrganizer().SetQuickCheck(trFunction, m_controlParam ? m_controlParam.Text : "");
	vector<string>	vstrNames, vstrVals, vstrTemp;
	vector			vVals, vTemp;
	nlf_get_independent_variables(trFunction, &vstrNames);
	char			chDelimiter = ',';
	string			strNames = FuncOrganizer().GetFittingPara(trFunction);
	strNames.GetTokens(vstrTemp, chDelimiter);
	vstrNames.Append(vstrTemp);
	
	getIndepVarsVal(vVals);
	m_FFWParamGrid.GetParamsVals(vTemp);
	vVals.Append(vTemp);
	convert_double_vector_to_string_vector(vVals, vstrVals, vVals.GetSize());
	ASSERT( vstrNames.GetSize() == vstrVals.GetSize() );
	FuncOrganizer().SetQuickCheckItems(trFunction, vstrNames, vstrVals);
	/// end FFW_NEW_GUI_DESIGN
	///------ End SAVE_USER_CHANGED_IN_FIT_FUNCTION_WIZARD_INTO_FDF

	return true;
}

///Jasmine 06/25/10 ORG390-P5 MOVE_FFW_HINTS_TO_TXT
virtual string FFWEquationPageBase::GetPageHintsName(bool bNextPage/* = false*/)
{
	if ( !bNextPage )
		return "";
	else
		return "Function next page";
}
///End MOVE_FFW_HINTS_TO_TXT

///Jasmine 06/21/10 ORG-343 QUICK_CHECK_FUNCTION_BODY 
bool FFWEquationPageBase::evaluateDependentVar()
{
	TreeNode trFunction = m_pHolder->m_trFunction;
	if( !UpdatePageGUIToTree(trFunction) )
	{
		ASSERT(0);
		return false;
	}	
	
	///Sophy 7/5/2010 ORG-432-S12 CHECK_EQUATION_PARAMS_SETTINGS
	string strErrMsg;
	int nErr = CheckEquation(strErrMsg);
	if ( nErr != FFW_EQUATION_OK )
	{
		m_controlDependVar.Text = strErrMsg;
		return false;
	}
	///end CHECK_EQUATION_PARAMS_SETTINGS
	
	/// Hong 07/01/10 ORG-432 FFW_NEW_GUI_DESIGN
	//string strIndepVal = m_controlIndependVar.Text;
	//string strParamVal = m_controlParam.Text;
	
	//vector vIndepValue, vParamValue;
	//int nIndepNum = FuncOrganizer().ParseIndependVarsValue(vIndepValue, trFunction, strIndepVal, ',');
	//int nParamNum = FuncOrganizer().ParseFittingParamValue(vParamValue, trFunction, strParamVal, ',');
	vector 	vIndepValue, vParamValue;
	int 	nIndepNum = getIndepVarsVal(vIndepValue);
	int 	nParamNum = m_FFWParamGrid.GetParamsVals(vParamValue);
	/// end FFW_NEW_GUI_DESIGN
	int nDepNum = nlf_get_dependent_variables(trFunction);
	
	matrix mIndVars, mDepVars;
	mIndVars.SetSize(1, nIndepNum);
	mDepVars.SetSize(1, nDepNum);
	if(mIndVars.SetRow(vIndepValue, 0) != 0)
		ASSERT(0);
	
	NumericFunction	nf(m_pHolder->m_trFunction);
	///------ Folger 08/16/10 ORG-756-P1-P2 BETTER_ERROR_CHECKING_FOR_FITTING_FUNCTION_LT_EVALUATION
	//bool bRet = nf.Evaluate(vParamValue, 1, mDepVars, mIndVars);
	bool bRet = nf.Evaluate(vParamValue, 1, mDepVars, mIndVars, NLSFEVALUATE_CHECK_LT_VARS_FULLY_USED);
	///------ End BETTER_ERROR_CHECKING_FOR_FITTING_FUNCTION_LT_EVALUATION

	vector vDepValue;
	if( mDepVars.GetAsVector(vDepValue) )
	{
		string strDepVal = FuncOrganizer().CombineDependVarsWithValue(vDepValue, trFunction, ',');
		m_controlDependVar.Text = strDepVal;
	}
	
	return true;
}
///End QUICK_CHECK_FUNCTION_BODY

/// Hong 07/01/10 ORG-432 FFW_NEW_GUI_DESIGN
int	FFWEquationPageBase::getIndepVarsVal(vector& vv)
{
	int				nIndep = nlf_get_independent_variables(m_pHolder->m_trFunction);
	vv.SetSize(nIndep);
	vector<uint>	vIDs = {IDC_FIT_FUNC_INDEPEND_VAR_VALUE1, IDC_FIT_FUNC_INDEPEND_VAR_VALUE2, IDC_FIT_FUNC_INDEPEND_VAR_VALUE3, IDC_FIT_FUNC_INDEPEND_VAR_VALUE4};
	Control			ctrl;
	for ( int ii = 0; ii < nIndep && ii < vIDs.GetSize(); ii++ )
	{
		ctrl = GetItem(vIDs[ii]);
		vv[ii] = atof(ctrl.Text);
	}
	return nIndep;
}
/// end FFW_NEW_GUI_DESIGN

///Sophy 7/5/2010 ORG-432-S12 CHECK_EQUATION_PARAMS_SETTINGS
//virtual
BOOL FFWEquationPageBase::OnNext()
{
	string strErrMsg;
	int nErr = CheckEquation(strErrMsg);
	if ( nErr == FFW_EQUATION_INVALID_CONTANT || nErr == FFW_EQUATION_COMPILE_ERROR || nErr == FFW_EQUATION_PEAK_ATTRIB_ERROR )
	{
		MessageBox(strErrMsg, STR_ERROR, MB_OK);
		return FALSE;
	}
	return FFWPageBase::OnNext();
}

int FFWEquationPageBase::CheckEquation(string& strErrMsg)
{
	int ii, nSize;
	//constant checking
	vector<string> vsVariables, vsValues;
	m_gridConstant.GetColValues(CONSTANT_VARIABLE_COLUMN, vsVariables);
	m_gridConstant.GetColValues(CONSTANT_VALUE_COLUMN, vsValues);
	nSize = vsVariables.GetSize();
	for ( ii = m_gridConstant.GetRowOffset(); ii < nSize; ii++ )
	{
		if ( is_missing_value(atof(vsValues[ii])) )
		{
			strErrMsg.Format(_L("%s is not a valid value for constant parameter %s."), vsValues[ii].IsEmpty() ? ftoa(NANUM) : vsValues[ii], vsVariables[ii]);
			return FFW_EQUATION_INVALID_CONTANT;
		}
	}
	
	//compile function
	NumericFunction nf(m_pHolder->m_trFunction);
	if ( !nf.CheckCompileOC() )
	{
		ocu_load_msg_str(NLSF_ERR_COMPILE_NUMERIC_FUNCTION, &strErrMsg);			
		return FFW_EQUATION_COMPILE_ERROR;
	}
	
	//check peak attribs
	if ( FuncOrganizer().IsPeak(m_pHolder->m_trFunction) )
	{
		vector<string> vsVals;
		m_FFWParamGrid.GetColValues(NLPARAMGRIDCOLTYPE_PEAK_ATTRIBUTE, vsVals, m_FFWParamGrid.GetRowOffset());
#define	MIN_PEAK_FUNCTION_PARAMS	4
		if ( vsVals.GetSize() < MIN_PEAK_FUNCTION_PARAMS ||
			 vsVals[0].CompareNoCase(STR_OFFSET_PEAK_INFO) != 0 ||
			 vsVals.Find(STR_X_CENTER_PEAK_INFO) < 0 ||
			 vsVals.Find(STR_X_WIDTH_PEAK_INFO) < 0 ||
			 vsVals.Find(STR_AMPLITUDE_PEAK_INFO) < 0 )
		{
			ocu_load_err_msg_str(MSG_FFW_PEAK_FUNCTION, &strErrMsg);///Jasmine 07/14/10 ORG-540-P3
			return FFW_EQUATION_PEAK_ATTRIB_ERROR;
		}
	}
	
	//parameter checking
	vector<string> vsParamNames, vsParamValues;
	m_FFWParamGrid.GetColValues(NLPARAMGRIDCOLTYPE_NAME, vsParamNames);
	m_FFWParamGrid.GetColValues(NLPARAMGRIDCOLTYPE_VALUE, vsParamValues);
	nSize = vsParamNames.GetSize();
	for ( ii = m_gridConstant.GetRowOffset(); ii < nSize; ii++ )
	{
		if ( is_missing_value(atof(vsParamValues[ii])) )
		{
			strErrMsg.Format(_L("%s is not a valid value for parameter %s."), vsParamValues[ii].IsEmpty() ? ftoa(NANUM) : vsParamValues[ii], vsParamNames[ii]);
			return FFW_EQUATION_INVALID_PARAMS;
		}
	}
	
	//check independents
	vector	vIndepValue;
	vector<string> vsIndepVars;
	int 	nIndepNum = getIndepVarsVal(vIndepValue);
	nlf_get_independent_variables(m_pHolder->m_trFunction, &vsIndepVars);
	for ( ii = 0; ii < nIndepNum; ii++ )
	{
		if ( is_missing_value(vIndepValue[ii]) )
		{
			strErrMsg.Format(_L("%s is not a valid value for independent variable %s."), ftoa(vIndepValue[ii]), vsIndepVars[ii]);
			return FFW_EQUATION_INVALID_INDEPS;
		}
	}
	
	///Sophy 7/7/2010 ORG-432-S14 WARNING_MSG_WHEN_EVALUATE_WITH_TOO_MANY_INDEPS
	const int nMaxIndeps = 4;
	if ( nIndepNum > nMaxIndeps )
	{
		strErrMsg = _L("Evaluation supports no more than 4 indenpedent variables");
		return FFW_EQUATION_TOO_MANY_INDEPS;
	}
	///end WARNING_MSG_WHEN_EVALUATE_WITH_TOO_MANY_INDEPS
	return FFW_EQUATION_OK;
}
///end CHECK_EQUATION_PARAMS_SETTINGS

/*------------------------------------------------------------------------------*
 * FFWEquationPageBase End	 													*
 *------------------------------------------------------------------------------*/
 
///------ Folger 07/06/10 ORG-432-S13 CENTRALIZE_FUNCTION_BODY_PAGE_RESOURCES
class FFWFitFuncBodyPage;
class FFWFuncBodyBase
{
public:
	FFWFuncBodyBase(FFWFitFuncBodyPage* pPage, FFWFunctionOrganizer& funcOrganizer, TreeNode& trFunction)
	{
		m_pPage = pPage;
		m_pFuncOrganizer = &funcOrganizer;
		m_trFunction = trFunction;
		m_ctrlBody = GetItem(IDC_FIT_FUNC_FUNCTION_BODY_EDIT);
		m_ctrlBodyLabel = GetItem(IDC_FIT_FUNC_FUNCTION_BODY_EDIT_TEXT);
	}

	virtual	string	GetName()														{ return "FFWFuncBodyBase"; }
	virtual	string	GetTitle()														{ return GetName(); }
	virtual string	GetPageHintsName(bool bNextPage = false)						{ return bNextPage ? "Function next page" : ""; }
	virtual	void	UpdateControls()		{}
	virtual	bool	UpdateTreeToPageGUI()											{ return true; }
	virtual	bool 	UpdatePageGUIToTree()											{ return true; }

	virtual void	OnContentChange()												{} /// Bill 07/08/2010 ORG-478-P4 CONTENT_MISS_AFTER_RETURN_DIALOG
	virtual	void	OpenCodeBuilder(Window& wndParent)								{}
	virtual	void	DerivativesCheck()												{}
	virtual	int		Compile(string& strErrMsg)														{ return FFW_EQUATION_OK; }	///Sophy 7/12/2010 ORG-518-P2 IMPROVE_ERR_MSG_FOR_QUICK_CHECK
	///Sophy 8/10/2010 ORG-745-P3 IMPROVE_ERR_MSG_IN_LABTALK_FUNCTION_TYPE
	virtual	bool	IsRuntimeCheckEnable()											{ return false; }
	virtual	void	RuntimeCheck(string& strErrMsg)
	{
		if ( IsRuntimeCheckEnable() )
		{
#define	MAX_ERR_MSG_LENGTH	256
			LPSTR lpBuff = strErrMsg.GetBuffer(MAX_ERR_MSG_LENGTH);
			LT_get_last_err(lpBuff, MAX_ERR_MSG_LENGTH);
			LT_get_last_err(NULL, 0); //clear error message after retrieve.
			strErrMsg.ReleaseBuffer();
			if ( !strErrMsg.IsEmpty() )
				strErrMsg = "(" + strErrMsg + ")";
		}
	}		
	///end IMPROVE_ERR_MSG_IN_LABTALK_FUNCTION_TYPE
	
	///Jasmine 08/10/10 ORG-745-P4 ALLOW_EXTERNAL_DLL_HAS_EMPTY_ANNOTATION
	virtual bool 	IsFormulaEssential(){return true;}
	///End ALLOW_EXTERNAL_DLL_HAS_EMPTY_ANNOTATION
	
protected:
	Control			GetItem(int nID)
	{
		return m_pPage->GetItem(nID);
	}

	BOOL			ScreenToClient(RECT* lpRect)
	{
		return m_pPage->ScreenToClient(lpRect);
	}

	BOOL			GetClientRect(RECT& rr, Control ctrl)
	{
		ctrl.GetWindowRect(&rr);
		return ScreenToClient(&rr);
	}

	void			StringToEditText(const string & str, Edit & edit)
	{
		m_pPage->StringToEditText(str, edit);
	}

	void			EditTextToString(Edit & edit, string & str)
	{
		m_pPage->EditTextToString(edit, str);
	}

	RECT			UpdateBodyControl(Control& ctrlBody, RECT& rrBodyLabel)
	{
		int		nGap = ControlGap();
		
		RECT	rr;
		GetClientRect(rr, ctrlBody);
		rr.top = rrBodyLabel.bottom + nGap;
		rr.left = rrBodyLabel.left;
		ctrlBody.MoveWindow(&rr);

		return rr;
	}

	RECT			UpdateBodyLabelControl(Control& ctrlBodyLabel)
	{
		RECT	rrBodyLabel;
		GetClientRect(rrBodyLabel, ctrlBodyLabel);
		OffsetRect(&rrBodyLabel, m_pPage->FuncBodyPoint().x - rrBodyLabel.left, m_pPage->FuncBodyPoint().y - rrBodyLabel.top);
		ctrlBodyLabel.MoveWindow(&rrBodyLabel);
		return rrBodyLabel;
	}

	int				ControlGap()												{ return 5; }
	
	string			GetBodyLabel()
	{
		string	strAdvLabel = GetAdvBodyLabel();
		string	str;
		if ( strAdvLabel.IsEmpty() )
			str = GetBasicBodyLabel();
		else
			str.Format("%s (%s)", GetBasicBodyLabel(), strAdvLabel);
		return str;
	}
	virtual	string	GetBasicBodyLabel()		{ return _L("Function Body"); }
	virtual	string	GetAdvBodyLabel()
	{
		return _L("Dependent Variables") + " : " + m_pFuncOrganizer->GetDependVars(m_trFunction, ',');
	}

protected:
	FFWFunctionOrganizer*	m_pFuncOrganizer;
	TreeNode				m_trFunction;
	Control					m_ctrlBody;
	Control					m_ctrlBodyLabel;

private:
	FFWFitFuncBodyPage*		m_pPage;
};

class FFWExpression : public FFWFuncBodyBase
{
public:
	FFWExpression(FFWFitFuncBodyPage* pPage, FFWFunctionOrganizer& funcOrganizer, TreeNode& trFunction) : FFWFuncBodyBase(pPage, funcOrganizer, trFunction)
	{
		m_ctrlDependVar = GetItem(IDC_FIT_FUNC_EQUATION_LEFT_TEXT);
	}
	~FFWExpression()
	{
	}

	virtual	string	GetName()									{ return "FFWExpressionPage"; }
	virtual	string	GetTitle()									{ return _L("Expression Function"); }

	virtual string	GetPageHintsName(bool bNextPage = false)
	{
		if ( bNextPage )
			return FFWFuncBodyBase::GetPageHintsName(bNextPage);
		
		return "Single Expression";
	}

	virtual	void	UpdateControls()
	{
		m_ctrlBodyLabel.Text =GetBodyLabel();

		int		nGap = ControlGap();
		RECT	rrBodyLabel;
		rrBodyLabel = UpdateBodyLabelControl(m_ctrlBodyLabel);
		
		m_ctrlDependVar.Visible = TRUE;
		
		RECT	rr;
		GetClientRect(rr, m_ctrlDependVar);
		
		OffsetRect(&rr, rrBodyLabel.left - rr.left, rrBodyLabel.bottom + nGap - rr.top);
		m_ctrlDependVar.MoveWindow(&rr);
		
		RECT	rr1;
		GetClientRect(rr1, m_ctrlBody);
		rr1.top = rr.top;
		rr1.left = rr.right + nGap;
		m_ctrlBody.MoveWindow(&rr1);
	}

	virtual	bool	UpdateTreeToPageGUI()
	{
		string strEquation = m_pFuncOrganizer->GetFormula(m_trFunction);
		int nFound = strEquation.Find('=', 0);
		if ( nFound >= 0 )
			strEquation.Delete(0, nFound + 1);
		
		m_ctrlBody.Text = strEquation;
		
		m_ctrlDependVar.Text = m_pFuncOrganizer->GetDependVars(m_trFunction, ',') + "=";
		return true;
	}
	///Sophy 8/10/2010 ORG-745-P3 IMPROVE_ERR_MSG_IN_LABTALK_FUNCTION_TYPE
	//virtual
	bool	IsRuntimeCheckEnable()											{ return true; }
	///end IMPROVE_ERR_MSG_IN_LABTALK_FUNCTION_TYPE
	virtual	string	GetAdvBodyLabel()		{ return ""; }
protected:
private:
	Control		m_ctrlDependVar;
};

class FFWEquations : public FFWFuncBodyBase
{
public:
	FFWEquations(FFWFitFuncBodyPage* pPage, FFWFunctionOrganizer& funcOrganizer, TreeNode& trFunction) : FFWFuncBodyBase(pPage, funcOrganizer, trFunction)
	{
	}
	~FFWEquations()
	{
	}

	virtual	string	GetName()									{ return "FFWMultiEquationPage"; }
	virtual	string	GetTitle()									{ return _L("Multiple Equations"); }

	virtual string	GetPageHintsName(bool bNextPage = false)
	{
		if ( bNextPage )
			return FFWFuncBodyBase::GetPageHintsName(bNextPage);
		
		return "Multiple Equations";
	}

	virtual	void	UpdateControls()
	{
		m_ctrlBodyLabel.Text =GetBodyLabel();

		RECT	rrBodyLabel;
		rrBodyLabel = UpdateBodyLabelControl(m_ctrlBodyLabel);

		UpdateBodyControl(m_ctrlBody, rrBodyLabel);
	}

	virtual	bool	UpdateTreeToPageGUI()
	{
		string strFuncBody =  m_pFuncOrganizer->GetFormula(m_trFunction);
		StringToEditText(strFuncBody, m_ctrlBody);
		return true;
	}
	///Sophy 8/10/2010 ORG-745-P3 IMPROVE_ERR_MSG_IN_LABTALK_FUNCTION_TYPE
	//virtual
	bool	IsRuntimeCheckEnable()											{ return true; }
	///end IMPROVE_ERR_MSG_IN_LABTALK_FUNCTION_TYPE

	///------ Folger 08/11/10 ORG-756-P3 BETTER_CHECKING_FOR_VALID_EQUATIONS
	virtual	int		Compile(string& strErrMsg)
	{
		string	strFuncBody;
		EditTextToString(m_ctrlBody, strFuncBody);
		
		NumericFunction nf(m_trFunction);
		if ( !nf.CheckEquations(strFuncBody, &strErrMsg) )
			return FFW_EQUATION_COMPILE_ERROR;

		return 0;
	}
	///------ End BETTER_CHECKING_FOR_VALID_EQUATIONS
protected:
private:
};

class FFWLTOCBase : public FFWFuncBodyBase
{
public:
	FFWLTOCBase(FFWFitFuncBodyPage* pPage, FFWFunctionOrganizer& funcOrganizer, TreeNode& trFunction) : FFWFuncBodyBase(pPage, funcOrganizer, trFunction)
	{
		m_btnCheckDeriv = GetItem(IDC_FIT_FUNC_DERIVATIVES_CHECK);
	}
	~FFWLTOCBase()
	{
	}

	virtual	void	DerivativesCheck()
	{
		m_pFuncOrganizer->SetDerivative(m_btnCheckDeriv.Check, m_trFunction);
	}
protected:
	virtual	bool	UpdateTreeToPageGUI()
	{
		m_btnCheckDeriv.Check = m_pFuncOrganizer->IsDerivative(m_trFunction);
		return true;
	}
	
	virtual	bool 	UpdatePageGUIToTree()
	{
		string	strFuncBody;
		EditTextToString(m_ctrlBody, strFuncBody);
		
		m_pFuncOrganizer->SetDerivative(m_btnCheckDeriv.Check, m_trFunction);
		return true;
	}

	Button		m_btnCheckDeriv;
private:
};

class FFWLabtalk : public FFWLTOCBase
{
public:
	FFWLabtalk(FFWFitFuncBodyPage* pPage, FFWFunctionOrganizer& funcOrganizer, TreeNode& trFunction) : FFWLTOCBase(pPage, funcOrganizer, trFunction)
	{
	}
	~FFWLabtalk()
	{
	}

	virtual	string	GetName()									{ return "FFWLabtalkPage"; }
	virtual	string	GetTitle()									{ return _L("LabTalk Script Function"); }

	virtual string	GetPageHintsName(bool bNextPage = false)
	{
		if ( bNextPage )
			return FFWFuncBodyBase::GetPageHintsName(bNextPage);
		
		return "LabTalk Script Function";
	}

	virtual	void	UpdateControls()
	{
		m_ctrlBodyLabel.Text =GetBodyLabel();

		int		nGap = ControlGap();
		RECT	rrBodyLabel;
		rrBodyLabel = UpdateBodyLabelControl(m_ctrlBodyLabel);
		
		m_btnCheckDeriv.Visible = TRUE;
		
		RECT	rr;
		rr = UpdateBodyControl(m_ctrlBody, rrBodyLabel);

		RECT	rr1;
		GetClientRect(rr1, m_btnCheckDeriv);
		
		OffsetRect(&rr1, rr.right - rr1.right, rrBodyLabel.top - rr1.top);
		m_btnCheckDeriv.MoveWindow(&rr1);
	}
	
	///Sophy 8/10/2010 ORG-745-P3 IMPROVE_ERR_MSG_IN_LABTALK_FUNCTION_TYPE
	//virtual
	bool	IsRuntimeCheckEnable()											{ return true; }
	///end IMPROVE_ERR_MSG_IN_LABTALK_FUNCTION_TYPE
protected:
private:
};

class FFWOriginC : public FFWLTOCBase
{
public:
	FFWOriginC(FFWFitFuncBodyPage* pPage, FFWFunctionOrganizer& funcOrganizer, TreeNode& trFunction) : FFWLTOCBase(pPage, funcOrganizer, trFunction)
	{
		m_btnOpenCB = GetItem(IDC_FIT_FUNC_OPEN_CODE_BUILDER);
	}
	~FFWOriginC()
	{
	}

	virtual	string	GetName()									{ return "FFWOCFunctionPage"; }
	virtual	string	GetTitle()									{ return _L("Origin C Fitting Function"); }

	virtual string	GetPageHintsName(bool bNextPage = false)
	{
		if ( bNextPage )
			return FFWFuncBodyBase::GetPageHintsName(bNextPage);
		
		return "Origin C Fitting Function";
	}

	virtual	void	UpdateControls()
	{
		m_ctrlBodyLabel.Text =GetBodyLabel();

		int		nGap = ControlGap();
		RECT	rrBodyLabel;
		rrBodyLabel = UpdateBodyLabelControl(m_ctrlBodyLabel);
		
		m_btnCheckDeriv.Visible = TRUE;
		m_btnOpenCB.Visible = TRUE;

		RECT	rr;
		rr = UpdateBodyControl(m_ctrlBody, rrBodyLabel);
		
		RECT	rr1;
		GetClientRect(rr1, m_btnCheckDeriv);
		
		RECT	rr2;
		GetClientRect(rr2, m_btnOpenCB);

		OffsetRect(&rr2, rr.right - rr2.right, rrBodyLabel.top - rr2.top - nGap);
		m_btnOpenCB.MoveWindow(&rr2);		

		OffsetRect(&rr1, rr2.left - rr1.left - RECT_WIDTH(rr1), rrBodyLabel.top - rr1.top);
		m_btnCheckDeriv.MoveWindow(&rr1);
	}

	virtual	void	OpenCodeBuilder(Window& wndParent)
	{
		string	strFuncBody;
		EditTextToString(m_ctrlBody, strFuncBody);		
		m_pFuncOrganizer->SetFormula(strFuncBody, m_trFunction);
		Functions.EditFunctionInCodeBuilder(m_trFunction, wndParent);
	}

	/// Bill 07/08/2010 ORG-478-P4 CONTENT_MISS_AFTER_RETURN_DIALOG
	virtual void	OnContentChange()
	{
		string strFuncBody = m_pFuncOrganizer->GetFormula(m_trFunction);
		StringToEditText(strFuncBody, m_ctrlBody);
	}
	/// End CONTENT_MISS_AFTER_RETURN_DIALOG
	///Sophy 7/12/2010 ORG-518-P2 IMPROVE_ERR_MSG_FOR_QUICK_CHECK
	//virtual
	int		Compile(string& strErrMsg)
	{
		string	strFuncBody;
		EditTextToString(m_ctrlBody, strFuncBody);		
		m_pFuncOrganizer->SetFormula(strFuncBody, m_trFunction);
		
		NumericFunction nf(m_trFunction);
		if ( !nf.CheckCompileOC() )
		{
			///Sophy 7/8/2010 ORG-518-P7 IMPROVE_OC_COMPILE_ERR_MSG_ON_QUICK_CHECK
			//ocu_load_msg_str(NLSF_ERR_COMPILE_NUMERIC_FUNCTION, &strErrMsg);
			strErrMsg = _L("Compile error. Click the Open Code Builder button for details");
			///end IMPROVE_OC_COMPILE_ERR_MSG_ON_QUICK_CHECK
			return FFW_EQUATION_COMPILE_ERROR;
		}

	}
protected:
private:
	Button		m_btnOpenCB;
};

class FFWExternalDLL : public FFWFuncBodyBase
{
public:
	FFWExternalDLL(FFWFitFuncBodyPage* pPage, FFWFunctionOrganizer& funcOrganizer, TreeNode& trFunction) : FFWFuncBodyBase(pPage, funcOrganizer, trFunction)
	{
		m_ctrlDLLFileLabel = GetItem(IDC_FIT_FUNC_DLL_FILE_EDIT_TEXT);
		m_ctrlDLLFuncLabel = GetItem(IDC_FIT_FUNC_DLL_FUNC_EDIT_TEXT);
		m_edDLLFile = GetItem(IDC_FIT_FUNC_DLL_FILE_EDIT);
		m_edDLLFunc = GetItem(IDC_FIT_FUNC_DLL_FUNC_EDIT);
	}
	~FFWExternalDLL()
	{
	}

	virtual	string	GetName()									{ return "FFWExternalDLLPage"; }
	virtual	string	GetTitle()									{ return _L("External DLL"); }

	virtual string	GetPageHintsName(bool bNextPage = false)
	{
		if ( bNextPage )
			return FFWFuncBodyBase::GetPageHintsName(bNextPage);
			
		return "External DLL";
	}

	virtual	void	UpdateControls()
	{
		m_ctrlBodyLabel.Text =GetBodyLabel();
		
		int		nGap = ControlGap();
		RECT	rrBodyLabel;
		rrBodyLabel = UpdateBodyLabelControl(m_ctrlBodyLabel);

		m_ctrlDLLFileLabel.Visible = TRUE;
		m_ctrlDLLFuncLabel.Visible = TRUE;
		m_edDLLFile.Visible = TRUE;
		m_edDLLFunc.Visible = TRUE;

		RECT	rrDLLFileLabel;
		GetClientRect(rrDLLFileLabel, m_ctrlDLLFileLabel);

		RECT	rrDLLFuncLabel;
		GetClientRect(rrDLLFuncLabel, m_ctrlDLLFuncLabel);

		RECT	rrDLLFile;
		GetClientRect(rrDLLFile, m_edDLLFile);

		RECT	rrDLLFunc;
		GetClientRect(rrDLLFunc, m_edDLLFunc);

		OffsetRect(&rrDLLFileLabel, rrBodyLabel.left - rrDLLFileLabel.left, rrBodyLabel.top - rrDLLFileLabel.top);
		m_ctrlDLLFileLabel.MoveWindow(&rrDLLFileLabel);

		OffsetRect(&rrDLLFile, rrDLLFileLabel.left - rrDLLFile.left + RECT_WIDTH(rrDLLFileLabel) + nGap, rrBodyLabel.top - rrDLLFile.top - nGap);
		m_edDLLFile.MoveWindow(&rrDLLFile);

		OffsetRect(&rrDLLFuncLabel, rrDLLFile.left - rrDLLFuncLabel.left + RECT_WIDTH(rrDLLFile) + nGap, rrBodyLabel.top - rrDLLFuncLabel.top);
		m_ctrlDLLFuncLabel.MoveWindow(&rrDLLFuncLabel);

		OffsetRect(&rrDLLFunc, rrDLLFuncLabel.left - rrDLLFunc.left + RECT_WIDTH(rrDLLFuncLabel) + nGap, rrBodyLabel.top - rrDLLFunc.top - nGap);
		m_edDLLFunc.MoveWindow(&rrDLLFunc);
		
		OffsetRect(&rrBodyLabel, 0, rrDLLFileLabel.bottom + nGap - rrBodyLabel.top);
		m_ctrlBodyLabel.MoveWindow(&rrBodyLabel);
		
		UpdateBodyControl(m_ctrlBody, rrBodyLabel);
	}

	///Jasmine 08/02/10 ORG-591-P7 DETECH_EXTERNAL_DLL_SOURCE
	virtual int		Compile(string& strErrMsg)
	{
		if( m_edDLLFile.Text.IsEmpty() || m_edDLLFunc.Text.IsEmpty() )
		{
			//strErrMsg.Format("%s or %s cannot be empty.", m_ctrlDLLFileLabel.Text, m_ctrlDLLFuncLabel.Text);
			ocu_load_msg_str(FFWERR_ST_CANNOT_BE_EMPTY_EX, &strErrMsg, m_ctrlDLLFileLabel.Text, NULL, m_ctrlDLLFuncLabel.Text);
			return FFW_EQUATION_EMPTY_DLL;
		}
		
		return FFWFuncBodyBase::Compile(strErrMsg);
	}
	///End DETECH_EXTERNAL_DLL_SOURCE
	
	virtual	bool	UpdateTreeToPageGUI()
	{
		string strSource = m_pFuncOrganizer->GetSource(m_trFunction);
		if ( strSource.Compare(STR_NO_DLL_SOURCE) == 0 )
			strSource = "";
		
		int nIndex = strSource.Find('.');
		string strDll = strSource.Left(nIndex);
		string strFunc = strSource.Right(strSource.GetLength() - 1 - nIndex);
		
		m_edDLLFile.Text  = strDll;
		m_edDLLFunc.Text = strFunc;
		return true;
	}

	virtual	bool 	UpdatePageGUIToTree()
	{
		string	strSource;
		if ( lstrlen(m_edDLLFile.Text) == 0 || lstrlen(m_edDLLFunc.Text) == 0 )
			strSource = STR_NO_DLL_SOURCE;
		else
			strSource = m_edDLLFile.Text + "." + m_edDLLFunc.Text;
		
		m_pFuncOrganizer->SetSource(strSource, m_trFunction);
		return true;
	}
	
	///Jasmine 08/10/10 ORG-745-P4 ALLOW_EXTERNAL_DLL_HAS_EMPTY_ANNOTATION
	virtual bool 	IsFormulaEssential(){return false;}
	///End ALLOW_EXTERNAL_DLL_HAS_EMPTY_ANNOTATION
	
protected:
	virtual	string	GetBasicBodyLabel()												{ return _L("Annotation"); }

private:
	Control		m_ctrlDLLFileLabel;
	Control		m_ctrlDLLFuncLabel;
	Edit		m_edDLLFile;
	Edit		m_edDLLFunc;
};

#define		ON_FFW_EVALUATE_PAGE_MSGS \
			PAGE_ON_INIT(OnInitPage) \
			PAGE_ON_ACTIVE(OnActivatePage) \
			PAGE_ON_KILLACTIVE(OnKillActiviePage) \
			PAGE_ON_NEXT(OnNext) \
			PAGE_ON_BACK(OnBack) \
			\
			ON_BN_CLICKED(FFW_EVALUATE_BTN, OnEvaluateClick)\
			\
			ON_GRID_AFTER_EDIT(IDC_FIT_FUNC_PARAM_GRID, OnAfterEditParaControl)\
			\
			ON_TAB_SEL_CHANGE(IDC_FIT_FUNC_PARAM_TAB, OnTabChange)

class FFWFitFuncBodyPage : public FFWPageBase
{
public:
	FFWFitFuncBodyPage(int nID = 0);
	~FFWFitFuncBodyPage();

	EVENTS_BEGIN
		ON_FFW_EVALUATE_PAGE_MSGS
		///Sophy 7/8/2010 ORG-518-P6 DISABLE_EDIT_PARAM_AND_CONSTANT_NAME
		ON_GRID_BEFORE_EDIT(IDC_FIT_FUNC_PARAM_GRID, OnBeforeEditParaControl)
		ON_GRID_BEFORE_EDIT(IDC_FIT_FUNC_CONSTANT_GRID, OnBeforeEditParaControl)
		ON_GRID_AFTER_EDIT(IDC_FIT_FUNC_CONSTANT_GRID, OnAfterEditParaControl)	///Sophy 7/12/2010 ORG-518-P3 TRIM_PARAM_VALUE_AND_CONSTANT_BEFORE_SAVE
		//end DISABLE_EDIT_PARAM_AND_CONSTANT_NAME
		ON_BN_CLICKED(IDC_FIT_FUNC_OPEN_CODE_BUILDER, OnOpenCodeBuilder);
		///Jasmine 07/29/10 ORG-591-P7 FINSH_EVENT_IS_TOO_LATE_SO_DISABLE_ONCE_FIND_ERROR
		ON_EN_KILLFOCUS(IDC_FIT_FUNC_FUNCTION_BODY_EDIT, OnFunctionBodyChange)
		ON_EN_KILLFOCUS(IDC_FIT_FUNC_DLL_FILE_EDIT, OnFunctionBodyChange)
		ON_EN_KILLFOCUS(IDC_FIT_FUNC_DLL_FUNC_EDIT, OnFunctionBodyChange)
		///End FINSH_EVENT_IS_TOO_LATE_SO_DISABLE_ONCE_FIND_ERROR
		ON_BN_CLICKED(IDC_FIT_FUNC_DERIVATIVES_CHECK, OnDerivativesCheck);
	EVENTS_END

	POINT&			FuncBodyPoint()		{ return m_ptFuncBody; }
	void			OnContentChange(); /// Bill 07/08/2010 ORG-478-P4 CONTENT_MISS_AFTER_RETURN_DIALOG
protected:

	virtual BOOL	OnInitPage();
	virtual	BOOL	OnActivatePage();
	virtual	BOOL	OnNext();
	BOOL 			OnEvaluateClick(Control ctrl);
	void			OnBeforeEditParaControl(Control flxControl, int nRow, int nCol, BOOL* pCancel);	///Sophy 7/8/2010 ORG-518-P6 DISABLE_EDIT_PARAM_AND_CONSTANT_NAME
	void  			OnAfterEditParaControl(Control flxControl, int nRow, int nCol);
	BOOL 			OnTabChange(Control ctrl);
	void			OnOpenCodeBuilder(Control ctrl);
	BOOL			OnFunctionBodyChange(Control ctrl);	///Jasmine 07/29/10 ORG-591-P7 FINSH_EVENT_IS_TOO_LATE_SO_DISABLE_ONCE_FIND_ERROR
	void			OnDerivativesCheck(Control ctrl);

	bool			InitGridConstant();
	bool			InitGridParam();
	bool			InitTabControls();	

	virtual bool 	UpdateTreeToPageGUI(const TreeNode& trFunction);
	virtual bool 	UpdatePageGUIToTree(TreeNode& trFunction);
	/// Bill 07/12/2010	ADD_PEAK_FUNC_AND_QUICK_CHECK_HINT
	virtual string	GetPageHints(bool bNextPage = false);
	/// End ADD_PEAK_FUNC_AND_QUICK_CHECK_HINT

	virtual string	GetPageHintsName(bool bNextPage = false);
	
	bool 			evaluateDependentVar();	
	int				getIndepVarsVal(vector& vv);	
	int				CheckEquation(string& strErrMsg);
	void			HideAllFuncBodyControls();

	void			UpdateTitle();
	void			UpdateControls();
private:
	void			UpdateFuncBody();
	
	void			checkEnableFinishBtn();	///Jasmine 07/29/10 ORG-591-P7 FINSH_EVENT_IS_TOO_LATE_SO_DISABLE_ONCE_FIND_ERROR
	
protected:
	FFWParamSetting 		m_FFWParamGrid;
	FFWConstantSetting 		m_gridConstant;
	TabControl				m_tabParameter;
	
	Control					m_controlDependVar;
	Edit					m_editEquation;

	FFWFuncBodyBase*		m_pFuncBody;

	POINT					m_ptFuncBody;
};

FFWFitFuncBodyPage::FFWFitFuncBodyPage(int nID/* = 0*/) : FFWPageBase(nID)
{
	m_pFuncBody = NULL;
}
FFWFitFuncBodyPage::~FFWFitFuncBodyPage()
{
	NICE_SAFE_REMOVAL(m_pFuncBody);
}

/// virtual
BOOL FFWFitFuncBodyPage::OnInitPage()
{	
	m_controlDependVar = GetItem(IDC_FIT_FUNC_DEPEND_VAR);

	if ( !InitGridConstant() || !InitGridParam() || !InitTabControls() )
		return FALSE;
	                 
	m_editEquation = GetItem(IDC_FIT_FUNC_FUNCTION_BODY_EDIT);

	Control	ctrlEquationLabel = GetItem(IDC_FIT_FUNC_FUNCTION_BODY_EDIT_TEXT);
	RECT		rr;
	ctrlEquationLabel.GetWindowRect(&rr);
	ScreenToClient(&rr);
	m_ptFuncBody.x = rr.left;
	m_ptFuncBody.y = rr.top;

	BitmapRadioButton btnEvaluate = GetItem(FFW_EVALUATE_BTN);
	vector<string> vsTips(1);
	vsTips[0] = _L("Evaluate");
	btnEvaluate.Init(1, IDB_APPLY_BTN, 16, vsTips);

	BitmapRadioButton btnOpenCB = GetItem(IDC_FIT_FUNC_OPEN_CODE_BUILDER);
	vsTips[0] = _L("Open Code Builder");
	btnOpenCB.Init(1, IDB_OPEN_CB, 16, vsTips);
	
	FFWPageBase::OnInitPage();
	
	return TRUE;
}

/// virtual
BOOL	FFWFitFuncBodyPage::OnActivatePage()
{
	UpdateFuncBody();
	UpdateTitle();
	UpdateControls();
	BOOL bRet =  FFWPageBase::OnActivatePage();
	
	m_controlDependVar.Text = "";
	///Jasmine 07/29/10 ORG-591-P7 FINSH_EVENT_IS_TOO_LATE_SO_DISABLE_ONCE_FIND_ERROR
	checkEnableFinishBtn();
	///End FINSH_EVENT_IS_TOO_LATE_SO_DISABLE_ONCE_FIND_ERROR
	
	return bRet;
}

#define		NEW_FUNCBODY_ARGUMENTS		this, FuncOrganizer(), m_pHolder->m_trFunction
void	FFWFitFuncBodyPage::UpdateFuncBody()
{
	NICE_SAFE_REMOVAL(m_pFuncBody);

	TreeNode	trFunction = m_pHolder->m_trFunction;

	string		strType = FuncOrganizer().GetType(trFunction);
	if ( strType.Compare(STR_FUNCTION_TYPE_EXTERN_DLL) == 0 )
	{
		m_pFuncBody = new FFWExternalDLL(NEW_FUNCBODY_ARGUMENTS);
	}
	else
	{
		string strForm = FuncOrganizer().GetForm(trFunction);
		
		if ( strForm.Compare(STR_FUNCTION_FORM_EXPRESSION) == 0 )
			m_pFuncBody = new FFWExpression(NEW_FUNCBODY_ARGUMENTS);
		else if ( strForm.Compare(STR_FUNCTION_FORM_EQUATIONS) == 0 )
			m_pFuncBody = new FFWEquations(NEW_FUNCBODY_ARGUMENTS);
		else if ( strForm.Compare(STR_FUNCTION_FORM_Y_SCRIPT) == 0 )
			m_pFuncBody = new FFWLabtalk(NEW_FUNCBODY_ARGUMENTS);
		else if ( strForm.Compare(STR_FUNCTION_FORM_ORIGIN_C) == 0 )
			m_pFuncBody = new FFWOriginC(NEW_FUNCBODY_ARGUMENTS);
		else
			m_pFuncBody = new FFWExpression(NEW_FUNCBODY_ARGUMENTS);
	}
}

BOOL FFWFitFuncBodyPage::OnEvaluateClick(Control ctrl)
{
	return evaluateDependentVar();
}

///Sophy 7/8/2010 ORG-518-P6 DISABLE_EDIT_PARAM_AND_CONSTANT_NAME
void FFWFitFuncBodyPage::OnBeforeEditParaControl(Control flxControl, int nRow, int nCol, BOOL* pCancel)
{

	if ( GetDlgCtrlID(flxControl.GetSafeHwnd()) == GetDlgCtrlID(m_FFWParamGrid.GetCtrnlSafeHwnd()) ) //param grid
	{
		if ( NLPARAMGRIDCOLTYPE_NAME == nCol && pCancel )
		{
			*pCancel = TRUE;
		}
		///Jasmine 07/14/10 ORG-486-S1 CENTRALIZE_PEAK_ATTRIB_TO_NLFIT
		else
			m_FFWParamGrid.OnBeforeEditParaControl(flxControl, nRow, nCol, pCancel);
		///End CENTRALIZE_PEAK_ATTRIB_TO_NLFIT
		
	}
	else if ( GetDlgCtrlID(flxControl.GetSafeHwnd()) == GetDlgCtrlID(m_gridConstant.GetCtrnlSafeHwnd()) ) //constant grid
	{
		if ( CONSTANT_VARIABLE_COLUMN == nCol && pCancel )
		{
			*pCancel = TRUE;
		}
	}
}
///end DISABLE_EDIT_PARAM_AND_CONSTANT_NAME

///Jasmine 07/29/10 ORG-591-P7 FINSH_EVENT_IS_TOO_LATE_SO_DISABLE_ONCE_FIND_ERROR
void FFWFitFuncBodyPage::checkEnableFinishBtn()
{
	bool bEnable = true;
	
	///Jasmine 08/18/10 ORG-820-S1 NOT_ALLOW_FINISH_UNTIL_DERIVED_PARAM_CHECK_OK
	bEnable = !FuncOrganizer().HasDerivedParameters(m_pHolder->m_trFunction);
	if(bEnable)
	///End NOT_ALLOW_FINISH_UNTIL_DERIVED_PARAM_CHECK_OK
	{
		string strErrMsg;
		int nErr = CheckEquation(strErrMsg);
		if ( nErr == FFW_EQUATION_INVALID_CONTANT || nErr == FFW_EQUATION_COMPILE_ERROR || nErr == FFW_EQUATION_PEAK_ATTRIB_ERROR || nErr == FFW_EQUATION_EMPTY_FORMULA 
			 || nErr == FFW_EQUATION_EMPTY_DLL)	///Jasmine 08/02/10 ORG-591-P7 DETECH_EXTERNAL_DLL_SOURCE
			bEnable = false;
	}
	m_pHolder->EnableFinishButton(bEnable);
}

BOOL FFWFitFuncBodyPage::OnFunctionBodyChange(Control ctrl)
{
	checkEnableFinishBtn();
	
	return TRUE;
}
///End FINSH_EVENT_IS_TOO_LATE_SO_DISABLE_ONCE_FIND_ERROR

void  FFWFitFuncBodyPage::OnAfterEditParaControl(Control flxControl, int nRow, int nCol)
{
	///Sophy 7/12/2010 ORG-518-P3 TRIM_PARAM_VALUE_AND_CONSTANT_BEFORE_SAVE
	//since we do NOT allow editing parameters and constants on the grids, this code is not needed any more.
	//if (NLPARAMGRIDCOLTYPE_NAME == nCol)
	//{
		//vector<string> vsNames;
//
		//m_FFWParamGrid.GetColValues(NLPARAMGRIDCOLTYPE_NAME, vsNames);
//
		//string strNew = vsNames[nRow];
//
		//vsNames.RemoveAt(nRow);
		//vsNames.RemoveAt(0);
//
		//if ( vsNames.Find(strNew) != -1)
		//{
			//string strErrMsg;
//
			//strErrMsg.Format(_L("The parameter %s already exists"), strNew);
//
			//MessageBox(strErrMsg, STR_ERROR, MB_OK);
//
			//string strDummy("");
//
			//m_FFWParamGrid.SetCell(nRow, nCol, strDummy);			
		//}
	//}
//
	//m_FFWParamGrid.OnAfterEdit(flxControl, nRow, nCol);
	if ( GetDlgCtrlID(flxControl.GetSafeHwnd()) == GetDlgCtrlID(m_FFWParamGrid.GetCtrnlSafeHwnd()) ) //param grid
	{
		if ( NLPARAMGRIDCOLTYPE_VALUE == nCol )
		{
			string strValue = m_FFWParamGrid.GetCell(nRow, nCol);
			TRIM_STR(strValue);
			m_FFWParamGrid.SetCell(nRow, nCol, strValue);
		}

		/// Bill 07/15/2010 ORG-576-S1 MOVE_TO_NEXT_ROW_IF_USER_PRESS_ENTER
		m_FFWParamGrid.OnAfterEdit(nRow, nCol);
		/// MOVE_TO_NEXT_ROW_IF_USER_PRESS_ENTER
	}
	else if ( GetDlgCtrlID(flxControl.GetSafeHwnd()) == GetDlgCtrlID(m_gridConstant.GetCtrnlSafeHwnd()) ) //constant grid
	{
		if ( CONSTANT_VALUE_COLUMN == nCol )
		{
			string strValue = m_gridConstant.GetCell(nRow, nCol);
			TRIM_STR(strValue);
			m_gridConstant.SetCell(nRow, nCol, strValue);
		}

		/// Bill 07/15/2010 ORG-576-S1 MOVE_TO_NEXT_ROW_IF_USER_PRESS_ENTER
		m_gridConstant.OnAfterEdit(nRow, nCol);
		/// End MOVE_TO_NEXT_ROW_IF_USER_PRESS_ENTER
	}
	///end TRIM_PARAM_VALUE_AND_CONSTANT_BEFORE_SAVE
	
	///Jasmine 07/29/10 ORG-591-P7 FINSH_EVENT_IS_TOO_LATE_SO_DISABLE_ONCE_FIND_ERROR
	checkEnableFinishBtn();
	///End FINSH_EVENT_IS_TOO_LATE_SO_DISABLE_ONCE_FIND_ERROR
}

BOOL FFWFitFuncBodyPage::OnTabChange(Control ctrl)
{
	bool bParamTab = FFW_PARAM_TAB == m_tabParameter.GetCurSel();
	m_FFWParamGrid.SetVisible(bParamTab);
	m_gridConstant.SetVisible(!bParamTab);
	return TRUE;
}

bool FFWFitFuncBodyPage::InitGridParam()
{
	m_FFWParamGrid.Init(IDC_FIT_FUNC_PARAM_GRID, *this, "junk");
	
	m_FFWParamGrid.ShowGroup(0);

	return true;
}

bool FFWFitFuncBodyPage::InitGridConstant()
{
	m_gridConstant.Init(IDC_FIT_FUNC_CONSTANT_GRID, *this);
	return true;
}

bool FFWFitFuncBodyPage::InitTabControls()
{
	m_tabParameter = GetItem(IDC_FIT_FUNC_PARAM_TAB);
	if(!m_tabParameter)
		return false;
	
	m_tabParameter.InsertItem(FFW_PARAM_TAB, _L("Parameters"));
	m_tabParameter.InsertItem(FFW_CONST_TAB, _L("Constants"));
	
	RECT rTab;
	m_tabParameter.GetWindowRect(&rTab);
	ScreenToClient(&rTab);
	m_tabParameter.AdjustRect(FALSE, &rTab);
	
	m_FFWParamGrid.MoveWindow(rTab);
	m_gridConstant.MoveWindow(rTab);

	OnTabChange(m_tabParameter);
	
	return true;
}

virtual bool FFWFitFuncBodyPage::UpdateTreeToPageGUI(const TreeNode& trFunction)
{
	bool bPeakFunction = FuncOrganizer().IsPeak(m_pHolder->m_trFunction);
	m_FFWParamGrid.HideCol(NLPARAMGRIDCOLTYPE_PEAK_ATTRIBUTE, !bPeakFunction);

	m_FFWParamGrid.SetTree(m_pHolder->m_trFunction);
	m_FFWParamGrid.ResizeCols();

	//constant
	vector<string> vsVariables;
	vector<string> vsValues;
 	int nCount = FuncOrganizer().GetConstants(m_pHolder->m_trFunction, vsVariables, vsValues);
	m_gridConstant.Update(vsVariables, vsValues);
	m_gridConstant.ResizeCols();
	
	//function body
	if(m_editEquation)
	{
		string strFuncBody = FuncOrganizer().GetFormula(trFunction);
		StringToEditText(strFuncBody, m_editEquation);
	}

	//evaluate controls
	char ch = ',';
	string strIndepNames = FuncOrganizer().GetIndependVars(trFunction, ch);
	vector<string> vsNames;
	int nNames = strIndepNames.GetTokens(vsNames, ch);
	
	ch = ';';
	string strIndepVars = FuncOrganizer().GetIndependVarsWithValue(trFunction, ch);	
	vector vValues;
	FuncOrganizer().ParseIndependVarsValue(vValues, trFunction, strIndepVars, ch);
	///Sophy 7/8/2010 ORG-518-P8 LIMIT_NUM_INDEPS_TO_3_ON_QUICK_CHECK
	//int nMaxNum = 4;
	//vector<int> vnLabels = {IDC_FIT_FUNC_INDEPEND_VAR1, IDC_FIT_FUNC_INDEPEND_VAR2, IDC_FIT_FUNC_INDEPEND_VAR3, IDC_FIT_FUNC_INDEPEND_VAR4};
	//vector<int> vnEdits = {IDC_FIT_FUNC_INDEPEND_VAR_VALUE1, IDC_FIT_FUNC_INDEPEND_VAR_VALUE2, IDC_FIT_FUNC_INDEPEND_VAR_VALUE3, IDC_FIT_FUNC_INDEPEND_VAR_VALUE4};
	int nMaxNum = 3;
	vector<int> vnLabels = {IDC_FIT_FUNC_INDEPEND_VAR1, IDC_FIT_FUNC_INDEPEND_VAR2, IDC_FIT_FUNC_INDEPEND_VAR3};
	vector<int> vnEdits = {IDC_FIT_FUNC_INDEPEND_VAR_VALUE1, IDC_FIT_FUNC_INDEPEND_VAR_VALUE2, IDC_FIT_FUNC_INDEPEND_VAR_VALUE3};
	///end LIMIT_NUM_INDEPS_TO_3_ON_QUICK_CHECK
	ASSERT( nMaxNum == vnLabels.GetSize() && nMaxNum == vnEdits.GetSize() );
	for(int ii = 0; ii < nMaxNum; ii++)
	{
		Control label 	= GetItem( vnLabels[ii] );
		Control edit	= GetItem( vnEdits[ii] );
		if(ii < nNames)
		{
			label.Text = vsNames[ii] + " = ";
			if( ii < vValues.GetSize() )
				edit.Text = ftoa( vValues[ii] );
			label.Visible = edit.Visible = true;
		}
		else
		{
			label.Visible = edit.Visible = false;
		}
	}
	
	return m_pFuncBody->UpdateTreeToPageGUI();
}

virtual bool FFWFitFuncBodyPage::UpdatePageGUIToTree(TreeNode& trFunction)
{
	//parameter
	m_FFWParamGrid.GetTree(trFunction);
	
	//constant
	vector<string> vsVariables, vsValues;
	m_gridConstant.GetColValues(CONSTANT_VARIABLE_COLUMN, vsVariables);
	m_gridConstant.GetColValues(CONSTANT_VALUE_COLUMN, vsValues);

	vsVariables.RemoveAt(0);
	vsValues.RemoveAt(0);
	for (int ii = vsVariables.GetSize() - 1 ; ii >= 0 ; --ii)
	{
		///Sophy 7/8/2010 ORG-518-P3 TRIM_PARAM_VALUE_AND_CONSTANT_BEFORE_SAVE
		TRIM_STR(vsVariables[ii])
		TRIM_STR(vsValues[ii])
		///end TRIM_PARAM_VALUE_AND_CONSTANT_BEFORE_SAVE
		if ( vsVariables[ii] == "")
		{
			vsVariables.RemoveAt(ii);
			vsValues.RemoveAt(ii);
		}
	}
	FuncOrganizer().SetConstants(vsVariables, vsValues, trFunction);
	
	//function body
	string strFormula = m_editEquation ? m_editEquation.Text : "";
	FuncOrganizer().SetFormula(strFormula, trFunction);
	
	//evaluate controls
	FuncOrganizer().ClearQuickCheck(trFunction);
	vector<string>	vstrNames, vstrVals, vstrTemp;
	vector			vVals, vTemp;
	nlf_get_independent_variables(trFunction, &vstrNames);
	char			chDelimiter = ',';
	string			strNames = FuncOrganizer().GetFittingPara(trFunction);
	strNames.GetTokens(vstrTemp, chDelimiter);
	vstrNames.Append(vstrTemp);
	
	getIndepVarsVal(vVals);
	m_FFWParamGrid.GetParamsVals(vTemp);
	vVals.Append(vTemp);
	convert_double_vector_to_string_vector(vVals, vstrVals, vVals.GetSize());
	ASSERT( vstrNames.GetSize() == vstrVals.GetSize() );
	FuncOrganizer().SetQuickCheckItems(trFunction, vstrNames, vstrVals);

	return m_pFuncBody->UpdatePageGUIToTree();
}

/// Bill 07/12/2010 ADD_PEAK_FUNC_AND_QUICK_CHECK_HINT
virtual string FFWFitFuncBodyPage::GetPageHints(bool bNextPage)
{
	if ( bNextPage )
		return FFWPageBase::GetPageHints(true);
	else
	{
		string strHint;

		if ( FuncOrganizer().IsPeak(m_pHolder->m_trFunction) )
		{
			string strPeakHint;
			strPeakHint = GetHintsBySection("Set Peak Attribute");
			strHint += strPeakHint + "\r\n\r\n";
		}
		///jasmine 07/15/10 ORG-2-P15 ADD_HINTS_FOR_PARAMTAB_AND_CONSTTAB
		string strParamTabHints =  GetHintsBySection("Parameter Tab");
		if( !strParamTabHints.IsEmpty() )
			strHint += strParamTabHints + "\r\n\r\n";
		
		string strConstTabHints =  GetHintsBySection("Constant Tab");
		if( !strConstTabHints.IsEmpty() )
			strHint += strConstTabHints + "\r\n\r\n";
		///End ADD_HINTS_FOR_PARAMTAB_AND_CONSTTAB
		strHint += FFWPageBase::GetPageHints(false);

		string strQuickCheckHint;
		strQuickCheckHint = GetHintsBySection("Quick Check");
		strHint += "\r\n\r\n" + strQuickCheckHint;

		return strHint;
	}
}
/// End ADD_PEAK_FUNC_AND_QUICK_CHECK_HINT

/// virtual
string FFWFitFuncBodyPage::GetPageHintsName(bool bNextPage/* = false*/)
{
	return m_pFuncBody->GetPageHintsName(bNextPage);
}
///End MOVE_FFW_HINTS_TO_TXT

bool FFWFitFuncBodyPage::evaluateDependentVar()
{
	TreeNode trFunction = m_pHolder->m_trFunction;
	if( !UpdatePageGUIToTree(trFunction) )
	{
		ASSERT(0);
		return false;
	}	
	
	string strErrMsg;
	int nErr = CheckEquation(strErrMsg);
	///Sophy 7/8/2010 ORG-518-P2 IMPROVE_ERR_MSG_FOR_QUICK_CHECK
	//if ( nErr != FFW_EQUATION_OK )
	if ( nErr == FFW_EQUATION_COMPILE_ERROR 
		|| nErr == FFW_EQUATION_TOO_MANY_INDEPS  //as to Max's suggestion, when too many indeps, no need to do evaluate since it might be slow.
		|| nErr == FFW_EQUATION_EMPTY_FORMULA
		|| nErr == FFW_EQUATION_EMPTY_DLL)///Jasmine 08/02/10 ORG-591-P7 DETECH_EXTERNAL_DLL_SOURCE
	///end IMPROVE_ERR_MSG_FOR_QUICK_CHECK
	{
		m_controlDependVar.Text = strErrMsg;
		return false;
	}
	vector 	vIndepValue, vParamValue;
	int 	nIndepNum = getIndepVarsVal(vIndepValue);
	int 	nParamNum = m_FFWParamGrid.GetParamsVals(vParamValue);
	int nDepNum = nlf_get_dependent_variables(trFunction);
	
	matrix mIndVars, mDepVars;
	mIndVars.SetSize(1, nIndepNum);
	mDepVars.SetSize(1, nDepNum);
	if(mIndVars.SetRow(vIndepValue, 0) != 0)
		ASSERT(0);
	
	NumericFunction	nf(m_pHolder->m_trFunction);
	///------ Folger 08/16/10 ORG-756-P1-P2 BETTER_ERROR_CHECKING_FOR_FITTING_FUNCTION_LT_EVALUATION
	//bool bRet = nf.Evaluate(vParamValue, 1, mDepVars, mIndVars);
	bool bRet = nf.Evaluate(vParamValue, 1, mDepVars, mIndVars, NLSFEVALUATE_CHECK_LT_VARS_FULLY_USED);
	///------ End BETTER_ERROR_CHECKING_FOR_FITTING_FUNCTION_LT_EVALUATION

	vector vDepValue;
	if( mDepVars.GetAsVector(vDepValue) )
	{
		///Sophy 7/14/2010 ORG-518-P10 SHOW_ERROR_MSG_WHEN_EVALUATE_INVALID_EQUATION
		if ( strErrMsg.IsEmpty() )
		{
			///Sophy 8/10/2010 ORG-745-P3 IMPROVE_ERR_MSG_IN_LABTALK_FUNCTION_TYPE
//#define	MAX_ERR_MSG_LENGTH	256
			//LPSTR lpBuff = strErrMsg.GetBuffer(MAX_ERR_MSG_LENGTH);
			//LT_get_last_err(lpBuff, MAX_ERR_MSG_LENGTH);
			//strErrMsg.ReleaseBuffer();
			//if ( !strErrMsg.IsEmpty() )
				//strErrMsg = "(" + strErrMsg + ")";
			m_pFuncBody->RuntimeCheck(strErrMsg);
			///end IMPROVE_ERR_MSG_IN_LABTALK_FUNCTION_TYPE
		}
		///end SHOW_ERROR_MSG_WHEN_EVALUATE_INVALID_EQUATION
		string strDepVal = FuncOrganizer().CombineDependVarsWithValue(vDepValue, trFunction, ',');
		///Sophy 7/8/2010 ORG-518-P2 IMPROVE_ERR_MSG_FOR_QUICK_CHECK
		//m_controlDependVar.Text = strDepVal;
		string strResult;
		strResult.Format("%s %s", strDepVal, strErrMsg);
		m_controlDependVar.Text = strResult;
		///end IMPROVE_ERR_MSG_FOR_QUICK_CHECK
	}
	
	return true;
}

int	FFWFitFuncBodyPage::getIndepVarsVal(vector& vv)
{
	int				nIndep = nlf_get_independent_variables(m_pHolder->m_trFunction);
	vv.SetSize(nIndep);
	///Sophy 7/8/2010 ORG-518-P8 LIMIT_NUM_INDEPS_TO_3_ON_QUICK_CHECK
	//vector<uint>	vIDs = {IDC_FIT_FUNC_INDEPEND_VAR_VALUE1, IDC_FIT_FUNC_INDEPEND_VAR_VALUE2, IDC_FIT_FUNC_INDEPEND_VAR_VALUE3, IDC_FIT_FUNC_INDEPEND_VAR_VALUE4};
	vector<uint>	vIDs = {IDC_FIT_FUNC_INDEPEND_VAR_VALUE1, IDC_FIT_FUNC_INDEPEND_VAR_VALUE2, IDC_FIT_FUNC_INDEPEND_VAR_VALUE3};
	///end LIMIT_NUM_INDEPS_TO_3_ON_QUICK_CHECK
	Control			ctrl;
	for ( int ii = 0; ii < nIndep && ii < vIDs.GetSize(); ii++ )
	{
		ctrl = GetItem(vIDs[ii]);
		vv[ii] = atof(ctrl.Text);
	}
	return nIndep;
}

//virtual
BOOL FFWFitFuncBodyPage::OnNext()
{
	string strErrMsg;
	int nErr = CheckEquation(strErrMsg);
	if ( nErr == FFW_EQUATION_INVALID_CONTANT || nErr == FFW_EQUATION_COMPILE_ERROR || nErr == FFW_EQUATION_PEAK_ATTRIB_ERROR || nErr == FFW_EQUATION_EMPTY_FORMULA
		|| nErr == FFW_EQUATION_EMPTY_DLL)///Jasmine 08/02/10 ORG-591-P7 DETECH_EXTERNAL_DLL_SOURCE
	{
		MessageBox(strErrMsg, STR_ERROR, MB_OK);
		return FALSE;
	}
	return FFWPageBase::OnNext();
}

int FFWFitFuncBodyPage::CheckEquation(string& strErrMsg)
{
	///Jasminie 07/30/10 ORG-591-P7 PRECOMPILE_FILE_MAKE_COMPILE_CHECKING_FAIL
	TreeNode trFunction = m_pHolder->m_trFunction;
	///Sophy 7/20/2010 ORG-591-P6 WRONG_EVALUE_RESULT_DUE_TO_OLD_PRECOMPILE_FILES
	string strFunctionName, strFileName;
	nlf_get_func_names(trFunction, strFunctionName, strFileName);
	nlf_delete_precompile_files(strFunctionName);
	///end WRONG_EVALUE_RESULT_DUE_TO_OLD_PRECOMPILE_FILES
	///End PRECOMPILE_FILE_MAKE_COMPILE_CHECKING_FAIL
	
	int ii, nSize;
	//constant checking
	vector<string> vsVariables, vsValues;
	m_gridConstant.GetColValues(CONSTANT_VARIABLE_COLUMN, vsVariables);
	m_gridConstant.GetColValues(CONSTANT_VALUE_COLUMN, vsValues);
	nSize = vsVariables.GetSize();
	for ( ii = m_gridConstant.GetRowOffset(); ii < nSize; ii++ )
	{
		TRIM_STR(vsValues[ii])
		if ( is_missing_value(atof(vsValues[ii])) )
		{
			strErrMsg.Format(_L("(%s = %s invalid)"), vsVariables[ii], vsValues[ii].IsEmpty() ? _L("<empty>") : vsValues[ii]);
			return FFW_EQUATION_INVALID_CONTANT;
		}
	}
	
	///Sophy 7/8/2010 ORG-518-P2 IMPROVE_ERR_MSG_FOR_QUICK_CHECK
	//check function body
	string strFormula;
	EditTextToString(m_editEquation, strFormula);
	ocu_skip_C_comments(&strFormula);
	TRIM_STR(strFormula)
	if ( strFormula.IsEmpty() )
	{
		if( m_pFuncBody->IsFormulaEssential() )///Jasmine 08/10/10 ORG-745-P4 ALLOW_EXTERNAL_DLL_HAS_EMPTY_ANNOTATION
		{
			strErrMsg = _L("Function body is empty");
			return FFW_EQUATION_EMPTY_FORMULA;
		}
	}
	///end IMPROVE_ERR_MSG_FOR_QUICK_CHECK
	
	//compile function
	///Sophy 7/12/2010 ORG-518-P2 IMPROVE_ERR_MSG_FOR_QUICK_CHECK
	//NumericFunction nf(m_pHolder->m_trFunction);
	//if ( !nf.CheckCompileOC() )
	//{
		/////Sophy 7/8/2010 ORG-518-P7 IMPROVE_OC_COMPILE_ERR_MSG_ON_QUICK_CHECK
		////ocu_load_msg_str(NLSF_ERR_COMPILE_NUMERIC_FUNCTION, &strErrMsg);
		//strErrMsg = _L("Compile error. Click Open Code Builder button for details");
		/////end IMPROVE_OC_COMPILE_ERR_MSG_ON_QUICK_CHECK
		//return FFW_EQUATION_COMPILE_ERROR;
	//}
	int nErrCode = FFW_EQUATION_OK;
	if ( (nErrCode = m_pFuncBody->Compile(strErrMsg)) != FFW_EQUATION_OK )
	{
		return nErrCode;
	}
	///end IMPROVE_ERR_MSG_FOR_QUICK_CHECK
	
	//check peak attribs
	if ( FuncOrganizer().IsPeak(m_pHolder->m_trFunction) )
	{
		vector<string> vsVals;
		m_FFWParamGrid.GetColValues(NLPARAMGRIDCOLTYPE_PEAK_ATTRIBUTE, vsVals, m_FFWParamGrid.GetRowOffset());
#define	MIN_PEAK_FUNCTION_PARAMS	4
		if ( vsVals.GetSize() < MIN_PEAK_FUNCTION_PARAMS ||
			 vsVals[0].CompareNoCase(STR_OFFSET_PEAK_INFO) != 0 ||
			 vsVals.Find(STR_X_CENTER_PEAK_INFO) < 0 ||
			 vsVals.Find(STR_X_WIDTH_PEAK_INFO) < 0 ||
			 vsVals.Find(STR_AMPLITUDE_PEAK_INFO) < 0 )
		{
			ocu_load_err_msg_str(MSG_FFW_PEAK_FUNCTION, &strErrMsg);///Jasmine 07/14/10 ORG-540-P3
			return FFW_EQUATION_PEAK_ATTRIB_ERROR;
		}
	}
	
	//parameter checking
	vector<string> vsParamNames, vsParamValues;
	m_FFWParamGrid.GetColValues(NLPARAMGRIDCOLTYPE_NAME, vsParamNames);
	m_FFWParamGrid.GetColValues(NLPARAMGRIDCOLTYPE_VALUE, vsParamValues);
	nSize = vsParamNames.GetSize();
	for ( ii = m_gridConstant.GetRowOffset(); ii < nSize; ii++ )
	{
		if ( is_missing_value(atof(vsParamValues[ii])) )
		{
			strErrMsg.Format(_L("(%s = %s invalid)"), vsParamNames[ii], vsParamValues[ii].IsEmpty() ? _L("<empty>") : vsParamValues[ii]);
			return FFW_EQUATION_INVALID_PARAMS;
		}
	}
	
	//check independents
	vector	vIndepValue;
	vector<string> vsIndepVars;
	int 	nIndepNum = getIndepVarsVal(vIndepValue);
	nlf_get_independent_variables(m_pHolder->m_trFunction, &vsIndepVars);
	for ( ii = 0; ii < nIndepNum; ii++ )
	{
		if ( is_missing_value(vIndepValue[ii]) )
		{
			strErrMsg.Format(_L("(%s = %s invalid)"), vsIndepVars[ii], ftoa(vIndepValue[ii]));
			return FFW_EQUATION_INVALID_INDEPS;
		}
	}
	
	///Sophy 7/7/2010 ORG-432-S14 WARNING_MSG_WHEN_EVALUATE_WITH_TOO_MANY_INDEPS
	const int nMaxIndeps = 3;
	if ( nIndepNum > nMaxIndeps )
	{
		//strErrMsg = _L("(Cannot evaluate function with more than 3 independent variables)");
		ocu_load_err_msg_str(FFWERR_INVALID_FUNCTION_INDEPS_NUMBER, &strErrMsg);
		return FFW_EQUATION_TOO_MANY_INDEPS;
	}
	///end WARNING_MSG_WHEN_EVALUATE_WITH_TOO_MANY_INDEPS
	return FFW_EQUATION_OK;
}

void	FFWFitFuncBodyPage::HideAllFuncBodyControls()
{
	vector<int>		vnIDs = { IDC_FIT_FUNC_EQUATION_LEFT_TEXT
		, IDC_FIT_FUNC_DERIVATIVES_CHECK
		, IDC_FIT_FUNC_OPEN_CODE_BUILDER
		, IDC_FIT_FUNC_DLL_FILE_EDIT_TEXT
		, IDC_FIT_FUNC_DLL_FILE_EDIT
		, IDC_FIT_FUNC_DLL_FUNC_EDIT_TEXT
		, IDC_FIT_FUNC_DLL_FUNC_EDIT
	};

	for ( int ii=0; ii<vnIDs.GetSize(); ++ii )
		GetItem(vnIDs[ii]).Visible = FALSE;
}

void	FFWFitFuncBodyPage::UpdateTitle()
{
	vector<string>	vs;
	int		nTokens = str_separate(m_wndParent.Text, STR_DIALOG_TITLE_SEPARATOR, vs);
	if ( nTokens != 2 )
		return;
	vs[1] = m_pFuncBody->GetTitle();
	m_wndParent.Text = str_combine(vs, STR_DIALOG_TITLE_SEPARATOR);
}

void	FFWFitFuncBodyPage::UpdateControls()
{
	HideAllFuncBodyControls();	
	m_pFuncBody->UpdateControls();
}

void	FFWFitFuncBodyPage::OnOpenCodeBuilder(Control ctrl)
{
	m_pFuncBody->OpenCodeBuilder(m_wndParent);
}

/// Bill 07/08/2010 ORG-478-P4 CONTENT_MISS_AFTER_RETURN_DIALOG
void	FFWFitFuncBodyPage::OnContentChange()
{
	m_pFuncBody->OnContentChange();
}
/// End CONTENT_MISS_AFTER_RETURN_DIALOG

void	FFWFitFuncBodyPage::OnDerivativesCheck(Control ctrl)
{
	m_pFuncBody->DerivativesCheck();
	
	checkEnableFinishBtn();///Jasmine 08/02/10 ORG-591-P7 FINSH_EVENT_IS_TOO_LATE_SO_DISABLE_ONCE_FIND_ERROR
}
///------ End CENTRALIZE_FUNCTION_BODY_PAGE_RESOURCES

#endif//_FFW_FUNC_BODY_PAGE_H
