#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	method_del,
	method_missing,
	method_mask,
};
//put additional include files here
#include <event_utils.h> /// Hong 10/22/09 QA80-14475-S1 USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE


//-------- Modification Log ------------------
//CPY 10/16/09 HIDE_REF_COL_FROM_GUI
///Sim 10-20-2009 QA81-14475-P2 SUPPORT_OFFSET_FOR_DEL_MISSING_MASKED_ROWS
///Kyle 10/21/2009 QA80-14475-P4 REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
///CPY 10/21/09 QA80-14475-P6 MISSING_VALUES_SHOWING_AT_END_OF_SHEET_AFTER_DEL
/// Hong 10/22/09 QA80-14475-S1 USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
/// Kyle 10/30/2009 QA80-14475-P11 REORDER_CHECKS_IF_WKS_PROTECTED
/// Sim 12-09-2009 QA81-14524-P6 FIX_REDUCE_ROW_TO_NEW_COL_MISS_MASK_STATUS

static bool _check_input(TreeNode& trGetN, string& strErrMsg)
{
	/// Hong 10/22/09 QA80-14475-S1 USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
	/*
	Worksheet wks;
	if( !okxf_resolve_string_get_origin_object(trGetN.iw.strVal, &wks) || !wks)
	{
		strErrMsg = CER_NO_WORKSHEET;
		return false;
	}
	if( wks.GetNumCols() <= 0 || wks.GetNumRows() <= 0)
	{
		strErrMsg = XFERR_WKS_IS_EMPTY;
		return false;
	}
	*/
	TreeNode	trInput = trGetN.irng;
	Range 		drInput;
	if ( !okxf_resolve_tree_construct_range(&trInput, &drInput) )
	{
		strErrMsg = CER_FFT_GET_INPUT_FAIL;
		return false;
	}
	Worksheet 	wks;
	int			nC1, nC2;
	if ( !drInput.GetRange(wks, nC1, nC2) || !wks )
	{
		strErrMsg = CER_NO_WORKSHEET;
		return false;
	}
	vector		vv;
	if ( 0 == drInput.GetNumData() || !drInput.GetData(vv, 0) || 0 == vv.GetSize() )
	{
		strErrMsg = CER_NO_DATA;
		return false;
	}
	/// end USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
	//--- CPY 10/16/09 HIDE_REF_COL_FROM_GUI
	/*
	if(trGetN.method.nVal != method_del)
	{
		int r1, r2, c1, c2;
		Datasheet ds;
		TreeNode trRange = trGetN.rng;
		DataRange rData;
		okxf_resolve_tree_construct_range(&trRange, &rData);
		
		string strRng = trRange.strVal;
		if( !strRng.IsEmpty() && !rData )
		{
			strErrMsg = CER_COL_NUM_NOT_ONE;
			return false;
		}

		if( rData && rData.GetNumRanges() >= 1 )
		{
			if( rData.GetNumRanges() > 1 || !rData.GetRange( 0, r1, c1, r2, c2, ds) || c1!=c2 )
			{
				strErrMsg = CER_COL_NUM_NOT_ONE;		// Please select a range with only one subrange.
				return false;
			}
			Worksheet wksRng = ds;
			if( wksRng != wks )
			{
				strErrMsg = _L("Please select the Reference Column from the Input Worksheet.");
				return false;
			}
		}
	}
	else
	*/
	//--- end HIDE_REF_COL_FROM_GUI
	{
		int nRows = wks.GetNumRows();
		if(trGetN.start.nVal <= 0 || trGetN.start.nVal > nRows)
		{
			strErrMsg = XF_WDELROWS_STARTING_ROW;
			return false;
		}
		if(trGetN.end.nVal >= 0 && trGetN.end.nVal < trGetN.start.nVal)
		{
			strErrMsg = XF_WDELROWS_ENDING_ROW;
			return false;
		}
		if(trGetN.del.nVal < 1 || trGetN.del.nVal >= nRows)
		{
			strErrMsg = XF_WDELROWS_DEL_ROWS;
			return false;
		}
		if(trGetN.skip.nVal < 1 || trGetN.skip.nVal >= nRows)
		{
			strErrMsg = XF_WDELROWS_SKIP_ROWS;
			return false;
		}
	}
	return true;
}

