#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	range_row,
	range_energy,
};
enum{
	method_shirley,
	method_tougaard,
};
enum{
	option_bh,
	option_ap,
};


//put additional include files here
#include <..\OriginLab\ocPFM.h>
#include <..\OriginLab\PAWizCore.h>
#include <..\OriginLab\XFWizard_utils.h>
#include <event_utils.h>

//------ Folger 12/11/08 v8.0985 ADD_HELPID_FOR_PAXPS
#include <o8dlg.h>
//------
/*------------------------------------------------------------------------------*
 * Modification Log:  															*
 *	Folger 12/03/08 v8.0982 CHECK_CREATE_BASELINE_SHOULD_BE_MEMBER_OF_PAWIZCORE	*
 *	Folger 12/11/08 v8.0985 ADD_HELPID_FOR_PAXPS								*
 *	Sim 01-07-2008 QA80-12833 FIX_APPLY_XF_WIZ_XF_TWICE							*
 *------------------------------------------------------------------------------*/

static void _update_gui(TreeNode& trGetN)
{
	trGetN.r1.Show = trGetN.r2.Show = 	(trGetN.range.nVal == range_row? true:false);
	trGetN.e1.Show = trGetN.e2.Show = 	(trGetN.range.nVal == range_energy? true:false);
	
	trGetN.option.Show = (trGetN.method.nVal == method_tougaard? true:false);
	if(trGetN.method.nVal == method_tougaard)
	{
		trGetN.option.Show = true;
		trGetN.bh.Show = (trGetN.option.nVal == option_bh? true:false);
		trGetN.b1.Show = (trGetN.option.nVal == option_ap? true:false);
	}
	else
	{
		trGetN.b1.Show = false;
		trGetN.bh.Show = true;
		trGetN.option.nVal = option_bh;
		
	}

}

///Sandy 2008-12-24 enlarge range input type to double as energy
//static bool	calc_tougaard_baseline(const vector& vx,const vector& vy, vector& vbx, vector& vby, int iMin, int iMax, int nBase, double dBaseHeight)
static bool	calc_tougaard_baseline(const vector& vx,const vector& vy, vector& vbx, vector& vby, double dStart, double dEnd, int nBase, double dBaseHeight, bool bIndexOrEnergyInput)
{

	int nSize = vy.GetSize();
	if(vx.GetSize() != nSize || nSize < 2)
	{
		return false;
	}

	bool bBase;
	bBase = (bool)nBase;
	vbx = vx;
	vby.SetSize(nSize);
	bBase = !bBase;//Sandy 2008-11-24 when this Flag is false, the parameter means final height.
	
	
	//int nRet=opfm_tougaard(vx, vy, nSize, iMin, iMax, bBase, dBaseHeight, vby);	
	int nRet=opfm_tougaard(vx, vy, nSize, dStart, dEnd, bBase, dBaseHeight, vby, bIndexOrEnergyInput);	///Sandy 2008-12-24 enlarge range input type to double as energy

	if(nRet != 0)
	{
		error_report("opfm_tougaard fail");
		return false;
	}
	return true;
}

///Sandy 2008-12-24 enlarge range input type to double as energy
//static bool	calc_shirley_baseline(const vector& vx,const vector& vy, vector& vbx, vector& vby, int iMin, int iMax, double dBaseHeight)
static bool	calc_shirley_baseline(const vector& vx,const vector& vy, vector& vbx, vector& vby, double dStart, double dEnd, double dBaseHeight, bool bIndexOrEnergyInput)
{
		
	int nSize = vy.GetSize();
	if(vx.GetSize() != nSize || nSize < 2)
	{
		return false;
	}

	vbx = vx;
	vby.SetSize(nSize);
	
	///Sandy 2008-12-24 enlarge range input type to double as energy
	//int nRet=opfm_shirley(vx, vy, nSize, iMin, iMax, dBaseHeight, vby);	
	int nRet=opfm_shirley(vx, vy, nSize, dStart, dEnd, dBaseHeight, vby, bIndexOrEnergyInput);	

	if(nRet != 0)
	{
		error_report("opfm_shirley fail");
		return false;
	}
	return true;
}

