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

//---------------- Modification Log --------------
//CPY 11/03/08 HIDDEN_BOOK_FAILED_SEL_RANGE
//YuI 11/04/08 QA70-12501 INIFINE_LOOP_IN_WDELUP_XFUNCTION
//Kyle 11/12/2008 QA80-12565 OUT_MESSAGE_TO_RESULTS_LOG
//Kyle 11/20/2008 ADD_OPTION_TO_COPY_COLUMN_LABELS
//CPY 11/29/08 QA80-12565 OUT_MSG_SHOULD_BE_USING_STANDARD_METHOD
/// Iris 6/04/2009 OUTPUT_NUM_DUPLICATE
/// CPY 6/18/09 DUP_COUNTS_OUTPUT_TO_VEC
/// Kenny 6/22/2009 USE_NEW_VERSION_OF_FIND_DUPLICATES_TO_DELETE_DUPLICATES
/// Folger 07/08/09 QA80-12431-P3 REDUNDANT_COLUMN_IS_CREATED_AFTER_NEW_SHEET_AND_OUTPUT_COUNTS
/// Iris 7/14/2009 QA80-13924 ROLLBACK_DUPLICATE_COUNTS_OUTPUT_AS_CHECKBOX
/// Kenny 7/14/2009 QA80-13924-P1 WDELDUP_SHOULD_SUPPORT_UNDO
/// Kyle 11/20/2009 QA80-12431-P4 USE_COLUMN_TO_GET_THE_VALUE_AND_IGNORE_MASK
/// Folger 12/17/09 QA81-14856-P2 WDELDUP_SHOULD_NOT_CLEAR_COUNTS_ON_RECALCULATE
/// Kyle 12/31/2009 QA80-12431-P6 COUNTS_KEEP_ONE_TO_ONE_CORRESPONDING_WITH_THE_DATA
/// Kyle 06/24/2010 ORG-304 COPY_COLUMN_DESIGNATIONS_FROM_SOURCE_WORKSHEET
/// Kyle 09/19/2010 ORG-1007-P1 WDELDUP_IMPROVE_SPEED
//------------------------------------------------

///------ Folger 07/08/09 QA80-12431-P3 REDUNDANT_COLUMN_IS_CREATED_AFTER_NEW_SHEET_AND_OUTPUT_COUNTS
static	int&		_get_input_wks_original_column_size(TreeNode& trGetN = NULL)
{
	static	int		l_nInputWksOriginalSize = 0;
	if ( trGetN )
	{
		TreeNode trRange = trGetN.irng;
		DataRange rData;
		okxf_resolve_tree_construct_range(&trRange, &rData);
	
		int r1, r2, c1, c2;
		Worksheet	wks;
		if( rData && rData.GetNumRanges() && rData.GetRange(0, r1, c1, r2, c2, wks) )
			l_nInputWksOriginalSize = wks.GetNumCols();
	}
	
	return l_nInputWksOriginalSize;
}
///------ End REDUNDANT_COLUMN_IS_CREATED_AFTER_NEW_SHEET_AND_OUTPUT_COUNTS


