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

//----------- Modification Log --------------
// CPY 3/17/09 QA70-13295 MOVE_NEW_LOCATION_TO_MIDDLE_OF_WKS
// Iris 3/20/2009 QA80-13295-P2 SUPPORT_SELECT_TO_NEW_RANGE_CHECKBOX
// Iris 3/20/2009 QA80-13295-P3 ADD_HINT_FOR_CURRENT_POS_AND_KEEP_GOTO_EDIT_BOX_EMPTY
/// Iris 3/26/2009 QA80-133295-P6 KEEP_ENTIRE_COL_SELECT_IF_ORIGINAL_SELECTION_IS_ENTIRE_COL
/// Iris 3/26/2009 QA80-133295-S7 CHANGE_TOTOCOL_VARIABLE_TO_COLUMN_TYPE
/// Iris 7/22/2009 QA80-13986 KEEP_ENTIRE_ROW_SELECTED
/// Iris 11/25/2009 QA81-14736 GOTO_LAST_CELL_SHOULD_ACCORDING_TO_DATA_BOUND
/// Folger 09/21/2010 CTRL_G_RUNTIME_ERROR_WHEN_MATRIX_WINDOW_ACTIVE

/// Iris 3/26/2009 QA80-133295-S7 CHANGE_TOTOCOL_VARIABLE_TO_COLUMN_TYPE
static bool s_bRowIsEmpty;
static bool s_bColIsEmpty;
///end CHANGE_TOTOCOL_VARIABLE_TO_COLUMN_TYPE

static int _get_range_num_from_range_vector(Worksheet& wks, vector<int>& vec, bool bIsRow)
{
	int nn = vec[vec.GetSize()-1];
	if(nn<0)
	{
		if(bIsRow)
			return wks.GetNumRows()-1;
		else
			return wks.GetNumCols()-1;
	}
	return nn;
}

/// Iris 7/22/2009 QA80-13986 KEEP_ENTIRE_ROW_SELECTED
//static bool _check_get_sel_range(Worksheet& wks, int* pr1 = NULL, int* pr2 = NULL, int* pc1 = NULL, int* pc2 = NULL, bool *pbEntireColumn = NULL)
static bool _check_get_sel_range(Worksheet& wks, int* pr1 = NULL, int* pr2 = NULL, int* pc1 = NULL, int* pc2 = NULL, bool *pbEntireColumn = NULL, bool *pbEntireRow = NULL)
///end KEEP_ENTIRE_ROW_SELECTED
{
	int c1, c2, r1, r2;
	int nRet = wks.GetSelection(c1, c2, r1, r2);
	
	/// Iris 3/26/2009 QA80-133295-P6 KEEP_ENTIRE_COL_SELECT_IF_ORIGINAL_SELECTION_IS_ENTIRE_COL
	if( pbEntireColumn )
		*pbEntireColumn = WKS_SEL_COLUMN & nRet? true : false;
	///end KEEP_ENTIRE_COL_SELECT_IF_ORIGINAL_SELECTION_IS_ENTIRE_COL
	
	/// Iris 7/22/2009 QA80-13986 KEEP_ENTIRE_ROW_SELECTED
	if( pbEntireRow )
		*pbEntireRow = WKS_SEL_ROW & nRet? true : false;
	///end KEEP_ENTIRE_ROW_SELECTED	
	
	if(pr1 || pr2 || pc1 || pc2)
	{
		vector<int> vR1, vC1, vR2, vC2;
		if( wks.GetSelectedRange(vR1, vC1, vR2, vC2) )
		{
			// if current exist multiple selctions, then dep on last selction just like Excel
			if(pr1)
				*pr1 = _get_range_num_from_range_vector(wks, vR1, true);
			if(pr2)
				*pr2 = _get_range_num_from_range_vector(wks, vR2, true);
			if(pc1)
				*pc1 = _get_range_num_from_range_vector(wks, vC1, false);
			if(pc2)
				*pc2 = _get_range_num_from_range_vector(wks, vC2, false);
		}
	}
	
	if( WKS_SEL_RANGE & nRet || WKS_SEL_EDIT == nRet)
		return true;	 
		
	return false;
}