static bool _check_inputs(TreeNode& trGetN, string& strErrMsg)
{
	int nSize;
	XYRange xy;
	TreeNode trXY = trGetN.iy;
	if(!trXY.IsValid()|| !okxf_resolve_tree_construct_range(&trXY, &xy))
	{
		strErrMsg = CER_INVALID_XYRANGE; 
		return false;
	}
	vector vx, vy;
	if(!xy.GetData(vy, vx) || vy.GetSize() < 1)
	{
		strErrMsg = XFERR_GET_DATA_FAILED;	
		return false;
	}
	
	double dXMin, dXMax;
	//vx.GetMinMax(dXMin, dXMax);
	uint nIndexMin, nIndexMax;
	vx.GetMinMax(dXMin, dXMax, &nIndexMin, &nIndexMax);
	nSize = vx.GetSize();
	
	///Sandy 2009-2-6 add auto optional string to compute data-relative variable
	double dMinY = vy[nIndexMin];
	_auto_parameters(nSize,dXMin,dXMax,dMinY, trGetN.r1, trGetN.r2, trGetN.e1, trGetN.e2, trGetN.bh, trGetN.b1);
	
	
	//if(trGetN.range.nVal == range_energy && (trGetN.e1.dVal < dXMin || trGetN.e2.dVal > dXMax))
	//{
		//strErrMsg = XFERR_INVALID_ARG; 
		//return false;		
	//}
	if(trGetN.range.nVal == range_row && (trGetN.r1.dVal < 1 || trGetN.r2.dVal > nSize))
	{
		strErrMsg = XFERR_INVALID_ARG; 
		return false;		
	}	
	

	
	return true;
}

static int _xps_baseline(const XYRange& iy, const int& range, const int& r1, const int& r2, const double& e1, const double& e2, 
		const int& method, const int& option, const double& bh, const double& b1, vector& vbx, vector& vby)
{
	vector vtx, vty;
		
	if(!iy.GetData(vty, vtx) || vtx.GetSize() < 10)
	{
		return XFERR_INVALID_ARG;
	}
	
	vector<uint> vn;
	vtx.Sort(SORT_ASCENDING, true, vn);
	vty.Reorder(vn);
	
	///Sandy 2008-12-24 enlarge range input type to double as energy
	//int rr1, rr2;
	double dr1, dr2;
	bool bIndexOrEnergyInput;
	if(range == range_energy)
	{
		//vector<uint> vecIndex1, vecIndex2;
	    //if( vtx.Find(vecIndex1, e1) == -1 ||  vtx.Find(vecIndex2, e2) == -1)
	    	//{
	    		//return XFERR_INVALID_ARG;
	    	//}
		//rr1 = vecIndex1[0];
		//rr2 = vecIndex2[0];
		dr1 = e1;
		dr2 = e2;
		bIndexOrEnergyInput = false;
	}
	else
	{
		//rr1 = r1-1;
		//rr2 = r2-1;
		dr1 = r1-1;
		dr2 = r2-1;
		bIndexOrEnergyInput = true;
	}
	
	//vector vx, vy;
	//vtx.GetSubVector(vx, rr1, rr2);
	//vty.GetSubVector(vy, rr1, rr2);
	
	int nSize = vty.GetSize();
	if(method == method_shirley)
	{
		///Sandy 2008-12-24 enlarge range input type to double as energy
		//if(!calc_shirley_baseline(vtx, vty, vbx, vby, rr1, rr2,  bh))
		if(!calc_shirley_baseline(vtx, vty, vbx, vby, dr1, dr2,  bh, bIndexOrEnergyInput))
		{
			return XFERR_INVALID_ARG;
		}
	}
	else if(method == method_tougaard)
	{
		double dd;
		if(option == option_bh)
			dd = bh;
		else
			dd = b1;
		
		///Sandy 2008-12-24 enlarge range input type to double as energy
		//if(!calc_tougaard_baseline(vtx, vty, vbx, vby, rr1, rr2, option, dd))
		if(!calc_tougaard_baseline(vtx, vty, vbx, vby, dr1, dr2, option, dd, bIndexOrEnergyInput))
		{
			return XFERR_INVALID_ARG;
		}
	}
	
    //vector vxTemp, vyTemp;
    //vxTemp = vtx;
    //vyTemp = vty;
    //
    //vyTemp.SetSubVector(vby, rr1);
	

	return true;
}

