/*------------------------------------------------------------------------------*
 * File Name: FitPolynomial.cpp													*
 * Creation: CPY 6/25/2004														*
 * Purpose: OriginC Class for Polynomial Regression								*
 * Copyright (c) Originlab Corp. 2004											*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 * Echo 4/30/05 ERROR_SIZE_INPUT												*
 * Iris 06/27/05 ADD_CUSTOM_TABLE_TO_SOURCE_GRAPH								*
 *	ML 4/28/2006 FRIENDLY_CUSTOM_TABLE_THEME_GENERATION							*
 *	CPY 10/14/06 SEPARATE_OUT_OPERATION_BASE_INTO_SEPARATE_HEADER				*
 *  Iris 10/18/06 MISS_DATA_LABEL_IN_IMTABLE									*
 *	Echo 2/12/07 ADD_ERROR_REPORT												*
 *	Cheney 2007-5-16 NLFIT_SHOULD_CHECK_IF_EXIST_EMPTY_SUBRANGE					*
 *	Cheney 2007-5-17 LINEAR_FIT_SHOULD_CONSISTENT_WITH_FIT_NL					*
 *	Cheney 2007-6-7 SHOULD_CHECK_EVENT_ID_IN_EVENT_FUNC							*
 *	Cheney 2007-6-19 ALWAYS_FIND_XY_FROM_CUMULATIVE_FIT_CURVE_IF_PEAK_FIT		*
 *	Arvin 08/02/07 CHECK_WEIGHT_DATA_HAS_MISSING_AND_NEGATIVE_VALUES			*
 *	Arvin 08/10/07 QA70-10197 ADD_NONE_OPTION_FOR_ERROR_AS_WEIGHT_IN_LR_PR_AND_MR
 *	Fisher 11/14/07 ADD_MAP_ID_TO_CHM											*
 *	Arvin 01/28/08 QA70-10923 CALC_CONFIDENCE_AND_PREDICTION_BANDS				*
 *	Arvin 02/14/08 QA70-11094 SUPPORT_PLOT_MULTI_FITTED_CURVES_IN_ONE_GRAPH_IN_LR_PR_AND_FITNL
 *	Hong 09/03/08 QA80-12130 NLFIT_SESSION_SUPPORT_SEPARATE_FIT					*
 *	Sophy 11/21/2008 v8.976 QA80-12591-P3 ADD_ERRMSG_WHEN_FITCURVE_XDATATYPE_IS_LOG_WITH_NEGATIVE_INPUT
 *	Sophy 11/28/2008 v8.0980d QA80-12591-P5 ADD_AUTO_SUPPORT_FOR_LR_AND_PR_FITCURVE_XDATATYPE
 *	Folger 04/14/09 QA80-12786-P2 DATE_TIME_FORMAT_NOT_PROPERLY_UPDATED_FOR_X_DATA_TYPE_WHEN_CHANGE_PARAM
 *  Iris 10/28/2009 QA81-14546 CHANGE_GUI_REPORT_TABLE_LABEL					*
 *------------------------------------------------------------------------------*/
 
#include <origin.h>
#include <event_utils.h>
#include <report_utils.h>
#include "FitCommon.h"
#include <o8dlg.h>

#ifdef _FOR_SMART_LOADING_ONLY
#include "wksOperation.h" //---- CPY 10/14/06 SEPARATE_OUT_OPERATION_BASE_INTO_SEPARATE_HEADER
#include "analysis_utils.h"
#include <stats_utils.h>
#include "stats_guis.h"
#include "stats_operations.h"
#include "nlsf_utils.h" /// Iris 7/08/2008 CLEAN_DUP_CALC_AVE_DATA_CODE_IN_NLSF_PREVIEW_AND_OP
#include "graph_utils.h" //---- Iris 11/19/2008 v8.0975 QA80-12591-P2 FIX_APPARENT_FIT_ON_GRAPH_CUSTOM_RANGE_GET_INCORRECT_X
#endif

#define STR_TAG_POLYNOMIAL_ORDER   "polynomialOrder"	///Cheney 2007-11-16 OUTPUT_POLYNOMIAL_ORDER_FOR_FIT_PLOYNOMIAL

#include <xfutils.h>  ///Echo 2/12/07 ADD_ERROR_REPORT

///Echo 2/12/07 ADD_ERROR_REPORT
static bool _check_data_pts(double dPoints)
{
	if (dPoints < 0)
		return false;
	
	if (dPoints - (int)dPoints != 0)
		return false;
	
	return true;
}
static bool _check_conf_level(TreeNode trConfLev)
{
	if (trConfLev.Enable)
		return check_conf_level(trConfLev);
	
	return true;		
}

