#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	operator_add,
	operator_sub,
	operator_div,
	operator_mul,
	operator_pow,
};
enum{
	operand_const,
	operand_data,
};

#include <o8dlg.h>

/*------------------------------------------------------------------------------*
 * Modification Log:															*
 * Folger 06/19/07 IMPROVEMENT_MATHTOOL											*
 * Echo 8/2/07 LLVC_NOT_BETTER_THAN_CUV											*
 * Echo 8/10/07 USE_FN_TO_GET_CURVE_FROM_XY										*
 * Echo 8/20/07	SET_BOUND_FOR_OUTPUT											*
 *	ML 8/20/2007 QA70-10261 OC_INITIALIZING_CURVE_FOR_OUTPUT_XYRANGE			*
 *	Echo 8/28/07 IY2_CAN_BE_OPTIONAL											*
 *	Echo 11/21/07 QA70-10489	SUPPORT_COMMON_CURVE							*
 *	Echo 12/10/2007 MUST_FORCE_CURVE_DESTRUCTOR_EXEC_FOR_RESCALE				*
 *	Folger 07/23/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS						*
 *	Folger 07/31/08 SHOULD_CHANGE_IY2_TO_UNASSGINED_WHEN_OPEN_DIALOG			*
 *	Max 7/30/08 v8.0912 CENTRALIZE_ERR_CHECKING									*
 *	Folger/Max v8.914b 8/1/2008 REFERENCE_DATA_SHOULD_REFRESH_WITH_OPERAND		*
 *	Echo 9/4/08 QA70-12148 v8.0932 ERROR_IN_DIFF_SIZE_DATA						*
 *	Folger 09/25/08 QA80-12276 SET_SAMPLING_INTERVAL_FOR_YXRANGE_OUTPUT			*
 *	ML 12/23/2008 CURVE_CONSTRUCTORS_FROM_XYRANGE_AND_DATAPLOT_WITH_TEMP_SERIES	*
 *	Kyle 02/19/2009 QA80-12146-P2 PREVENT_DOING_OPERATION_FROM_THE_DATA_ITSELF	*
 *	Kyle 02/23/2009 QA80-12146 UNDO_PREVENT_DOING_OPERATION_FROM_THE_DATA_ITSELF*
 *	Kyle 02/24/2009 QA80-13169 CHECK_IF_TWO_RANGE_HAVE_COMMON_RANGE				*
 *	Kyle 02/24/2009 SKIP_REFERENCE_DATA_IF_OPERAND_IS_CONST						*
 *	ML 2/26/2009 QA70-13169 RESAMPLE_DESTINATION_CURVE_SHOULD_OPTIONALLY_TAKE_i1_FROM_SOURCE
 *	Kyle 07/28/2009 QA80-13979	ALWAYS_UPDATE_X_IF_USE_COMMON_RANGE_ONLY_IS_CHECKED
 *	Kyle 09/22/2009 QA80-13169 SHIFT_RIGHT_THE_RESULT_TO_FIX_THE_INPUT_BOUNDS	*
 *	Kyle 09/22/2009 QA80-14023 FIX_SAMPLING_IS_NOT_RESET_IF_SET_INPUT_AS_OUTPUT	*
 *  Iris 1/04/2010 QA81-14877-S2 DIFF_ERR_MSG_FOR_NONE_REFER_DATA				*
 *------------------------------------------------------------------------------*/

 
//put additional include files here
static void _mathtool_operation(const Curve& cuvInput, const int& nOper, const int& nUseConstant, const double& dConstant, const Curve& cuvRange, Curve& cuvOutput)
{ 	
	switch(nOper)
	{
	case operator_add:
		if(nUseConstant)
			cuvOutput = cuvInput + dConstant; 
		else
			cuvOutput = cuvInput + cuvRange;
		break;
	case operator_sub:
		if(nUseConstant)
			cuvOutput = cuvInput - dConstant;
		else
			cuvOutput = cuvInput - cuvRange;
		break;
	case operator_div:
		if(nUseConstant)
		{
			if(is_equal(0,dConstant))
			{
				XF_THROW(XFERR_DIVIDED_BY_ZERO);
			}
			cuvOutput = cuvInput / dConstant;		
		}
		else
		{
			//for(int i =0; i<cuvInput.GetSize(); i++)
				//if(is_equal(0,cuvRange[i,i]))
				//{
					//XF_THROW(XFERR_DIVIDED_BY_ZERO);
				//}
			cuvOutput = cuvInput / cuvRange;
		}
		break;
	case operator_mul:
		if(nUseConstant)
			cuvOutput = cuvInput * dConstant;
		else
			cuvOutput = cuvInput * cuvRange;
		break;
	case operator_pow:
		cuvOutput = cuvInput;
		if(nUseConstant)
			cuvOutput = pow(cuvInput,dConstant);
		else
			cuvOutput = pow(cuvInput, cuvRange);
		break;

	}
}

