/*------------------------------------------------------------------------------*
 * File Name:	SurfaceFPreviewCtrl.h											*
 * Creation: 	Iris															*
 * Purpose: FitSession and PreviewCtrl for Surface fit							*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:  															*
 *	Hong 09/28/08 V8.0949 SURFACE_FAIL_COMPILE_DUE_TO_MOVE_PREVIEW_ONDESTROY_CODE_TO_DESTRUCTOR
 *	Hong 10/17/08 QA80-10624 NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT				*
 *	Sophy 11/1/2008 IMPROVE_CODE_SKIP_PLOT_FITCURVE_ON_RESIDUAL_CHANGE			*
 *	Sophy 11/20/2008 QA80-10599-P6 FIX_FITCURVE_GRAPH_AXES_RESCALE_PROBLEM		*
 *	Sophy 2/23/2009 v8.0984b UPDATE_XYZ_PREVIEW_DATA_WHEN_CUSTOMIZE_INPUTDATA_RANGE
 *	Sophy 3/3/2009 v8.0990 FIX_RUNTIME_ERROR_WHEN_USE_CHEBYSHEV2D_AS_FUNCTION_IN_MATRIX_FITTING
 *	Sophy 4/27/2009 v8.0987 QA80-13178 UPDATE_FITCURVE_RESIDUAL_PLOTS_SETTINGS_FOR_UPDATE_3D_RESIDUAL_PREVIEW
 *------------------------------------------------------------------------------*/


#ifndef _SURFACE_FIT_PREVIEWCTRL_H_    
#define _SURFACE_FIT_PREVIEWCTRL_H_

//----CPY 3/24/2008 NO_NEED_TO_REDUCE_NUMBER_OF_FIT_CONTOUR_LINES
//#define FIT_CONTOUR_LEVEL_REDUCTION_FROM_DATA_LEVELS 2 // number of contour levels on the fit surface is less then the data level by this factor
#define FIT_CONTOUR_LEVEL_REDUCTION_FROM_DATA_LEVELS 1
//---- end NO_NEED_TO_REDUCE_NUMBER_OF_FIT_CONTOUR_LINES
//--- end

class SurfaceFitPreviewCtrl : public NLFitPreviewCtrl
{
public:
	SurfaceFitPreviewCtrl(NLFitSession* pNLFSession) : NLFitPreviewCtrl(pNLFSession) {}
	/// Hong 09/28/08 V8.0949 SURFACE_FAIL_COMPILE_DUE_TO_MOVE_PREVIEW_ONDESTROY_CODE_TO_DESTRUCTOR
	//void 	OnDestroy();
	/// end SURFACE_FAIL_COMPILE_DUE_TO_MOVE_PREVIEW_ONDESTROY_CODE_TO_DESTRUCTOR
	bool 	UpdateResidualContourLevels(GraphLayer& gl = NULL);
	//virtual
	bool	SetResidualLimits(const double& dIRL, const double& dORL);///Sophy 4/27/2009 v8.0987 QA80-13178 UPDATE_FITCURVE_RESIDUAL_PLOTS_SETTINGS_FOR_UPDATE_3D_RESIDUAL_PREVIEW
	
protected:
	virtual int		GetPlotType() {return -1;}
	
	bool			GetResidualLayer(GraphLayer& gl);
	
	/// Iris NLF_81
	//virtual bool	PlotSourceCurves(DataRange& dr, DataRange& drSrc, PreviewCtrlInfo* pPreviewCtrlInfo, NLFitSessionBase& nlfitSessionBase);
	///end NLF_81
	
	bool    		PlotSourceDataInResidualTab(GraphLayer& glResidual);
	
	//------- CPY 3/4/08 QA-11206 XYZ_PREVIEW_NOT_SHOWING
	//virtual
	int  			GetYDataColIndex(int nDataset = 0, int nPeak = 0, int nNumPeak = 1) { return GetXDataColIndex(nDataset, nNumPeak) + 1 + nPeak;	}
	int 			GetZDataColIndex(int nDataset = 0) {return GetYDataColIndex(0) + 1;}	
	//----
	
	/// Iris NLF_81, to do 
	/*
	//----- CPY 3/5/08 QA-11206 SURFACE_CONTOUR_XY_RESCALE_BADLY
	//virtual 
	/// Hong 07/05/08 QA80-11206 MORE_FIX_SURFACE_FIT_CONTOUR_LEVEL_CHANGED_BY_RESCALE
	//bool RescaleFitCurvesGraph(GraphLayer& gl, const NLFitSessionBase& nlfitSessionBase, const FitResultCurveDataOptions& fitOptionsX, DataRange& drSrc, const FitResultCurveDataOptions& fitOptionsY = NULL);
	bool RescaleFitCurvesGraph(GraphLayer& gl, const NLFitSessionBase& nlfitSessionBase, const FitResultCurveDataOptions& fitOptionsX, DataRange& drSrc, const FitResultCurveDataOptions& fitOptionsY = NULL, DWORD dwRescaleCtrl = 0);
	/// end MORE_FIX_SURFACE_FIT_CONTOUR_LEVEL_CHANGED_BY_RESCALE
	//-----
	
	//----- CPY 4/8/08 SURFACE_FIT_CONTOUR_PLOT_NEEDS_DIFF_LEGEND_UPDATE
	virtual bool UpdateLegend(GraphLayer& gl, const NLFitSessionBase& nlfitSessionBase, const DataRange& drSrc) 
	{
		return true;// will add this later, for now just do nothing
	}
	//-----
	*/
	///end NLF_81

private:
	bool 			plotSourceCurves();	
};

