/*------------------------------------------------------------------------------*
 * File Name:PeakFitPreviewCtrl.h												*
 * Creation: Sophy 10/7/2008													*
 * Purpose: OriginC Header file for PA fit Preview								*
 * Copyright (c) Originlab Corp. 2003, 2004, 2005, 2006, 						*
 * All Rights Reserved															*
 *	Folger 01/04/09 QA80-12962 MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
 *	Folger 02/03/09 PA_FITTING_WITH_BASELINE_FAILS_TO_GET_CORRECT_RESIDUAL_DATA	*
 *	Folger 02/04/09 QA80-12962 ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
 *	Folger 02/10/09 PA_FITTING_FAILS_TO_PREPARE_RESIDUAL_DATA_FOR_SINGLE_PEAK_CASE
 *	Folger 11/24/09 SHOULD_NOT_RESCALE_PREIVEW_AFTER_CHANGE_FUNCTION_IN_PA_FITTING
 *------------------------------------------------------------------------------*/
 
#ifndef _PEAKFIT_PREVIEWCTRL_H_
#define _PEAKFIT_PREVIEWCTRL_H_
#include "NLFitPreviewCtrl.h"
#include "PeakFitCurves.h"

//-------------------------------------PeakFitPreviewCtrl class begin (General XY Fitting Preview ctrl class)---------------------------------------	
//#define	DERIVATIVE_WKS_NAME	"DerivateWks" /// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
class PeakFitPreviewCtrl : public NLFitPreviewCtrl
{
public:
	PeakFitPreviewCtrl(NLFitSession* pNLFSession)
	{
		m_pNLFSession = pNLFSession;
		m_PreviewCtrlInfo.bPlotCumulativeCurve = true; ///Sophy, follow old pa preview logic
	}
	
	//virtual
	bool 	UpdatePreviewGraph(DWORD dwUpdateBits = FITPREVIEW_INIT, PreviewCtrlInfo* pPreviewCtrlInfo = NULL, bool* pUpdateLegend = NULL);
	
	//virtual
	//bool 	SetPreviewGraph(GraphPage& gp, int nType, int nLayer = 0); /// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	
	/// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	//void	SetShowSpecialPreview( bool bShowResidual, bool bShow2ndDerivative ); 
	void	SetShowSpecialPreview( bool bShowResidual ); 
	///end  MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	
protected:
	//virtual 
	NLFCurvesBase* GetNLFCurvesObject() 
	{  
		if(NULL == m_pNLFCurves)
		{
			ASSERT(m_pNLFSession);
			m_pNLFCurves = new PeakFitCurves(m_pNLFSession);
		}
		return m_pNLFCurves;
	} 
	///------ Folger 01/04/09 QA80-12962 MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	///virtual
	int  GetXDataColIndex(int nDataset = 0, int nPeaks = 1, int nPeak = -1);

	///virtual
	int  GetYDataColIndex(int nDataset = 0, int nPeak = 0, int nPeaks = 1);
	///------ End MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	
	///------ Folger 02/03/09 PA_FITTING_WITH_BASELINE_FAILS_TO_GET_CORRECT_RESIDUAL_DATA
	/// virtual
	void SubtractBaseline(const vector vx, vector& vy);
	///------ End PA_FITTING_WITH_BASELINE_FAILS_TO_GET_CORRECT_RESIDUAL_DATA
	
	///------ Folger 02/10/09 PA_FITTING_FAILS_TO_PREPARE_RESIDUAL_DATA_FOR_SINGLE_PEAK_CASE
	/// virtual
	int GetResidualYDataColIndex(int nDataset = 0, int nPeak = 0, int nPeaks = 1);
	///------ End PA_FITTING_FAILS_TO_PREPARE_RESIDUAL_DATA_FOR_SINGLE_PEAK_CASE
	
private:
	//method
	//virtual
	//bool	updatePreviewData( DWORD dwUpdateBits ); /// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	
	// bool	updateDerivativeData(); /// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	
	int		setupResidualPlot(); ///Sophy, already do plot in base class, just need to setup plot style
	//int		plotDerivative(); /// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
		