///Echo 8/10/07 USE_FN_TO_GET_CURVE_FROM_XY
/*
bool curve_from_range(Curve& cuvData, const XYRange xyData)
{
	if (!xyData)
		return false;
	
	int r1, r2, c2, nColX, nColY;
	Worksheet wksTmp, wks;
	string strRange;
	Column col;
	xyData.GetRange(0, r1, nColX, r2, c2, wksTmp, &strRange);
	xyData.GetRange(1, r1, nColY, r2, c2, wks, &strRange);
	if (wksTmp != wks)
		return false;
	
	wksTmp.Columns(nColX).SetType(OKDATAOBJ_DESIGNATION_X);
	
	cuvData.Attach(wks, nColX, nColY);	
	
	return true;
	
	
}
*/
///END USE_FN_TO_GET_CURVE_FROM_XY

//------ Folger 07/23/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
static	void	_set_output_range_comments(XYRange& oy, int nOperand, const Range& iy1, const XYRange& iy2, double const_, int nOperator)
{
	vector<string>		vsOperators = {
		"Add",
		"Subtracted by",
		"Divided by",
		"Multiply",
		"Powered by"
	};
	
	string		strOperand = nOperand == operand_data ? get_input_data_range_string(iy2) : ftoa(const_);
		
	string	strComments;
	strComments.Format("%s %s on %s", vsOperators[nOperator], strOperand, get_input_data_range_string(iy1));
	oy.SetOutputComment(strComments);
}
//------ End BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS

/// Folger/Max v8.914b 8/1/2008 REFERENCE_DATA_SHOULD_REFRESH_WITH_OPERAND 
static	void	_switch_referece_data(TreeNode& trGetN)
{
	string strRange;
	trGetN.iy2.GetAttribute(STR_DATA_ATTRIB, strRange);
	
	vector<int>		vnPDS = {PDS_OPTIONAL, PDS_UNASSIGNED};
	vector<string>	vsPDS;
	vsPDS.Add(STR_UNASSIGNED);
	vsPDS.Add(STR_OPTIONAL);
	
	int		nPDS = vnPDS[trGetN.operand.nVal == operand_const];
	string	strPDS = vsPDS[trGetN.operand.nVal == operand_const];
	
	if (okutil_cvt_str_to_predefined_type(strRange) == nPDS)
	{
		trGetN.iy2.SetAttribute(STR_DATA_ATTRIB, strPDS);
		okutil_getn_update_ranges(&trGetN);
	}
}
/// END REFERENCE_DATA_SHOULD_REFRESH_WITH_OPERAND

/// Max 7/30/08 v8.0912 CENTRALIZE_ERR_CHECKING
static int _check_input_xyrange_data_size(TreeNode& trGetN)
{
	XYRange xyTemp;
	bool bOK = xy_range_from_GetN_data_node(trGetN.iy1, xyTemp);
	if(bOK && xyTemp.IsValid())
	{
		vector vx, vy;
		// when operand euqals const, x can be missing values, otherwise can not
		if(trGetN.operand.nVal == operand_data)
			xyTemp.GetData(vy, vx,NULL, 0, 0);
		else
			xyTemp.GetData(vy, vx, NULL, 0, DRR_GET_MISSING | DRR_BAD_WEIGHT_TREATMENT);
			
		return vy.GetSize();
	}
	return -1;
}

///Kyle 02/19/2009 QA80-12146-P2 PREVENT_DOING_OPERATION_FROM_THE_DATA_ITSELF
static bool check_if_two_range_intersect(TreeNode & trGetN)
{
	DataRange rng1, rng2;
	TreeNode trRange1, trRange2;
	trRange1 = trGetN.iy1;
	trRange2 = trGetN.iy2;
	okxf_resolve_tree_construct_range(&trRange1, &rng1);
	okxf_resolve_tree_construct_range(&trRange2, &rng2);

	return check_if_two_range_intersect(rng1, rng2);
}

