#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	type_any,
	type_left,
	type_right,
};
/*------------------------------------------------------------------------------*
 * Modification Log:															*
 *	Kenny 11/13/2009 QA81-14661 XF_LEVEL_CROSSING_NEED_OPTION_TO_GET_DIRECTION_AND_X_INDEX*
 *	CPY 11/27/09 QA81-14661-P5 LEVEL_CROSSING_NEED_OPTION_TO_SKIP_NOISY_SPIKES	*
 *	Folger 12/19/09 QA81-14661-P14 XINDEX_IS_WRONG_ON_INPUT_DATA_WITH_MISSING_VALUE
 *------------------------------------------------------------------------------*/

//put additional include files here

//put your own support static functions here

static	void	_set_output_range_comments(const XYRange& iy, double level, Range& rngZeroXs)
{
	string strlevel = ftoa(level);
	string strComments;
	strComments.Format(_L("X values of Y= %s Level Crossing of %s"), strlevel, get_input_data_range_string(iy));
	if(rngZeroXs.IsValid())
		rngZeroXs.SetOutputComment(strComments);
}
	

void levelcrossing(const XYRange& iy, const double& level, int& ncrossing, vector& oy, vector& direction, vector& xindex, const int& type, const int& pts)
{
	DWORD dwRules = DRR_NO_WEIGHTS | DRR_GET_DEPENDENT | DRR_NO_FACTORS;
	int nNumRanges = iy.GetNumData(dwRules);
	if (nNumRanges < 1)
		XF_THROW(XFERR_AT_LEAST_ONE_XYRANGE);	
	vector vX, vY, vZeroX;
	ncrossing = 0;
	
	///------ Folger 12/19/09 QA81-14661-P14 XINDEX_IS_WRONG_ON_INPUT_DATA_WITH_MISSING_VALUE
	//iy.GetData(vY, vX, NULL);  //// note that all the missing value will be trimmed in getting this data
	iy.GetData(vY, vX, NULL, 0, DRR_GET_MISSING);
	///------ End XINDEX_IS_WRONG_ON_INPUT_DATA_WITH_MISSING_VALUE
	if(0 == vY.GetSize() || 0 == vX.GetSize())
	{
		XF_THROW(CER_NO_DATA);
	}
	//--- CPY 11/27/09 QA81-14661-P5 LEVEL_CROSSING_NEED_OPTION_TO_SKIP_NOISY_SPIKES
	/*
	int nSize = vX.GetSize();
	vZeroX.SetSize(nSize);
	
	/// Kenny 11/13/2009 QA81-14661 XF_LEVEL_CROSSING_NEED_OPTION_TO_GET_DIRECTION_AND_X_INDEX
	//int nRet = ocmath_get_level_crossing(nSize, vX, vY, level, &ncrossing, vZeroX);
	vY -= level;
	vector<int> vnDir(nSize);
	int nRet = ocmath_emd_get_zero_crossing(nSize, vX, vY, &ncrossing, vZeroX, vnDir);
	/// End QA81-14661 XF_LEVEL_CROSSING_NEED_OPTION_TO_GET_DIRECTION_AND_X_INDEX
	
	if(nRet<0)
	{
		XF_THROW(XFERR_AT_LEAST_ONE_XYRANGE); // todo: throw error 
	}
	else
	{
		if(ncrossing>0)
		{
			/// Kenny 11/13/2009 QA81-14661 XF_LEVEL_CROSSING_NEED_OPTION_TO_GET_DIRECTION_AND_X_INDEX
			//vZeroX.SetSize(ncrossing);
			//oy = vZeroX;
			if (oy)
			{
				vZeroX.SetSize(ncrossing);
				oy = vZeroX;
			}
			if (direction)
			{
				vnDir.SetSize(ncrossing);
				direction = vnDir;
			}
			if (xindex)
			{
				xindex.SetSize(ncrossing);
				ASSERT(vZeroX.GetSize() == ncrossing);
				int nNearest[3];
				for (int ii = 0; ii < ncrossing; ++ii)
				{
					ocmath_find_nearest_index(vX, nSize, vZeroX[ii], 
							&nNearest[type_left], &nNearest[type_right], &nNearest[type_any]);
					xindex[ii] = nNearest[type];
				}
			}
			/// End QA81-14661 XF_LEVEL_CROSSING_NEED_OPTION_TO_GET_DIRECTION_AND_X_INDEX
		}
		
		/// Kenny 11/13/2009 QA81-14661 XF_LEVEL_CROSSING_NEED_OPTION_TO_GET_DIRECTION_AND_X_INDEX
		if (!oy)
		{
			return;
		}
		/// End QA81-14661 XF_LEVEL_CROSSING_NEED_OPTION_TO_GET_DIRECTION_AND_X_INDEX
		
		Range rngZeroX;
		rngZeroX = oy.GetSourceDataRange();
		_set_output_range_comments(iy, level, rngZeroX);
		
		Worksheet wks;
		int c1, c2;
		rngZeroX.GetRange(wks, c1, c2);
		ASSERT(c1 == c2);
		Column col(wks, c1);
		col.SetType(OKDATAOBJ_DESIGNATION_X);
	}*/
	
	//vY -= level;
	vector vRoots;
	vector<int> vnDirection, vnIndices;
	int nRet = find_roots(vX, vY, vRoots, level, vnDirection, pts, vnIndices, type);
	if(nRet<0)
	{
		switch ( nRet )
		{
		case OE_BAD_PARAM:
			XF_THROW_EX(CER_DATA_TOO_FEW, 2);
		case FIND_ROOTS_INVALID_DURATION_POINTS:
			XF_THROW_EX(CER_INVALID_POSITIVE_INTEGER, _L("Number of Duration Points"));
		
		default:
			XF_THROW("\r\n");
		}
	}
	ncrossing = nRet;
	if (oy)
	{
		oy = vRoots;
		Range rngZeroX;
		rngZeroX = oy.GetSourceDataRange();
		_set_output_range_comments(iy, level, rngZeroX);
	}
	if(direction)
		direction = vnDirection;
	if(xindex)
		xindex = vnIndices;
	
	//--- end LEVEL_CROSSING_NEED_OPTION_TO_SKIP_NOISY_SPIKES
	
	
}

//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 levelcrossing_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return levelcrossing_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	return false;

}

int levelcrossing_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	return false;
}
//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 levelcrossing_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{

}
//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 levelcrossing_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
