#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
//put additional include files here
#include <stats_utils.h>
#include <..\originlab\nlsf_utils.h> 
#include <..\originlab\grobj_utils.h>
#include <..\originlab\GraphObjTools.h>
#include <..\originlab\graph_utils.h> // to compile source file for the access of getting layer pos in QuickFit.c
#include <..\originlab\QuickFit.h>

/*------------------------------------------------------------------------------*
 * Modification Log:															*
 *	Folger 01/12/09 QA81-14832 ADD_OPTION_TO_GENERATE_NEW_FIT_CURVE_FOR_EACH_OUTPUT
 *  Iris 1/29/2010 FIX_LEGEND_UPDATE_PROBLEM									*
 *	Sophy 3/3/2010 WRONG_LENGEND_DUE_TO_XYRANGE_SETOUTPUTCOMMENT_DELAY			*
 *------------------------------------------------------------------------------*/

//put your own support static functions here

///Sophy 4/13/2010 QA81-15308 GET_GRAPHLAYER_OF_INPUTDATA_IN_XF_BODY
//static bool _get_input_graph_layer(const DataRange& iy, GraphLayer& gl, int* pnPlotUID = NULL)
//{
	//vector<uint> vn;
	//iy.GetPlots(vn);
	//
	//DataPlot dp;
	//int nPlotUID;
	//if(vn.GetSize() > 0)
	//{
		//nPlotUID = vn[0];
		//dp = Project.GetObject(nPlotUID);
	//}
	//if(!dp)
	//{
		//return false;		
	//}	
	//dp.GetParent(gl);
	//if( pnPlotUID )
		//*pnPlotUID = nPlotUID;
	//return true;
//}
///end GET_GRAPHLAYER_OF_INPUTDATA_IN_XF_BODY

static	void	_set_output_range_comments(XYRange &oy, const XYRange& iy, LPCSTR lpcszFunc, int nOrder)
{
	//--- Iris 1/23/2010 remove "Quick Fit" from output sheet comments label
	//string str = "%s Quick Fit of %s";
	//------- Iris 2/23/2010 to fix missed 'Fit' in LR fit legend
	/*
	string str;
	if( nOrder > 0 )
		str = "%s of %s";
	else
		str = "%s Fit of %s";
	*/
	string str = "%s Fit of %s";
	//-------
	//---
	string strComments;
	if(nOrder == 0)
	{
		strComments.Format(str, lpcszFunc, get_input_data_range_string(iy));
	}
	else
	{
		/// Iris 1/21/2010 USE_NTH_ORDER_REPLACE_REAL_NAME_FOR_LR
		/*
		string strFunc = "";
		switch(nOrder)
		{
		case 1:
			strFunc = _L("Linear");
			break;
		case 2:
			strFunc = _L("Quadratic");
			break;
		case 3:
			strFunc = _L("Cubic");
			break;
		default:
			ASSERT(false);
		}
		*/
		string strFunc = quick_fit_get_lr_function_name(nOrder, true);
		///End USE_NTH_ORDER_REPLACE_REAL_NAME_FOR_LR
		strComments.Format(str, strFunc, get_input_data_range_string(iy));
	}

	if(oy != NULL && oy.IsValid())
	{
		///Sophy 3/3/2010 WRONG_LENGEND_DUE_TO_XYRANGE_SETOUTPUTCOMMENT_DELAY in VC level, XYRange will update Column comments field when XF return, but here we need to set Comments in real-time
		//oy.SetOutputComment(strComments);
		Column colY;
		if ( oy.GetYColumn(colY) )
			colY.SetComments(strComments);
		///end WRONG_LENGEND_DUE_TO_XYRANGE_SETOUTPUTCOMMENT_DELAY
	}
}



