#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
//put additional include files here
#include <..\Originlab\curve_utils.h>
#include <okocUtils.h> ///okoc_out_msg

#include <event_utils.h>		///------ Folger 03/13/09 QA80-13262 CONVERT_OBJECT_VARIABLE_OPTIOANL_TO_NEW_IN_XF_DIALOG

// Modification Log
// CPY 12/8/2007 QA80-10788 FIND_FLAT_REGIONS_IN_CURVE remove Cloud's code and start new codes	
// Folger 03/13/09 QA80-13262 CONVERT_OBJECT_VARIABLE_OPTIOANL_TO_NEW_IN_XF_DIALOG
/// Folger 04/10/09 QA80-13262-P2 OPTIONAL_SHOWN_INSTEAD_OF_NEW_AFTER_RESET_THEME
#define MAX_BASE_REGIONS 100
#define SHOW_INTERNAL_MSGS 1


void findBase(const XYRange& iy, const double& flat, const int& dir, const double& h, const double& pts, const double& tol, const double& max, const double& step, int& i1, int& i2, double& a, double& b, double& aerr, double& berr, double& r, XYRange& oy, const int& cntrl)
{
	vector vxData, vyData;
	
	if( !iy.GetData(vyData, vxData) )
		XF_THROW(XFERR_GET_DATA_FAILED);
	
	int nSize = vxData.GetSize();
	int N = flat >= 1.0? (0.5 + flat) : (0.5 + flat*nSize);
	double dMax = max; // fraction of data to do the baseline search
	if(max >= 1.0) // user is specifying number of points
		dMax = max / nSize;// then we convert it to fraction of total size
	//number of points to do initial fit for subsequent comparison
	int nPts0 = pts >= 1.0? (0.5 + pts) : (0.5 + pts*nSize);
	if(nPts0 < 2) nPts0 = 2;
	int nStep;
	if(step == 0)
		nStep = 0;
	else
		nStep = pts >= 1.0? (0.5 + step) : (0.5 + step*nSize);
	
	vector<int> vBegs, vEnds;
	int nRet;
	if(dir != 0) // begin or end
	{
		int nOffset = abs(dir) -1; // 1 and -1 will have no offset
		int i2;
		nRet = ocmath_check_linear(nSize, vxData, vyData, &i2, dMax, tol, nOffset, dir>0?true:false, nPts0, nStep);
		int i1 =  dir> nOffset? 0 : nSize- nOffset-1;
		if(nRet == OE_NOERROR)
		{
			int it;
			if(dir < 0) {SWAP(i1, i2, it);}
			if(i2 > i1 + 1)
			{
				vBegs.Add(i1);
				vEnds.Add(i2);
			}
		}
	}
	else
	{
		//nRet = find_base_regions(vxData, vyData, N, vBegs, vEnds, tol, dMax, chk);
		vBegs.SetSize(MAX_BASE_REGIONS);
		vEnds.SetSize(MAX_BASE_REGIONS);
		nRet = ocmath_find_base_regions(nSize, vxData, vyData, N, MAX_BASE_REGIONS, vBegs, vEnds, tol, dMax, nPts0);
		if (nRet > 0)
		{
			vBegs.SetSize(nRet);
			vEnds.SetSize(nRet);
		}
	}
	if(nRet < 0)
	{
		out_int("nRet = ", nRet);
		XF_THROW(XFERR_FAIL_EVAL);
	}
	int nn = vBegs.GetSize();
	int nFound = -1, nRange = -1;
	if(nn == 0)
	{
		i1 = 0, i2 = 0;
		return;
	}
	
	LRresults* pResults = (LRresults*)malloc(sizeof(LRresults) * nn);
	/// Cloud 12/11/07 QA80-10788 USE_OCMATH
	//if(fit_linear_multi_regions(vxData, vyData, vBegs, vEnds, pResults) <= 0)
	if(ocmath_fit_linear_multi_regions(nSize, vxData, vyData, nn, vBegs, vEnds, pResults) <= 0)
	/// End USE_OCMATH
	{
		free(pResults);
		XF_THROW(XFERR_FAIL_EVAL);
	}
	LRresults* pp = pResults;
	for(int ii = 0 ; ii < vBegs.GetSize(); ii++, pp++)
	{
		if(h != 0 && fabs(pp->b) > h)
			continue;
		nn = pp->i2 - pp->i1;
		if(cntrl & SHOW_INTERNAL_MSGS)
		{
			string strMsg;
			strMsg.Format("%d: %d --> %d\n slope=%g, R=%g, AdR=%g\n", ii+1, vBegs[ii]+1, vEnds[ii]+1, pp->b, pp->Rvalue, pp->AdjRSq);
			okoc_out_msg(strMsg, 'D');
		}
		if(nRange < nn)
		{
			nRange = nn;
			nFound = ii;
		}
	}
	if(nFound < 0 || nRange < 2) // not found
	{
		i1 = 0, i2 = 0;
		free(pResults);	
		return;
	}
	pp = pResults + nFound;
	i1 = pp->i1 + 1; // OC index to LT index
	i2 = pp->i2 + 1;
	a = pp->a;
	b = pp->b;
	aerr = pp->aErr;
	berr = pp->bErr;
	//---CPY 12/16/07 FIT_LR_R_VALUE_SHOULD_NOT_USE_ADJ_R_SUMSQR
	//R = pp->AdjRSq;
	r = pp->Rvalue;
	if(b < 0)
		r = -pp->Rvalue;
	//---
	if(oy)
	{
		vector vx(2), vy(2);
		vx[0] = vxData[pp->i1], vx[1] = vxData[pp->i2];
		for(int ii = 0; ii < 2; ii++)
			vy[ii] = pp->a + vx[ii] * pp->b;
	
		oy.SetData(&vy, &vx);
		xf_check_plot_output_rng_in_source_rng_graph(iy, oy, NULL, IDM_PLOT_LINESYMB, SYSCOLOR_RED);
	}
	free(pResults);	
	
}