static bool check_if_two_range_intersect(const DataRange& rng1, const DataRange& rng2)
{
	if(!rng1.IsValid() || !rng2.IsValid())
		return false;
	DataRange Yrng1, Yrng2;
	int r1, c1, r2, c2;
	Worksheet wks;
	rng1.GetRange( "Y", r1, c1, r2, c2, wks );
	Yrng1.Add( "Y", wks, r1, c1, r2, c2 );

	rng2.GetRange( "Y", r1, c1, r2, c2, wks);
	Yrng2.Add( "Y", wks, r1, c1, r2, c2 );

	return Yrng1.Intersects(Yrng2);
}
///End PREVENT_DOING_OPERATION_FROM_THE_DATA_ITSELF

static int _check_err_condition(TreeNode& trGetN, string* pstrErrMsg = NULL)
{
	string strErrMsg;
	int nErr = CER_NO_ERROR;
	
	//--- Iris 1/04/2010 QA81-14877-S2 DIFF_ERR_MSG_FOR_NONE_REFER_DATA
	/*
	if( get_input_xyrange_num(trGetN.iy1) != 1 || (trGetN.operand.nVal == operand_data && get_input_xyrange_num(trGetN.iy2) != 1) )
	{	
		nErr = CER_NOT_ONE_XYRANGE;
		strErrMsg = nErr;	
	}	
	*/
	if( get_input_xyrange_num(trGetN.iy1) != 1 )
	{	
		nErr = CER_FFT_GET_INPUT_FAIL;
		strErrMsg = nErr;
	}	
	else if( (trGetN.operand.nVal == operand_data && get_input_xyrange_num(trGetN.iy2) != 1) )
	{
		nErr = CER_GET_REFER_DATA_FAIL;
		strErrMsg = nErr;
	}
	//---
	else if(0>= _check_input_xyrange_data_size(trGetN) || (trGetN.operand.nVal == operand_data && 0>=get_input_xyrange_data_size(trGetN.iy2)) )
	{	
		nErr = CER_NO_DATA;
		strErrMsg = nErr;	
	}
	else if(trGetN.const.Show==1 && trGetN.const.dVal == NANUM)
	{
		nErr = CER_EMPTY_VARIABLE;
		strErrMsg = nErr;
		strErrMsg += ":" + _L("Input Constant number");
	}
	///Kyle 02/24/2009 QA80-13169 CHECK_IF_TWO_RANGE_HAVE_COMMON_RANGE
	else if(trGetN.operand.nVal == operand_data && trGetN.common.nVal && !have_common_range(trGetN.iy1, trGetN.iy2))
	{
		nErr = XFERR_NO_COMMON_RANGE;
		strErrMsg = nErr;
	}
	///End CHECK_IF_TWO_RANGE_HAVE_COMMON_RANGE
	
	///Kyle 02/23/2009 QA80-12146 UNDO_PREVENT_DOING_OPERATION_FROM_THE_DATA_ITSELF
	/////Kyle 02/19/2009 QA80-12146-P2 PREVENT_DOING_OPERATION_FROM_THE_DATA_ITSELF
	//else if(trGetN.operand.nVal == operand_data && check_if_two_range_intersect(trGetN))
	//{
		//nErr = XFERR_RANGE_INTERSECT;
		//strErrMsg = nErr;
	//}
	/////End PREVENT_DOING_OPERATION_FROM_THE_DATA_ITSELF
	///End UNDO_PREVENT_DOING_OPERATION_FROM_THE_DATA_ITSELF
	if(pstrErrMsg != NULL)
		*pstrErrMsg = strErrMsg;
	return nErr;
}
/// END CENTRALIZE_ERR_CHECKING