void quickfit(const XYRange& iy, const string& func, const int& order, const int& roi, XYRange& oy, const int& color, const int& replace)
{
	/// Iris 12/15/09 QA81-14832 QUICK_NLSF_FITTING_TABLE
	GraphLayer gl;
	int nInputPlotUID;
	///Sophy 4/13/2010 QA81-15308 GET_GRAPHLAYER_OF_INPUTDATA_IN_XF_BODY
	//if( !_get_input_graph_layer(iy, gl, &nInputPlotUID) )
	if ( !get_graphlayer_from_input(iy, gl, &nInputPlotUID) )
	///end GET_GRAPHLAYER_OF_INPUTDATA_IN_XF_BODY
	{		
		XF_THROW(CER_INVALID_RANGE);
	}
	///End QUICK_NLSF_FITTING_TABLE
	
	QuickFitResults		stFitResults;
	DWORD dwCntrl = roi ? NLSF_QUICKFIT_ROI_RESULT : 0;
	vector 				vFitX, vFitY;
	int	nRet = nlsf_quick_fit(gl, stFitResults, vFitX, vFitY, func, order, iy, dwCntrl);	
	if ( NLSF_QUICKFIT_ERROR_NONE != nRet )
	{
		string strErr;
		if( ocu_load_msg_str(nRet, &strErr) )
		{
			XF_THROW(strErr);
		}
	}
	
	// output fit curve data and plot on source graph
	oy.SetData(&vFitY, &vFitX);
	_set_output_range_comments(oy, iy, func, order);
	//------Iris 12/24/2009 USE_GET_SET_RELATED_DATASET
	/*
	DataPlot dpResult;
	xf_check_plot_output_rng_in_source_rng_graph(iy, oy, &dpResult);
	
	if( !dpResult ) // return invalid data plot if already plotted
	{
		vector<uint> vnPlots;
		oy.GetPlots(vnPlots);
		if( vnPlots.GetSize() > 0 )
			dpResult = (DataPlot)Project.GetObject(vnPlots[0]);
	}	
	*/
	//stFitResults.nLastSourcePlotUID = nInputPlotUID;
	/// Iris 1/29/2010 SET_QUICK_FIT_CURVE_COLOR
	//xf_check_plot_output_rng_in_source_rng_graph(iy, oy);
	/// Iris 2/04/2010 FIX_QUICK_FIT_OUTPUT_PLOT_NOT_UPDATE_COLOR_IF_HAS_PLOTTED
	//xf_check_plot_output_rng_in_source_rng_graph(iy, oy, NULL, IDM_PLOT_LINE, color);
	DataPlot dp;
	xf_check_plot_output_rng_in_source_rng_graph(iy, oy, &dp, IDM_PLOT_LINE, color);	
	if( dp )
		dp.SetColor(color);
	///End FIX_QUICK_FIT_OUTPUT_PLOT_NOT_UPDATE_COLOR_IF_HAS_PLOTTED
	///End SET_QUICK_FIT_CURVE_COLOR
	//------USE_GET_SET_RELATED_DATASET
	
	/// Iris 1/29/2010 FIX_LEGEND_UPDATE_PROBLEM
	//legend_update(gl);
	legend_update(gl, -1, false, false);
	///End FIX_LEGEND_UPDATE_PROBLEM
	Page pg = gl.GetPage();
	pg.Refresh(true);
	
	// save input & output range to page storage
	//------Iris 12/24/2009 USE_GET_SET_RELATED_DATASET
	/*
	int nOutputPlotUID = 0;
	if( dpResult )
	{
		nOutputPlotUID = dpResult.GetUID(true);
	}
	okutil_quick_fit_set_io_range_UID(gl.GetUID(true), nInputPlotUID, nOutputPlotUID);
	*/
	// clear the related dataset for all data plot
	//int nCount = 0;
	//----Iris 12/29/2009 allow do separate quick fit on multiple data plots in one layer.
	/*
	foreach(DataPlot dp in gl.DataPlots)
	{
		//DatasetObject dsTemp;
		//if( dp.GetRelatedDataset(STR_QUICK_FIT_RELATED_DATASET, dsTemp) && dsTemp )
		{
			dp.RemoveRelatedDataset(STR_QUICK_FIT_RELATED_DATASET);
			//nCount++;
		}
	}
	*/
	//----
	//ASSERT(0 == nCount || 1 == nCount); // if even do quick fit on this graph layer, then should only eixst one fit result.
	
	// set fit plot as related dataset on source plot
	DataPlot dpIn;
	dpIn = (DataPlot)Project.GetObject(nInputPlotUID);
	ASSERT(dpIn);	
	
	Column colFitY;
	oy.GetYColumn(colFitY);
	DatasetObject dsFit(colFitY);
	dpIn.SetRelatedDataset(STR_QUICK_FIT_RELATED_DATASET, dsFit);
	//------USE_GET_SET_RELATED_DATASET
	
	///Sophy 1/8/2010 FILTER_RESULT_CURVE_IN_QUICK_FIT_ROI_TOOL
	tag_columns_in_data_range(oy, STR_DATASETOBJ_FITCURVE);
	///end FILTER_RESULT_CURVE_IN_QUICK_FIT_ROI_TOOL
	// output
	QuickFitPlotInfo	stPlotInfo;
	stPlotInfo.nUID = nInputPlotUID;
	int			c1, c2;
	Datasheet	ds;
	iy.GetRange(0, stPlotInfo.nFrom, c1, stPlotInfo.nTo, c2, ds);
	quick_fit_source_plot_info_access(stPlotInfo, gl, FALSE);
	///Sophy 1/12/2010 SHOW_LEGEND_IN_RESULT_TABLE
	//quick_fit_output_report(gl, iy, stFitResults, func, order);
	/// Iris 2/20/2010 MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
	//quick_fit_output_report(gl, iy, stFitResults, func, order, false, roi);	
	quick_fit_output_report(gl, iy, stFitResults, func, order, false, roi, replace);
	///End MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
	///end SHOW_LEGEND_IN_RESULT_TABLE
	
}