static string _get_size_str(Worksheet& wks)
{
	int nRows = wks.GetNumRows();
	int nCols = wks.GetNumCols();
	///Iris 4/01/2009 QA80-13295-S10 SIMPLE_HIT
	/*
	string strRow = nRows > 1 ? _L("Rows") : _L("Row");
	string strCol = nCols > 1 ? _L("Columns") : _L("Column");
	
	string str;	
	str.Format(" %d %s, %d %s", nCols, strCol, nRows, strRow);
	*/
	string str;
	str.Format(" %d * %d", nCols, nRows);
	///end SIMPLE_HIT
	return str;
}

static string _get_current_pos_str(Worksheet& wks)
{
	string str;
	
	vector<int> vR1, vC1, vR2, vC2;
	if( wks.GetSelectedRange(vR1, vC1, vR2, vC2) > 0 )
	{	
		int r1 = vR1[vR1.GetSize()-1];
		int c1 = vC1[vC1.GetSize()-1];
		int r2 = vR2[vR2.GetSize()-1];
		int c2 = vC2[vC2.GetSize()-1];		
		
		Column col1(wks, c1);
		Column col2(wks, c2);
		
		string strNameCol1 = col1.GetName();	
		string strNameCol2 = col2.GetName();
		
		if( r1 == r2 && c1 == c2 ) // one cell selected
		{
	 		str.Format(" %s[%d]", strNameCol1, r1+1);
		}
		else
		{
	 		str.Format(" %s[%d] : %s[%d]", strNameCol1, r1+1, strNameCol2, r2+1);	
		}			
	}	
	return str;
}

/// Iris 11/25/2009 QA81-14736 GOTO_LAST_CELL_SHOULD_ACCORDING_TO_DATA_BOUND
//static int _convert_row_col_from_str_to_index(Worksheet& wks, LPCSTR lpcszPos, bool bIsRow, bool* pbEmpty = NULL)
//lpcszColIndex only used when bIsRow is true.
static int _convert_row_col_from_str_to_index(Worksheet& wks, LPCSTR lpcszPos, bool bIsRow, bool* pbEmpty = NULL, LPCSTR lpcszColIndex = NULL, bool* pbExtendSelection = NULL)
///end GOTO_LAST_CELL_SHOULD_ACCORDING_TO_DATA_BOUND
{
	string strPos(lpcszPos);
	strPos.TrimLeft();
	strPos.TrimRight();
	
	double dSelRow, dSelCol;
	LT_get_var("selr1", &dSelRow);
	LT_get_var("selc1", &dSelCol);	
	
	if(strPos.IsEmpty()) //empty means current selection
	{
		if(pbEmpty)
			*pbEmpty = true;
		
		double xx;
		if(bIsRow)
			xx = dSelRow;
		else
			xx = dSelCol;
		return is_missing_value(xx) ? 0 : xx-1;
	}
	else
	{
		if(pbEmpty)
			*pbEmpty = false;
	}
	
	if( !bIsRow ) 
	{
		Column col;
		okxf_resolve_string_get_origin_object(lpcszPos, &col);
		if(col)
			return col.GetIndex();
	}
	
	/// Iris 4/07/2009 QA80-13295-P8 SUPPORT_SCRIPT
	// int index = atoi(strPos);
	int index;
	if( bIsRow && !is_numeric(strPos) ) // if not numeric, Row string will be a LT variable
	{
		double dPos;
		LT_get_var(strPos, &dPos);
		index = (int)dPos;
	}
	else
	{
		index = atoi(strPos);
	}
	///end SUPPORT_SCRIPT
	
	if(0 == index) // Enter 0 for last Column or Row
	{
		/// Iris 11/25/2009 QA81-14736 GOTO_LAST_CELL_SHOULD_ACCORDING_TO_DATA_BOUND
		//index = bIsRow? wks.GetNumRows() : wks.GetNumCols();
		if( bIsRow )
		{
			if( lpcszColIndex && pbExtendSelection )
			{
				int nDestCol = _convert_row_col_from_str_to_index(wks, lpcszColIndex, false);
				Column col(wks, nDestCol);			
				if( col )
				{
					if( *pbExtendSelection )
					{
						int nSelCol = dSelCol -1; //convert to 0 offset
						int iR1, iR2, iC1 = nSelCol < nDestCol? nSelCol : nDestCol, iC2 = nSelCol < nDestCol? nDestCol : nSelCol;
						wks.GetBounds(iR1, iC1, iR2, iC2);
						index = iR2 + 1;
					}
					else
					{
						if( -1 == col.GetUpperBound() ) // empty column, get last row
							index = wks.GetNumRows();
						else
							index = col.GetUpperBound() + 1; // 1 offset
					}
				}
			}
			else
				index = wks.GetNumRows();
		}
		else
		{
			index = wks.FindFirstEmpty();
			if( -1 == index ) // no empty column
				index = wks.GetNumCols();
		}
		///end GOTO_LAST_CELL_SHOULD_ACCORDING_TO_DATA_BOUND
	}	
	index--;// transfer to 0 offset
	
	return index; 
}


