#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
#include <GetNBox.h>
#include <Operation.h>
#include <ReportTree.h>
#include <report_utils.h>
#include <event_utils.h>
#include <..\Originlab\wksOperation.h>
#ifdef	_FOR_SMART_LOADING_ONLY
#include  <..\originlab\nlsf_utils.h>
#endif //_FOR_SMART_LOADING_ONLY

/*------------------------------------------------------------------------------*
 * Modification Log:															*
 * Iris 01/16/2007 IMPLEMENT_SSR_DF_ON_COMBINED_DATA							*
 * Echo 07/11/30 QA70-10589-P3 v8.0757	FITCMP_SUPPORT_POLY_ORDER				*
 * Echo 08/1/22 QA70-10975 v8.0790 FITCMP_RUNTIME_ERROR							*
 * Iris 12/25/2009 QA81-14890-S3 SET_TABLE_DEFAULT_CLOSE						*
 * Folger 05/07/10 QA81-15382 YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA		*
 * Folger 10/08/2010 ORG-1225-P1 RUNTIME_ERROR_WHEN_FIT_COMPARE_DATA_FROM_MATRIX_SOURCE
 * Folger 10/09/2010 ORG-1225-P2 FIT_COMPARE_DATASET_RUNTIME_ERROR_FOR_INPUT_WITHOUT_X_RANGE
 * Folger 10/19/2010 ORG-1283-P1 LINEARFIT_FAILED_TO_GET_FTEST_RESULT_IF_NO_WEIGHT
 *------------------------------------------------------------------------------*/

///------ Folger 05/07/10 QA81-15382 YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
//static bool _get_all_xy_data(TreeNode& trGUI, vector& vX, vector& vY)
static bool _get_all_xy_data(TreeNode& trGUI, vector& vX, vector& vY, vector& vYErr)
{
	TreeNode 	trInput = trGUI.InputData;
	
	DataRange 	dr;
	dr.Create();
	dr.SetTree(trInput);
	
	DWORD 	dwRules = DRR_GET_DEPENDENT | DRR_NO_FACTORS;
	int		nNumData = dr.GetNumData(dwRules);
	if(nNumData <= 0)
		return false;
	
	vX.SetSize(0);
	vY.SetSize(0);
	///------ Folger 05/07/10 QA81-15382 YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
	vYErr.SetSize(0);
	///------ End YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
	
	for( int ii = 0; ii < nNumData; ii++)
	{
		///------ Folger 05/07/10 QA81-15382 YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
		//DWORD 	dwPlotID;
		//vector 	vTempX, vTempY;
		//dr.GetData( dwRules, ii, &dwPlotID, NULL, &vTempY, &vTempX);
		//vX.Append(vTempX);
		//vY.Append(vTempY);
		
		DataRange	drSub;
		drSub.Create();
		if ( !dr.GetSubRange(drSub, dwRules, ii) )
		{
			ASSERT(FALSE);
			continue;
		}

		string		strName;
		Datasheet	ds;
		int			nR1, nC1, nR2, nC2;
		///------ Folger 10/09/2010 ORG-1225-P2 FIT_COMPARE_DATASET_RUNTIME_ERROR_FOR_INPUT_WITHOUT_X_RANGE
		//int			nYErrIndex = 2;
		//if ( drSub.GetRange(nYErrIndex, nR1, nC1, nR2, nC2, ds, &strName) && strName.CompareNoCase("W") == 0 )
		//{
			//drSub.SetRange(nYErrIndex, ds, nR1, nC1, nR2, nC2, "ED");
		//}
		int			nIndex = drSub.GetRange("W", nR1, nC1, nR2, nC2, ds);
		if ( nIndex >= 0 )
		{
			drSub.SetRange(nIndex, ds, nR1, nC1, nR2, nC2, "ED");
		}
		///------ End FIT_COMPARE_DATASET_RUNTIME_ERROR_FOR_INPUT_WITHOUT_X_RANGE
		
		vector 	vTempX, vTempY, vTempYErr;
		XYRange	xy(drSub);
		xy.GetData(vTempY, vTempX, &vTempYErr, ii, dwRules);
		
		vX.Append(vTempX);
		vY.Append(vTempY);
		vYErr.Append(vTempYErr);
		///------ End YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
	}
	return true;
}