static void _show_method(TreeNode& trGetN)
{
	bool bDel = trGetN.method.nVal==method_del;

	///---Sim 10-20-2009 QA81-14475-P2 SUPPORT_OFFSET_FOR_DEL_MISSING_MASKED_ROWS
	//trGetN.start.Show = bDel;
	trGetN.start.Show = true;
	///---END QA81-14475-P2 SUPPORT_OFFSET_FOR_DEL_MISSING_MASKED_ROWS
	trGetN.end.Show = false;			// always hide this from gui
	trGetN.del.Show = bDel;
	trGetN.skip.Show = bDel;
	//--- CPY 10/16/09 HIDE_REF_COL_FROM_GUI
	//trGetN.hint.Show = !bDel;
	trGetN.rng.Show = false;
	//trGetN.undo.Show = trGetN.fast.nVal? false:true;		///Kyle 10/21/2009 QA80-14475-P4 REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
	//---
}


enum
{
	GETROW_MISSING	= 0x00000001,
	GETROW_MASKED	= 0x00000002,
};
enum
{
	//REFCOL_ANY	= 0x00000000,
	REFCOL_ALL		= 0x00000001, // all of reference columns, else to any of reference columns
};
///Kyle 10/21/2009 QA80-14475-P4 REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
//static bool _get_rows(vector<uint>& vIndexRows, const Worksheet& wks, int nRefC1 = 0, int nRefC2 = -1, int nStartRow = 0, int nEndRow = -1, DWORD dwOptions = GETROW_MISSING | GETROW_MASKED, DWORD dwRefColOptions = 0)
//---CPY 10/21/09 QA80-14475-P6 MISSING_VALUES_SHOWING_AT_END_OF_SHEET_AFTER_DEL
//static int _get_rows_push_end(vector<uint>& vOrder, const Worksheet& wks, int nRefC1 = 0, int nRefC2 = -1, int nStartRow = 0, int nEndRow = -1, DWORD dwOptions = GETROW_MISSING | GETROW_MASKED, DWORD dwRefColOptions = 0) 
static int _get_rows_push_end(vector<uint>& vOrder, const Worksheet& wks, int nRefC1, int nRefC2, int nStartRow, int nEndRow, DWORD dwOptions = GETROW_MISSING | GETROW_MASKED, DWORD dwRefColOptions = 0)
//---
///End REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
{
	if ( nRefC2 < 0 )
		nRefC2 = wks.GetNumCols() - 1;
	
	if ( nRefC1 > nRefC2 )
		///Kyle 10/21/2009 QA80-14475-P4 REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
		//return false;
		return -1;
		///End REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END

	int nRows = wks.GetNumRows();
	vector<byte> vRows(nRows);
	vRows = 0;
	if(nEndRow < 0 || nEndRow >= nRows)
	//---CPY 10/21/09 QA80-14475-P6 MISSING_VALUES_SHOWING_AT_END_OF_SHEET_AFTER_DEL
	//	nEndRow = nRows - 1;
		return -2; //caller must pass in correct end, not allow -1
		
	nRows = nEndRow + 1; // this might be wrong as should consider nStartRow > 0, will check later
	//---
	if(nStartRow < 0 || nStartRow > nEndRow)
		///Kyle 10/21/2009 QA80-14475-P4 REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
		//return false;
		return -3;
		///End REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
	
	bool nCols = 0;
	for ( int nCol = nRefC1; nCol <= nRefC2; nCol++ )
	{
		Column col(wks, nCol);
		if ( !col )
			continue;
		
		if ( (GETROW_MISSING & dwOptions) && (OKCOLTYPE_TEXT == col.GetFormat()) )
			continue;
		
		nCols++;
		
		vector<byte> vCurRows(nRows);
		vCurRows = 0;
		
		if ( GETROW_MISSING & dwOptions )
		{
			DatasetObject dsobj(col);
			vector<uint> vuRows;
			if ( 0 < dsobj.GetNANUMRows(vuRows, true, true) )
			{
				vCurRows.Replace(vuRows, 1);
			}
		}
		
		if ( GETROW_MASKED & dwOptions )
		{
			DatasetObject dsobj(col);
			dsobj.GetMask(vCurRows);
			vCurRows.SetSize(nRows);
		}
		
		vRows += vCurRows;
		
	}

	if ( nCols <= 0 )
	///Kyle 10/21/2009 QA80-14475-P4 REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
	//	return false;
		return -4;
	///End REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END

	// Trim before start
	if ( 0 < nStartRow )
	{
		vRows.RemoveAt(0, nStartRow);		
		vRows.InsertAt(0, 0, nStartRow);
	}
	// Trim after end
	if ( 0 < ( nRows - 1 - nEndRow ) )
	{
		ASSERT(false);//--CPY 10/21/09 QA80-14475-P6 MISSING_VALUES_SHOWING_AT_END_OF_SHEET_AFTER_DEL, I see no reason for this
		vRows.RemoveAt(nEndRow + 1, nRows - 1 - nEndRow);		
		vRows.InsertAt(nEndRow + 1, 0, nRows - 1 - nEndRow);
	}
	///Kyle 10/21/2009 QA80-14475-P4 REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
	//vRows.Find(MATREPL_TEST_GREATER, (REFCOL_ALL & dwRefColOptions) ? (nCols - 1) : 0, vIndexRows);
	//
	//return true;
	vector<uint> vn;
	int nRet = vRows.Find(MATREPL_TEST_GREATER, (REFCOL_ALL & dwRefColOptions) ? (nCols - 1) : 0, vn);
	
	vn.Data(0, nRows-1, 1);
	vn += (vRows * nRows);
	vn.Sort(SORT_ASCENDING, false, vOrder);
	
	return nRet;
	///End REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
}
///---END QA81-14475 WORKSHEET_DEL_ROWS