///Sandy 2009-2-6 add auto optional string to compute data-relative variable
void  _auto_parameters(int nSize, double dXMin, double dXMax, double dMinY, TreeNode trR1, TreeNode trR2, TreeNode trE1, TreeNode trE2, TreeNode trBH, TreeNode trB1)
{
		//double e1 = trGetN.e1.dVal;
		//double e2 = trGetN.e2.dVal;
		//trGetN.e1.dVal = (e1 == NANUM  ? dXMin : e1);
		//trGetN.e2.dVal = (e2 == NANUM  ? dXMax : e2);
		//trGetN.r1.dVal = (trGetN.r1.dVal == 0  ?     1 : trGetN.r1.dVal);
		//trGetN.r2.dVal = (trGetN.r2.dVal == -1 ? nSize : trGetN.r2.dVal);
		//trGetN.bh.dVal = (trGetN.bh.dVal == NANUM ? vy[nIndexMin] : trGetN.bh.dVal);
		//trGetN.b1.dVal = (trGetN.b1.dVal == NANUM ? 0 : trGetN.b1.dVal);
	if ( 1 == octree_get_auto_support(&trR1) )
	{
		trR1.dVal =  1;
	}
	if ( 1 == octree_get_auto_support(&trR2) )
	{
		trR2.dVal =  nSize;
	}
	if ( 1 == octree_get_auto_support(&trE1) )
	{
		trE1.dVal =  dXMin;
	}
	if ( 1 == octree_get_auto_support(&trE2) )
	{
		trE2.dVal =  dXMax;
	}
	if ( 1 == octree_get_auto_support(&trBH) )
	{
		trBH.dVal =  dMinY;
	}
	if ( 1 == octree_get_auto_support(&trB1) )
	{
		trB1.dVal =  0;
	}
}


void pa_xpsbase(const XYRange& iy, const int& range, const int& r1, const int& r2, const double& e1, const double& e2, const int& method, const int& option, const double& bh, const double& b1, const int& nXFCorePointer, XYRange& oyb, const TreeNode& btn_subtract, const int& subtract)
{
							   
	vector vbx, vby;
	string strErrMsg;
	int nRet = _xps_baseline(iy, range,  r1,  r2, e1,  e2,  method, option,  bh,  b1, vbx, vby);
	if(!nRet)
		XF_THROW(nRet);
	
	///---Sim 01-07-2008 QA80-12833 FIX_APPLY_XF_WIZ_XF_TWICE
	//PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(getnhandler);
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(NODE_NAME_XF_WIZ_CORE_POINTER);
	///---END QA80-12833 FIX_APPLY_XF_WIZ_XF_TWICE
	if(!paCore)
		XF_THROW(XF_ERR_INVALID_PA_INSTANCE);	
		
	paCore->SetXPSMethod(method);///---Sandy 2008-11-18 add for keep this info for report of fitting
	
	XYRange xyBaseline;
	if(paCore->GetBaselineRange(xyBaseline) && xyBaseline.IsValid())
		xyBaseline.SetData(&vby, &vbx, 0, NULL, DRS_SET_COL_DESIGNATIONS);	
		
	///Sandy 2008-12-30 centralize code to pawizcore		
	int goal = paCore->GetCurrGoal();
	if(goal == PA_GOAL_CREATE_BASELINE )//if goal is create baseline, baseline should output to user assigned dataset
	{
		output_baseline_if_create_baseline(iy, oyb, paCore, vbx, vby);
	}
	
}