static bool _get_create_combined_data_range(TreeNode& trGUI1, const TreeNode& trGUI2, Worksheet& wks, XYRange& drCombinedData)
{
	vector 	vX1, vY1, vX2, vY2;
	///------ Folger 05/07/10 QA81-15382 YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
	//if( !_get_all_xy_data(trGUI1, vX1, vY1) || !_get_all_xy_data(trGUI2, vX2, vY2) )
	vector 	vYErr1, vYErr2;
	if( !_get_all_xy_data(trGUI1, vX1, vY1, vYErr1) || !_get_all_xy_data(trGUI2, vX2, vY2, vYErr2) )
	///------ End YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
		return false;
	
	vector 	vX, vY;
	///------ Folger 05/07/10 QA81-15382 YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
	vector	vYErr;
	///------ End YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
	vX.Append(vX1);
	vX.Append(vX2);
	vY.Append(vY1);
	vY.Append(vY2);
	///------ Folger 05/07/10 QA81-15382 YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
	vYErr.Append(vYErr1);
	vYErr.Append(vYErr2);
	///------ End YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
	if(vX.GetSize() != vY.GetSize())
		return false;
	
	/*
	uint	nSize = vY.GetSize();
	if( OE_NOERROR != ocmath_xy_remove_duplicates(&nSize, vX, vY) )
		return false;
	*/
	
	///------ Folger 05/07/10 QA81-15382 YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
	//wks.SetSize(-1, 2);
	wks.SetSize(-1, 3);
	///------ End YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
	drCombinedData.Add(wks, 0, "X");
	drCombinedData.Add(wks, 1, "Y");
	///------ Folger 05/07/10 QA81-15382 YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
	//drCombinedData.SetData(&vY, &vX);
	///------ Folger 10/19/2010 ORG-1283-P1 LINEARFIT_FAILED_TO_GET_FTEST_RESULT_IF_NO_WEIGHT
	if ( vYErr.GetSize() > 0 )
	///------ End LINEARFIT_FAILED_TO_GET_FTEST_RESULT_IF_NO_WEIGHT
		drCombinedData.Add(wks, 2, "ED");
	drCombinedData.SetData(&vY, &vX, 0, &vYErr);
	///------ End YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
	return true;	
}
///end IMPLEMENT_SSR_DF_ON_COMBINED_DATA

///------ Folger 05/07/10 QA81-15382 YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
static	TreeNode	_prepare_input_data(TreeNode& trGUI, XYRange& xy)
{
	///------ Folger 10/08/2010 ORG-1225-P1 RUNTIME_ERROR_WHEN_FIT_COMPARE_DATA_FROM_MATRIX_SOURCE
	if ( !xy )
	{
		TreeNode	trJunk;
		return trJunk;
	}
	///------ End RUNTIME_ERROR_WHEN_FIT_COMPARE_DATA_FROM_MATRIX_SOURCE
	
	TreeNode	trInputData = trGUI.InputData.Clone();
	
	TreeNode	trRange1 = trInputData.Range1;
	if ( trRange1 )
	{
		Tree	tr;
		xy.GetTree(tr);
		///------ Folger 10/19/2010 ORG-1283-P1 LINEARFIT_FAILED_TO_GET_FTEST_RESULT_IF_NO_WEIGHT
		//for ( int ii=0; ii<trRange1.Children.Count(); ++ii )
		int		nTRCount = tr.Children.Count();
		for ( int ii=0; ii<nTRCount && ii<trRange1.Children.Count(); ++ii )
		///------ End LINEARFIT_FAILED_TO_GET_FTEST_RESULT_IF_NO_WEIGHT
		{
			trRange1.Children.Item(ii).strVal = tr.Children.Item(ii).strVal;
		}
	}
	else
	{
		ASSERT(FALSE);
	}
	return trInputData;
}
///------ End YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA

static void _get_aic(vector& vAIC, const double dSSR, const double DF, const double dN)
{
	vAIC.SetSize(5);
	vAIC[0] = dSSR;
	vAIC[1] = dN;
	vAIC[2] = dN - DF;//number of parameters
	vAIC[3] = ocmath_AIC(vAIC[1], vAIC[2], vAIC[0], NULL);
}