static int fitpolynomial_event1(TreeNode& tr, int nRow, int nEvent, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& getNCountainer, string& strAux, string& strErrMsg)
{
	DECLARE_BUTTON_ENABLES   //support more buttons enable/disable
	
	int nErr = CER_NO_ERROR;
	
	///Cheney 2007-6-7 SHOULD_CHECK_EVENT_ID_IN_EVENT_FUNC	
	///Cheney 2007-7-6 SHOULD_CHECK_ERR_WHEN_THEME_CHANGE_ALSO
	//if(GETNE_ON_VALUE_CHANGE == nEvent  || GETNE_ON_INIT == nEvent)
	if(GETNE_ON_VALUE_CHANGE == nEvent  || GETNE_ON_INIT == nEvent || GETNE_ON_THEME == nEvent)
	///end SHOULD_CHECK_ERR_WHEN_THEME_CHANGE_ALSO
	///end SHOULD_CHECK_EVENT_ID_IN_EVENT_FUNC
	{
		///Cheney 2007-5-16 NLFIT_SHOULD_CHECK_IF_EXIST_EMPTY_SUBRANGE	
		//if(get_input_xyrange_num(tr.InputData) < 1)
		//	nErr = CER_XY_LS_ONE;
		TreeNode trInput = tr.InputData;
		if(!okutil_is_fitter_data_node_ready(&trInput) )
			nErr = CER_INPUT_RANGE_EMPTY;
		///end NLFIT_SHOULD_CHECK_IF_EXIST_EMPTY_SUBRANGE
		
		///Cheney 2007-7-11 SHOULD_CHECK_DATARANGE_IF_IS_VALID
		if(nErr == CER_NO_ERROR)
		{
			DataRange dr;
			dr.Create(trInput, FALSE);
			if( !dr.IsValid() )
				nErr = XFERR_INVALID_RANGE;
		}
		///end SHOULD_CHECK_DATARANGE_IF_IS_VALIDs
		
		///Cheney 2007-5-17 LINEAR_FIT_SHOULD_CONSISTENT_WITH_FIT_NL
		//else if(0>= get_input_xyrange_data_size(tr.InputData))
			//nErr = CER_NO_DATA;
		/////end LINEAR_FIT_SHOULD_CONSISTENT_WITH_FIT_NL
	
		if (nErr == CER_NO_ERROR)
		{
			TreeNode trParamConf = tr.Quantities.Parameters.Confidence;
			/// Iris 10/29/2009 QA81-14546 OP_DLG_NEW_STRUCTURE
			//TreeNode trFitConf = tr.Graph1.Confidence;
			TreeNode trFitConf = OP_GUI_FITCURVE_PLOT_SETTINGS(tr).Confidence;
			///end OP_DLG_NEW_STRUCTURE
			if (!_check_conf_level(trParamConf) || !_check_conf_level(trFitConf))
			{
				nErr = CER_INVALID_CONF_LEV;
			}
		}
		/// Iris 11/02/2009 QA81-14546 OP_DLG_NEW_STRUCTURE
		//if (nErr == CER_NO_ERROR && !_check_data_pts(tr.Graph1.XDataType.N.dVal))
		if (nErr == CER_NO_ERROR && !_check_data_pts(OP_GUI_FIT_X_DATA_BRANCH(tr).N.dVal))
		///end OP_DLG_NEW_STRUCTURE
		{
			nErr = CER_INVALID_DATA_NUM;
		}
		///Sophy 4/11/2008 CHECK_REPORT_DATA_BOOK_NAME_DIFFERENT
		string strRet = "";
		if( CER_NO_ERROR == nErr )
		{
			nErr = check_report_book_curve_book( tr, strRet );
		}
		///end CHECK_REPORT_DATA_BOOK_NAME_DIFFERENT
		
		/// Iris 5/29/2008 AVOID_NEGATIVE_IN_ARRANGE_GRAPHS_INTO_COL
		/// Iris 10/29/2009 QA81-14546 OP_DLG_NEW_STRUCTURE
		//TreeNode	trGraphNumCols = tr.Output.PlotSettings.GraphNumCols;
		TreeNode	trGraphNumCols = OP_GUI_GRAPH_ARRANGEMENT_NODE(tr).GraphNumCols;
		///end OP_DLG_NEW_STRUCTURE
		if(nErr == CER_NO_ERROR && trGraphNumCols && (! check_is_positive_integer(trGraphNumCols)))
		{
			nErr = CER_INVALID_POSITIVE_INTEGER;
			strRet = STR_GRAPH_INTO_NUM_COLS + " ";
		}
		///end AVOID_NEGATIVE_IN_ARRANGE_GRAPHS_INTO_COL
		
		///Sophy 11/21/2008 v8.976 QA80-12591-P3 ADD_ERRMSG_WHEN_FITCURVE_XDATATYPE_IS_LOG_WITH_NEGATIVE_INPUT
		if( nErr == CER_NO_ERROR )
		{
			/// Iris 11/02/2009 QA81-14546 OP_DLG_NEW_STRUCTURE
			//nErr = check_input_logx_datatype(tr.InputData, tr.Graph1.XDataType);
			nErr = check_input_logx_datatype(tr.InputData, OP_GUI_FIT_X_DATA_BRANCH(tr));
			///end OP_DLG_NEW_STRUCTURE
		}
		
		if( CER_NO_ERROR == nErr )
		{			
			/// Iris 11/02/2009 QA81-14546 OP_DLG_NEW_STRUCTURE
			//nErr = check_logx_customize_x_range(tr.Graph1.XDataType);
			nErr = check_logx_customize_x_range(OP_GUI_FIT_X_DATA_BRANCH(tr));
			///end OP_DLG_NEW_STRUCTURE
		}
		///end ADD_ERRMSG_WHEN_FITCURVE_XDATATYPE_IS_LOG_WITH_NEGATIVE_INPUT

		if (nErr != CER_NO_ERROR)
		{
			bOKEnable = false;
			strErrMsg = nErr;
			if( !strRet.IsEmpty() )
				strErrMsg += ":" + strRet;
		}
		
		///Arvin 08/02/07 CHECK_WEIGHT_DATA_HAS_MISSING_AND_NEGATIVE_VALUES
		if(nErr == CER_NO_ERROR)
		{
			check_get_weight_data_err_msg(tr, strErrMsg);
			///------ Folger 04/14/09 QA80-12786-P2 DATE_TIME_FORMAT_NOT_PROPERLY_UPDATED_FOR_X_DATA_TYPE_WHEN_CHANGE_PARAM
			/// Iris 11/02/2009 QA81-14546 OP_DLG_NEW_STRUCTURE
			//stats_update_xdatatype_min_max_by_auto(tr.InputData, tr.Graph1.XDataType);
			stats_update_xdatatype_min_max_by_auto(tr.InputData, OP_GUI_FIT_X_DATA_BRANCH(tr));
			///end OP_DLG_NEW_STRUCTURE
			///------ End DATE_TIME_FORMAT_NOT_PROPERLY_UPDATED_FOR_X_DATA_TYPE_WHEN_CHANGE_PARAM
		}
		///end CHECK_WEIGHT_DATA_HAS_MISSING_AND_NEGATIVE_VALUES
		
	}
	
	///Sophy 10/9/2008 QA80-10536-P12 REMOVE_FITTEDVALUE_FROM_RESIDUAL_AND_FINDXY_IF_NO_FITTED_CURVES_PLOT
	string strNodeName( lpcszNodeName );
	if( strNodeName.CompareNoCase("Graph1") == 0 )
		fitlinear_fitted_curves_option_changed( tr );
	///end REMOVE_FITTEDVALUE_FROM_RESIDUAL_AND_FINDXY_IF_NO_FITTED_CURVES_PLOT

	///Sophy 11/28/2008 v8.0980d QA80-12591-P5 ADD_AUTO_SUPPORT_FOR_LR_AND_PR_FITCURVE_XDATATYPE
	///------ Folger 04/14/09 QA80-12786-P2 DATE_TIME_FORMAT_NOT_PROPERLY_UPDATED_FOR_X_DATA_TYPE_WHEN_CHANGE_PARAM
	//if( strNodeName.CompareNoCase("Min") == 0 || strNodeName.CompareNoCase("Max") == 0 || strNodeName.CompareNoCase("Range") == 0 )
	if( strNodeName.CompareNoCase("InputData") == 0 || strNodeName.CompareNoCase("Min") == 0 || strNodeName.CompareNoCase("Max") == 0 || strNodeName.CompareNoCase("Range") == 0 )
	///------ End DATE_TIME_FORMAT_NOT_PROPERLY_UPDATED_FOR_X_DATA_TYPE_WHEN_CHANGE_PARAM
		/// Iris 11/02/2009 QA81-14546 OP_DLG_NEW_STRUCTURE
		//stats_update_xdatatype_min_max_by_auto(tr.InputData, tr.Graph1.XDataType);
		stats_update_xdatatype_min_max_by_auto(tr.InputData, OP_GUI_FIT_X_DATA_BRANCH(tr));
		///end OP_DLG_NEW_STRUCTURE
	///end ADD_AUTO_SUPPORT_FOR_LR_AND_PR_FITCURVE_XDATATYPE

	return true;

}
///end ADD_ERROR_REPORT