class XYZSurfaceFitPreviewCtrl : public SurfaceFitPreviewCtrl
{
public:
	XYZSurfaceFitPreviewCtrl(NLFitSession* pNLFSession) : SurfaceFitPreviewCtrl(pNLFSession) {}	
	/// Hong 09/28/08 V8.0949 SURFACE_FAIL_COMPILE_DUE_TO_MOVE_PREVIEW_ONDESTROY_CODE_TO_DESTRUCTOR
	//void 	OnDestroy();
	/// end SURFACE_FAIL_COMPILE_DUE_TO_MOVE_PREVIEW_ONDESTROY_CODE_TO_DESTRUCTOR
	bool 	UpdateResidualContourLevels(GraphLayer& gl = NULL);
	
protected:
	int GetPlotType() { return IDM_PLOT_TRI_CONTOUR;	}	
	
	//virtual 
	NLFCurvesBase* GetNLFCurvesObject() 
	{  
		if(NULL == m_pNLFCurves)
		{
			ASSERT(m_pNLFSession);
			m_pNLFCurves = new SurfaceFitCurves(m_pNLFSession);
		}
		return m_pNLFCurves;
	} 	
	
private:	
	//virtual 
	bool 	updatePreviewData(DWORD dwUpdateBits);
	bool	updateFitData(int nWksType);
	bool 	updateFitCurveData();
	bool	updateResidualData();
	
	//virtual
	///Sophy 11/1/2008 IMPROVE_CODE_SKIP_PLOT_FITCURVE_ON_RESIDUAL_CHANGE
	//int 	plotFitCurvesAndResidual();	
	int 	plotFitCurvesAndResidual( DWORD dwUpdateBits = FITPREVIEW_REPLOT );	//plot both defaultly
	///end IMPROVE_CODE_SKIP_PLOT_FITCURVE_ON_RESIDUAL_CHANGE
	bool    plotXYZFitCurves();
	bool 	plotXYZResidual();
	
	bool 	setFitColumnLongName(Column& col, int nDataset, int nMultiplicity, bool bResidual = false);	
	
	/// Iris NLF_81 
	//bool 	PrepareWks(Worksheet& wks, NLFitSessionBase& nlfitSessionBase, int nWksType);
	///end NLF_81
	
	//virtual
	void 	setWksColTypeAndFormat(Worksheet& wks, int nColumns, int nXNumCols = 1);

//private:
	//Worksheet			m_FitCurvesWks;// all numeric cols
	//Worksheet			m_wksResidual;
};

class MatSurfaceFitPreviewCtrl : public SurfaceFitPreviewCtrl
{
public:
	MatSurfaceFitPreviewCtrl(NLFitSession* pNLFSession) : SurfaceFitPreviewCtrl(pNLFSession) {}
	/// Hong 09/28/08 V8.0949 SURFACE_FAIL_COMPILE_DUE_TO_MOVE_PREVIEW_ONDESTROY_CODE_TO_DESTRUCTOR
	//void	OnDestroy();	
	~MatSurfaceFitPreviewCtrl();
	/// end SURFACE_FAIL_COMPILE_DUE_TO_MOVE_PREVIEW_ONDESTROY_CODE_TO_DESTRUCTOR
	bool 	UpdateResidualContourLevels(GraphLayer& gl = NULL); 
	
protected:
	int 	GetPlotType() { return IDM_PLOT_CONTOUR; }
	
	//virtual 
	NLFCurvesBase* GetNLFCurvesObject() 
	{  
		if(NULL == m_pNLFCurves)
		{
			ASSERT(m_pNLFSession);
			m_pNLFCurves = new MatrixFitCurves(m_pNLFSession);
		}
		return m_pNLFCurves;
	} 	
private:
	bool	getTempMatrixLayer(MatrixLayer* pml, int nMatType);	
	bool	prepareMat(int nMatType);
	
	//virtual 
	bool 	updatePreviewData(DWORD dwUpdateBits);
	bool 	updateMatFitCurveData();	
	bool	updateMatResidualData();	
	
	//virtual
	///Sophy 11/1/2008 IMPROVE_CODE_SKIP_PLOT_FITCURVE_ON_RESIDUAL_CHANGE
	//int 	plotFitCurvesAndResidual();	
	int 	plotFitCurvesAndResidual( DWORD dwUpdateBits = FITPREVIEW_REPLOT );	//plot both defaultly
	///end IMPROVE_CODE_SKIP_PLOT_FITCURVE_ON_RESIDUAL_CHANGE
	bool 	plotMatFitCurves();	
	bool 	plotMatResidual();
	
	
private:
	MatrixLayer					m_mlFitCurves;	
	MatrixLayer					m_mlResidual; //when do matrix fit, should use matSrc - matFit, then plot, it is faster then plot by wks
};

/// Hong 09/28/08 V8.0949 SURFACE_FAIL_COMPILE_DUE_TO_MOVE_PREVIEW_ONDESTROY_CODE_TO_DESTRUCTOR
/*
void SurfaceFitPreviewCtrl::OnDestroy()
{
	NLFitPreviewCtrlBase::OnDestroy();
}
*/
/// end SURFACE_FAIL_COMPILE_DUE_TO_MOVE_PREVIEW_ONDESTROY_CODE_TO_DESTRUCTOR