///Kyle 10/21/2009 QA80-14475-P4 REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
//static int _construct_row_indices_to_delete(vector<uint>& vnIndices, const Worksheet& wks, const Range& rng, int method, int start, int end, int del, int skip)
/// Hong 10/22/09 QA80-14475-S1 USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
//static int _construct_row_order_push_delete_end(vector<uint>& vnOrder, const Worksheet& wks, const Range& rng, int method, int start, int end, int del, int skip)
static int _construct_row_order_push_delete_end(vector<uint>& vnOrder, const Worksheet& wks, const Range& rng, int method, int start, int end, int del, int skip, int nSrcC1 = 0, int nSrcC2 = -1)
/// end USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
///End REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
{
	//--- CPY 10/21/09 QA80-14475-P6 MISSING_VALUES_SHOWING_AT_END_OF_SHEET_AFTER_DEL
	if(end < 0 || end >= wks.GetNumRows())
		return -8;
	//---
	
	if(method == method_del)
	{
		///Kyle 10/21/2009 QA80-14475-P4 REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
		//if(!_get_rows(vnIndices, wks.GetNumRows(), start, end, del, skip))
		//	return -1;
		//--- CPY 10/21/09 QA80-14475-P6 MISSING_VALUES_SHOWING_AT_END_OF_SHEET_AFTER_DEL
		//return okutil_reorder_push_skip(&vnOrder, wks.GetNumRows(), del, skip, start, end);
		return okutil_reorder_push_skip(&vnOrder, end + 1, del, skip, start, -1);
		//---
		///End REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
	}
	else
	{
		DWORD dwOptions = method==method_missing ? GETROW_MISSING : GETROW_MASKED;
		if(!rng || rng.GetNumRanges()==0 )
		{
			///Kyle 10/21/2009 QA80-14475-P4 REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
			//if(!_get_rows(vnIndices, wks, 0, -1, start, end, dwOptions))
			//	return -1;
			/// Hong 10/22/09 QA80-14475-S1 USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
			//return _get_rows_push_end(vnOrder, wks, 0, -1, start, end, dwOptions);
			return _get_rows_push_end(vnOrder, wks, nSrcC1, nSrcC2, start, end, dwOptions);
			/// end USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
			///End REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
		}
		else if( rng.GetNumRanges() == 1 )
		{
			Datasheet ds;
			int r1, c1, r2, c2;
			rng.GetRange( 0, r1, c1, r2, c2, ds);
			ASSERT(c1 == c2);
			///Kyle 10/21/2009 QA80-14475-P4 REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
			//if(!_get_rows(vnIndices, wks, c1, c2, start, end, dwOptions))
			//	return -1;
			return _get_rows_push_end(vnOrder, wks, c1, c2, start, end, dwOptions);
			///End REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
		}
		else
			return -101;
	}
	///Kyle 10/21/2009 QA80-14475-P4 REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
	//return vnIndices.GetSize();
	return -102;
	///End REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
}