static int _check_row_col_error(TreeNode& trGetN, Worksheet& wks, bool bIsRow)
{
	string 	strPos;
	string 	str2ndPos; /// Iris 11/25/2009 QA81-14736 GOTO_LAST_CELL_SHOULD_ACCORDING_TO_DATA_BOUND
	int 	nCount;
	if(bIsRow)
	{
		strPos = trGetN.r1.strVal;
		str2ndPos = trGetN.c1.strVal; /// Iris 11/25/2009 QA81-14736 GOTO_LAST_CELL_SHOULD_ACCORDING_TO_DATA_BOUND
		nCount = wks.GetNumRows();
	}
	else
	{
		strPos = trGetN.c1.strVal;
		str2ndPos = trGetN.r1.strVal; /// Iris 11/25/2009 QA81-14736 GOTO_LAST_CELL_SHOULD_ACCORDING_TO_DATA_BOUND
		nCount = wks.GetNumCols();			
	}
	
	/// Iris 11/25/2009 QA81-14736 GOTO_LAST_CELL_SHOULD_ACCORDING_TO_DATA_BOUND
	//int	index = _convert_row_col_from_str_to_index(wks, strPos, bIsRow);
	bool bExtendSelection = trGetN.select.nVal;
	int	index = _convert_row_col_from_str_to_index(wks, strPos, bIsRow, NULL, str2ndPos, &bExtendSelection);	
	///end GOTO_LAST_CELL_SHOULD_ACCORDING_TO_DATA_BOUND
	if( index >= 0 && index < nCount )
		return CER_NO_ERROR;
	
	return XFERR_INVALID_ROW_COL_INDEX;	
}

static void _get_new_range(int& nNewFrom, int& nNewTo, int nCurrentFrom, int nCurrentTo, int nSpecified, bool bEmptySpecify, bool bExtendSelection)
{
	if(bEmptySpecify)
	{
		nNewFrom = nCurrentFrom;
		nNewTo = nCurrentTo;
	}
	else
	{
		/// Iris 3/30/2009 QA80-13295-P5 SHOULD_INCLUDE_ORIGINAL_RANGE_IF_EXTEND_SEL_CHOOSE
		//nNewFrom = bExtendSelection? nCurrentFrom : nSpecified;
		//nNewTo = nSpecified;
		if(bExtendSelection)
		{
			nNewFrom = nCurrentFrom;
			nNewTo = nSpecified;
			if(nSpecified < nCurrentFrom)
			{
				nNewFrom = nSpecified;
				nNewTo = nCurrentTo;
			}		
		}
		else
		{
			nNewFrom = nSpecified;
			nNewTo = nSpecified;
		}	
		///end SHOULD_INCLUDE_ORIGINAL_RANGE_IF_EXTEND_SEL_CHOOSE
	}
}

static bool _check_set_ranges(Worksheet& wks, int nNewR1, int nNewR2, int nNewC1, int nNewC2)
{
	vector<int> vR1, vC1, vR2, vC2;
	if( WKS_SEL_NONE == wks.GetSelectedRange(vR1, vC1, vR2, vC2) )
	{
		vR1.Add(nNewR1);
		vC1.Add(nNewC1);
		vR2.Add(nNewR2);
		vC2.Add(nNewC2);
	}
	else
	{
		vR1[vR1.GetSize()-1] = nNewR1;
		vC1[vC1.GetSize()-1] = nNewC1;
		vR2[vR2.GetSize()-1] = nNewR2;
		vC2[vC2.GetSize()-1] = nNewC2;		
	}
	return wks.SetSelectedRange(vR1, vC1, vR2, vC2);	
}