/// Iris NLF_81
/*

//----- CPY 3/5/08 QA-11206 SURFACE_CONTOUR_XY_RESCALE_BADLY
//virtual 
/// Hong 07/05/08 QA80-11206 MORE_FIX_SURFACE_FIT_CONTOUR_LEVEL_CHANGED_BY_RESCALE
//bool SurfaceFitPreviewCtrl::RescaleFitCurvesGraph(GraphLayer& gl, const NLFitSessionBase& nlfitSessionBase, const FitResultCurveDataOptions& fitOptionsX, DataRange& drSrc, const FitResultCurveDataOptions& fitOptionsY)
bool SurfaceFitPreviewCtrl::RescaleFitCurvesGraph(GraphLayer& gl, const NLFitSessionBase& nlfitSessionBase, const FitResultCurveDataOptions& fitOptionsX, DataRange& drSrc, const FitResultCurveDataOptions& fitOptionsY, DWORD dwRescaleCtrl) // = NULL, 0
/// end MORE_FIX_SURFACE_FIT_CONTOUR_LEVEL_CHANGED_BY_RESCALE
{
	if(!gl)
		return false;
	/// Hong 07/05/08 QA80-11206 MORE_FIX_SURFACE_FIT_CONTOUR_LEVEL_CHANGED_BY_RESCALE
	//gl.Rescale();
	gl.Rescale(dwRescaleCtrl);
	/// end MORE_FIX_SURFACE_FIT_CONTOUR_LEVEL_CHANGED_BY_RESCALE
	return true;
}
//-----

bool	SurfaceFitPreviewCtrl::PlotSourceCurves(DataRange& dr, DataRange& drSrc, PreviewCtrlInfo* pPreviewCtrlInfo, NLFitSessionBase& nlfitSessionBase)
{	
	m_vnSrcPlotInfo.SetSize(2);

	for (int ii = 0; ii < nlfitSessionBase.GetNumDataset(); ii++)
		plotSourceCurvesEachDataset(ii, dr, drSrc, pPreviewCtrlInfo, nlfitSessionBase);

	return true;
}

bool	SurfaceFitPreviewCtrl::plotSourceCurvesEachDataset(int nIndex, DataRange &dr, DataRange& drSrc, PreviewCtrlInfo* pPreviewCtrlInfo, NLFitSessionBase& nlfitSessionBase)
{
	DWORD dwPlotUID = nlfitSessionBase.GetPlotUID(nIndex);
	plotSourceData(dr, nIndex, nlfitSessionBase.GetNumDataset(), dwPlotUID, m_nFitCurveLayer);
	return true;
}
*/
///end NLF_81


/// Iris NLF_81
//bool	SurfaceFitPreviewCtrl::plotSourceData(DataRange &dr, int nIndex, int nNumDataset, DWORD& dwPlotUID, int nLayer)
bool	SurfaceFitPreviewCtrl::plotSourceCurves()
///end NLF_81
{
	if(!m_graph)
		return error_report("Invalid fit curve preview graph!");
	
	CleanFitCurveGraphLayer(m_nFitCurveLayer);	
	ResetSourcePlotUIDs();
	m_vnSrcPlotIndex.SetSize(2);

	GraphLayer 	gl;
	if(!GetFitCurveGraphLayer(gl, m_nFitCurveLayer))
		return false;
	
	DWORD		dwPlotUID;
	int			nPlotType = GetPlotType();	
	uint 		nCntrl = GAP_USE_TEMPLATE | GAP_ALLOW_DUPLICATE_COL;	
	int			nPlot = GetNLFCurvesObject()->PlotSourceCurve(gl, 0, &dwPlotUID, 0, 0, nPlotType, nCntrl);	
	
	SetSourcePlotInfo(nPlot, 0, m_pNLFSession->GetNumDataset(), m_nFitCurveLayer);	
	SetSourcePlotUID(dwPlotUID);					
	
	return  true;	
}


bool	SurfaceFitPreviewCtrl::GetResidualLayer(GraphLayer& gl)
{
	if(!m_gpResidual)
		return false;
	
	gl = m_gpResidual.Layers();	
	return true;
}


bool    SurfaceFitPreviewCtrl::PlotSourceDataInResidualTab(GraphLayer& glResidual)
{
	if(!glResidual)
		return false;
	
	//DataRange drSrc;
	//drSrc = m_pNLFSession->GetSrcDataRange();
	//if(!drSrc)
		//return error_report("Can not get source DataRange");
	//
	//uint 		nCntrl = GAP_USE_TEMPLATE; 
	//int 		nPlotType = GetPlotType();
	//int 		nPlot = glResidual.AddPlot(drSrc, nPlotType, nCntrl);
	//if(nPlot < 0)
		//return false;
		
	DWORD		dwPlotUID = 0;
	///Sophy 7/30/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
	//int		nPlot = GetNLFCurvesObject()->PlotSourceCurve(glResidual, 0, &dwPlotUID, 0, 0, GetPlotType(), GAP_USE_TEMPLATE );
	int		nPlot = GetNLFCurvesObject()->PlotSourceCurve(glResidual, 0, &dwPlotUID, 0, 0, GetPlotType(), GAP_USE_TEMPLATE, true );
	///end CLEAN_MATRIXFIT_PREVIEW_CONTROL
	if( nPlot < 0 )
		error_report("SurfaceFitPreviewCtrl::PlotSourceDataInResidualTab fail to plot source curve on residual graph");

	/// Iris NLF_81 doing
	//SetSourcePlotInfo(nPlot, 0, m_pNLFSession->GetNumDataset(), glResidual.GetIndex());
	//SetSourcePlotUID(dwPlotUID);	
	///end NLF_81
	
	return true;
}