void mathtool(const XYRange& iy1, const int& operator, const int& operand, const XYRange& iy2, const double& const, const int& common, const int& rescale, XYRange& oy, double& xmin, double& xmax, double& xmean, double& ymin, double& ymax, double& ymean)
{
	
	vector vx1, vy1, vx2, vy2;
	
	if (iy1.IsValid() && iy1.GetData(vy1, vx1, NULL, 0, DRR_GET_MISSING | DRR_BAD_WEIGHT_TREATMENT)) 
	{
		if(0 == vy1.GetSize() || 0 == vx1.GetSize())
		{
			/// Max 7/30/08 v8.0912 USE_NON_ARGUMENT_ERROR_CODE
			//XF_THROW(CER_DATA_TOO_FEW);
			XF_THROW(CER_NO_DATA);
			///------
		}
	}
	else
	{
		XF_THROW(XFERR_GET_DATA_FAILED);
	}
	
	//bool bNotMonotonic = false;
	///Folger 06/19/07 IMPROVEMENT_MATHTOOL
	//if (!operand)
	if (operand == operand_data)
	///End IMPROVEMENT_MATHTOOL
	{
		///Kyle 02/23/2009 QA80-12146 UNDO_PREVENT_DOING_OPERATION_FROM_THE_DATA_ITSELF
		/////Kyle 02/19/2009 QA80-12146-P2 PREVENT_DOING_OPERATION_FROM_THE_DATA_ITSELF
		//if(check_if_two_range_intersect(iy1, iy2))
			//XF_THROW(XFERR_RANGE_INTERSECT);
		/////End PREVENT_DOING_OPERATION_FROM_THE_DATA_ITSELF
		///End UNDO_PREVENT_DOING_OPERATION_FROM_THE_DATA_ITSELF
	
		if(iy2.IsValid() && iy2.GetData(vy2, vx2))
		{
			if(0 == vy2.GetSize() || 0 == vx2.GetSize())
			{
				/// Max 7/30/08 v8.0912 USE_NON_ARGUMENT_ERROR_CODE
				//XF_THROW(CER_DATA_TOO_FEW);
				XF_THROW(CER_NO_DATA);
				///------
			}
		}
		else
		{
			/// Max 7/30/08 v8.0912 USE_NON_ARGUMENT_ERROR_CODE
			//XF_THROW(CER_DATA_TOO_FEW);
			XF_THROW(XFERR_GET_DATA_FAILED);
			///------
		}
		//bNotMonotonic = MONO_NOT == ocmath_is_monotonic(vx2, vx2.GetSize(), false);
	}
	
	///Echo 8/10/07 USE_FN_TO_GET_CURVE_FROM_XY
	/// TD 09-17-2008 QA80-12148 IMPROVE_CURVE_ARITHMATICS_IN_OC
	//Curve cuv1(iy1);
	//Curve cuv2(iy2);
	///Echo 9/4/08 QA70-12148 v8.0932 ERROR_IN_DIFF_SIZE_DATA
	///Echo 9/11/08 
	//I have used a temp solution to TrimRight of cuv1 and cuv2 in simple math tool. But best we can get it fixed in low level. 
	//cuv1.TrimRight();
	//cuv2.TrimRight();
	/// end IMPROVE_CURVE_ARITHMATICS_IN_OC
	///end ERROR_IN_DIFF_SIZE_DATA
	/// ML 8/20/2007 QA70-10261 OC_INITIALIZING_CURVE_FOR_OUTPUT_XYRANGE
	//Curve cuvOutput(oy, false);
	BOOL	bCurveOutNoX = FALSE;
	///Echo 8/28/07 IY2_CAN_BE_OPTIONAL
	//if ( oy )
		//bCurveOutNoX = oy.IsIntersect(iy1) || oy.IsIntersect(iy2);
	///Kyle 07/28/2009 QA80-13979	ALWAYS_UPDATE_X_IF_USE_COMMON_RANGE_ONLY_IS_CHECKED, bCurveOutNoX==FALSE will update the output x
	//if ( oy )
	if ( !common && oy )
	///End ALWAYS_UPDATE_X_IF_USE_COMMON_RANGE_ONLY_IS_CHECKED
	{
		bCurveOutNoX = oy.IsIntersect(iy1);
		if (iy2)
			bCurveOutNoX = bCurveOutNoX || oy.IsIntersect(iy2);
	}
	///end IY2_CAN_BE_OPTIONAL	
	
	{///Echo 12/10/2007 MUST_FORCE_CURVE_DESTRUCTOR_EXEC_FOR_RESCALE
	/// TD 09-17-2008 QA80-12206 SIMPLE_MATH_TOOL_MESSUP_INPUT_DATA
	//Curve	cuvOutput(oy, bCurveOutNoX);		// it will write into oy in its destructor
	/// end OC_INITIALIZING_CURVE_FOR_OUTPUT_XYRANGE
	Curve	cuvOutput(oy, bCurveOutNoX, TRUE);		// it will write into oy in its destructor
	/// ML 12/23/2008 CURVE_CONSTRUCTORS_FROM_XYRANGE_AND_DATAPLOT_WITH_TEMP_SERIES
	//Curve cuv1(iy1);
	//Curve cuv2(iy2);
	Curve cuv1(0, iy1);
	Curve cuv2(0, iy2);
	/// end CURVE_CONSTRUCTORS_FROM_XYRANGE_AND_DATAPLOT_WITH_TEMP_SERIES
	/// end SIMPLE_MATH_TOOL_MESSUP_INPUT_DATA
	
	///Kyle 09/22/2009 QA80-13169 SHIFT_RIGHT_THE_RESULT_TO_FIX_THE_INPUT_BOUNDS
	BOOL	bTrimLeft = true;
	int		nRowOffset = 0;
	if( operand && common )
	{
		if( oy.IsIntersect(iy1) )
		{
			if( nRowOffset < cuv1.GetLowerBound() )
				nRowOffset = cuv1.GetLowerBound();
			bTrimLeft = false;
		}
		if( oy.IsIntersect(iy2) )
		{
			if( nRowOffset < cuv2.GetLowerBound() )
				nRowOffset = cuv2.GetLowerBound();
			bTrimLeft = false;
		}
	}
	else if ( oy )
	{
		bTrimLeft = !bCurveOutNoX;
	}
	///End SHIFT_RIGHT_THE_RESULT_TO_FIX_THE_INPUT_BOUNDS
	
	///Echo 8/17/07	RANGE_NOT_WORK_FINE_FOR_DEVIDE_AND_POWER
	//_mathtool_operation(cuv1, operator, 1-operand, const, cuv2, cuvOutput);
	///Echo 8/20/07	SET_BOUND_FOR_OUTPUT
	int iBegin, iEnd, iBegin2, iEnd2;
	///Echo 11/21/07 QA70-10489	SUPPORT_COMMON_CURVE
	/*
	iBegin = cuv1.GetLowerBound();
	iEnd = cuv1.GetUpperBound();
	if (iy2 && common)
	{
		iBegin2 = cuv2.GetLowerBound();
		iEnd2 = cuv2.GetUpperBound();
		iBegin = max(iBegin, iBegin2);
		iEnd = min(iEnd, iEnd2);	
	}
	*/
	///END SUPPORT_COMMON_CURVE
	///END SET_BOUND_FOR_OUTPUT
	
	///Echo 11/21/07 QA70-10489	SUPPORT_COMMON_CURVE
	//_mathtool_operation(cuv1, operator, 1-operand, const, cuv2, cuvOutput);
	if (iy2 && common)
	{
		///Kyle 02/24/2009 QA80-13169 CHECK_IF_TWO_RANGE_HAVE_COMMON_RANGE
		if(!have_common_range(iy1, iy2))
			XF_THROW(XFERR_NO_COMMON_RANGE);
		///End CHECK_IF_TWO_RANGE_HAVE_COMMON_RANGE
		/// ML 2/26/2009 QA70-13169 RESAMPLE_DESTINATION_CURVE_SHOULD_OPTIONALLY_TAKE_i1_FROM_SOURCE
		//Curve cvUnion(cuv1, cuv2, true);
		//
		// The constructor cuvOutput(oy, bCurveOutNoX, TRUE) used above will cause the curve object cuvOutput
		// to write in the destructor by matching row indices. This means that we have to make sure that the
		// result has the proper row offset with is the same as in the source cuv1, which is what the fourth
		// argument 'true' ensures.
		Curve cvUnion(cuv1, cuv2, true, true);	
		/// end RESAMPLE_DESTINATION_CURVE_SHOULD_OPTIONALLY_TAKE_i1_FROM_SOURCE
		iBegin = cvUnion.GetLowerBound();
		iEnd = cvUnion.GetUpperBound();
		_mathtool_operation(cvUnion, operator, 1-operand, const, cuv2, cuvOutput);		
	}else
	{
		iBegin = cuv1.GetLowerBound();
		iEnd = cuv1.GetUpperBound();
		_mathtool_operation(cuv1, operator, 1-operand, const, cuv2, cuvOutput);		
	}
	///END SUPPORT_COMMON_CURVE
	///Kyle 09/22/2009 QA80-13169 SHIFT_RIGHT_THE_RESULT_TO_FIX_THE_INPUT_BOUNDS
	if( operand && common )
	{
		if(nRowOffset > iBegin)
		{
			int nOffset = nRowOffset - iBegin;
			vector vMissing(nOffset);
			vMissing = NANUM;
			cuvOutput.Append(vMissing);
			cuvOutput.Sort(NS_MISSING_AS_SMALLEST);
			iBegin+=nOffset;
			iEnd+=nOffset;
		}
	}
	///END SHIFT_RIGHT_THE_RESULT_TO_FIX_THE_INPUT_BOUNDS
	BOOL bRet;
	bRet = cuvOutput.SetLowerBound(iBegin);
	bRet = cuvOutput.SetUpperBound(iEnd);
	bRet = cuvOutput.SetXBounds(iBegin, iEnd);
	///END RANGE_NOT_WORK_FINE_FOR_DEVIDE_AND_POWER
	
	///Echo 12/10/2007 MUST_FORCE_CURVE_DESTRUCTOR_EXEC_FOR_RESCALE
	//------ Folger 09/25/08 QA80-12276 SET_SAMPLING_INTERVAL_FOR_YXRANGE_OUTPUT
	//cuvOutput.CopyData(vx1, vy1);
	///Kyle 09/22/2009 QA80-14023 FIX_SAMPLING_IS_NOT_RESET_IF_SET_INPUT_AS_OUTPUT
	//if ( cuvOutput.CopyData(vx1, vy1) )
		//update_output_xyrange_even_sampling(oy, &vx1, 0, iy1);
	///End FIX_SAMPLING_IS_NOT_RESET_IF_SET_INPUT_AS_OUTPUT
	//------
	
	///Kyle 02/24/2009 QA80-13169 CHECK_IF_TWO_RANGE_HAVE_COMMON_RANGE, trim left
	///Kyle 09/22/2009 QA80-13169 SHIFT_RIGHT_THE_RESULT_TO_FIX_THE_INPUT_BOUNDS
	//if(cuvOutput.HasX() && !bCurveOutNoX && iBegin > 0)
	if(cuvOutput.HasX() && bTrimLeft && iBegin > 0)
	///End SHIFT_RIGHT_THE_RESULT_TO_FIX_THE_INPUT_BOUNDS
	{
		cuvOutput.TrimLeft(true);
		iEnd -= iBegin;
		iBegin = 0;					///Kyle 09/22/2009 QA80-14023 FIX_SAMPLING_IS_NOT_RESET_IF_SET_INPUT_AS_OUTPUT
		cuvOutput.SetUpperBound(iEnd);
		cuvOutput.SetXBounds(0, iEnd);
	}
	///End CHECK_IF_TWO_RANGE_HAVE_COMMON_RANGE
	
	///Kyle 09/22/2009 QA80-14023 FIX_SAMPLING_IS_NOT_RESET_IF_SET_INPUT_AS_OUTPUT
	if ( cuvOutput.CopyData(vx1, vy1) )
	{
		if(iBegin > 0)			// update vx1 with row offset
		{
			double dXInc;
			int nErr = ocmath_sampling_resolution(vx1.GetSize(), vx1, &dXInc);
			if( nErr==OE_NOERROR || nErr==OE_NOT_SPACED_EQUALLY)
				vx1 -= dXInc * iBegin;
		}
		update_output_xyrange_even_sampling(oy, &vx1);
	}
	///End FIX_SAMPLING_IS_NOT_RESET_IF_SET_INPUT_AS_OUTPUT
	
	}
	///end MUST_FORCE_CURVE_DESTRUCTOR_EXEC_FOR_RESCALE
	
	xf_check_plot_output_rng_in_source_rng_graph(iy1, oy, NULL, IDM_PLOT_LINE, SYSCOLOR_RED, GAP_GROUP_PLOTS | GAP_USE_TEMPLATE | GAP_ALLOW_DUPLICATE_COL, rescale);
	
	///Echo 8/17/07 Temp code to set ouput X Column Type. The code can be removed if QA70-10252 is fixed
	//if (oy)
	//{
		//int r1, r2, c2, nColX;
		//Worksheet wksTmp;
		//string strRange;
		//oy.GetRange(0, r1, nColX, r2, c2, wksTmp, &strRange);
		//wksTmp.Columns(nColX).SetType(OKDATAOBJ_DESIGNATION_X);
	//}
	/*
	///Echo 8/2/07 LLVC_NOT_BETTER_THAN_CUV
	Curve cuv1;
	curve_from_range(cuv1, iy1);
	
	Curve cuv2;
	if(iy2) curve_from_range(cuv2, iy2);
		
	Curve cuvOutput;
	curve_from_range(cuvOutput, oy);
	_mathtool_operation(cuv1, operator, operand-1, const, cuv2, cuvOutput);
	*/
	
	//else
	//{
		//vx2.SetSize(vx1.GetSize());
		//vy2.SetSize(vy1.GetSize());
		////switch(dir)
		////{
		///////Folger 06/19/07 IMPROVEMENT_MATHTOOL
		//////case 0:
		////case dir_Y:
		///////End IMPROVEMENT_MATHTOOL
			////vx2 = vx1;
			////vy2 = const;
			////break;
		///////Folger 06/19/07 IMPROVEMENT_MATHTOOL
		//////case 1:
		////case dir_X:
		///////End IMPROVEMENT_MATHTOOL
			////vx2 = const;
			////vy2 = vy1;
			////break;
		////}
		//vx2 = vx1;
		//vy2 = const;
	//}
	//
	////if ( MONO_NOT == ocmath_is_monotonic(vx1, vx1.GetSize(), false) ||  bNotMonotonic)
	////{
		////warning_msg_box(CWARN_NONMONOTONIC_X, true);
		////vector<uint> vnIndeces;
		////vx1.Sort(SORT_ASCENDING, TRUE, vnIndeces);
		////vy1.Reorder(vnIndeces);
		////vx2.Sort(SORT_ASCENDING, TRUE, vnIndeces);
		////vy2.Reorder(vnIndeces);
	////}
	//
	//int nSize1 = vx1.GetSize();
	//int nSize2 = vx2.GetSize();
	//vector vOutX(nSize1), vOutY(nSize1);
	//vOutX = NANUM;  
	//vOutY = NANUM;
	////switch(dir)
	////{
	///////Folger 06/19/07 IMPROVEMENT_MATHTOOL
	//////case 0:
	////case dir_Y:
	///////End IMPROVEMENT_MATHTOOL
		////ocmath_simple_math(nSize1, vOutX, vOutY, nSize1, vx1, vy1, nSize2, vx2, vy2, operator, common);
		////break;
	///////Folger 06/19/07 IMPROVEMENT_MATHTOOL
	//////case 1:
	////case dir_X:
	///////End IMPROVEMENT_MATHTOOL
		////ocmath_simple_math(nSize1, vOutY, vOutX, nSize1, vy1, vx1, nSize2, vy2, vx2, operator, common);
		////break;
	////}
	//ocmath_simple_math(nSize1, vOutX, vOutY, nSize1, vx1, vy1, nSize2, vx2, vy2, operator, common);
	///// Max 7/27/07 should not trim output
	///*
	//vOutX.Trim();
	//vOutY.Trim();
	//*/
	//if(oy.SetData(&vOutY, &vOutX))
	//{
		//DataPlot dp = oy.MakePlot(iy1);
		///// Max 6/16/07 NO_NEED
		///*
		//if (dp)
		//{
			////dp.SetColor(color);		///Folger 06/19/07 IMPROVEMENT_MATHTOOL
			//GraphLayer gl;
			//dp.GetParent(gl);
			//gl.Rescale();
		//}
		//*/
		///// NO_NEED
	//}
	///end LLVC_NOT_BETTER_THAN_CUV
			
	//Output stats values.
	//oy.GetData(vy1, vx1);///Echo 8/2/07 LLVC_NOT_BETTER_THAN_CUV
	vx1.GetMinMax(xmin, xmax);
	vy1.GetMinMax(ymin, ymax);
	vx1.Sum(xmean);
	xmean /= vx1.GetSize();
	vy1.Sum(ymean);
	ymean /= vy1.GetSize();
	
	//LT_execute("legend -s");
	
	//------ Folger 07/23/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
	_set_output_range_comments(oy, operand, iy1, iy2, const, operator);
	//------
	
}