static bool fit_polynomial_dlg_event(TreeNode& trGUI, int nRow, int nType, Dialog& dlgGetNBox)    
{
	if( TRGP_CHECK == nType )
		///Arvin 08/10/07 QA70-10197 ADD_NONE_OPTION_FOR_ERROR_AS_WEIGHT_IN_LR_PR_AND_MR
		//trGUI.Fit.UseReducedChiSq.Show = trGUI.Fit.ErrBarWeight.nVal;
		trGUI.Fit.UseReducedChiSq.Show = trGUI.Fit.ErrBarWeight.nVal == ERRBARWEIGHT_INSTRUMENTAL;
		///end ADD_NONE_OPTION_FOR_ERROR_AS_WEIGHT_IN_LR_PR_AND_MR

	return true;
}

///Cheney 2007-11-16 OUTPUT_POLYNOMIAL_ORDER_FOR_FIT_PLOYNOMIAL
//for both GUI's check box and report statistic table
static TreeNode _check_add_polynomial_order_node(TreeNode& trStatistics, int nVal, int nID)
{
	TreeNode trRow = trStatistics.AddNumericNode(nVal, STR_TAG_POLYNOMIAL_ORDER, nID);
	trRow.SetAttribute( STR_DATAID_ATTRIB, IDE_FIT_POLYNOMIAL_ORDER );
	trRow.SetAttribute( STR_LABEL_ATTRIB, STR_POLYNOMIAL_ORDER );
	return trRow;
}
///end OUTPUT_POLYNOMIAL_ORDER_FOR_FIT_PLOYNOMIAL