///Sophy 4/27/2009 v8.0987 QA80-13178 UPDATE_FITCURVE_RESIDUAL_PLOTS_SETTINGS_FOR_UPDATE_3D_RESIDUAL_PREVIEW
bool	SurfaceFitPreviewCtrl::SetResidualLimits(const double& dIRL, const double& dORL)
{
	return GetNLFCurvesObject()->SetResidualLimits(dIRL, dORL);
}
///end UPDATE_FITCURVE_RESIDUAL_PLOTS_SETTINGS_FOR_UPDATE_3D_RESIDUAL_PREVIEW


/// Iris NLF_81, to do 
/*
bool 	XYZSurfaceFitPreviewCtrl::PrepareWks(Worksheet& wks, NLFitSessionBase& nlfitSessionBase, int nWksType)
{
	if(!wks)
	{
#ifdef _DEBUG_FIT  // this will turn on general debug help like making all temp win visible and plot clickable
		wks.Create(NULL);		//------- CPY 3/4/08 QA-11206 XYZ_PREVIEW_NOT_SHOWING
#else
		wks.Create(NULL, CREATE_HIDDEN | CREATE_SET_MISSING_IN_MANAGER);
#endif	
		string strPageName;
		switch(nWksType)
		{
		case WKS_FIT_CURVES:
			strPageName = "tmpFcv1";
			break;
		case WKS_RESIDUAL:
			strPageName = "tmpRcv1";
			break;
		default:
			//------- CPY 3/4/08 QA-11206 XYZ_PREVIEW_NOT_SHOWING
			//break;
			return error_report("XYZSurfaceFitPreviewCtrl::PrepareWks found invalid wks type");
			//-------
		}	
		if( !strPageName.IsEmpty() )
			wks.GetPage().Rename(strPageName);
	}
	
	wks.SetSize(-1,0); //must reset column number and type if m_nMultiplicity is changed		
	//------- CPY 3/4/08 QA-11206 XYZ_PREVIEW_NOT_SHOWING
	// the following code is typical example of double storage of logic	
	//for(int index=0; index<nlfitSessionBase.GetNumDataset(); index++)
	//{
		//int nColumns = NUM_DATASET_PER_FITTED_CURVE;		
		//
		//int nMultiplicity = nlfitSessionBase.GetNumFitY();		
		//nColumns += nMultiplicity; 
		//
		//setWksColTypeAndFormat(wks, nColumns);
	//}		
	int nColumns = GetZDataColIndex()+1;
	setWksColTypeAndFormat(wks, nColumns);
	//------- end XYZ_PREVIEW_NOT_SHOWING
	return true;
}
*/
//end NLF_81

void    XYZSurfaceFitPreviewCtrl::setWksColTypeAndFormat(Worksheet& wks, int nColumns, int nXNumCols)
{	
	for(int ii = 0; ii < nColumns; ii++)
	{
		int nCol = wks.AddCol();
		Column 	col(wks, nCol);		
		col.SetFormat(OKCOLTYPE_NUMERIC);
		
		if(ii == 0)
		{
			col.SetType(OKDATAOBJ_DESIGNATION_X);
		}			
		else if(ii == 1)
		{
			col.SetType(OKDATAOBJ_DESIGNATION_Y);
		}
		else
			col.SetType(OKDATAOBJ_DESIGNATION_Z);	
		
		DatasetObject dobj(col);
		dobj.Info.SYSTEM.PARAMETERS.TAG$ = STR_DATASETOBJ_FITCURVE;
	}
}

/// Hong 09/28/08 V8.0949 SURFACE_FAIL_COMPILE_DUE_TO_MOVE_PREVIEW_ONDESTROY_CODE_TO_DESTRUCTOR
/*
void XYZSurfaceFitPreviewCtrl::OnDestroy()
{
	SurfaceFitPreviewCtrl::OnDestroy();
	/// Iris NLF_81, to do , should be destory in base class 
	//if(m_FitCurvesWks)
		//m_FitCurvesWks.Destroy();
	//if(m_wksResidual)
		//m_wksResidual.Destroy();	
	///end NLF_81
}
*/
/// end SURFACE_FAIL_COMPILE_DUE_TO_MOVE_PREVIEW_ONDESTROY_CODE_TO_DESTRUCTOR

bool 	XYZSurfaceFitPreviewCtrl::updatePreviewData(DWORD dwUpdateBits)
{
	if( !updateFitCurveData() )
		return false;
	
	return updateResidualData();
}

bool 	XYZSurfaceFitPreviewCtrl::setFitColumnLongName(Column& col, int nDataset, int nMultiplicity, bool bResidual)
{
	string strColName;
	if(bResidual)
	{
		strColName = _L("Regular Residual");
		if(nMultiplicity > 1)
			strColName = _L("Cumulative Residual");
	}
	else
	{
		strColName = _L("Fit Curve") + " " + ftoa(nDataset + 1);
		if(nMultiplicity > 1)
			strColName = _L("Cumulative Peak Fit");
	}
	if(!col)
		return false;
	
	col.SetLongName(strColName);
	return true;
}