//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 mathtool_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return mathtool_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	//------ Folger 07/31/08 SHOULD_CHANGE_IY2_TO_UNASSGINED_WHEN_OPEN_DIALOG
	if ( nEventID == GETNE_ON_INIT || nEventID == GETNE_ON_THEME || nEventID > 0 && lstrcmp(lpcszNodeName, "operand") == 0 )
	{
		_switch_referece_data(trGetN);
	}
	//------ End SHOULD_CHANGE_IY2_TO_UNASSGINED_WHEN_OPEN_DIALOG
	
	bool bShowXYRange = false;
	bool bShowConstant = false;	
	switch(trGetN.operand.nVal)
	{
		///Folger 06/19/07 IMPROVEMENT_MATHTOOL
		//case 0:
		case operand_data:
		///End IMPROVEMENT_MATHTOOL
			bShowXYRange = true;
			break;
		///Folger 06/19/07 IMPROVEMENT_MATHTOOL
		//case 1:
		case operand_const:
		///End IMPROVEMENT_MATHTOOL
			bShowConstant = true;
			break;
	}
			
	trGetN.iy2.Show = bShowXYRange;
	trGetN.const.Show = bShowConstant;
	trGetN.common.Enable = bShowXYRange;
	
	/// Folger/Max v8.914b 8/1/2008 REFERENCE_DATA_SHOULD_REFRESH_WITH_OPERAND
	/*
	if (!bShowXYRange)
	{
		//trGetN.common.nVal = false;
		//trGetN.common.Show = false;
		trGetN.iy2.SetAttribute("Data", STR_OPTIONAL);	
	}
	*/
	/// END REFERENCE_DATA_SHOULD_REFRESH_WITH_OPERAND
	
	XYRange xyTemp;
	bool bOK = xy_range_from_GetN_data_node(trGetN.iy1, xyTemp);
	if(bOK && xyTemp.IsValid())
	{
		vector<uint> vnUID;
		xyTemp.GetPlots(vnUID);
		trGetN.rescale.Enable = ( vnUID[0] <= 0 ) ? false : true;
	}
	
	///Folger 06/19/07 IMPROVEMENT_MATHTOOL
	//GraphLayer gl = Project.ActiveLayer();
	//if(!gl.IsValid())
		//trGetN.color.Show = false;
	///End IMPROVEMENT_MATHTOOL
	/// Max 6/19/07 USE_V_OPTION_STRING
	/*
	trGetN.xmin.Show = false;
	trGetN.xmax.Show = false;
	trGetN.xmean.Show = false;
	trGetN.ymin.Show = false;
	trGetN.ymax.Show = false;
	trGetN.ymean.Show = false;
	*/
	/// END USE_V_OPTION_STRING
	int nErr = CER_NO_ERROR;
	/// Max 7/30/08 v8.0912 CENTRALIZE_ERR_CHECKING
	/*
	///Folger 06/19/07 IMPROVEMENT_MATHTOOL
	//	if(get_input_xyrange_num(trGetN.iy1) != 1 || get_input_xyrange_num(trGetN.iy2) != 1 && bShowXYRange)
	if(get_input_xyrange_num(trGetN.iy1) != 1 || bShowXYRange&&get_input_xyrange_num(trGetN.iy2) != 1)
	///End IMPROVEMENT_MATHTOOL
		nErr = CER_NOT_ONE_XYRANGE;
	///Folger 06/19/07 IMPROVEMENT_MATHTOOL
	if (trGetN.const.dVal == NANUM)
	{
		strErrMsg = CER_EMPTY_VARIABLE;
		strErrMsg += ":" + _L("Input Const number");
	}
	///End IMPROVEMENT_MATHTOOL
	*/
	nErr = _check_err_condition(trGetN, strErrMsg);
	/// END CENTRALIZE_ERR_CHECKING
	
	if(nErr != CER_NO_ERROR)
	{
		bOKEnable = false;
		//strErrMsg = nErr;
	}
	return true;
	

}

