#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
//put additional include files here

//------------- Modification Log ---------------------
// CPY 3/9/09 REMOVE_LABEL_HANDLING_TO_ALLOW_GIVING_OUT_FOR_SR4
// CPY 3/9/09 NEED_TO_TRIM_TO_GET_INITIAL_COL_AS_EMPTY
// Kyle 03/12/2009 BRING_BACK_SUPPORTING_OF_LABELS_COPY
// Kyle 09/30/2009 QA80-14396 GET_DUPLICATED_X_ACCORDINGLY
// YuI 10/20/09 QA70-14477 OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
// Folger 10/21/09 QA80-14477 MORE_WORK_ON_OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
// Folger 10/23/09 QA81-14477-P1 WMERGEXY_FAILS_TO_UNDO_ROWS_ADDED

//--- CPY 3/9/09 PROPER_ADDINT_TO_ARRAY
//	vyOut[vnIndices[jj]] = vyIn[ii];
static void _set_at(vector& vy, int ii, double y)
{
	if(ii >= vy.GetSize())
		vy.SetSize(ii+1);
	
	vy[ii] = y;
}
//---

/// YuI 10/20/09 QA70-14477 OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
//	static bool _merge_xy_data(const vector& vxIn, const vector& vyIn, vector& vxOut, vector& vyOut, Worksheet& wksOut)
static bool _merge_xy_data(const vector& vxIn, const vector& vyIn, vector& vxOut, vector& vyOut, Worksheet& wksOut, int nPrecision)
/// end OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
{
	//---- CPY 3/9/09 NEED_TO_TRIM_TO_GET_INITIAL_COL_AS_EMPTY
	// missing data at end of destination cols should be removed
	//vxOut.TrimRight(true);
	//vyOut.TrimRight(true);
	//
	//// add back some missing values if x & y do not match
	//if(vxOut.GetSize() != vyOut.GetSize())
	//{
		//int nXSize = vxOut.GetSize(),
			//nYSize = vyOut.GetSize();
		//if(nXSize > nYSize)
			//vyOut.InsertAt(nYSize, NANUM, nXSize - nYSize);
		//else
			//vxOut.InsertAt(nXSize, NANUM, nYSize - nXSize);
	//}
	ASSERT(vxOut.GetSize() == vyOut.GetSize());
	//----
	if(0 == vxOut.GetSize() && 0 == vyOut.GetSize())
	{
		vxOut = vxIn;
		vyOut = vyIn;
		return true;
	}
	// temp
//	vyOut = vyIn;
//	return true;
	
	
	int nSizeIn = vxIn.GetSize(),
		nSizeOut = vxOut.GetSize();
	
	//bool bIsMonot = ocmath_is_monotonic(vxOut, vxOut.GetSize(), true);
	//bool bIsIncre = true;
	//if(bIsMonot && vxOut.GetSize() > 1)
		//bIsIncre = vxOut[1] > vxOut[0];
	int nMonot = ocmath_is_monotonic(vxOut, vxOut.GetSize(), false);
	bool bIsMonot = (nMonot == MONO_INCREASE || nMonot == MONO_DECREASE);
	bool bIsIncre = nMonot == MONO_INCREASE;

	vector<uint> vnOrder;
	if(!bIsMonot || bIsIncre)
		vxIn.Sort(SORT_ASCENDING, TRUE, vnOrder);
	else
		vxIn.Sort(SORT_DESCENDING, TRUE, vnOrder);
	vyIn.Reorder(vnOrder);
	
	int nIndexToInsert = -1;		// to remember last row index inserted
	vector<uint> vnIndices;
	///Kyle 09/30/2009 QA80-14396 GET_DUPLICATED_X_ACCORDINGLY
	/*
	for(int ii = 0; ii < nSizeIn; ii++)
	{
		if(	is_missing_value(vxIn[ii]) ||
			(ii>0 && is_equal(vxIn[ii], vxIn[ii-1])))
			continue;

		if(vxOut.Find(vnIndices, vxIn[ii]) > 0)
		{
			for(int jj = vnIndices.GetSize() - 1; jj >= 0; jj--)
			//--- CPY 3/9/09 PROPER_ADDINT_TO_ARRAY
			//	vyOut[vnIndices[jj]] = vyIn[ii];
				_set_at(vyOut, vnIndices[jj], vyIn[ii]);
			//---
		}
		else
		{
			if(bIsMonot)
			{
				nIndexToInsert++;
				if(bIsIncre)
				{
					while(nIndexToInsert < vxOut.GetSize() && vxOut[nIndexToInsert] < vxIn[ii])
						nIndexToInsert++;
				}
				else
				{
					while(nIndexToInsert < vxOut.GetSize() && vxOut[nIndexToInsert] > vxIn[ii])
						nIndexToInsert++;
				}
			}
			else
			{
				nIndexToInsert = vxOut.GetSize();
			}
			if(!wksOut.InsertRow(nIndexToInsert ))
				return false;
			
			vxOut.InsertAt(nIndexToInsert, vxIn[ii]);
			vyOut.InsertAt(nIndexToInsert, vyIn[ii]);

		}
	}
	*/
	int iBegin = 0, iEnd;
	while(iBegin < nSizeIn)
	{
		if(	is_missing_value(vxIn[iBegin]) )
		{
			iBegin++;
			continue;
		}
		///------ Folger 10/21/09 QA80-14477 MORE_WORK_ON_OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
		//iEnd = iBegin + 1;
		//while( iEnd < nSizeIn && is_equal(vxIn[iBegin], vxIn[iEnd]) )
			//iEnd++;
		iEnd = vxIn.Find(vnIndices, vxIn[iBegin], _ONAN, nPrecision, iBegin) + iBegin;
		///------ End MORE_WORK_ON_OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
		
		/// YuI 10/20/09 QA70-14477 OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
		//	vxOut.Find(vnIndices, vxIn[iBegin]);
		vxOut.Find(vnIndices, vxIn[iBegin], _ONAN, nPrecision);
		/// end OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY

		for(int ii=iBegin; ii<iEnd; ii++)
		{
			if(vnIndices.GetSize() > 0)
			{
				vyOut[vnIndices[0]] = vyIn[ii];
				vnIndices.RemoveAt(0);				// the one is set should be removed from the vector
			}
			else
			{
				if(bIsMonot)
				{
					nIndexToInsert++;
					if(bIsIncre)
					{
						while(nIndexToInsert < vxOut.GetSize() && vxOut[nIndexToInsert] <= vxIn[ii])
							nIndexToInsert++;
					}
					else
					{
						while(nIndexToInsert < vxOut.GetSize() && vxOut[nIndexToInsert] >= vxIn[ii])
							nIndexToInsert++;
					}
				}
				else
				{
					nIndexToInsert = vxOut.GetSize();
				}
				///------ Folger 10/23/09 QA81-14477-P1 WMERGEXY_FAILS_TO_UNDO_ROWS_ADDED
				//if(!wksOut.InsertRow(nIndexToInsert ))
				if(!wksOut.InsertRow(nIndexToInsert, TRUE))
				///------ End WMERGEXY_FAILS_TO_UNDO_ROWS_ADDED
					return false;
				
				vxOut.InsertAt(nIndexToInsert, vxIn[ii]);
				vyOut.InsertAt(nIndexToInsert, vyIn[ii]);
			}
		}
		for(ii = vnIndices.GetSize()- 1; ii>=0; ii--)
			vyOut[vnIndices[ii]] = NANUM;
		iBegin = iEnd;
	}
	///End GET_DUPLICATED_X_ACCORDINGLY
	return true;
}
//--------- CPY 3/9/09 REMOVE_LABEL_HANDLING_TO_ALLOW_GIVING_OUT_FOR_SR4