bool	XYZSurfaceFitPreviewCtrl::updateFitData(int nWksType)
{
	Worksheet* pwks = GetTempWks(nWksType);
	if( NULL == pwks )
		return error_report("Found NULL pwks pointer");
	///Sophy 2/23/2009 v8.0984b UPDATE_XYZ_PREVIEW_DATA_WHEN_CUSTOMIZE_INPUTDATA_RANGE
	/*
	bool bFirstTime = false;
	if(!pwks->IsValid() && m_pNLFSession->GetNumDataset() > 0)
	{
		if( !PrepareWks(nWksType) )
			return error_report("Fail to prepare wks in XYZSurfaceFitPreviewCtrl::updateFitData");		
		
		bFirstTime = true; // temp solution, need to get from NLFitSessionBase if Source Data is new
	}	
	
	vector 	vx, vy, vz;
	if( !m_pNLFSession->GetInputData(vx, vy, vz) )
		return false;
	
	
	//---- CPY 3/4/08 QA-11206 SURFACE_FIT_SHOULD_DEFAULT_TO_SRC_DATA_OR_NEED_PROPER_XY_GENERATED
	// this will need to be cleaned up, right now, 
	// nlfitSessionBase.GetFit(vFitX, vFitY, vFitZ, ii)
	// generated XY and XY are the same, so cannot generate fit surface with XY same vector
	// as that will lead to a straight line
	// I will rewrite this to make it simple but overall clean up may still be needed
	// use source data XY for now, may need to add code to reduce number of points
	vector	vFitX, vFitY, vFitZ;
	vFitX = vx;
	vFitY = vy;
	
	int		nX = GetXDataColIndex();
	int		nY = GetYDataColIndex();
	int		nZ = GetZDataColIndex();
	Column 	colZ(*pwks, nZ);
	if( !colZ )
		return error_report("Z col not prepared in fit curve wks, or PrepareWks not called?");
	
	bool bIsResidual = WKS_RESIDUAL == nWksType? true : false;
	if(	bFirstTime )
	{
		///Sophy 11/20/2008 QA80-10599-P6 FIX_FITCURVE_GRAPH_AXES_RESCALE_PROBLEM
		GetNLFCurvesObject()->SetFitCurveScaleRange(vFitX, false);
		GetNLFCurvesObject()->SetFitCurveScaleRange(vFitY, true);
		///end FIX_FITCURVE_GRAPH_AXES_RESCALE_PROBLEM
		Dataset dsX(*pwks, nX);
		dsX = vFitX;
		Dataset dsY(*pwks, nY);
		dsY = vFitY;
		
		setFitColumnLongName(colZ, 0, m_pNLFSession->GetNumPeaks(), bIsResidual);
	}
	
	if( !GetNLFCurvesObject()->GetFitZ(vFitX, vFitY, vFitZ, m_pNLFSession->GetNLParamsMngr()))
		return error_report("Fail to get fitted data in nlfitSessionBase.GetFitZ!\n");	
		
	Dataset dsZ(*pwks, nZ);
	dsZ = bIsResidual? vz - vFitZ : vFitZ;	
	
	Dataset dsX(*pwks, nX);
	dsX = vFitX;
	
	Dataset dsY(*pwks, nY);
	dsY = vFitY;
	*/
	vector vX, vY, vZ;
	if ( !m_pNLFSession->GetInputData(vX, vY, vZ) )
		return false;
	
	//---- CPY 3/4/08 QA-11206 SURFACE_FIT_SHOULD_DEFAULT_TO_SRC_DATA_OR_NEED_PROPER_XY_GENERATED
	// this will need to be cleaned up, right now, 
	// nlfitSessionBase.GetFit(vFitX, vFitY, vFitZ, ii)
	// generated XY and XY are the same, so cannot generate fit surface with XY same vector
	// as that will lead to a straight line
	// I will rewrite this to make it simple but overall clean up may still be needed
	// use source data XY for now, may need to add code to reduce number of points
	vector	vFitX, vFitY, vFitZ;
	vFitX = vX;
	vFitY = vY;
	
	int		nXCol = GetXDataColIndex();
	int		nYCol = GetYDataColIndex();
	int		nZCol = GetZDataColIndex();
	bool	bIsResidual = (WKS_RESIDUAL == nWksType);
	
	if ( !pwks->IsValid() ) //first time, source data is new
	{
		if( !PrepareWks(nWksType) )
			return error_report("Fail to prepare wks in XYZSurfaceFitPreviewCtrl::updateFitData");		


		GetNLFCurvesObject()->SetFitCurveScaleRange(vFitX, false);
		GetNLFCurvesObject()->SetFitCurveScaleRange(vFitY, true);
		
		Column 	colZ(*pwks, nZCol);
		if( !colZ )
			return error_report("Z col not prepared in fit curve wks, or PrepareWks not called?");
		setFitColumnLongName(colZ, 0, m_pNLFSession->GetNumPeaks(), bIsResidual);
	}
	
	if( !GetNLFCurvesObject()->GetFitZ(vFitX, vFitY, vFitZ, m_pNLFSession->GetNLParamsMngr()) )
		return error_report("Fail to get fitted data in nlfitSessionBase.GetFitZ!\n");	

	//update fit data to temp wks
	Column colX(*pwks, nXCol);
	Column colY(*pwks, nYCol);
	Column colZ(*pwks, nZCol);
	
	if ( !colX || !colY || !colZ )
		return error_report("Can not access XYZ columns in surface fitting preview worksheet!");
	vectorbase& vbXData = colX.GetDataObject();
	vbXData = vFitX;
	
	vectorbase& vbYData = colY.GetDataObject();
	vbYData = vFitY;
	
	vectorbase& vbZData = colZ.GetDataObject();
	vbZData = bIsResidual ? vZ - vFitZ : vFitZ;
	///end UPDATE_XYZ_PREVIEW_DATA_WHEN_CUSTOMIZE_INPUTDATA_RANGE
	return true;	
}