class OC_REGISTERED FitPolynomial : public FitRegression
{
protected:
	// Virtual 
	string GetClassName() {return STR_FITTEROPERATION_CLASS_FITPOLYNOMIAL;}
	//virtual 
	//----- CPY 9/30/07 FIX_CHENEY_MODIFY_TITLE_AS_MAX_SAID
	//virtual 
	string GetDlgDescription(int nOption)
	{
		return _L("Perform Polynomial Fitting");
	}
	//-----
	
	// virtual 
	// fisher 11/14/2007 ADD_MAP_ID_TO_CHM
	int GetHelpID()
	{
		return IDD_FIT_POLYNOMIAL;
	}

	string GetAnalysisName(int nOption)
	{
		string str = _L("Polynomial Fit");
		return str;
	}
	
	//virtual 
	string 	GetResultBookName(TreeNode& trGUI) { return E_STR_PR_REPORT_TABLE_BOOK_SHORT_NAME; } /// Iris 3/21/2008 v8.0829 QA80-10934 ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
	
	///Iris 3/23/05 HIDDEN_CORRELATION_IN_PR_MR
	/// Iris 6/04/05 FILTER_STATS_REPORT
	void FilterStatsReport(TreeNode& trOp)
	{
		FitterOperation::FilterStatsReport(trOp);
		
		vector<int> vnNodesToHide = {IDE_FIT_CORRELATION};
		tree_set_attributes(trOp.Calculation, vnNodesToHide, "0");
	}
	///end FILTER_STATS_REPORT
	///end HIDDEN_CORRELATION_IN_PR_MR
	
	/// Iris 6/04/05 ADD_FILTER_FITTING_GUI
	//virtual
	void    FilterFittingGUI(TreeNode& trOp)
	{
		FitRegression::FilterFittingGUI(trOp);

		vector<int> vnNodesToHide = {IDE_FIT_CORRELATION, IDE_LR_FIX_SLOPE, 
		IDE_PARAM_FIX,	///Iris 10/13/05 REMOVE_FIX_FOR_LR_PR_MR Leo said "there is no place to "Fix" the parameter in LR, PR, MR, so should remove this"
		IDE_PARAM_DEPENDENCY, ///Arvin 05/22/07 REMOVE_DEPENDENCY_FOR_LR_PR_MR as larry's suggestion
		IDE_LR_FIX_SLOPE_AT};		
		tree_set_attributes(trOp.GUI, vnNodesToHide, "0");
		///Arvin 05/22/07 HIDE_PLOT_SETTING_BRANCH_FOR_LR_PR_WHILE_FROM_DATA_SHEET by larry's suggestion
		///Cheney 2007-11-19 SHOUDL_JUST_HIDE_PASTERESULTTABLE_NODE
		//TreeNode trPlotSettings = trOp.GUI.Output.PlotSettings;
		//if(trPlotSettings)
		//{
			//GraphLayer gl = Project.ActiveLayer();
			//trPlotSettings.Show = gl.IsValid() ? true : false;
		//}
		/// Iris 10/29/2009 QA81-14546 OP_DLG_NEW_STRUCTURE
		//TreeNode trPasteResultTable = trOp.GUI.Output.PlotSettings.PasteResultTable;
		TreeNode trPasteResultTable = OP_GUI_GRAPH_ARRANGEMENT_NODE(trOp.GUI).PasteResultTable;
		///end OP_DLG_NEW_STRUCTURE
		if(trPasteResultTable)
		{
			GraphLayer gl = Project.ActiveLayer();
			trPasteResultTable.Show = gl.IsValid() ? true : false;
		}
		///end SHOUDL_JUST_HIDE_PASTERESULTTABLE_NODE
		///end HIDE_PLOT_SETTING_BRANCH_FOR_LR_PR_WHILE_FROM_DATA_SHEET
	}
	///----
	
	/// Iris 10/28/2009 QA81-14546 CHANGE_GUI_REPORT_TABLE_LABEL
	/*
	/// Iris 4/17/2008 SPECIAL_REPORT_TABLE_NAME_FOR_DIFF_TOOLS
	//virtual	
	string	GetReportTableGUIName(TreeNode& trGUI)
	{
		return STR_OUTPUT_PR_FIT_REPORT_TABLE;
	}
	///end SPECIAL_REPORT_TABLE_NAME_FOR_DIFF_TOOLS
	*/
	///end CHANGE_GUI_REPORT_TABLE_LABEL
	
	// Virtual
	BOOL Construct(TreeNode& tr, int nOption = 0)
	{
		if( FitRegression::Construct(tr, nOption) )
		{
			/// Iris 6/04/05 ADD_FILTER_FITTING_GUI
			/////Iris 01/06/2005 REMOVE_CORRELATION_FOR_MR_PR
			////tr.GUI.Fit.RemoveChild("FixSlope");
			////tr.GUI.Fit.RemoveChild("FixSlopeAt");
			//tr.GUI.Fit.FixSlope.Remove();
			//tr.GUI.Fit.FixSlopeAt.Remove();
			//tr.GUI.Quantities.Statistics.Correlation.Remove();
			/////end REMOVE_CORRELATION_FOR_MR_PR
			//
			/////Iris 5/24/05 XY_WEIGHTING
			//if(tr.GUI.Fit.XWeight)
				//tr.GUI.Fit.XWeight.Remove();
			/// end ADD_FILTER_FITTING_GUI
			_check_add_polynomial_order_node(tr.GUI.Quantities.Statistics, 0, TRGP_CHECK); ///Cheney 2007-11-16 OUTPUT_POLYNOMIAL_ORDER_FOR_FIT_PLOYNOMIAL
			
			return TRUE;
		}
		return FALSE;
	}
	
