#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	trim_right,
	trim_all,
};
enum{
	option_unlink,
	option_link,
};
//put additional include files here

//put your own support static functions here
//trim options
enum {
	OPT_TRIM_RIGHT = 0, //trim all the cell with missing value at the end of the column
	OPT_TRIM_ALL = 1, //trim all the cell with missing value in a column
};

enum {
	OPT_TRIM_UNLINKED = 0,
	OPT_TRIM_LINKED = 1
};


void rtrim(const Range& irng, const int& trim, const int& option)
{
	
	SheetRangesList rngList(irng);
	int nNumSheets = rngList.GetNumSheets();
	for ( int iSheet = 0; iSheet < nNumSheets; iSheet++ )
	{
		DataRange drSub;
		if ( !rngList.GetWksSubRange(iSheet, drSub) )
			continue;
	
		const int nNumRanges = drSub.GetNumRanges();
		if ( nNumRanges == 0 ) //no data selected.
			return;
	
		vector<int> vnCols(0);
		Worksheet wks;
		for ( int iRange = 0; iRange < nNumRanges; iRange++ )
		{
			int iCol1, iCol2;
			drSub.GetRange(wks, iCol1, iCol2, iRange);
			for ( int idx = iCol1; idx <= iCol2; idx++ )
				vnCols.Add(idx);
		}
		
		vector<uint>	vnIndices; //for OPT_TRIM_LINKED option
		
		for ( int idx = 0; idx < vnCols.GetSize(); idx++ )
		{
			Column col(wks, vnCols[idx]);
			vectorbase& vb = col.GetDataObject();
			
			if ( OPT_TRIM_RIGHT == trim && OPT_TRIM_UNLINKED == option )
				vb.TrimRight();
			else if ( OPT_TRIM_ALL == trim && OPT_TRIM_UNLINKED == option )
				vb.Trim();
			else if ( OPT_TRIM_LINKED == option )
			{
				int nEnd = vb.GetUpperBound();
				if ( nEnd >= vnIndices.GetSize() )
				{
					int nOldSize = vnIndices.GetSize();
					vnIndices.SetSize(nEnd + 1);
					vector<uint> vnNewIndices;;
					vnNewIndices.Data(nOldSize, nEnd, 1);
					vnIndices.Replace(vnNewIndices, 0); //reset all new items
				}
				//get indices of NANUM
				vector<uint> vnMissing;
				vector vbTmp = vb; //temparay solution, should be updated when #13553 fixed.
				if ( vbTmp.Find(vnMissing, NANUM) > 0 )
				{
					//if OPT_TRIM_RIGHT, should filter those items that are not at the end.
					if ( OPT_TRIM_RIGHT == trim )
					{
						vnMissing.Sort();
						int iPlaceToTrim = vbTmp.GetSize() - 1;
						int iItemToRemove = vnMissing.GetSize() - 1;;
						while ( iItemToRemove >= 0 && vnMissing[iItemToRemove] == iPlaceToTrim )
						{
							iItemToRemove--;
							iPlaceToTrim--;
						}
						//e.g, if vbTmp is {1,NANUM,3,4,5,NANUM, 7, NANUM, NANUM}, then vnMissing is {1, 5, 7, 8}
						//iItemToRemove's initial value is 2, and iPlaceToTrim's initial value is 8
						//then after the code above, iItemToRemove will be 0, and iPlaceToTrim will be 6, vnMissing[iItemToRemove] = 5, so should remove 5 and any item before it(in this example is 1) from vnMissing
						//since the last items in vnMissing is not consecutive
						while ( iItemToRemove >= 0 ) 
							vnMissing.RemoveAt(iItemToRemove--);
					}
					
					vnIndices.Replace(vnMissing, 1); //flag the rows that have missing value and will be removed
				}
			}
			else
			{
				ASSERT(FALSE); //should never come here
				out_int("Invalid Trim Option : ", trim);
			}
		}
		
		//special handling for OPT_TRIM_LINKED
		if ( OPT_TRIM_LINKED == option )
		{
			vector<uint> vnMissing;
			if ( vnIndices.Find(vnMissing, 1) > 0 ) //get the row indices into vnMissing if the row contains missing value
			{
				for ( idx = 0; idx < vnCols.GetSize(); idx++ )
				{
					Column col(wks, vnCols[idx]);
					vectorbase& vb = col.GetDataObject();
					
					vector vTmp = vb;
					vector<int> vnMissingTmp;
					vnMissingTmp = vnMissing;
					vnMissingTmp.Sort(); //sort ascending
					
					int iSize = vnMissingTmp.GetSize();;
					while ( iSize > 0 && vnMissingTmp[iSize - 1] >= vTmp.GetSize() ) //trim items if it is larger than the bound of vTmp
						iSize--;
					
					vnMissingTmp.SetSize(iSize); //remove all invalid indices
					
					if ( vnMissingTmp.GetSize() > 0 )
						vTmp.RemoveAt(vnMissingTmp); //remove rows that should be removed according to option.
					
					vb = vTmp;
				}
			}
		}
	}
}

//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 rtrim_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return rtrim_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	//strAux = optional string for XF Wizard Bar, like DLG_NEED_CHANGE_GRID etc, it will be invalid if from internal node value change event
	return false;

}

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