bool 	XYZSurfaceFitPreviewCtrl::updateFitCurveData()
{
	return updateFitData(WKS_FIT_CURVES);
}

bool	XYZSurfaceFitPreviewCtrl::updateResidualData()
{
	return updateFitData(WKS_RESIDUAL);	

}
//---- end REWRITE_RESIDULE_PLOT_CODE

///Sophy 11/1/2008 IMPROVE_CODE_SKIP_PLOT_FITCURVE_ON_RESIDUAL_CHANGE
//int	XYZSurfaceFitPreviewCtrl::plotFitCurvesAndResidual()
int	XYZSurfaceFitPreviewCtrl::plotFitCurvesAndResidual( DWORD dwUpdateBits )
///end IMPROVE_CODE_SKIP_PLOT_FITCURVE_ON_RESIDUAL_CHANGE
{
	
	int nRet = 0;
	///Sophy 11/1/2008 IMPROVE_CODE_SKIP_PLOT_FITCURVE_ON_RESIDUAL_CHANGE
	if( !(dwUpdateBits & FITPREVIEW_REPLOT) )
	{
		m_vnFitPlotIndex.SetSize(m_pNLFSession->GetNumDataset()); 
		if( plotXYZFitCurves() )
			nRet++;
	}///Sophy 11/1/2008 IMPROVE_CODE_SKIP_PLOT_FITCURVE_ON_RESIDUAL_CHANGE

	
	if( plotXYZResidual() )
		nRet++;
	
	return nRet;
	///End NOT_PLOT_FITCURVE_OR_RESIDUAL_IF_NOT_ASK
}

bool	XYZSurfaceFitPreviewCtrl::plotXYZFitCurves()
{
	if(!m_FitCurvesWks)
		return false;
	
	GraphLayer gl;
	if( !GetFitCurveGraphLayer(gl, m_nFitCurveLayer) )	///Jasmine 03/21/08 QA80-10198 SPECIFY_PREVIEW_LAYER_IN_MULTILAYER_GRAPH_FOR_SINGLE_DEPS_INDEPS
		return false;
	
	int		nIndex = 0; //always only one input data for surface fitting
	int		nX = GetXDataColIndex(nIndex);
	int		nY = nX+1;
	int		nZ = nY+1;
	DataRange dr;
	//------- CPY 3/4/08 QA-11206 XYZ_PREVIEW_NOT_SHOWING
	// should use the simpler notation
	/*
	dr.Add("X", m_FitCurvesWks, 0, nX, -1, nX);
	dr.Add("Y", m_FitCurvesWks, 0, nY, -1, nY);
	dr.Add("Z", m_FitCurvesWks, 0, nZ, -1, nZ);
	*/
	dr.Add(m_FitCurvesWks, nX, "X");
	dr.Add(m_FitCurvesWks, nY, "Y");
	dr.Add(m_FitCurvesWks, nZ, "Z");
	//------ end XYZ_PREVIEW_NOT_SHOWING
	///Sophy 9/2/2008 CLEAN_NLFPREVIEW_AND_NLFCURVE
	/*
	uint 		nCntrl = GAP_USE_TEMPLATE; 
	int 		nPlot = gl.AddPlot(dr, IDM_PLOT_TRI_CONTOUR, nCntrl);
	if(nPlot < 0)
		return false;
	return true;
	*/
	/// Hong 10/17/08 QA80-10624 NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
	//return GetNLFCurvesObject()->PlotFitCurve(gl, dr) >= 0;
	return GetNLFCurvesObject()->PlotFitCurve(gl, dr, m_pNLFSession->GetDataObject()) >= 0;
	/// end NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
	///end CLEAN_NLFPREVIEW_AND_NLFCURVE
}

bool 	XYZSurfaceFitPreviewCtrl::plotXYZResidual()
{
	if(!m_wksResidual)
		return false;
	GraphLayer 	glResidual = m_gpResidual.Layers(0);
	if(!glResidual)
		return false;
	if(!PlotSourceDataInResidualTab(glResidual))
		return error_report("plotSourceDataInResidualTab failed!");
	//------ CPY 3/4/08 QA-11206 REWRITE_RESIDULE_PLOT_CODE
	/*
	int		nIndex = 0; //always only one input data for surface fitting
	int		nX = GetXDataColIndex(nIndex);
	int		nY = GetYDataColIndex(nIndex, 0, 1);
	int		nZ = nY+1;
	DataRange dr;
	dr.Add("X", m_wksResidual, 0, nX, -1, nX);
	dr.Add("Y", m_wksResidual, 0, nY, -1, nY);
	dr.Add("Z", m_wksResidual, 0, nZ, -1, nZ);
	*/
	int		nX = GetXDataColIndex(0);
	int		nY = GetYDataColIndex(0);
	int		nZ = GetZDataColIndex(0);
	DataRange dr;
	dr.Add(m_wksResidual, nX, "X");
	dr.Add(m_wksResidual, nY, "Y");
	dr.Add(m_wksResidual, nZ, "Z");
	//----- end REWRITE_RESIDULE_PLOT_CODE
	
	///Sophy 9/2/2008 CLEAN_NLFPREVIEW_AND_NLFCURVE
	/*	
	uint 		nCntrl = GAP_USE_TEMPLATE; 
	int 		nPlotType = GetPlotType();
	int 		nPlot = glResidual.AddPlot(dr, nPlotType, nCntrl);
	if(nPlot < 0)
		return false;
	return true;
	*/
	return GetNLFCurvesObject()->PlotResidual(glResidual, dr) >= 0;	
	///end CLEAN_NLFPREVIEW_AND_NLFCURVE
}