static void _mergexy_copy_labels(const XYRange& iy, XYRange& oy, const string& strLabels)
{
	if(strLabels.IsEmpty())
		return;
	
	vector<int> vnIndices;
	if(!okutil_convert_labels_string_to_indices(strLabels, &vnIndices))	// to do
		return;
	vnIndices.Sort();
	int nSize = vnIndices.GetSize();

	Column 	colInX, colInY, colOutX, colOutY;
	iy.GetXColumn(colInX);
	iy.GetYColumn(colInY);
	oy.GetXColumn(colOutX);
	oy.GetYColumn(colOutY);
	
	if(!(colInX && colInY && colOutX && colOutY))
		return;

	Worksheet wksOut;
	colOutY.GetParent(wksOut);
	if(!wksOut)
		return;

	for(int ii=0; ii < nSize; ii++)
	{
		if(	vnIndices[ii] < 0 ||
			ii>0 && vnIndices[ii] == vnIndices[ii-1])
			continue;

		string strLabel;
		if(colInY.GetExtendedLabel(strLabel, vnIndices[ii]))
		{
			wksOut.CheckAddLabelByType(vnIndices[ii]);
			colOutY.SetExtendedLabel(strLabel, vnIndices[ii]);
		}
		
		if(colOutX.GetExtendedLabel(strLabel, vnIndices[ii]) && strLabel.IsEmpty() && colInX.GetExtendedLabel(strLabel, vnIndices[ii]) && !strLabel.IsEmpty() )
			colOutX.SetExtendedLabel(strLabel, vnIndices[ii]);
	}
}