void wdeldup(const Range& irng, const int& keep1st, const int& sensitive, const int& undo, Worksheet& ow, const int& counts)
{
	// get source data to vector<string>
	///Kyle 11/20/2009 QA80-12431-P4 USE_COLUMN_TO_GET_THE_VALUE_AND_IGNORE_MASK
	/*
	vector<string> vsCol;
	DWORD dwPlotID;
	irng.GetData(DRR_NO_WEIGHTS|DRR_GET_MISSING, 0, &dwPlotID, NULL, &vsCol);
	*/
	///End USE_COLUMN_TO_GET_THE_VALUE_AND_IGNORE_MASK
	
	// worksheet
	Worksheet wksSrc;
	int r1, c1, r2, c2;
	irng.GetRange(0, r1, c1, r2, c2, wksSrc);
	if(!wksSrc)
		XF_THROW(XFERR_INVALID_RANGE);
	///Kyle 11/20/2009 QA80-12431-P4 USE_COLUMN_TO_GET_THE_VALUE_AND_IGNORE_MASK
	vector<string> vsCol;
	Column col(wksSrc, c1);
	if( !col )
		XF_THROW(XFERR_INVALID_RANGE);
	col.GetStringArray(vsCol, r1, r2);
	///End USE_COLUMN_TO_GET_THE_VALUE_AND_IGNORE_MASK
	if(!ow)
		XF_THROW(XFERR_INVALID_RANGE);
	///------ Folger 12/17/09 QA81-14856-P2 WDELDUP_SHOULD_NOT_CLEAR_COUNTS_ON_RECALCULATE
	int		nNumCols = _get_input_wks_original_column_size();
	///------ End WDELDUP_SHOULD_NOT_CLEAR_COUNTS_ON_RECALCULATE
	if(wksSrc != ow)
	{
		/// YuI 11/04/08 QA70-12501 INIFINE_LOOP_IN_WDELUP_XFUNCTION
		//	ow.CreateCopy(wksSrc, CREATE_VISIBLE_SAME, DCTRL_COPY_DEFAULT | DCTRL_COPY_USE_EXIST_OKPTR );
		///Kyle 11/20/2008 ADD_OPTION_TO_COPY_COLUMN_LABELS
		//wksSrc.CopyTo(ow, 0, -1, 0, -1, 0, -1, CPYT_COPY_COLUMN_FORMAT);
		///Kyle 06/24/2010 ORG-304 COPY_COLUMN_DESIGNATIONS_FROM_SOURCE_WORKSHEET
		//wksSrc.CopyTo(ow, 0, -1, 0, -1, 0, -1, CPYT_COPY_COLUMN_FORMAT|CPYT_COPY_COLUMN_LABELS);
		wksSrc.CopyTo(ow, 0, -1, 0, -1, 0, -1, CPYT_COPY_COLUMN_FORMAT|CPYT_COPY_COLUMN_LABELS|CPYT_COPY_COLUMN_DESIGNATIONS);
		///End COPY_COLUMN_DESIGNATIONS_FROM_SOURCE_WORKSHEET
		///End ADD_OPTION_TO_COPY_COLUMN_LABELS
		/// end INIFINE_LOOP_IN_WDELUP_XFUNCTION
		///------ Folger 07/08/09 QA80-12431-P3 REDUNDANT_COLUMN_IS_CREATED_AFTER_NEW_SHEET_AND_OUTPUT_COUNTS
		///------ Folger 12/17/09 QA81-14856-P2 WDELDUP_SHOULD_NOT_CLEAR_COUNTS_ON_RECALCULATE
		//ow.SetSize(-1, _get_input_wks_original_column_size());
		///------ End WDELDUP_SHOULD_NOT_CLEAR_COUNTS_ON_RECALCULATE
		///------ End REDUNDANT_COLUMN_IS_CREATED_AFTER_NEW_SHEET_AND_OUTPUT_COUNTS
	}
	
	// get rows indices to delete
	vector<int> vnMapIndices;
	vector<uint> vnR1s;
	/// Kenny 6/22/2009 USE_NEW_VERSION_OF_FIND_DUPLICATES_TO_DELETE_DUPLICATES
	//int nDup = vsCol.FindDuplicates( vnMapIndices, vnR1s, sensitive);		// case sensitive	
	vector<uint> vnOccurrences;
	int nDup = vsCol.FindDuplicates( vnMapIndices, vnR1s, sensitive, vnOccurrences);	// case sensitive
	
	/// Kenny 7/14/2009 QA80-13924-P1 WDELDUP_SHOULD_SUPPORT_UNDO
	//vector<int> vnMapIndicesOrigin;
	//vnMapIndicesOrigin = vnMapIndices;
	/// End QA80-13924-P1 WDELDUP_SHOULD_SUPPORT_UNDO
	///End USE_NEW_VERSION_OF_FIND_DUPLICATES_TO_DELETE_DUPLICATES
	
	if(keep1st)
	{
		/// Kenny 6/22/2009 USE_NEW_VERSION_OF_FIND_DUPLICATES_TO_DELETE_DUPLICATES
		///// Iris 6/04/2009 OUTPUT_NUM_DUPLICATE this is temp solution, should improve FindDuplicates in vc level replace coding in XF with OC
		//if(counts)
		//{
			//vector<int> vnDepCounts;
			//vnDepCounts.SetSize(vsCol.GetSize());
			//vnDepCounts = 1;
			//
			//vector vMapIndicesTemp;
			//vMapIndicesTemp = vnMapIndices;
			//for(int ii = 0; ii < vnR1s.GetSize(); ii++)
			//{
				//int nR1Index = vnR1s[ii];
				//
				//vector<uint> vn;
				//int nCount = vMapIndicesTemp.Find(MATREPL_TEST_EQUAL, vnMapIndices[nR1Index], vn);
				//ASSERT( nCount > 1 );
				//
				//vnDepCounts[nR1Index] = nCount;
			//}
			////---- CPY 6/18/09 DUP_COUNTS_OUTPUT_TO_VEC
			////int nCountsCol = ow.AddCol();
			////ow.Columns(nCountsCol).SetLongName(_L("Counts"));
			////Dataset ds(ow, nCountsCol);
			////ds = vnDepCounts;
			//counts = vnDepCounts;
			////----
		//}
		/////end OUTPUT_NUM_DUPLICATE
		///End USE_NEW_VERSION_OF_FIND_DUPLICATES_TO_DELETE_DUPLICATES
	
		vnMapIndices.Replace(vnR1s, -1);
	}
	
	uint wBitwiseOption = MATREPL_TEST_GREATER | MATREPL_TEST_LESSTHAN;		// set as !=
	vector<uint> vnRowsToDel;
	int nRows = vnMapIndices.Find( wBitwiseOption, -1, vnRowsToDel);
	if(vnRowsToDel.GetSize() > 0)
		vnRowsToDel = vnRowsToDel + r1;		// offset
	
	/// Iris 7/14/2009 QA80-13924 ROLLBACK_DUPLICATE_COUNTS_OUTPUT_AS_CHECKBOX
	/*
	/// Kenny 6/22/2009 USE_NEW_VERSION_OF_FIND_DUPLICATES_TO_DELETE_DUPLICATES
	if(counts)
	{
		int nUniqueCount = vsCol.GetSize() - nRows;
		if(keep1st)
			nUniqueCount -= vnR1s.GetSize();
		if(keep1st)
		{
			const int nOccurrencesGroupSize = vnOccurrences.GetSize();
			const int nCountSize = nUniqueCount + nOccurrencesGroupSize;
			counts.SetSize( nCountSize );
			
			vector<bool> vbOccurrencesFlag( nOccurrencesGroupSize );
			vbOccurrencesFlag = false;
			
			int nCountIndex = 0;
			for(int ii = 0; ii < vnMapIndicesOrigin.GetSize() && nCountIndex < nCountSize; ++ii)
			{
				int nMapIndex = vnMapIndicesOrigin[ii];
				if (-1 == nMapIndex )
				{
					counts[ nCountIndex++ ] = 1;
				}
				else if ( !vbOccurrencesFlag[nMapIndex] )
				{
					counts[ nCountIndex++ ] = vnOccurrences[nMapIndex];
					vbOccurrencesFlag[nMapIndex] = true;
				}
			}
		}
		else
		{
			counts.SetSize( nUniqueCount );
			counts = 1;
		}		
	}
	///End USE_NEW_VERSION_OF_FIND_DUPLICATES_TO_DELETE_DUPLICATES
	*/
	if( counts )
	{
		vector vCounts(vsCol.GetSize());
		vCounts = 1;
		if(keep1st)
		{
			for(int index = 0; index < vnR1s.GetSize() && index < vnOccurrences.GetSize(); index++)
			{
				if( vnR1s[index] < vCounts.GetSize() )
					vCounts[vnR1s[index]] = vnOccurrences[index];
			}
		}
		///Kyle 12/31/2009 QA80-12431-P6 COUNTS_KEEP_ONE_TO_ONE_CORRESPONDING_WITH_THE_DATA
		if(r1 > 0)
			vCounts.InsertAt(0, NANUM, r1);
		///End COUNTS_KEEP_ONE_TO_ONE_CORRESPONDING_WITH_THE_DATA
		
		///------ Folger 12/17/09 QA81-14856-P2 WDELDUP_SHOULD_NOT_CLEAR_COUNTS_ON_RECALCULATE
		///// Kenny 7/14/2009 QA80-13924-P1 WDELDUP_SHOULD_SUPPORT_UNDO
		////int nCountsCol = ow.AddCol();
		//int nCountsCol = ow.AddCol(NULL, undo);
		///// End QA80-13924-P1 WDELDUP_SHOULD_SUPPORT_UNDO
		//ow.Columns(nCountsCol).SetLongName(_L("Counts"));
		//Dataset ds(ow, nCountsCol);
		Column		col(ow, nNumCols++);
		if ( !col )
		{
			col.Attach(ow, ow.AddCol(NULL, undo));
		}
		col.SetLongName(_L("Counts"));
		Dataset		ds(col);
		///------ End WDELDUP_SHOULD_NOT_CLEAR_COUNTS_ON_RECALCULATE
		ds = vCounts;
		
		col.SetLowerBound(r1);					///Kyle 12/31/2009 QA80-12431-P6 COUNTS_KEEP_ONE_TO_ONE_CORRESPONDING_WITH_THE_DATA
	}
	///end ROLLBACK_DUPLICATE_COUNTS_OUTPUT_AS_CHECKBOX
	
	///------ Folger 12/17/09 QA81-14856-P2 WDELDUP_SHOULD_NOT_CLEAR_COUNTS_ON_RECALCULATE
	ow.SetSize(-1, nNumCols);
	///------ End WDELDUP_SHOULD_NOT_CLEAR_COUNTS_ON_RECALCULATE
	
	///Kyle 09/19/2010 ORG-1007-P1 WDELDUP_IMPROVE_SPEED
	/*
	// delect rows
	vector<int> vnRowBegin;
	vnRowBegin = vnRowsToDel;
	//----- CPY 11/03/08 HIDDEN_BOOK_FAILED_SEL_RANGE, this will no longer be a problem after 12513 is fixed but we should have err checking anyway
	//ow.SetSelectedRange( vnRowBegin )
	//vnRowBegin.SetSize( 0 );
	//ow.SetSelectedRange( vnRowBegin );
	if(ow.SetSelectedRange( vnRowBegin ))
	{
		ow.DeleteSelection( undo );
		///Kyle 11/12/2008 QA80-12565 OUT_MESSAGE_TO_RESULTS_LOG
		string strMsg;
		strMsg.Format(_L("%d row(s) were deleted"), vnRowBegin.GetSize());
		//----- CPY 11/29/08 QA80-12565 OUT_MSG_SHOULD_BE_USING_STANDARD_METHOD
		//Project.OutStringToResultsLog( strMsg );
		warning_msg_box(strMsg, false, 'I');
	
		//-----
		///End OUT_MESSAGE_TO_RESULTS_LOG
	}
	else
		printf("failed to select rows in %s, it might be hidden\n", ow.GetName());
	
	ow.SetSelectedRange( NULL );//unsel all, will trigger internal clean up for temp win created for hidden book as well
	//----- end HIDDEN_BOOK_FAILED_SEL_RANGE
	*/
	if( worksheet_delete_rows(ow, vnRowsToDel, undo) )
	{
		string strMsg;
		strMsg.Format(_L("%d row(s) were deleted"), vnRowsToDel.GetSize());
		warning_msg_box(strMsg, false, 'I');
	}
	else
		printf("failed to select rows in %s, it might be hidden\n", ow.GetName());
	///End WDELDUP_IMPROVE_SPEED
}