bool 	XYZSurfaceFitPreviewCtrl::UpdateResidualContourLevels(GraphLayer& gl)
{
	GraphLayer gltemp;
	if(gl)
		gltemp = gl;
	else
	{
		if( !GetResidualLayer(gltemp) )
			return false;
	}
	
	vector 	vData;
	int 	nDataset = 0; //only one dataset for surface fitting
	int		nColZ = GetYDataColIndex(nDataset) + 1;
	Dataset dsRe(m_wksResidual, nColZ);
	vData = dsRe;
	DataPlot 	dp = gltemp.DataPlots();
	return nlsf_update_residual_contour_levels(gltemp, dp, vData);
	
}


/// Hong 09/28/08 V8.0949 SURFACE_FAIL_COMPILE_DUE_TO_MOVE_PREVIEW_ONDESTROY_CODE_TO_DESTRUCTOR
/*
void	MatSurfaceFitPreviewCtrl::OnDestroy()
{
	SurfaceFitPreviewCtrl::OnDestroy();
	if(m_mlFitCurves)
		m_mlFitCurves.Destroy();
	if(m_mlResidual)
		m_mlResidual.Destroy();
}
*/
MatSurfaceFitPreviewCtrl::~MatSurfaceFitPreviewCtrl()
{
	RemoveFitCurves();///Sophy 11/1/2008 v8.0964c FIX_NLEND_FAIL_CREATE_FIT_CURVE_IN_SRC_GRAPH
	if(m_mlFitCurves)
		m_mlFitCurves.Destroy();
	if(m_mlResidual)
		m_mlResidual.Destroy();
}
/// end SURFACE_FAIL_COMPILE_DUE_TO_MOVE_PREVIEW_ONDESTROY_CODE_TO_DESTRUCTOR

bool	MatSurfaceFitPreviewCtrl::getTempMatrixLayer(MatrixLayer* pml, int nMatType)
{
	switch(nMatType)
	{
	case MAT_FIT_CURVES:
		pml = &m_mlFitCurves;
		break;
	case MAT_RESIDUAL_CURVES:
		pml = &m_mlResidual;
		break;
	default:
		return false;
	}	
	return true;
}

bool	MatSurfaceFitPreviewCtrl::prepareMat(int nMatType)	
{
	MatrixLayer* pml = NULL;
	///Sophy 7/24/2008 FIX_FAIL_TO_GET_MATRIX_LAYER
	/*
	if( !getTempMatrixLayer(pml, nMatType) )
		return false;
	*/
	if( MAT_FIT_CURVES == nMatType )
		pml = &m_mlFitCurves;
	else if( MAT_RESIDUAL_CURVES == nMatType )
		pml = &m_mlResidual;
	else
		return false;
	///end FIX_FAIL_TO_GET_MATRIX_LAYER
	ASSERT(pml);	
	if(pml->IsValid())
		return true; // no need prepare again if already valid
	
	pml->Create("Origin", CREATE_HIDDEN | CREATE_SET_MISSING_IN_MANAGER);	
    if( MAT_FIT_CURVES == nMatType )
    	pml->GetPage().Rename("NLFitCuvMat");
    else
    	pml->GetPage().Rename("NLFitResidualMat");
    
	pml->SetNumRows(ROW_NUM);
	pml->SetNumCols(COL_NUM);
	return true;
}

///Sophy 11/1/2008 IMPROVE_CODE_SKIP_PLOT_FITCURVE_ON_RESIDUAL_CHANGE
//int	MatSurfaceFitPreviewCtrl::plotFitCurvesAndResidual()
int	MatSurfaceFitPreviewCtrl::plotFitCurvesAndResidual( DWORD dwUpdateBits )
///end IMPROVE_CODE_SKIP_PLOT_FITCURVE_ON_RESIDUAL_CHANGE
{

	int nRet = 0;
	///Sophy 11/1/2008 IMPROVE_CODE_SKIP_PLOT_FITCURVE_ON_RESIDUAL_CHANGE
	if( !(dwUpdateBits & FITPREVIEW_REPLOT) )
	{
		m_vnFitPlotIndex.SetSize(m_pNLFSession->GetNumDataset()); 
		prepareMat( MAT_FIT_CURVES );
		if( plotMatFitCurves() )
			nRet++;
	}///Sophy 11/1/2008 IMPROVE_CODE_SKIP_PLOT_FITCURVE_ON_RESIDUAL_CHANGE
	
	prepareMat( MAT_RESIDUAL_CURVES );
	if( plotMatResidual() )
		nRet++;
	return nRet;
	///End NOT_PLOT_FITCURVE_OR_RESIDUAL_IF_NOT_ASK
}