static bool _mergexy_check_input_settings(TreeNode& trGetN, string& strErrMsg)
{
	int nErr = CER_NO_ERROR;
	int nSize =  get_input_xyrange_data_size(trGetN.iy);
	if(get_input_xyrange_num(trGetN.iy) < 1)
		nErr = XFERR_AT_LEAST_ONE_XYRANGE;
	else if(nSize <= 0)
		nErr = CER_NO_DATA;
	
	if(nErr != CER_NO_ERROR)
	{
		strErrMsg = nErr;
		return false;
	}
	
	if(get_input_xyrange_num(trGetN.oy) < 1)
	{
		strErrMsg = XFERR_AT_LEAST_ONE_XYRANGE;
		return false;
	}
	
	string strLabels = trGetN.label.strVal;
	vector<int> vnIndices;
	if(!strLabels.IsEmpty() && !okutil_convert_labels_string_to_indices(strLabels, &vnIndices))
	{
		strErrMsg = "Invalid Label Type String!";	// to do
		return false;
	}

	return true;
}
//----------- end REMOVE_LABEL_HANDLING_TO_ALLOW_GIVING_OUT_FOR_SR4

///------ Folger 10/21/09 QA80-14477 MORE_WORK_ON_OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
static	BOOL	_is_colx_date_time_format(TreeNode& trXY)
{
	XYRange		xy;
	if ( okxf_resolve_tree_construct_range(&trXY, &xy) && xy )
	{
		Column	colX;
		if ( xy.GetXColumn(colX) && colX )
		{
			int		nFormat = colX.GetFormat();
			return OKCOLTYPE_TIME == nFormat || OKCOLTYPE_DATE == nFormat;
		}
	}
	
	return FALSE;
}
///------ End MORE_WORK_ON_OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY

/// YuI 10/20/09 QA70-14477 OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
static void	_compute_auto_precision(TreeNode& trInput, TreeNode& trOuput, TreeNode& trPrecision)
{
	///------ Folger 10/21/09 QA80-14477 MORE_WORK_ON_OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
	if ( 1 == octree_get_auto_support(&trPrecision) )
	{
		double	rr;
		LT_get_var("@SD", &rr);
				
		if ( _is_colx_date_time_format(trInput) || _is_colx_date_time_format(trOuput) )
			rr = 0.0;
		
		trPrecision.nVal = rr;
	}
	///------ End MORE_WORK_ON_OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
}
/// end OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY

void wmergexy(const XYRange& iy, XYRange& oy, const string& label, const string& hint_label, const int& precision)
{
	
	vector vxIn, vyIn, vxOut, vyOut;
	
	if (iy.IsValid() && iy.GetData(vyIn, vxIn, NULL, 0, DRR_GET_MISSING | DRR_BAD_WEIGHT_TREATMENT))
	{
		if(0 == vyIn.GetSize() || 0 == vxIn.GetSize())
		{
			XF_THROW(CER_NO_DATA);
		}
	}
	else
	{
		XF_THROW(XFERR_GET_DATA_FAILED);
	}
	
	if (!oy.IsValid() || !oy.GetData(vyOut, vxOut, NULL, 0, DRR_GET_ALL_XY | DRR_TRIM_MISSING_FROM_END | DRR_BAD_WEIGHT_TREATMENT))
		XF_THROW(XFERR_GET_DATA_FAILED);
	// in case y is shorter than x, and oy.GetData will only get dataes with the shorter size, so use temporary code here
	//if (!oy.IsValid())
		//XF_THROW(XFERR_GET_DATA_FAILED);
	//Column coX, coY;
	//oy.GetXColumn(coX);
	//oy.GetYColumn(coY);
	//if(!coX || !coY)
		//XF_THROW(XFERR_GET_DATA_FAILED);
	//vectorbase& vx = coX.GetDataObject();
	//vxOut = vx;
	//vectorbase& vy = coY.GetDataObject();
	//vyOut = vy;
	
	Worksheet wksOut;
	int r1, c1, r2, c2;
	if(!oy.GetRange(0, r1, c1, r2, c2, wksOut) || !wksOut)
		XF_THROW(XFERR_INVALID_RANGE);
	
	/// YuI 10/20/09 QA70-14477 OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
	//	if(!_merge_xy_data(vxIn, vyIn, vxOut, vyOut, wksOut) || !oy.SetData( &vyOut, &vxOut))
	if(!_merge_xy_data(vxIn, vyIn, vxOut, vyOut, wksOut, precision) || !oy.SetData( &vyOut, &vxOut))
	/// end OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
		XF_THROW(XFERR_FAIL_IN_SET_XYRANGE_DATA);
	
	///Kyle 03/12/2009 BRING_BACK_SUPPORTING_OF_LABELS_COPY
	////--------- CPY 3/9/09 REMOVE_LABEL_HANDLING_TO_ALLOW_GIVING_OUT_FOR_SR4
	////_mergexy_copy_labels(iy, oy, label);
	//if(label.Find('L') >= 0)//for now, only handle LN copying
	//{
		//Column ciX, ciY;//, coX, coY;
		//iy.GetXColumn(ciX);iy.GetYColumn(ciY);
		////oy.GetXColumn(coX);oy.GetYColumn(coY);
		//if(ciX && ciY && coX && coY)
		//{
			//string strLNix = ciX.GetLongName(), strLNiy = ciY.GetLongName();
			//string strLNox = coX.GetLongName(), strLNoy = coY.GetLongName();
			//if(strLNox.IsEmpty() && !strLNix.IsEmpty())
				//coX.SetLongName(strLNix);
			//
			//coY.SetLongName(strLNiy);
		//}
		//else
			//warning_msg_box("One of the input or output column not found", false, MB_OK, 'W');
	//}
	//--------- end REMOVE_LABEL_HANDLING_TO_ALLOW_GIVING_OUT_FOR_SR4
	_mergexy_copy_labels(iy, oy, label);
	///End BRING_BACK_SUPPORTING_OF_LABELS_COPY
	
	
}

//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 wmergexy_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return wmergexy_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	//---- CPY 3/9/09 REMOVE_LABEL_HANDLING_TO_ALLOW_GIVING_OUT_FOR_SR4
	
	if(!_mergexy_check_input_settings(trGetN, strErrMsg))
	{
		bOKEnable = false;
	}
	
	//----
	/// YuI 10/20/09 QA70-14477 OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
	_compute_auto_precision(trGetN.iy, trGetN.oy, trGetN.precision);
	/// end OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
	return true;

}

int wmergexy_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 wmergexy_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	/// YuI 10/20/09 QA70-14477 OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
	_compute_auto_precision(trGetN.iy, trGetN.oy, trGetN.precision);
	/// end OPTION_TO_CUSTOMIZE_PRECISION_FOR_WMERGEXY
}
//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 wmergexy_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