static void _fitcmp_update_result_sheet(TreeNode& trRes, TreeNode trGUI)
{
	if (!fitcmp_check_stats(trRes))
	{
		XYRange 	dr;
		dr.Create();
		dr.SetTree(trGUI.InputData);
		string		strClass;
		trRes.GetAttribute(STR_ANALYSIS_ATTRIB, strClass);
		if ( lstrcmp(strClass, "FitPolynomial") || lstrcmp(strClass, "FitLinear") )
			strClass = "FitNL";
		string		strModel;
		if(trRes.Notes.Model)
			strModel = trRes.Notes.Model.strVal;
		
		///Echo 08/1/22 QA70-10975 v8.0790 FITCMP_RUNTIME_ERROR
		int nOrder = (trGUI.Order) ? trGUI.Order.nVal : 2;
		op_fit_on_data(strClass, dr, trRes, strModel, NULL, nOrder);
		/*
		///Echo 07/11/30 QA70-10589 P3 v8.0757	FITCMP_SUPPORT_POLY_ORDER
		//op_fit_on_data(strClass, dr, trRes, strModel);
		op_fit_on_data(strClass, dr, trRes, strModel, NULL, trGUI.Order.nVal);
		///end FITCMP_SUPPORT_POLY_ORDER		
		*/
		///end FITCMP_RUNTIME_ERROR		
	}
	
}
static void _fitcmp_data_update_report_tree(ReportTree& rtRootTable,
										TreeNode& trRes1, TreeNode& trRes2, 
										TreeNode& trGUI1, TreeNode&trGUI2,
										string strReport1, string strReport2, //string strFunction, 
										bool bFitParams, bool bFitStats,
										vector<string>& vstrFitReport)
{
	//////////////////////////////////////////////////////////////////
	// 	To get essential stats value
	//////////////////////////////////////////////////////////////////
	_fitcmp_update_result_sheet(trRes1, trGUI1);
	_fitcmp_update_result_sheet(trRes2, trGUI2);
	
	double dSSR1, dSSR2, DF1, DF2, dN1, dN2;
	fitcmp_get_stats_value(trRes1, trRes2, &dSSR1, &dSSR2, &DF1, &DF2, &dN1, &dN2);
	
	//////////////////////////////////////////////////////////////////
	// 	Notes
	//////////////////////////////////////////////////////////////////
	
	report_tree_create(rtRootTable, _L("Fit Comparison of Data"));
	///Iris 12/25/2009 QA81-14890-S3 SET_TABLE_DEFAULT_CLOSE
	if( rtRootTable.Notes )
		set_table_open(rtRootTable.Notes, false);
	///End SET_TABLE_DEFAULT_CLOSE

	//////////////////////////////////////////////////////////////////
	// Description
	//////////////////////////////////////////////////////////////////
	fitcmp_add_descrp(rtRootTable, trRes1, trRes2, trGUI1, trGUI2, true, vstrFitReport);

	
	//////////////////////////////////////////////////////////////////
	// F-test
	//////////////////////////////////////////////////////////////////
	
	dSSR2 += dSSR1;
	DF2 += DF1;
	
	//--- Iris 01/16/2007 IMPLEMENT_SSR_DF_ON_COMBINED_DATA
	WorksheetPage	wksPage;
	wksPage.Create("origin", CREATE_HIDDEN);
	Worksheet		wks = wksPage.Layers();

	XYRange	drCombined;
	_get_create_combined_data_range(trGUI1, trGUI2, wks, drCombined);
	
	string		strClass;
	trRes1.GetAttribute(STR_ANALYSIS_ATTRIB, strClass);
	///Arvin 07/18/07 v8.0662 FIT_COMPARISION_OF_DATASETS_INCONSISTENT_BETWEEN_NLFIT_AND_LR
	//if ( lstrcmp(strClass, "FitPolynomial") || lstrcmp(strClass, "FitLinear") )
	//	strClass = "FitNL";
	///end FIT_COMPARISION_OF_DATASETS_INCONSISTENT_BETWEEN_NLFIT_AND_LR
	
	string		strModel;
	if(trRes1.Notes.Model)
		strModel = trRes1.Notes.Model.strVal;
	
	Tree		trStatsResult;	
	///Echo 07/11/30 QA70-10589 P3 v8.0757	FITCMP_SUPPORT_POLY_ORDER
	//if( op_fit_on_data(strClass, drCombined, trStatsResult, strModel) )
	int nOrder = 2;
	if (trGUI1.Order) 
		nOrder = trGUI1.Order.nVal;
	///------ Folger 05/07/10 QA81-15382 YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
	//if( op_fit_on_data(strClass, drCombined, trStatsResult, strModel, NULL, nOrder) )
	if( op_fit_on_data(strClass, drCombined, trStatsResult, strModel, NULL, nOrder, _prepare_input_data(trGUI1, drCombined)) )
	///------ End YERR_SHOULD_BE_COUNTED_IN_FIT_COMPARE_DATA
	///end 	FITCMP_SUPPORT_POLY_ORDER
	{			
		TreeNode tr = tree_get_node_by_tagname(trStatsResult, "RegStats", true);
		tr = tr.C1;
		if (tr.SSR)	dSSR1 = tr.SSR.dVal;
		if (tr.DOF)	DF1 = tr.DOF.dVal;
	}
	
	wksPage.Destroy();
	//end IMPLEMENT_SSR_DF_ON_COMBINED_DATA
		
	fitcmp_add_ftest(rtRootTable, dSSR1, dSSR2, DF1, DF2, true);
	
	
	//////////////////////////////////////////////////////////////////
	// Fit Parameters
	//////////////////////////////////////////////////////////////////
	if (bFitParams)
	{
		fitcmp_add_fit_params(rtRootTable, trRes1, trRes2, true);

	}
	//////////////////////////////////////////////////////////////////
	// Fit Statistics
	//////////////////////////////////////////////////////////////////
	if (bFitStats)
	{
		fitcmp_add_fit_stats(rtRootTable, trRes1, trRes2, true);
	}
}