//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 pa_xpsbase_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return pa_xpsbase_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
	ASSERT(paCore);
	
	_update_gui(trGetN);
	bOKEnable = _check_inputs(trGetN, strErrMsg);
	if(bOKEnable)
	{
		if(GETNE_ON_INIT == nEventID)
			//------ Folger 12/03/08 v8.0982 CHECK_CREATE_BASELINE_SHOULD_BE_MEMBER_OF_PAWIZCORE
			//create_baseline_plot(paCore);
			paCore->CheckCreateBaselinePlot();
			//------
		TreeNode trInput = trGetN.iy;
		if(!trInput)
			strErrMsg = XFERR_INVALID_RANGE;
		XYRange xyi;
		if( !okxf_resolve_tree_construct_range(&trInput, &xyi) || !xyi.IsValid())
			strErrMsg = XFERR_INVALID_RANGE;
		
	
		vector vbx, vby;
		int nErrCode = _xps_baseline(xyi, trGetN.range.nVal,  trGetN.r1.nVal,  trGetN.r2.nVal, trGetN.e1.dVal,  trGetN.e2.dVal,  trGetN.method.nVal, 
					 trGetN.option.nVal,  trGetN.bh.dVal,  trGetN.b1.dVal,  vbx, vby);
					 
		if(!nErrCode)
			strErrMsg = nErrCode;
		else
		{
			XYRange xyBaseline;
			if(paCore->GetBaselineRange(xyBaseline) && xyBaseline.IsValid())
				xyBaseline.SetData(&vby, &vbx, 0, NULL, DRS_SET_COL_DESIGNATIONS);	
		}
	
	}
	
	///Sandy 2008-12-30 centralize code to pawizcore
	if(process_create_baseline_handler(trGetN, nEventID, lpcszNodeName, paCore))
		return true;
	
	return true;

}

int pa_xpsbase_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	
	return 0;
}
//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 pa_xpsbase_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	
	if(nGetNDialog>=0)
	{
		PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
		if(!paCore)
		{
			nRet = XFEVT_ABORT;
			return;
		}			
		//Sandy 2008-10-23 add for output "<input>,<input>" range to source wks
		paCore->SetOriginalRangeToGetN(trGetN.iy);	
		
		//------ Folger 12/11/08 v8.0985 ADD_HELPID_FOR_PAXPS
		trGetN.SetAttribute(STR_HELPID_ATTRIB, IDD_PA_XPS_BASELINE);
		//------
		string strErrMsg;
		int nSize;
		XYRange xy;
		TreeNode trXY = trGetN.iy;
		if(!trXY.IsValid()|| !okxf_resolve_tree_construct_range(&trXY, &xy))
		{
			strErrMsg = CER_INVALID_XYRANGE; 
			xf_warning_msg_box(strErrMsg, false, 'E');
			nRet = XFEVT_ABORT;	
		}
		vector vx, vy;
		if(!xy.GetData(vy, vx) || vy.GetSize() < 1)
		{
			strErrMsg = XFERR_GET_DATA_FAILED;	
			xf_warning_msg_box(strErrMsg, false, 'E');
			nRet = XFEVT_ABORT;	
		}
		double dXMin, dXMax;
		uint nIndexMin, nIndexMax;
		vx.GetMinMax(dXMin, dXMax, &nIndexMin, &nIndexMax);
		nSize = vx.GetSize();
		
		///Sandy 2009-2-6 add auto optional string to compute data-relative variable
		/////---Sandy 2008-12-19 don't replace if the value is valid
		////trGetN.e1.dVal = dXMin;
		////trGetN.e2.dVal = dXMax;
		////trGetN.r1.dVal = 1;
		////trGetN.r2.dVal = nSize;
		//double e1 = trGetN.e1.dVal;
		//double e2 = trGetN.e2.dVal;
		//trGetN.e1.dVal = (e1 == NANUM  ? dXMin : e1);
		//trGetN.e2.dVal = (e2 == NANUM  ? dXMax : e2);
		//trGetN.r1.dVal = (trGetN.r1.dVal == 0  ?     1 : trGetN.r1.dVal);
		//trGetN.r2.dVal = (trGetN.r2.dVal == -1 ? nSize : trGetN.r2.dVal);
		////trGetN.bh.dVal = vy[nIndexMin];
		//trGetN.bh.dVal = (trGetN.bh.dVal == NANUM ? vy[nIndexMin] : trGetN.bh.dVal);
		//trGetN.b1.dVal = (trGetN.b1.dVal == NANUM ? 0 : trGetN.b1.dVal);
		/////---end of don't replace if the value is valid
		double dMinY = vy[nIndexMin];
		_auto_parameters(nSize,dXMin,dXMax,dMinY, trGetN.r1, trGetN.r2, trGetN.e1, trGetN.e2, trGetN.bh, trGetN.b1);
		update_dataformat_start_end_interval(trGetN.iy, trGetN, "e1", "e2");
		
	
		
		///Sandy 2008-12-30 Greg  suggested open xps baseline when create baseline, 
		process_create_baseline_before_execute(trGetN, dwCntrl, paCore);
	}
	    
}
//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 pa_xpsbase_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