int mathtool_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 mathtool_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	
	//------ fisher 11/16/07 ADD_MAP_ID_TO_CHM
	if(is_use_origin_chm())
		trGetN.SetAttribute(STR_HELPID_ATTRIB, IDD_XF_mathtool);	
	
	if ((dwCntrl & LTXF_THEME_USED) && (dwCntrl & LTXF_FROM_GUI_MENU) && nGetNDialog == 0)
	{
		//bool bOKEnable; 
		/// Max 7/30/08 v8.0912 CENTRALIZE_ERR_CHECKING
		//if(get_input_xyrange_num(trGetN.iy1) != 1 || get_input_xyrange_num(trGetN.iy2) != 1 && trGetN.iy2.Show)
		if(_check_err_condition(trGetN) != CER_NO_ERROR)
		///------
			nRet = XFEVT_PROCEED_WITH_DLG;		
	}	
	
	///Kyle 02/24/2009 SKIP_REFERENCE_DATA_IF_OPERAND_IS_CONST
	if(nGetNDialog == 0 && (dwCntrl & LTXF_EXECUTE) && trGetN.operand.nVal == operand_const)
	{
		trGetN.iy2.SetAttribute(STR_DATA_ATTRIB, STR_OPTIONAL);
		okutil_getn_update_ranges(&trGetN);
	}
	///End SKIP_REFERENCE_DATA_IF_OPERAND_IS_CONST
	
}
//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 mathtool_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