void dlgRowColGoto(const string& hintSize, const string& hintLast, const Column& c1, const string& r1, const int& select, const Worksheet& wks)
{
	if(!wks)
		return;
	bool bRolled = false;//---Jake 05/28/07 ADD_CURSOR_TO_THE_POSITION
	//----- CPY 3/17/09 QA70-13295 MOVE_NEW_LOCATION_TO_MIDDLE_OF_WKS
	/*
	if(r1 != NULL && r1 > 0)
	{
		string strLT = "y1=" + (r1-1);
		wks.LT_execute(strLT);
		bRolled = true;
	}
	if(c1 != NULL && c1 > 0)
	{
		string strLT = "x1=" + (c1-1);
		wks.LT_execute(strLT);
		bRolled = true;
	}
	*/
	
	/// Iris 3/20/2009 QA80-13295-P2 SUPPORT_SELECT_TO_NEW_RANGE_CHECKBOX
	/*
	if(r1 != NULL && r1 > 0)
	{
		bRolled = true;
	}
	if(c1 != NULL && c1 > 0)
	{
		bRolled = true;
	}
	
	ds_scroll_into_view(wks, r1-1, -1, c1-1, -1);
	//-----
	
	//---Jake 05/28/07 ADD_CURSOR_TO_THE_POSITION
	if(bRolled)
	{
		string script = "worksheet -s " + c1 + " " + r1 + " " + c1 + " " + r1 + ";";
		wks.LT_execute(script);
	}
	//---end ADD_CURSOR_TO_THE_POSITION
	*/	
	/// Iris 3/26/2009 QA80-133295-S7 CHANGE_TOTOCOL_VARIABLE_TO_COLUMN_TYPE
	//int nR1 = _convert_row_col_from_str_to_index(wks, r1, true, &bRowIsEmpty);
	//int nC1 = _convert_row_col_from_str_to_index(wks, c1, false, &bColIsEmpty);
	int nR1 = atoi(r1);
	int nC1 = c1.GetIndex();
	///end CHANGE_TOTOCOL_VARIABLE_TO_COLUMN_TYPE
	
	int r_1, r_2, c_1, c_2;
	bool bSelEntireColumn;
	/// Iris 7/22/2009 QA80-13986 KEEP_ENTIRE_ROW_SELECTED
	//bool bExtendSelection = _check_get_sel_range(wks, &r_1, &r_2, &c_1, &c_2, &bSelEntireColumn) && select; 
	bool bSelEntireRow; 
	bool bExtendSelection = _check_get_sel_range(wks, &r_1, &r_2, &c_1, &c_2, &bSelEntireColumn, &bSelEntireRow) && select; 
	///end KEEP_ENTIRE_ROW_SELECTED
	
	int nNewR1, nNewR2, nNewC1, nNewC2;
	_get_new_range(nNewR1, nNewR2, r_1, r_2, nR1, s_bRowIsEmpty, bExtendSelection);
	_get_new_range(nNewC1, nNewC2, c_1, c_2, nC1, s_bColIsEmpty, bExtendSelection);
	
	/// Iris 3/26/2009 QA80-133295-P6 KEEP_ENTIRE_COL_SELECT_IF_ORIGINAL_SELECTION_IS_ENTIRE_COL
	if( bSelEntireColumn && 0 == nNewR1 && nNewR2 == wks.GetNumRows()-1 )
		nNewR2 = -1;
	///end KEEP_ENTIRE_COL_SELECT_IF_ORIGINAL_SELECTION_IS_ENTIRE_COL
	
	/// Iris 7/22/2009 QA80-13986 KEEP_ENTIRE_ROW_SELECTED
	if( bSelEntireRow && 0 == nNewC1 && nNewC2 == wks.GetNumCols()-1 )
		nNewC2 = -1;
	///end KEEP_ENTIRE_ROW_SELECTED	
	
	bRolled = ( SCROLL_FAILED != ds_scroll_into_view(wks, nNewR1, nNewR2, nNewC1, nNewC2, SCROLL_TO_MIDDLE, true) );
	
	_check_set_ranges(wks, nNewR1, nNewR2, nNewC1, nNewC2);	
	///end SUPPORT_SELECT_TO_NEW_RANGE_CHECKBOX		
	
	
}

//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 dlgRowColGoto_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return dlgRowColGoto_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	Worksheet wks;
	okxf_resolve_string_get_origin_object(trGetN.wks.strVal, &wks);
	int nErr = CER_NO_ERROR;
	
	nErr = _check_row_col_error(trGetN, wks, true);	
	if( CER_NO_ERROR == nErr)
		nErr = _check_row_col_error(trGetN, wks, false);
	
	if(nErr != CER_NO_ERROR)
	{
		bOKEnable = false;
		strErrMsg = nErr;
	}
	
	return false;

}