//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 wdeldup_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return wdeldup_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	TreeNode trRange = trGetN.irng;
	DataRange rData;
	okxf_resolve_tree_construct_range(&trRange, &rData);
	
	int r1, r2, c1, c2;
	Datasheet ds;
	if(!rData || !rData.GetNumRanges() || !rData.GetRange( 0, r1, c1, r2, c2, ds) || c1!=c2)
	{
		strErrMsg = CER_NOT_SINGLE_RANGE;		// Please select a range with only one subrange.
		bOKEnable = false;
	}
	return false;

}

int wdeldup_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 wdeldup_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	if( nGetNDialog == 0 && !(dwCntrl & LTXF_SHOW_DIALOG) )
	{
		TreeNode trRange = trGetN.irng;
		DataRange rData;
		okxf_resolve_tree_construct_range(&trRange, &rData);
	
		int r1, r2, c1, c2;
		Datasheet ds;
		if(!rData || !rData.GetNumRanges() || !rData.GetRange( 0, r1, c1, r2, c2, ds) || c1!=c2)
			nRet = XFEVT_ABORT;
	}
	///------ Folger 07/08/09 QA80-12431-P3 REDUNDANT_COLUMN_IS_CREATED_AFTER_NEW_SHEET_AND_OUTPUT_COUNTS
	if ( 0 == nGetNDialog || -1 == nGetNDialog )
	{
		_get_input_wks_original_column_size(trGetN);
	}
	///------ End REDUNDANT_COLUMN_IS_CREATED_AFTER_NEW_SHEET_AND_OUTPUT_COUNTS
}
//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 wdeldup_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