	/// Iris 9/23/04 ADD_COV_AND_CORR_REPORT	
	//int		CallLLOC(TreeNode &trOp, vector &vY, vector &vX, matrix &mMultiIndep, vector &vWeights,
	//		FitParameter* psFitParameter, uint nSizeFitParams, RegStats* psRegStats, RegANOVA* psRegANOVA, RegCalcInternal* psInternal)
	///Arvin 12/04/06 ADD_CONF_PRED_BANDS_FOR_MR
	//int		CallLLOC(TreeNode &trOp, vector &vY, vector &vX, matrix &mMultiIndep, vector &vWeights,
	//		FitParameter* psFitParameter, uint nSizeFitParams, RegStats* psRegStats, RegANOVA* psRegANOVA, 
	//		RegCalcInternal* psInternal, matrix& mCov, matrix& mCorr)
	///Arvin 05/18/07 USE_REDUCED_CHISQ_CHECKBOX_NOT_WORK
	//int		CallLLOC(TreeNode &trOp, vector &vY, vector &vX, matrix &mMultiIndep, vector &vWeights,
			//FitParameter* psFitParameter, uint nSizeFitParams, RegStats* psRegStats, RegANOVA* psRegANOVA, 
			//RegCalcInternal* psInternal, matrix& mCov, matrix& mCorr, vector& vSerr = NULL)
	int		CallLLOC(TreeNode &trOp, vector &vY, vector &vX, matrix &mMultiIndep, vector &vWeights,
			FitParameter* psFitParameter, uint nSizeFitParams, RegStats* psRegStats, RegANOVA* psRegANOVA, 
			RegCalcInternal* psInternal, matrix& mCov, matrix& mCorr, vector& vSerr = NULL, int index = 0)
	///end USE_REDUCED_CHISQ_CHECKBOX_NOT_WORK
	///end ADD_CONF_PRED_BANDS_FOR_MR
	{
		TreeNode		trGUI = trOp.GUI;

		TreeNode		trFit = trGUI.Fit;
		
		////////////////////////		
		// Input settings:
		LROptions		sLROptions;
		sLROptions = trGUI.Fit;
		sLROptions.Confidence = trGUI.Quantities.Parameters.Confidence.dVal; /// Iris 8/11/06 v8.0460 QA70-7735-10 Confidence node has been move into Quantities to Compute branch
		sLROptions.Confidence /= 100;
		
		////////////////////////
		int				nOrder = trGUI.Order.nVal;

		///Echo 4/30/05 ERROR_SIZE_INPUT
		///// Iris 9/23/04 ADD_COV_AND_CORR_REPORT	
		////return stats_polynomial_fit(vX, vY, vWeights, nOrder, sLROptions, psFitParameter, nSizeFitParams, psRegStats, psRegANOVA);
		//if(trGUI.Fit.FixIntercept.nVal)
			//nSizeFitParams = nOrder;
		//else
			nSizeFitParams = nOrder + 1;
			
		///end ERROR_SIZE_INPUT
		///Arvin 05/18/07 USE_REDUCED_CHISQ_CHECKBOX_NOT_WORK
		TreeNode trInput = trGUI.InputData;
		if(!IsDatasetHasWeight(trInput, index))
			sLROptions.UseReducedChiSq = true;
		///end USE_REDUCED_CHISQ_CHECKBOX_NOT_WORK
		
		//--- CPY 10/1/04, cannot replace psFitParameter as is needed by caller
		//psFitParameter = (FitParameter*)calloc(nSizeFitParams, sizeof(FitParameter) );
		//---	
		int nRet = stats_polynomial_fit(vX, vY, vWeights, nOrder, sLROptions, psFitParameter, nSizeFitParams, psRegStats, psRegANOVA, mCov, mCorr);
		
		//free(psFitParameter);
		/// Iris 6/02/05 CALC_INTERNAL_FOR_FIT_POLY
		if( !nRet )
			nRet = ocmath_reg_plots(vX, vY, vWeights, vWeights.GetSize(), &sLROptions, psInternal);
		///end CALC_INTERNAL_FOR_FIT_POLY
		
		///Arvin 01/25/08 QA70-10923 CALC_CONFIDENCE_AND_PREDICTION_BANDS
		//Used to calculate confidence and prediction bands
		m_matCovariance = mCov;
		vector v;
		mCov.GetAsVector(v);
		///end CALC_CONFIDENCE_AND_PREDICTION_BANDS
		
		return nRet;
		///End ADD_COV_AND_CORR_REPORT
	}