int dlgRowColGoto_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 dlgRowColGoto_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	
	Worksheet wks;
	okxf_resolve_string_get_origin_object(trGetN.wks.strVal, &wks);
	///------ Folger 09/21/2010 CTRL_G_RUNTIME_ERROR_WHEN_MATRIX_WINDOW_ACTIVE
	if ( !wks )
	{
		//warning_msg_box(CER_NO_WORKSHEET, true);
		nRet = XFEVT_ABORT;
		return;
	}
	///------ End CTRL_G_RUNTIME_ERROR_WHEN_MATRIX_WINDOW_ACTIVE
	
	/// Iris 3/26/2009 QA80-133295-S7 CHANGE_TOTOCOL_VARIABLE_TO_COLUMN_TYPE
	if(nGetNDialog  == 0 || nGetNDialog == -1) // script mode or before click OK /// Iris 4/07/2009 QA80-13295-P8 SUPPORT_SCRIPT
	{	
		/// Iris 11/25/2009 QA81-14736 GOTO_LAST_CELL_SHOULD_ACCORDING_TO_DATA_BOUND
		//trGetN.r1.strVal = _convert_row_col_from_str_to_index(wks, trGetN.r1.strVal, true, &s_bRowIsEmpty); // 1 offset
		//trGetN.c1.strVal = _convert_row_col_from_str_to_index(wks, trGetN.c1.strVal, false, &s_bColIsEmpty) + 1; // 1 offset
		bool bExtendSelection = trGetN.select.nVal;
		trGetN.r1.strVal = _convert_row_col_from_str_to_index(wks, trGetN.r1.strVal, true, &s_bRowIsEmpty, trGetN.c1.strVal, &bExtendSelection); // 0 offset
		trGetN.c1.strVal = _convert_row_col_from_str_to_index(wks, trGetN.c1.strVal, false, &s_bColIsEmpty) + 1; // 1 offset
		///end GOTO_LAST_CELL_SHOULD_ACCORDING_TO_DATA_BOUND
	}
	///end CHANGE_TOTOCOL_VARIABLE_TO_COLUMN_TYPE
	
	/// Iris 4/07/2009 QA80-13295-P8 SUPPORT_SCRIPT
	//if(nGetNDialog >= 0)
	if(nGetNDialog > 0)
	///end SUPPORT_SCRIPT
	{		
		/// Iris 3/20/2009 QA80-13295-P2 SUPPORT_SELECT_TO_NEW_RANGE_CHECKBOX
		if( wks )
			trGetN.select.Enable = _check_get_sel_range(wks);		
		///end SUPPORT_SELECT_TO_NEW_RANGE_CHECKBOX			
	
		///Iris 4/01/2009 QA80-13295-S10 SIMPLE_HIT
		/*
		/// Iris 3/20/2009 QA80-13295-P3 ADD_HINT_FOR_CURRENT_POS_AND_KEEP_GOTO_EDIT_BOX_EMPTY
		TreeNode trHint = trGetN.hintCurrent;
		if(trHint)
		{
			string strLabel;
			trHint.GetAttribute(STR_LABEL_ATTRIB, strLabel);
			strLabel = _get_current_pos_str(wks);
			trHint.SetAttribute(STR_LABEL_ATTRIB, strLabel);			
		}
		///end ADD_HINT_FOR_CURRENT_POS_AND_KEEP_GOTO_EDIT_BOX_EMPTY
		*/
		///end SIMPLE_HIT
		
		TreeNode trHintSize = trGetN.hintSize;
		if(trHintSize)
		{
			string str;
			trHintSize.GetAttribute(STR_LABEL_ATTRIB, str);
			///Iris 4/01/2009 QA80-13295-S10 SIMPLE_HIT
			//str += _get_size_str(wks);
			str = _L("Size =") + _get_size_str(wks) + ", " + _L("Current =") + _get_current_pos_str(wks);
			///end SIMPLE_HIT
			trHintSize.SetAttribute(STR_LABEL_ATTRIB, str);			
		}
		
		foreach(TreeNode trn in trGetN.Children)
		{
			string strName = trn.tagName;
			if( 0 == strName.Find("hint") )
				trn.SetAttribute(STR_ATTRIB_DISPFMT, DISPLAY_EDITOR_USE_LABEL);
		}
		
	}
	
}
//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 dlgRowColGoto_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