	//virtual
	//bool	reloadPreviewTemplate(); /// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	
	///Sophy 10/6/2008 PA_PREVIEW_FIX_2ND_DERIVATIVE_GRAPHLAYER_WRONGLY_RESCALE
	//virtual
	int		getNeedRescaleLayerNum(const GraphPage& pg) { return 1;}
	///end PA_PREVIEW_FIX_2ND_DERIVATIVE_GRAPHLAYER_WRONGLY_RESCALE	
	
	///------ Folger 01/04/09 QA80-12962 MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	/// virtual
	int		getNumIndividualFitCurveCol(int nWksType = WKS_FIT_CURVES);
	
	/// virtual
	void 	setWksColTypeAndFormat(Worksheet& wks, int nColumns, int nXNumCols = 1);
	
	/// virtual
	bool	getFitDataRange(DataRange& drFit, int nDatasetIndex, int nPeak, int nPeaks, bool bIncCumulativeCurve = false, bool bIncPeakCurve = true );
	///------ End MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
private:
	//member data	
	//bool				m_bShowResidual;	// Kyle, move to base class
	/// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	/*
	bool				m_bShowDerivative;	
	Worksheet			m_wksDerivative;
	int					m_nDerivativeLayer;
	GraphPage			m_gpDerivative;
	*/
	///end MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
};