	int		GetParameters(TreeNode &trOp, int index = 0, vector<string> &vstrParameterNames = NULL, bool bIncNumPostfix = false, bool bIncDerivedParams = false, vector<bool>& vbIsDerived = NULL)
	{
		TreeNode	trGUI = trOp.GUI;
		int			nParams = trGUI.Order.nVal + 1;
		
		if(vstrParameterNames)
		{
			vstrParameterNames.SetSize(nParams);
			//for (int ii = 0; ii < nParams; ii++)
			//{
				//string		str;
				//str.Format("a%d", ii);
				//vstrParameterNames[ii] = str;
			//}
			vstrParameterNames[0] = _LE("Intercept");
			///Iris 10/18/06 MISS_DATA_LABEL_IN_IMTABLE
			/*
			DataRange 	dr;
			GetInput(dr, index);			
			string		strIndep, strDep;
			get_fit_data_label(dr, strIndep, strDep, true, 0);	
			*/
			string 	strData;
			GetEscapedMainDataString(trOp, strData, index+1); //+1 mean LT index, offset is 1
			///Arvin 02/15/08 QA70-11097 KEEP_ESCAPED_STRINGS	
			//ConvertEscapedString(strData);
			///end KEEP_ESCAPED_STRINGS
			///end MISS_DATA_LABEL_IN_IMTABLE
			for(int ii = 1; ii < nParams; ii++)
			{
				/// Iris 01/09/2007 CORRECT_PR_FORMULA
				//vstrParameterNames[ii] = ( 1 == ii )? strData : strData + "^" + ii;
				vstrParameterNames[ii] = "B" + ii;
				///end CORRECT_PR_FORMULA
			}
			
			/// Iris 12/29/2006 v8.0534 PARAM_NAME_AS_TAGNAME_FOR_CELL_LINKING 
			if(bIncNumPostfix)
			{
				ParamsNamesAddPostfix(vstrParameterNames, index);
			}
			///end PARAM_NAME_AS_TAGNAME_FOR_CELL_LINKING
		}
		
		return nParams;
	}
	//virtual 
	bool GetDisplayFormula(TreeNode& trOp, string& strFormula)
	{
		vector<string> vsNames;
		int nParams = GetParameters(trOp, 0, vsNames);
		
		string str;
		for(int ii = 0; ii < nParams; ii++)
		{
			string strTerm = vsNames[ii];
			if(ii > 0)
			{
				strTerm += (string)"*x^" + ii;
				str += " + ";
			}
			str += strTerm;
		}
		strFormula = (string)"y = " + str;
		return true;
	}

	///Cheney 2007-11-16 OUTPUT_POLYNOMIAL_ORDER_FOR_FIT_PLOYNOMIAL
	//virtual
	/// Hong 09/03/08 QA80-12130 NLFIT_SESSION_SUPPORT_SEPARATE_FIT
	//bool AddRegStatsToReportTree(TreeNode& trOp, int index, const string &strDataLabel, int nTotalNumData, const vector<string> &vstrFactors, const RegStats &sRegStats)
	bool AddRegStatsToReportTree(TreeNode& trOp, int index, const string &strDataLabel, int nTotalNumData, const vector<string> &vstrFactors, const RegStats &sRegStats, int* pnSetIndex = NULL)
	/// end NLFIT_SESSION_SUPPORT_SEPARATE_FIT	
	{
		/// Hong 09/03/08 QA80-12130 NLFIT_SESSION_SUPPORT_SEPARATE_FIT
		//if( !FitterOperation::AddRegStatsToReportTree(trOp, index, strDataLabel, nTotalNumData, vstrFactors, sRegStats) )
		if( !FitterOperation::AddRegStatsToReportTree(trOp, index, strDataLabel, nTotalNumData, vstrFactors, sRegStats, pnSetIndex) )
		/// end NLFIT_SESSION_SUPPORT_SEPARATE_FIT
			return false;
		
		if(trOp.GUI.Quantities.Statistics.polynomialOrder.nVal)
		{
			TreeNode trTable = tree_check_get_node(trOp.Calculation, "RegStats", IDST_REG_STATS_RESULTS);
			TreeNode trRow = check_add_enumerated_node(trTable, CALCULATION_REPORT_TABLE_COL_PREFIX, index + 1, IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB, strDataLabel);
			TreeNode tr = _check_add_polynomial_order_node(trRow, trOp.GUI.Order.nVal, 0); ///Cheney 2007-11-16 OUTPUT_POLYNOMIAL_ORDER_FOR_FIT_PLOYNOMIAL
			tr.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_Y);
		}
		return true;
	}
	///end OUTPUT_POLYNOMIAL_ORDER_FOR_FIT_PLOYNOMIAL
	
	///Arvin 02/14/08 QA70-11094 SUPPORT_PLOT_MULTI_FITTED_CURVES_IN_ONE_GRAPH_IN_LR_PR_AND_FITNL
	DWORD GetOutputOptions(const TreeNode& trOp)
	{
		DWORD dwOptions = FitterOperation::GetOutputOptions(trOp);
		dwOptions |= REPORT_PLOT_ALL_PLOTS_IN_ONE_GRAPH; 
		return dwOptions;
	}
	///end SUPPORT_PLOT_MULTI_FITTED_CURVES_IN_ONE_GRAPH_IN_LR_PR_AND_FITNL
	