//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 findBase_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return findBase_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	///------ Folger 04/10/09 QA80-13262-P2 OPTIONAL_SHOWN_INSTEAD_OF_NEW_AFTER_RESET_THEME
	if ( GETNE_ON_THEME == nEventID )
		check_convert_optional_outputs_to_new(trGetN);
	///------ End OPTIONAL_SHOWN_INSTEAD_OF_NEW_AFTER_RESET_THEME
	
	return false;

}

int findBase_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	
	//---- CPY 12/8/2007 QA80-10788 FIND_FLAT_REGIONS_IN_CURVE	
	// I have rewritten this, but keep Cloud's origional code inside findBase_make_tree
	/*
	vector vInputX, vInputY;
	int nSize;
	
	if( !iy.GetData(vInputY, vInputX) )
		XF_THROW(XFERR_GET_DATA_FAILED);
	
	nSize = vInputX.GetSize();
	double dMin, dMax;
	vInputY.GetMinMax(dMin, dMax);
	double dRange = dMax - dMin;
	int nPts = ocmath_get_noise_level(nSize, vInputY)/(dRange*0.005) * SMOOTH_LEVEL;
	if (nPts>nSize*0.2)
		nPts = nSize * 0.2;
	
	vector vytemp;
	vytemp = vInputY;
	int nRet = ocmath_savitsky_golay(vytemp, vInputY, nSize, nPts/2);
	if (nRet != OE_NOERROR)
		XF_THROW_EX(CER_UNKNOWN_ERROR_EX, nRet);
	
	vector<int> vs(nSize), ve(nSize);
	int nSec = ocmath_find_baseline_partion(nSize, vInputX, vInputY, N, sm, vs, ve);
	if (nSec < 0)
		XF_THROW_EX(CER_UNKNOWN_ERROR_EX, nRet);
	
	vs.SetSize(nSec);
	ve.SetSize(nSec);
	begin = vs;
	end = ve;
	vInputX.Trim();
	vInputY.Trim();
	
	FitParameter sFitParameter[2];
	RegStats sRegStats;
	nRet = ocmath_linear_fit(vInputX, vInputY, nSize, sFitParameter, NULL, 0, NULL, &sRegStats);
	if( OE_NOERROR != nRet )
		XF_THROW_EX(CER_UNKNOWN_ERROR_EX, nRet);
	
	a = sFitParameter[0].Value;		//Intercept
	aerr = sFitParameter[0].Error;
	b = sFitParameter[1].Value;		//Slope
	berr = sFitParameter[1].Error;
	R = sRegStats.AdjRSq;			//Adjusted residuel sum of squares
	
	oy.SetData(&vInputY, &vInputX);
	*/
	
	return -1;
}
//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 findBase_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	///------ Folger 03/13/09 QA80-13262 CONVERT_OBJECT_VARIABLE_OPTIOANL_TO_NEW_IN_XF_DIALOG
	if ( nGetNDialog > 0 )		/// open dialog
		check_convert_optional_outputs_to_new(trGetN);
	///------ End CONVERT_OBJECT_VARIABLE_OPTIOANL_TO_NEW_IN_XF_DIALOG
}
//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 findBase_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