//virtual
bool 	PeakFitPreviewCtrl::UpdatePreviewGraph(DWORD dwUpdateBits, PreviewCtrlInfo* pPreviewCtrlInfo, bool* pUpdateLegend ) //INIT, NULL, NULL;
{
	///Sophy 10/6/2008 FIX_REMOVE_SOURCE_PLOT_BY_MISTAKE_WHEN_UNDO_PA_FIT
	if( FITPREVIEW_REMOVE_FITS == dwUpdateBits )
	{
		m_bShowResidual = false;
		if( m_gpResidual )
			m_gpResidual.Detach();
		/// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
		//m_bShowDerivative = false;
		//if( m_gpDerivative )
		//	m_gpDerivative.Detach();
		///end MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	}
	///end FIX_REMOVE_SOURCE_PLOT_BY_MISTAKE_WHEN_UNDO_PA_FIT
	///------ Folger 11/24/09 SHOULD_NOT_RESCALE_PREIVEW_AFTER_CHANGE_FUNCTION_IN_PA_FITTING
	GraphLayer glResidual = m_gpResidual.Layers( m_nResidualLayer );
	if ( glResidual )
	{
		if ( O_QUERY_BOOL(dwUpdateBits, FITPREVIEW_REPLOT) )
			layer_set_link(glResidual, -1);
	}
	///------ End SHOULD_NOT_RESCALE_PREIVEW_AFTER_CHANGE_FUNCTION_IN_PA_FITTING
	bool bRet = NLFitPreviewCtrl::UpdatePreviewGraph( dwUpdateBits, pPreviewCtrlInfo, pUpdateLegend );
	if( !bRet )
		return false;
	
	///------ Folger 11/24/09 SHOULD_NOT_RESCALE_PREIVEW_AFTER_CHANGE_FUNCTION_IN_PA_FITTING
	//GraphLayer glResidual = m_gpResidual.Layers( m_nResidualLayer );	
	///------ End SHOULD_NOT_RESCALE_PREIVEW_AFTER_CHANGE_FUNCTION_IN_PA_FITTING
	if( m_bShowResidual )
		bRet = setupResidualPlot();
	
	/// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	//GraphLayer glDerivative = m_gpDerivative.Layers( m_nDerivativeLayer );
	//if( m_bShowDerivative )
	//	bRet = plotDerivative();
	///end MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	
	return bRet;
}

/// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
/*
//virtual
bool	PeakFitPreviewCtrl::updatePreviewData( DWORD dwUpdateBits )
{
	bool bRet = NLFitPreviewCtrl::updatePreviewData( dwUpdateBits );
	if( !bRet )
		return false;
	
	if( m_bShowDerivative )
		bRet = updateDerivativeData();
	
	return bRet;
}

bool	PeakFitPreviewCtrl::updateDerivativeData()
{
	vector vx, vy;
	m_pNLFSession->GetInputData( vx, vy );
	
	if( !m_wksDerivative.IsValid() )
	{
	#ifdef IS_PREVIEW_DEBUG_MODE
			m_wksDerivative.Create(NULL, CREATE_HIDDEN);
	#else
			m_wksDerivative.Create(NULL, CREATE_HIDDEN  | CREATE_SET_MISSING_IN_MANAGER);
	#endif
	}
	
	XYRange xyr;
	xyr.Add("X", m_wksDerivative, 0, 0, -1, 0);
	xyr.Add("Y", m_wksDerivative, 0, 1, -1, 1);	
	
	Column col;
	xyr.GetYColumn(col);
	col.SetLongName("2nd Derivative");

	vector v2ndDeriv;
	v2ndDeriv = vy;
	if(OE_NOERROR != ocmath_derivative(vx, v2ndDeriv, v2ndDeriv.GetSize()))
	{
		return false;
	}	
	
	if(OE_NOERROR != ocmath_derivative(vx, v2ndDeriv, v2ndDeriv.GetSize()))
	{
		return false;
	}
	
	xyr.SetData(&v2ndDeriv, &vx);
	
	return true;
}
*/
////end MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE

int		PeakFitPreviewCtrl::setupResidualPlot()
{
	GraphLayer	glResidual = m_gpResidual.Layers( m_nResidualLayer );
	glResidual.LT_execute("layer.x.atZero=1");
	
	DataPlot	dp = glResidual.DataPlots();
	ASSERT( dp );
	
	//dataplot format
	Tree	trFormat;
	trFormat.Root.Symbol.Shape.nVal =11;// spheres
	trFormat.Root.Symbol.Size.nVal = 1;
	trFormat.Root.Symbol.EdgeColor.nVal = SYSCOLOR_BLUE;
	trFormat.Root.DropLines.Vertical.nVal = 1;
	trFormat.Root.DropLines.VerticalWidth.nVal = 5;
	trFormat.Root.DropLines.VerticalColor.nVal = SYSCOLOR_BLUE;

	int nRet = dp.UpdateThemeIDs(trFormat.Root);
	if(0==nRet)
		dp.ApplyFormat(trFormat, true, true);
	else
		error_report("plot settings tree construction error");
	
	//graphlayer format
	Tree trGL;
	trGL.Root.Speed.Worksheet.nVal = 1;
	trGL.Root.Speed.Max.nVal = 30000;
	
	nRet = glResidual.UpdateThemeIDs(trGL.Root);
	if(0==nRet)
		glResidual.ApplyFormat(trGL, true, true);
	else
		error_report("gl settings tree construction error");

	glResidual.Rescale(ANL_NO_Y_EXPAND);
	layer_set_link(glResidual, 0, 1);
	apply_speed_mode( glResidual, 0, 1, 30000, 0, 0, 0 ); //SPEED_MODE_OFF;
	
	return 0;
}

/// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
/*
int		PeakFitPreviewCtrl::plotDerivative()
{
	XYRange xyRange;
	
	xyRange.Add("X", m_wksDerivative, 0, 0, -1, 0);
	xyRange.Add("Y", m_wksDerivative, 0, 1, -1, 1);
	
	if(!xyRange.IsValid())
		return 0;
	
	GraphLayer gl = m_gpDerivative.Layers( m_nDerivativeLayer );
	
	vector<int> 	vnPlotIndices;
	if( check_has_plotted_in_graph(xyRange, gl, vnPlotIndices) > 0 )
		return vnPlotIndices[0];
	
	int nRet = gl.AddPlot(xyRange, IDM_PLOT_LINE);
	if( nRet >= 0)
		gl.Rescale();
	
	gl.Rescale(ANL_NO_Y_EXPAND);
	layer_set_link(gl, 0, 1);
	
	return nRet;
}

//virtual
bool	PeakFitPreviewCtrl::reloadPreviewTemplate()
{
	bool	bRet = NLFitPreviewCtrlBase::reloadPreviewTemplate();
	if( !bRet )
		return false;
	
	DWORD 	dwNoClicks = NLFIT_PREVIEW_NOCLICK_BITS;
	string strTemplate;
	
	strTemplate = m_bIsNonePreview? NLSF_NO_PREVIEW_TEMPLATE : GetTemplate(true);
	page_load(m_gpDerivative, strTemplate, dwNoClicks);
	return bRet;
	
}
*/
///end MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE

/// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
/*
//virtual
bool 	PeakFitPreviewCtrl::SetPreviewGraph(GraphPage& gp, int nType, int nLayer)
{
	if( PREIVEW_2ND_DE == nType )
	{
		GraphLayer gl = gp.Layers( nLayer );
		if( !gl)
			return false;
		m_gpDerivative = gp;
		m_nDerivativeLayer = nLayer;
		return true;
	}
	else
		return NLFitPreviewCtrlBase::SetPreviewGraph(gp, nType, nLayer);
}

void	PeakFitPreviewCtrl::SetShowSpecialPreview( bool bShowResidual, bool bShow2ndDerivative )
{
	m_bShowResidual = bShowResidual;
	m_bShowDerivative = bShow2ndDerivative;
}
///end NEW_PA_ADD_ADVANCE_PREVIEW_GRAPH_SUPPORT
*/
void	PeakFitPreviewCtrl::SetShowSpecialPreview( bool bShowResidual)
{
	m_bShowResidual = bShowResidual;
}
///end MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE

///------ Folger 01/04/09 QA80-12962 MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
///virtual
int		PeakFitPreviewCtrl::getNumIndividualFitCurveCol(int nWksType/* = WKS_FIT_CURVES*/)
{
	if ( m_pNLFSession->GetUseSmartX() && nWksType == WKS_FIT_CURVES )		///------ Folger 02/04/09 QA80-12962 ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
		return 2 * m_pNLFSession->GetNumPeaks();
	
	return NLFitPreviewCtrl::getNumIndividualFitCurveCol(nWksType);
}

///virtual
int  PeakFitPreviewCtrl::GetXDataColIndex(int nDataset/* = 0*/, int nPeaks/* = 1*/, int nPeak/* = -1*/)
{
	// always has cumulative data column in normal xy fit, so columns are XCumulative, YCumulative, FitCurveX1, FitCurveY1, FitCurveX2, FitCurveY2...
	ASSERT(nDataset == 0);
	///------ Folger 02/04/09 QA80-12962 ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
	if ( !m_pNLFSession->GetUseSmartX() )
		return NLFitPreviewCtrl::GetXDataColIndex(nDataset, nPeaks, nPeak);
	///------ End ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
	if ( nPeak < 0 )
		return 0;		/// cumulative X column, can assume 0
	
	return NUM_DATASET_PER_FITTED_CURVE + 2 * nPeak;
}

///virtual
int  PeakFitPreviewCtrl::GetYDataColIndex(int nDataset/* = 0*/, int nPeak/* = 0*/, int nPeaks/* = 1*/)
{
	ASSERT(nDataset == 0);
	///------ Folger 02/04/09 QA80-12962 ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
	if ( !m_pNLFSession->GetUseSmartX() )
		return NLFitPreviewCtrl::GetYDataColIndex(nDataset, nPeak, nPeaks);
	///------ End ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
	return GetXDataColIndex(nDataset,nPeaks, nPeak) + 1;
}

/// virtual
void 	PeakFitPreviewCtrl::setWksColTypeAndFormat(Worksheet& wks, int nColumns, int nXNumCols/* = 1*/)
{
	NLFitPreviewCtrl::setWksColTypeAndFormat(wks, nColumns, nXNumCols);
	///------ Folger 02/04/09 QA80-12962 ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
	if ( !m_pNLFSession->GetUseSmartX() )
		return;
	///------ End ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
	int		nPeaks = m_pNLFSession->GetNumPeaks();
	for ( int nPeak=0; nPeak<nPeaks; ++nPeak )
	{
		Column col(wks, GetXDataColIndex(0, nPeaks, nPeak));
		if ( col )
			col.SetType(OKDATAOBJ_DESIGNATION_X);
	}
}

///virtual
bool	PeakFitPreviewCtrl::getFitDataRange(DataRange& drFit, int nDatasetIndex, int nPeak, int nPeaks, bool bIncCumulativeCurve/* = false*/, bool bIncPeakCurve/* = true*/ )
{
	///------ Folger 02/04/09 QA80-12962 ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
	if ( !m_pNLFSession->GetUseSmartX() )
		return NLFitPreviewCtrl::getFitDataRange(drFit, nDatasetIndex, nPeak, nPeaks, bIncCumulativeCurve, bIncPeakCurve);
	///------ End ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
	if(!m_FitCurvesWks.IsValid())
	{
		error_report("Found invalid m_FitCurvesWks in getFitDataRange");
		return false;
	}
	
	Dataset dsTempX,  dsTempY;
	int nXCol;
	int nYCol;
	
	if( nPeaks > 0 && bIncPeakCurve)
	{
		int		nNumPeaks = nPeak + 1;
		if ( nPeak < 0 )
		{
			nNumPeaks = nPeaks;
			nPeak = 0;
		}
		for ( ; nPeak<nNumPeaks; ++nPeak )
		{
			nXCol = GetXDataColIndex(nDatasetIndex, nPeaks, nPeak);
			dsTempX.Attach(m_FitCurvesWks, nXCol);
			nYCol = GetYDataColIndex(nDatasetIndex, nPeak, nPeaks );
			dsTempY.Attach(m_FitCurvesWks, nYCol);
			
			if ( !dsTempX || !dsTempY )
				return false;
			drFit.Add("X", m_FitCurvesWks, 0, nXCol , -1, nXCol);
			drFit.Add("Y", m_FitCurvesWks, 0, nYCol , -1, nYCol);
			drFit.Add("S", NULL);
		}
	}
	
	return NLFitPreviewCtrl::getFitDataRange(drFit, nDatasetIndex, nPeak, nPeaks, bIncCumulativeCurve, false);
}
///------ End MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA

///------ Folger 02/03/09 PA_FITTING_WITH_BASELINE_FAILS_TO_GET_CORRECT_RESIDUAL_DATA
/// virtual
void	PeakFitPreviewCtrl::SubtractBaseline(const vector vx, vector& vy)
{
	if ( m_pNLFSession->GetSubtractedMode() )
		return;
	
	vector	vBaselineX, vBaselineY;
	m_pNLFSession->GetBaselineData(vBaselineX, vBaselineY, NULL, false);
	subtract_baseline(vx, vy, vBaselineX, vBaselineY);
}
///------ End PA_FITTING_WITH_BASELINE_FAILS_TO_GET_CORRECT_RESIDUAL_DATA

///------ Folger 02/10/09 PA_FITTING_FAILS_TO_PREPARE_RESIDUAL_DATA_FOR_SINGLE_PEAK_CASE
/// virtual
int		PeakFitPreviewCtrl::GetResidualYDataColIndex(int nDataset/* = 0*/, int nPeak/* = 0*/, int nPeaks/* = 1*/)
{
	int nXCol = GetXDataColIndex(nDataset, nPeaks);
	return nXCol + 1;
}
///------ End PA_FITTING_FAILS_TO_PREPARE_RESIDUAL_DATA_FOR_SINGLE_PEAK_CASE

#endif _PEAKFIT_PREVIEWCTRL_H_