public:
	///Arvin 01/25/08 QA70-10923 CALC_CONFIDENCE_AND_PREDICTION_BANDS
	//Used to calculate confidence and prediction bands
	~FitPolynomial()
	{
		m_matCovariance.SetSize(0, 0);
	}
	///end CALC_CONFIDENCE_AND_PREDICTION_BANDS
	
	//virtual 
	///Cheney 2007-6-19 ALWAYS_FIND_XY_FROM_CUMULATIVE_FIT_CURVE_IF_PEAK_FIT
	//bool GetYFromX(const vector& vx, vector& vy, int nOuputIndex = 0, TreeNode& trOp = NULL, const matrix& mXs = NULL)
	bool GetYFromX(const vector& vx, vector& vy, int nOuputIndex = 0, TreeNode& trOp = NULL, const matrix& mXs = NULL, int nPeaks = 1, vector& vParams = NULL)
	///end ALWAYS_FIND_XY_FROM_CUMULATIVE_FIT_CURVE_IF_PEAK_FIT
	{
		//vector<string> vsNames;
		//int nParams = GetNumParams(trOp, vsNames);
		//
		//vector vParams;
		//vParams.SetSize(nParams);
		//
		//TreeNode		trParams;
		//FitParameter	sFitParameter[10];		// max num parameters (9 + 1 for constant term)
		//if( nParams != GetFitParameters(trOp, trParams, nOuputIndex, sFitParameter, nParams) )
			//return false;
		//
		//for(int nP = 0; nP < nParams; nP++)
		//{
			//vParams[nP] = sFitParameter[nP].Value;
		//}
		///Cheney 2007-6-19 ALWAYS_FIND_XY_FROM_CUMULATIVE_FIT_CURVE_IF_PEAK_FIT
		//vector 	vParams;
		//int 	nParams = GetFitParams(vParams, nOuputIndex, trOp);
		vector 	vParamstemp;
		int 	nParams = GetFitParams(vParamstemp, nOuputIndex, trOp);
		///end ALWAYS_FIND_XY_FROM_CUMULATIVE_FIT_CURVE_IF_PEAK_FIT
	
		vector vtemp(vx.GetSize());
		vtemp = 1;
		
		vy.SetSize(vx.GetSize());
		vy = 0;
		
		for (int ii = 0; ii< nParams; ii++)
		{
			double dParam = vParamstemp[ii];
			vy += vtemp * dParam;				
			vtemp *= vx;
		}
		///Cheney 2007-6-19 ALWAYS_FIND_XY_FROM_CUMULATIVE_FIT_CURVE_IF_PEAK_FIT
		if(vParams)
			vParams = vParamstemp;
		///end ALWAYS_FIND_XY_FROM_CUMULATIVE_FIT_CURVE_IF_PEAK_FIT
		
		return true;		
	}

	/// Iris 8/09/06 FIND_XY_FOR_PR
	//virtual 
	//bool GetXFromY(vector& vx, const vector& vy, int nOuputIndex = 0, TreeNode& trOp = NULL)
	//{
		//vector<string> vsNames;
		//int nParams = GetNumParams(trOp, vsNames);
		//
		//vector vParams;
		//vParams.SetSize(nParams)
		//
		//if(getFitParams(vParams, nParams, nOuputIndex, trOp))
		//{
			//vx = (vy - a) / b;
			//return true;
		//}
		//return false;
	//}
	///end FIND_XY_FOR_PR
	
	///Arvin 12/12/06 ADD_RESIDUAL_ANALYSIS_FOR_FITTING
	bool GetAllTypeResidualData(const TreeNode &trOp, const vector& vX, const vector& vRegularRes, vector& vStand, vector& vStud, vector& vStudDel, int index = 0, int nPeak = 0, vector &vY = NULL, vector &vWeights = NULL, matrix &mXs = NULL)
	{
		TreeNode		trGUI = trOp.GUI;
		TreeNode		trFit = trGUI.Fit;
		
		LROptions		sLROptions;
		sLROptions = trGUI.Fit;
		sLROptions.Confidence = trGUI.Quantities.Parameters.Confidence.dVal; 
		sLROptions.Confidence /= 100;		
		
		FitParameter	sFitParameter[MAX_MR_PARAMS + 1];	
		RegStats		sRegStats;
		RegANOVA		sRegANOVA;
		RegCalcInternal	sReg;
		vector vSerr;
		vector vH;
		int		nOrder = trGUI.Order.nVal;
		int nSizeFitParams = nOrder + 1;
		int nRet = stats_polynomial_fit(vX, vY, vWeights, nOrder, sLROptions, &sFitParameter, nSizeFitParams, &sRegStats, &sRegANOVA, NULL, NULL, vH);
		if (nRet != STATS_NO_ERROR)
				return false;
		
		vector vTemp1(vX.GetSize()), vTemp2(vX.GetSize());
		matrix mx(vX.GetSize(), nOrder+1);
		vTemp1 = 1; vTemp2 = 1;
		for(int ii = 0; ii < nOrder; ii++)
		{
			vTemp1 = vTemp1*vX;
			mx.SetColumn(vTemp1, ii);
		}
		mx.SetColumn(vTemp2, nOrder);
		int nNumPts = mx.GetNumRows();
		int nParam = nSizeFitParams;
		vStand.SetSize(nNumPts); vStud.SetSize(nNumPts); vStudDel.SetSize(nNumPts);
		vector vCook(nNumPts), vAtkinson(nNumPts);
		nRet = ocmath_diagnostic_residuals(nNumPts, nParam, sRegStats.ReducedChiSq, vRegularRes.GetSize(), vRegularRes, mx, vStand, vStud, vStudDel, vCook, vAtkinson, vH);
		if (nRet != STATS_NO_ERROR)
				return false;
		
		return true;
	}
	///end ADD_RESIDUAL_ANALYSIS_FOR_FITTING
	
	///Echo 2/12/07 ADD_ERROR_REPORT
	//virtual 
	PEVENT_GETN GetNewEventFunction()
	{
		return fitpolynomial_event1;
	}
	///end ADD_ERROR_REPORTprivate:
	
	///Arvin 01/25/08 QA70-10923 CALC_CONFIDENCE_AND_PREDICTION_BANDS
	bool CalcConfOrPredBounds(TreeNode &trOp, bool bConf, double dBoundLevel, vector& vLower, vector& vUpper, vector& vIndep1, vector &vFitY, GraphLayer& grLayAppar, FitParameter* psFitParameter, RegStats &stRegStats, RegCalcInternal* pstReg, vector& vSE, vector& vIndep2, int index = 0)
	{
		TreeNode 		trGUI = trOp.GUI;
		if(!trGUI)
			return false;
		
		int nRows = m_matCovariance.GetNumRows();
		int nCols = m_matCovariance.GetNumCols();
		int				nOrder = trGUI.Order.nVal;
		if(nRows != nOrder+1 || nCols != nOrder+1)
			return false;
		
		LROptions		sLROptions;
		sLROptions = trGUI.Fit;
		TreeNode trInput = trGUI.InputData;
		if(!IsDatasetHasWeight(trInput, index))
			sLROptions.UseReducedChiSq = true;

		double 			dBoundPerc = dBoundLevel/100.0;
		double 			dof = stRegStats.DOF;
		double 			dChiSq = stRegStats.ReducedChiSq;
		double			tvalue = tTable(1 - (1.0 - dBoundPerc) / 2, dof);
		int nRet = ocmath_calc_conf_and_pred_bands_for_polynomial(vIndep1, vFitY, vIndep1.GetSize(), m_matCovariance, &sLROptions, nOrder, dBoundPerc, dChiSq, tvalue, vLower, vUpper, bConf);
		if(nRet != OE_NOERROR)
			return false;
		
		return true;
	}
	///end CALC_CONFIDENCE_AND_PREDICTION_BANDS
	