void fitcmpdata(const Range& result1, const Range& result2, const int& param, const int& statics, ReportTree& rt)
{
	
	vector<string> vsReportTree;
	Tree		tr;
	TreeNode	trRes1 = tr.AddNode("Res1");
	TreeNode	trRes2 = tr.AddNode("Res2");
	Tree	trGUI1, trGUI2;
	if (!fitcmp_get_rt(result1, trRes1, trGUI1) || !fitcmp_get_rt(result2, trRes2, trGUI2))
		XF_THROW(CER_FITCMP_MODEL_INVALID_RT);
	
	vector<string> vstrFitReport(2);
	result1.GetRangeString(vstrFitReport[0]);
	result2.GetRangeString(vstrFitReport[1]);
	_fitcmp_data_update_report_tree(rt, trRes1, trRes2, trGUI1, trGUI2, vsReportTree[0], vsReportTree[1], param, statics, vstrFitReport);
	
}

//nEventID < 0 on event, like GETNE_ON_INIT, GETNE_ON_OK etc, >0 on change from control
//return 0 to do nothing, return PEVENT_GETN_RET_TO_CLOSE to close dialog
//dwEnables = bOKEnable, bBTN1Enable, bBTN2Enable, bBTN3Enable, , can set to false to disable OK/Apply buttons
//lpcszNodeName = the trGetN TreeNode tag name that generates the event, or is  if GETNE_ON_OK etc
//strAux = optional string for XF Wizard Bar, like DLG_NEED_CHANGE_GRID etc, it will be invalid if from internal node value change event
//strErrMsg = allowing messages to be shown
int fitcmpdata_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return fitcmpdata_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	int nErr = fitcmp_event(trGetN, true);
	if(nErr != CER_NO_ERROR)
	{
		bOKEnable = false;
		strErrMsg = nErr;
	}
	
	return true;
	

}

int fitcmpdata_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	return false;
}
//nGetNDialog = 0,1,2, corresponding to the XF GetN dropdown, 0 = dialog is not used
//you can change nRet to be one of XFEVT_PROCEED (defualt), XFEVT_ABORT, XFEVT_PROCEED_NO_DLG or XFEVT_PROCEED_WITH_DLG(when nGetNDialog = 0)
//nGetNDialog = -1 when Ok on GetN dialog to allow handler to preocess <auto> etc variables
//dwCntrl is combination of bits
//LTXF_FROM_GUI_MENU, LTXF_FROM_GUI_PROMPT, LTXF_FROM_AUTO_UPDATE, LTXF_FROM_FUNCTION, LTXF_THEME_USED, LTXF_CHANGE_PARAM
void fitcmpdata_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{

}
//nEventID < 0 on event, like GETNE_ON_INIT, GETNE_ON_OK etc, >0 on change from control
//return 0 to do nothing, return PEVENT_GETN_RET_TO_CLOSE to close dialog
//dwEnables = bOKEnable, bBTN1Enable, bBTN2Enable, bBTN3Enable, , can set to false to disable OK/Apply buttons
//lpcszNodeName = the trGetN TreeNode tag name that generates the event, or is  if GETNE_ON_OK etc
//strAux = optional string for XF Wizard Bar, like DLG_NEED_CHANGE_GRID etc, it will be invalid if from internal node value change event
//strErrMsg = allowing messages to be shown
int fitcmpdata_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