/// YuI Hong 10/22/09 QA80-14475-S1 USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
static BOOL	_delete_worksheet_range(Worksheet& wks, int nR1, int nC1, int nR2, int nC2)
{
	if( 0 == nC1 && wks.GetNumCols() - 1 == nC2 &&  wks.GetNumRows() - 1 == nR2 )
	{
		return wks.SetNumRows(nR1 , true)
	}
	else
	{
		BOOL bReturn = TRUE;
		vector<int> vR1, vC1, vR2, vC2;
		vR1.Add(nR1);
		vR2.Add(nR2);
		vC1.Add(nC1);
		vC2.Add(nC2);
		if( wks.SetSelectedRange(vR1, vC1, vR2, vC2) )
			wks.DeleteSelection(TRUE);
		else
			bReturn = FALSE;
			
		wks.SetSelectedRange(NULL);
		
		return bReturn;
	}
	
	return FALSE;
}
/// end USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE


void wdelrows(const Range& irng, const int& method, const Range& rng, const int& del, const int& skip, const int& start, const int& end, Range& orng)
{
	/// Hong 10/22/09 QA80-14475-S1 USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
	/*
	if(!iw || !ow)
		XF_THROW(XFERR_INVALID_RANGE);
	bool bOutputToInput = true;
	if(iw != ow)
	{
		iw.CopyTo(ow, 0, -1, 0, -1, 0, -1, CPYT_COPY_COLUMN_DESIGNATIONS|CPYT_COPY_COLUMN_FORMAT|CPYT_COPY_COLUMN_LABELS);
		bOutputToInput = false;
	}
	*/
	Worksheet		iw, ow;
	int				nSrcC1, nSrcC2, nDestC1, nDestC2;
	if ( !irng.GetRange(iw, nSrcC1, nSrcC2) )
		XF_THROW(XFERR_INVALID_RANGE);
	if ( !orng.GetRange(ow, nDestC1, nDestC2) )
		XF_THROW(XFERR_INVALID_RANGE);
	if ( -1 == nSrcC2 )
		nSrcC2 = iw.GetNumCols() - 1;
	if ( -1 == nDestC2 )
		nDestC2 = ow.GetNumCols() - 1;
	
	DWORD			wResults = 0;
	irng.IsIntersect(orng, NULL, NULL, &wResults);
	bool			bOutputToInput = (RNGINTSCT_FULL == wResults && nSrcC1 == nDestC1 && nSrcC2 == nDestC2);
	if ( !bOutputToInput && CER_NO_ERROR == check_1_cell(orng) )
	{
		irng.Replicate(orng, ow, 0, nDestC1);
		orng.GetRange(ow, nDestC1, nDestC2);
	}
	if ( !bOutputToInput )
	{
		int			nDesiredDestC2 = min(nDestC1 + nSrcC2 - nSrcC1, ow.GetNumCols() - 1);
		int			nLastDestIndex = nDestC2;
		if ( nDestC2 != nDesiredDestC2 )
		{
			nLastDestIndex = nDesiredDestC2;
			nDestC2 = nDesiredDestC2;
			orng.SetRange(0, ow, 0, nDestC1, -1, nDestC2);
		}
		int			nLastSrcIndex = nSrcC1 + nDestC2 - nDestC1;
		DWORD		dwCntrl = CPYT_COPY_COLUMN_DESIGNATIONS|CPYT_COPY_COLUMN_FORMAT|CPYT_COPY_COLUMN_LABELS;
		dwCntrl |= CPYT_COPY_MASK; ///---Sim 12-09-2009 QA81-14524-P6 FIX_REDUCE_ROW_TO_NEW_COL_MISS_MASK_STATUS
		if ( is_same_layer(iw, ow) )
			dwCntrl |= CPYT_ALLOW_SAME_LAYER_IF_NOT_INTERSECT;
		if ( RNGINTSCT_NONE == wResults )
			iw.CopyTo(ow, nSrcC1, nLastSrcIndex, 0, -1, nDestC1, -1, dwCntrl);
		else if ( nLastDestIndex != nLastSrcIndex )
		{
			for ( ; nLastDestIndex >= nDestC1; --nLastDestIndex, --nLastSrcIndex )
			{
				int	nRet = iw.CopyTo(ow, nLastSrcIndex, nLastSrcIndex, 0, -1, nLastDestIndex, -1, dwCntrl);
				// Worksheet::CopyTo support copy to itself if not intersect
				ASSERT( 0 == nRet );
			}
		}
	}
	/// end USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
	vector<uint> vnOrder;
	//--- CPY 10/21/09 QA80-14475-P6 MISSING_VALUES_SHOWING_AT_END_OF_SHEET_AFTER_DEL
	/*
	///Kyle 10/21/2009 QA80-14475-P4 REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
	//vector<uint> vnIndices;
	if( ow.GetNumRows() > iw.GetNumRows() )
		ow.SetNumRows(iw.GetNumRows());
	///End REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
	DWORD dw1 = GetTickCount();//--- CPY 10/15/09 CHK_SPEED
	
	int nStartRow = start - 1;			// 1 offset to 0 offset
	int nEndRow = end;
	if(nEndRow >= 0)
		nEndRow--;
	*/
	// change Kyle's code to pass in actual ending row index into remaining codes so decision of row size will be centralized
	//Kyle's code was calling GetNumRows() in low level which is not right as decision should be made in one place
	int nR1, nR2;
	///Kyle 10/23/2009 USE_INPUT_RANGE_BOUNDS
	//iw.GetBounds(nR1, 0, nR2, -1);
	iw.GetBounds(nR1, nSrcC1, nR2, nSrcC2);
	///End USE_INPUT_RANGE_BOUNDS
	//It seems that Kyle's reorder code has trouble if col has more rows at the end
	///Kyle 10/22/2009 no need to do this since Worksheet::Reorder() is updated to allow vnOrder.GetSize() <= the number rows
	//if(ow.GetNumRows() > nR2+1 )
	//	ow.SetNumRows(nR2+1);
	///End ---
	//key change is here
	int nStartRow = start - 1;			// 1 offset to 0 offset
	int nEndRow = end;
	if(nEndRow >= 0 && nEndRow <= nR2+1)
		nEndRow--;
	else
		nEndRow = nR2;	
	//--- end MISSING_VALUES_SHOWING_AT_END_OF_SHEET_AFTER_DEL
	
	///Kyle 10/21/2009 QA80-14475-P4 REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
	//int	nRowsToDel = _construct_row_indices_to_delete(vnIndices, iw, rng, method, nStartRow, nEndRow, del, skip);
	/// Hong 10/22/09 QA80-14475-S1 USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
	//int	nErr = _construct_row_order_push_delete_end(vnOrder, iw, rng, method, nStartRow, nEndRow, del, skip);
	int	nErr = _construct_row_order_push_delete_end(vnOrder, iw, rng, method, nStartRow, nEndRow, del, skip, nSrcC1, nSrcC2);
	/// end USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
	///End REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
	//--- CPY 10/15/09 CHK_SPEED
	//	DWORD dw2 = GetTickCount();
	//	printf("time taken to generate array = %f\n", (dw2 - dw1)/1000.);
	//---
	///Kyle 10/21/2009 QA80-14475-P4 REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
	//if(nRowsToDel < 0)
	if(nErr < 0)
	///End REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
		XF_THROW(XFERR_INVALID_ARG);
	///Kyle 10/21/2009 QA80-14475-P4 REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END, always support undo
	/*
	DWORD dwCntrl = WDR_INPUT_SORTED_ASC;
	if(fast == 0)
	{
		dwCntrl |= WDR_USE_SELECTIONS;
		if(undo) //undo not supported for fast del
			dwCntrl |= WDR_UNDO;
	}
	
	//assume sorted in this method, will need to add WKS_DELETE_ROWS_SORTED_DEC to indicate
	//vnIndices.Sort(SORT_DESCENDING);
	int nErr = ow.DeleteRows(vnIndices, 0, -1, dwCntrl);
	*/
	//--- CPY 10/21/09 QA80-14475-P6 MISSING_VALUES_SHOWING_AT_END_OF_SHEET_AFTER_DEL
	//if( !ow.Reorder(vnOrder, 0, -1, true) || !ow.SetNumRows(ow.GetNumRows() - nErr, true) )
	//	XF_THROW(CER_UNKNOWN_ERROR);
	/// Hong 10/22/09 QA80-14475-S1 USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
	//if( !ow.Reorder(vnOrder, 0, -1, true) )
	if(nErr > 0)			///Kyle 10/23/2009 DO_NOTHING_IF_NO_ROWS_TO_DELETE
	{
	if( !ow.Reorder(vnOrder, nDestC1, nDestC2, true) )
	/// end USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
	{
		///Kyle 10/30/2009 QA80-14475-P11 REORDER_CHECKS_IF_WKS_PROTECTED
		//nErr = -231;
		printf(_L("The selected data contains operation, deletion can not proceed."));
		return;
		///End REORDER_CHECKS_IF_WKS_PROTECTED
	}
	else {
		/// Hong 10/22/09 QA80-14475-S1 USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
		//if(!ow.SetNumRows(nEndRow - nErr, true))
		//	nErr = -232;
		/// YuI Hong 10/22/09 QA80-14475-S1 USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
		/*
		int			nDestNumRows = nEndRow - nErr;
		Column		cc;
		for ( int index = nDestC1; index <= nDestC2; index++ )
		{
			cc.Attach(ow, index);
			ASSERT(cc);
			if ( !cc.SetNumRows(nDestNumRows) ) // Hong, to do, need support undo here later
				nErr = -231;
		}
		*/
		_delete_worksheet_range(ow, nEndRow - nErr + 1, nDestC1, nEndRow, nDestC2);
		/// end USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
		/// end USE_RANGE_INPUT_OUTPUT_TO_SUPPORT_COLUMN_RANGE
	}
	}
	//--- end MISSING_VALUES_SHOWING_AT_END_OF_SHEET_AFTER_DEL
	
	///End REORDER_THE_WORKSHEET_AND_DELETE_FROM_THE_END
	if(nErr >= 0)
	{
	//		printf("time taken to DeleteRows (%d, %d)= %f\n", nRowsToDel, nErr, (GetTickCount() - dw2)/1000.);//--- CPY 10/15/09 CHK_SPEED
		string strMsg;
		strMsg.Format(_L("%d row(s) were deleted\n"), nErr);
		warning_msg_box(strMsg, false, 'I');
	}
	else
		printf("failed to delete rows in %s, error = %d\n", ow.GetName(), nErr);
	
	
	
}

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

}

int wdelrows_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 wdelrows_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	if( is_xf_startup(nGetNDialog, dwCntrl) && !(dwCntrl & LTXF_SHOW_DIALOG) )
	{
		string strErrMsg;
		if( !_check_input(trGetN, strErrMsg) )
			nRet = XFEVT_ABORT;
	}
	else if(nGetNDialog == 0 && (dwCntrl & LTXF_EXECUTE))
	{
		if(trGetN.method.nVal == method_del)
		{
			TreeNode trRng = trGetN.rng;
			if(trRng.GetNodeCount() > 0)
			{
				trRng.SetAttribute(STR_DATA_ATTRIB, STR_OPTIONAL);
				okutil_getn_update_ranges(&trGetN);
			}
			else
			{
				trRng.strVal = STR_OPTIONAL;
			}
		}
	}
}
//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 wdelrows_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