//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 quickfit_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return quickfit_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	return false;	

}

int quickfit_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 quickfit_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	/// Iris 2/20/2010 MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
	/*
	///------ Folger 01/12/09 QA81-14832 ADD_OPTION_TO_GENERATE_NEW_FIT_CURVE_FOR_EACH_OUTPUT
	if ( !quick_fit_replace_existing_curve() )
		return;
	///------ End ADD_OPTION_TO_GENERATE_NEW_FIT_CURVE_FOR_EACH_OUTPUT
	*/
	if( 0 == trGetN.replace.nVal )
		return;
	///End MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
	
	TreeNode trIn = trGetN.iy;
	DataRange drIn;
	okxf_resolve_tree_construct_range(&trIn, &drIn);
	
	GraphLayer  gl;
	int			nInputPlotUID;
	///Sophy 4/13/2010 QA81-15308 GET_GRAPHLAYER_OF_INPUTDATA_IN_XF_BODY
	//if( _get_input_graph_layer(drIn, gl, &nInputPlotUID) )
	if ( get_graphlayer_from_input(drIn, gl, &nInputPlotUID) )
	///end GET_GRAPHLAYER_OF_INPUTDATA_IN_XF_BODY
	{
		//------Iris 12/24/2009 USE_GET_SET_RELATED_DATASET
		//int nOutPlotUID;
		//if( okutil_quick_fit_get_io_range_UID(gl.GetUID(true), NULL, &nOutPlotUID) && 0 != nOutPlotUID )		
		//{
			//int nOutRangeUID = get_range_UID_from_plot_UID(nOutPlotUID);
		DataPlot dpIn;
		dpIn = (DataPlot)Project.GetObject(nInputPlotUID);
		DatasetObject dsFit;
		if( dpIn.GetRelatedDataset(STR_QUICK_FIT_RELATED_DATASET, dsFit) && dsFit )
		{
			string strRange;
			dsFit.GetRangeString(strRange);
			
			DataRange drFit;
			drFit.Add("Range1", strRange);
			
			Worksheet wks;
			int c1,c2;
			drFit.GetRange(wks, c1, c2);
			ASSERT(c1==c2); // only one column			
			int nXColIndex = wks.FindColIndex(c1, OKDATAOBJ_DESIGNATION_X); // find x column from y column
			
			XYRange xy;
			xy.Add(wks, nXColIndex, "X");
			xy.Add(wks, c1, "Y");			
			int nOutRangeUID = xy.GetUID(true);	
		//------USE_GET_SET_RELATED_DATASET
			
			vector<int> vOutputUID;
			vOutputUID.Add(nOutRangeUID);
			
			okxf_update_tree_from_ranges(&trGetN, 0, &vOutputUID);
		}			
	}
	
	
}
//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 quickfit_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