private:
	///Arvin 01/25/08 QA70-10923 CALC_CONFIDENCE_AND_PREDICTION_BANDS
	//Used to calculate confidence and prediction bands
	matrix m_matCovariance;
	///end CALC_CONFIDENCE_AND_PREDICTION_BANDS
	/// Iris 8/09/06 FIND_XY_FOR_PR  move to fitterOperation.h
	//bool getFitParams(vector& vParams, int nParams, int nOuputIndex, TreeNode& trOp = NULL)
	//{
		//if(NULL == trOp)
			//GetTree(trOp);
		//
		//Tree trParams;
		//if(!GetFitParameters(trOp, trParams))
			//return error_report("GetYFromX failed to get Parameters tree");				
		//
		//vParams.SetSize(nParams);
		//
		//FitParameter	sFitParameter[MAX_MR_PARAMS + 1];		// max num parameters (9 + 1 for constant term)
		//if(GetFitParameters(trOp, trParams, nOuputIndex, sFitParameter, MAX_MR_PARAMS + 1) == nParams)
		//{
			//for (int ii = 0; ii < nParams; ii++)
				//vParams[ii] = sFitParameter[ii].Value;
			//
			//return true;
		//}
		//return false;
	//}
	//end FIND_XY_FOR_PR
	
	/// ML 4/28/2006 FRIENDLY_CUSTOM_TABLE_THEME_GENERATION
	/*
	///Iris 06/27/05 ADD_CUSTOM_TABLE_TO_SOURCE_GRAPH
	int	getTableIdForGraph(string *pstr, TreeNode& trOp)
	{
		/// ML 12/22/2004 temp until Roman is done with the label work
		//return 0;
		// Custom for now:
		TreeNode		tr = getOrCreateCustomTable(trOp);
		if( !tr.IsValid() )
			return 0;

		int				nID = tr.ID;
		/// 
		if ( pstr )
		{
			*pstr = "RegrTable";
		}
		return nID;
	}
	///end ADD_CUSTOM_TABLE_TO_SOURCE_GRAPH
	*/
	/// end FRIENDLY_CUSTOM_TABLE_THEME_GENERATION
};

/*
   //col(1)    col(2)    col(3)    col(4)    col(5)    col(6)
   //fit X     fit Y     LCL     UCL     LPL     UPL


// Testing only
void pr_data(double a = 0.3, double b = 2.5, double c = -1.2, double xinc = 0.023)
{
	Worksheet wks = Project.ActiveLayer();
	if(!wks)
		return;

	Dataset aa(wks, 0);
	Dataset bb(wks, 1);

	int nSize = 100;

	aa.SetSize(nSize);
	bb.SetSize(nSize);
	double x;

	for(int ii = 0; ii < nSize; ii++)
	{
		x = ii * xinc;
		aa[ii] = x;
		bb[ii] = c*x*x + a*x + b;
	}
}	

*/