bool 	MatSurfaceFitPreviewCtrl::plotMatFitCurves()
{
	if(!m_mlFitCurves)
		return false;
	
	GraphLayer gl;
	if(!GetFitCurveGraphLayer(gl, m_nFitCurveLayer))
		return false;	

	DataRange drFitCurves;
	drFitCurves.Add(m_mlFitCurves, 0, "Z");
	
	/// Hong 10/17/08 QA80-10624 NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
	//int nPlot = GetNLFCurvesObject()->PlotFitCurve(gl, drFitCurves);
	int nPlot = GetNLFCurvesObject()->PlotFitCurve(gl, drFitCurves, m_pNLFSession->GetDataObject());
	/// end NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
	
	m_vnFitPlotIndex[0] = nPlot;
	return true;
}

bool 	MatSurfaceFitPreviewCtrl::plotMatResidual()
{
	if(!m_mlResidual)
		return false;
	
	GraphLayer 	glResidual = m_gpResidual.Layers(0);
	if(!glResidual)
		return false;
	
	if(!PlotSourceDataInResidualTab(glResidual))
		return error_report("plotSourceDataInResidualTab failed!");	

	DataRange dr;
	dr.Add(m_mlResidual, 0, "Z");
	
	return GetNLFCurvesObject()->PlotResidual(glResidual, dr) >= 0;	
}

bool 	MatSurfaceFitPreviewCtrl::UpdateResidualContourLevels(GraphLayer& gl)
{
	GraphLayer gltemp;
	if(gl)
		gltemp = gl;
	else
	{
		if( !GetResidualLayer(gltemp) )
			return false;
	}
	
	matrixbase& mat = m_mlResidual.MatrixObjects(0).GetDataObject();
	vector vData;
	mat.GetAsVector(vData, FALSE);
	
	DataPlot 	dp = gltemp.DataPlots();
	return nlsf_update_residual_contour_levels(gltemp, dp, vData);
	
}

//virtual
bool 	MatSurfaceFitPreviewCtrl::updatePreviewData(DWORD dwUpdateBits)
{
	if( !updateMatFitCurveData() )
		return false;
	return updateMatResidualData();		
}

bool 	MatSurfaceFitPreviewCtrl::updateMatFitCurveData()
{
	if(!m_mlFitCurves)
		prepareMat(MAT_FIT_CURVES);
	
	for(int ii = 0; ii < m_pNLFSession->GetNumDataset(); ii++)
	{
		vector 	vx, vy, vz;
		if( !m_pNLFSession->GetInputData(vx, vy, vz, ii) )
			return false;
		
		Matrix 	mat(m_mlFitCurves);
		vector	vFitX, vFitY;
		vFitX = vx;
		vFitY = vy;
		///Sophy 7/28/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
		//if( !GetNLFCurvesObject()->GetFitZ(vFitX, vFitY,  mat, m_pNLFSession->GetNLParamsMngr(), ii))
		if( !GetNLFCurvesObject()->GetFit( vFitX, vFitY, mat, m_pNLFSession->GetNLParamsMngr(), ii ) )
		///end CLEAN_MATRIXFIT_PREVIEW_CONTROL
			return error_report("Fail to get fitted data in NLFitSession::updateMatFitCurveData!\n");		
	
		double 			dXMin, dYMin, dXMax, dYMax;			
		vFitX.GetMinMax(dXMin, dXMax);
		vFitY.GetMinMax(dYMin, dYMax);		

		MatrixObject 	mo;
		mo = m_mlFitCurves.MatrixObjects(0);
		mo.SetXY(dXMin, dYMin, dXMax, dYMax);		
		
		///Sophy 11/20/2008 QA80-10599-P6 FIX_FITCURVE_GRAPH_AXES_RESCALE_PROBLEM
		GetNLFCurvesObject()->SetFitCurveScaleRange(vFitX, false);
		GetNLFCurvesObject()->SetFitCurveScaleRange(vFitY, true);		
		///end FIX_FITCURVE_GRAPH_AXES_RESCALE_PROBLEM
	}
	
	return true;
}

bool	MatSurfaceFitPreviewCtrl::updateMatResidualData()
{
	if(!m_mlResidual)
		prepareMat(MAT_RESIDUAL_CURVES);
	
	matrix matResidual;
	int nRows, nCols;
	double dXmin, dYmin, dXmax, dYmax;
	///Sophy 3/3/2009 v8.0990 FIX_RUNTIME_ERROR_WHEN_USE_CHEBYSHEV2D_AS_FUNCTION_IN_MATRIX_FITTING
	//GetNLFCurvesObject()->GetResidualData(matResidual, m_pNLFSession->GetDataObject(), m_pNLFSession->GetNLParamsMngr(), nRows, nCols, dXmin, dYmin, dXmax, dYmax);
	if ( !GetNLFCurvesObject()->GetResidualData(matResidual, m_pNLFSession->GetDataObject(), m_pNLFSession->GetNLParamsMngr(), nRows, nCols, dXmin, dYmin, dXmax, dYmax) )
		return false;
	///end FIX_RUNTIME_ERROR_WHEN_USE_CHEBYSHEV2D_AS_FUNCTION_IN_MATRIX_FITTING
	m_mlResidual.SetNumRows(nRows);
	m_mlResidual.SetNumCols(nCols);
	
	MatrixObject mo = m_mlResidual.MatrixObjects(0);
	mo.SetXY(dXmin, dYmin, dXmax, dYmax);
	matrixbase& m = mo.GetDataObject();
	m = matResidual;
	return true;
}

#endif //_SURFACE_FIT_PREVIEWCTRL_H_
