/*------------------------------------------------------------------------------*
 * File Name:MatObjHeadersDlg.c/h	 											*
 * Creation: Hong 05/18/10														*
 * Purpose: Main OC code for Matrix Object Headers Dialog						*
 * Copyright (c) Originlab Corp. 2010-2018										*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	Hong 05/27/10 ORG-131-P1 ADD_CONTEXT_MENU_TO_DELETE_UDL						*
 *	Hong 06/11/10 ORG-131-P14 UDL_SHOULD_NOT_SAME_AS_BUILDIN_LBL				*
 *	Hong 06/11/10 ORG-131-S1 REMOVE_ENUM_CONTEXT_MENU							*
 *	Hong 06/11/10 ORG-131-P15 KEEP_ROW_INDEX_WHEN_GOTO_ACTIVE_OBJ_COL			*
 *	Bill 07/14/2010 ORG-552-S1 BETTER_INDICATION_FOR_ACTIVE_MATRIX              *
 *	Kit	8/06/2010 ORG-736 RENAME_DIALOG_NAME_HEADERS_TO_LABELS					*			
 *------------------------------------------------------------------------------*/
#include <origin.h>
 
#include <GetNBox.h>
#include "DialogEx.h"
#include "GridControl.h"
#include "MatObjHeadersDlg.h"
#include "wksColLabels.h"




/// Kit 8/06/2010 ORG-736 RENAME_DIALOG_NAME_HEADERS_TO_LABELS
#define STR_DLG_NAME	_L("Matrix Dimension and Labels")
#define STR_DLG_TAB_X_NAME _L("X Labels")
#define STR_DLG_TAB_Y_NAME _L("Y Labels")
#define STR_DLG_TAB_Z_NAME _L("Z Labels")
/// End RENAME_DIALOG_NAME_HEADERS_TO_LABELS

#define STR_SHOW_PARAMS_REG_KEY	"ShowParams"
#define	STR_XY_AXIS_COL_HEADER	_L("|X Axis|Y Axis")
#define	STR_HDR_LN		_L("Long Name")
#define	STR_HDR_UNIT	_L("Units")
#define	STR_HDR_CMT		_L("Comments")


enum
{
	TAB_XY_MAP,
	TAB_X_HEADERS,
	TAB_Y_HEADERS,
	TAB_Z_HEADERS,
};

enum
{
	XY_ROW_START,
	///////////////////////////////////////////
	XY_ROW_DIMENSION		= XY_ROW_START,
	XY_ROW_FROM,
	XY_ROW_TO,
	XY_ROW_LN,
	XY_ROW_UNIT,
	XY_ROW_CMT,
	////////////////////////////////////////////
	XY_ROW_END,
};

enum
{
	XY_COL_X,
	XY_COL_Y,
	/////////////////////////////////////////////
	XY_COL_END,
};

enum
{
	CTXT_MENU_TO_LEFT,
	CTXT_MENU_TO_RIGHT,
	/// Hong 06/11/10 ORG-131-S1 REMOVE_ENUM_CONTEXT_MENU
	//CTXT_MENU_ENUM_TO_LEFT,
	//CTXT_MENU_ENUM_TO_RIGHT,
	/// end REMOVE_ENUM_CONTEXT_MENU
	CTXT_MENU_SEPARATOR,
	CTXT_MENU_SHOW_SYS_PARAMS,
	CTXT_MENU_ADD_UDL,
	CTXT_MENU_DELETE_UDL,
	CTXT_MENU_SEPARATOR2,
	CTXT_MENU_ACTIVE_OBJ,
};

MatObjHeadersDlg::MatObjHeadersDlg(MatrixLayer& ml)
 : ResizeDialog(IDD_MAT_DIM_HEADERS, "ODlg8")
{
	ASSERT(ml);
	m_ml = ml;
	m_bIsChanged = false;
}

MatObjHeadersDlg::~MatObjHeadersDlg()
{}

//virtual 
int	MatObjHeadersDlg::DoModalEx(HWND hParent)
{
	InitMsgMap();
	int			nRet = DoModal(hParent);
	return nRet;
}
	
BOOL	MatObjHeadersDlg::OnInitDialog()
{
	if ( !ResizeDialog::OnInitDialog() )
		return false;
	
	Text = STR_DLG_NAME;
	
	m_trTheme = m_ml.GetFormat(FPB_ALL|FPB_DATA, FOB_ALL|FPB_DATA, true, true);
	
	TreeNode		trX = m_trTheme.Root.Dimensions.X;
	TreeNode		trY = m_trTheme.Root.Dimensions.Y;
	string			strTemp;
	
	///Sophy 6/17/2010 ORG-131-P17 FORBID_CHANGE_MATRIX_DIMENTION_WHEN_CONTAINS_IMAGE
	GetItem(IDC_COL_SIZE).Enable = 
	GetItem(IDC_ROW_SIZE).Enable = !has_image(m_ml);
	///end FORBID_CHANGE_MATRIX_DIMENTION_WHEN_CONTAINS_IMAGE
	strTemp.Format("%d", trX.Size.nVal);
	GetItem(IDC_COL_SIZE).Text = strTemp;
	strTemp.Format("%d", trY.Size.nVal);
	GetItem(IDC_ROW_SIZE).Text = strTemp;
	
	strTemp = ftoa(trX.First.dVal);
	GetItem(IDC_AXIS_X_FIRST).Text = strTemp;
	strTemp = ftoa(trX.Last.dVal);
	GetItem(IDC_AXIS_X_LAST).Text = strTemp;
	strTemp = ftoa(trY.First.dVal);
	GetItem(IDC_AXIS_Y_FIRST).Text = strTemp;
	strTemp = ftoa(trY.Last.dVal);
	GetItem(IDC_AXIS_Y_LAST).Text = strTemp;

	
	// init axes tab
	m_tabCtrl = GetItem(IDC_TAB_AXES);
	m_tabCtrl.InsertItem(TAB_XY_MAP, _L("XY Mapping"));
	/// Kit 8/06/2010 ORG-736 RENAME_DIALOG_NAME_HEADERS_TO_LABELS
// 	m_tabCtrl.InsertItem(TAB_X_HEADERS, _L("X Headers"));
// 	m_tabCtrl.InsertItem(TAB_Y_HEADERS, _L("Y Headers"));
// 	m_tabCtrl.InsertItem(TAB_Z_HEADERS, _L("Z Headers"));
	m_tabCtrl.InsertItem(TAB_X_HEADERS, STR_DLG_TAB_X_NAME);
	m_tabCtrl.InsertItem(TAB_Y_HEADERS, STR_DLG_TAB_Y_NAME);
	m_tabCtrl.InsertItem(TAB_Z_HEADERS, STR_DLG_TAB_Z_NAME);
	/// End RENAME_DIALOG_NAME_HEADERS_TO_LABELS
	m_tabCtrl.SetCurSel(TAB_XY_MAP);
	updateControlsOnTabChange(TAB_XY_MAP);
	
	// init Z-axis grid
	m_gridZ.Init(IDC_GRID_Z_AXIS, *this);
	const int		nLabelTypes = RCLT_PARAM + PARAMS_MAX_NUM - RCLT_LONG_NAME;
	int				nNumUDL = getNumUserDefineParameters();
	int				nNumObjs = m_ml.MatrixObjects.Count();
	m_gridZ.SetupRowsCols(1, 1, nLabelTypes + nNumUDL + 1, nNumObjs + 1);
	// Col Header
	string			strColHeader;
	for ( int ii = 0; ii < m_ml.MatrixObjects.Count(); ii++ )
	{
		strTemp.Format("|Mat(%d)", ii + 1);
		strColHeader += strTemp;
	}
	m_gridZ.SetColHeader(strColHeader);
	/// Bill 07/14/2010 ORG-552-S1 BETTER_INDICATION_FOR_ACTIVE_MATRIX
	m_gridZ.SetBold(0, m_ml.GetActive() + m_gridZ.GetColOffset());
	/// End BETTER_INDICATION_FOR_ACTIVE_MATRIX
	// Row Header
	vector<string>	vsRowHeader;
	vsRowHeader.Add(STR_HDR_LN);
	vsRowHeader.Add(STR_HDR_UNIT);
	vsRowHeader.Add(STR_HDR_CMT);
	for ( int jj = 0; jj < PARAMS_MAX_NUM; jj++ )
	{
		if ( 0 != jj )
			strTemp.Format(_L("Parameters %d"), jj + 1);
		else
			strTemp = _L("Parameters");
		vsRowHeader.Add(strTemp);
	}
	vector<string>	vsNames;
	if ( 0 < getNumUserDefineParameters(&vsNames) )
		vsRowHeader.Append(vsNames);
	for ( int iRow = 0; iRow < vsRowHeader.GetSize(); iRow++ )
		m_gridZ.SetRowHeading(iRow, vsRowHeader[iRow]);
	// Cell Values
	vector<int>		vnTypes;
	vnTypes = GetLabelTypes();
	TreeNode		trLabels = m_trTheme.Root.Grid.Dimensions.Horizontal.Labels;
	vector<string>	vsTemp;
	foreach ( TreeNode trLabel in trLabels.Children )
	{
		int			nRow = find_in_list(trLabel.Type.nVal, vnTypes, false);
		ASSERT( -1 != nRow );
		vsTemp = trLabel.Data.strVals;
		m_gridZ.SetRowValues(nRow, vsTemp);
	}
	DWORD			wdVal;
	dlg_load_registry(STR_DLG_NAME, STR_SHOW_PARAMS_REG_KEY, wdVal, 0);
	if ( 0 == wdVal )
		ShowParameterRows(false);
	m_gridZ.ResizeCols();

	/// Bill 07/14/2010 ORG-552-S1 BETTER_INDICATION_FOR_ACTIVE_MATRIX
	m_bFirstTimeOpenZHeader = true;
	/// End BETTER_INDICATION_FOR_ACTIVE_MATRIX

	return TRUE;
}

BOOL	MatObjHeadersDlg::OnResize(int nType, int cx, int cy)
{
	MoveControlsHelper	helper(this);
	
	int				nGap = 5;	
	RECT			rt1, rt2;
	Control			ctrl;
	
	GetControlClientRect(IDOK, rt1);
	GetControlClientRect(IDC_TAB_AXES, rt2, &ctrl);
	rt2.bottom = rt1.top - nGap;
	MoveControl(ctrl, rt2);
	TabControl		tabCtrl = ctrl;
	tabCtrl.AdjustRect(FALSE, &rt2);
	GetControlClientRect(IDC_STATIC_HINT, rt1);
	MoveControl(IDC_STATIC_HINT, rt2.left + nGap, rt1.top);
	ctrl = GetItem(IDC_STATIC_PANEL);
	MoveControl(ctrl, rt2);
	ctrl = GetItem(IDC_GRID_Z_AXIS);
	rt2.bottom -= rt1.bottom - rt1.top + nGap;
	MoveControl(ctrl, rt2);
	
	GetControlClientRect(IDC_COL_SIZE, rt1);
	GetControlClientRect(IDC_AXIS_X_FIRST, rt2);
	UINT			nIDs[] = {IDC_AXIS_X_FIRST, IDC_AXIS_X_LAST, IDC_AXIS_Y_FIRST, IDC_AXIS_Y_LAST};
	MoveControls(nIDs, rt1.left - rt2.left, 0);
	
	GetControlClientRect(IDC_AXIS_LONGNAME, rt2);
	UINT			nIDs2[] = {IDC_AXIS_LONGNAME, IDC_AXIS_UNIT, IDC_AXIS_COMMENT};
	MoveControls(nIDs, rt1.left - rt2.left, 0);
	
	return true;
}

BOOL 	MatObjHeadersDlg::OnReady()
{
	m_gridZ.SetReady();
	return TRUE;
}

//BOOL 	MatObjHeadersDlg::OnDestroy()
//{}

BOOL	MatObjHeadersDlg::OnOK()
{
	if ( !m_bIsChanged )
		return TRUE;

#ifdef		_DEBUG
	Tree 			trJunk;
	trJunk = m_trTheme;
#endif		//_DEBUG
	CheckUserSettings();	///Sophy 7/13/2010 ORG-131-P21 MORE_WORK_ON_CHECK_USER_INPUT

	octree_delete_nodes_by_missing_attribute(&m_trTheme, STR_CHANGED_ATTRIB, true, true, false);
	m_ml.ApplyFormat(m_trTheme, TRUE, TRUE, TRUE);
	
	return TRUE;
}

BOOL	MatObjHeadersDlg::AddUserParameter()
{
	GETN_TREE(tr)
	GETN_STR(Name, _L("Name"), "")
	GETN_STR(value, _L("Value"), "")
		GETN_CURRENT_SUBNODE.SetAttribute(STR_SHOW_ATTRIB, FALSE);
	if ( GetNBox(tr, _L("Add User Parameter"), _L("Add User Parameter"), NULL, NULL, GetSafeHwnd()) )
	{
		string		strName = tr.Name.strVal;
		if ( strName.IsEmpty() )
			return false;
		
		string		strValue = tr.value.strVal;
		
		vector<string>	vsNames;
		getNumUserDefineParameters(&vsNames);
		/// Hong 06/11/10 ORG-131-P14 UDL_SHOULD_NOT_SAME_AS_BUILDIN_LBL
		if ( RCLT_INVALID != find_builtin_label(strName) )
		{
			MessageBox(GetSafeHwnd(), _L("Cannot rename as a built-in label name. Please specify a different label name."), NULL, MB_OK);
			return false;
		}
		/// end UDL_SHOULD_NOT_SAME_AS_BUILDIN_LBL
		if ( !is_in_list(strName, vsNames) )
		{
			vsNames.Add(strName);
			TreeNode		trUDLNames = m_trTheme.Root.Grid.Dimensions.Horizontal.UDLs;
			trUDLNames.strVals = vsNames;
			setChanged(trUDLNames);
			
			vector<string>	vsValue;
			vsValue.Add(strValue);
			int			nCount = m_ml.MatrixObjects.Count();
			vsValue.SetSize(nCount);
			for ( int ii = 1; ii < nCount; ii++ )
				vsValue[ii] = vsValue[0];

			
			int					nType = GetLabelType(m_gridZ.GetNumRows() - 1);
			TreeNode			trLabel = getLabelNode(nType);
			if ( nType < RCLT_UDL )
				nType = RCLT_UDL;
			else
				nType++;
			TreeNode			trNewLabel = trLabel.Clone();
			trNewLabel.ID = trLabel.ID + (trLabel.ID - trLabel.PrevNode.ID);
			trNewLabel.Type.nVal = nType;
			trNewLabel.Data.strVals = vsValue;
			TreeNode			trLabels;
			trLabels = trLabel.Parent();
			trLabels.AddNode(trNewLabel);
			setChanged(trNewLabel.Type);
			setChanged(trNewLabel.Data);

			// Update Grid
			m_gridZ.SetRowHeading(m_gridZ.GetNumRows(), strName, true);
			m_gridZ.SetRowValues(m_gridZ.GetNumRows() - 1, vsValue);
		}
		else
			;// Hong, to do, update values, need discuss
	}
	return TRUE;
}

BOOL 	MatObjHeadersDlg::OnEditRowSize(Control ctrl)
{
	TreeNode		trNode = m_trTheme.Root.Dimensions.Y.Size;
	return OnEditDimSize(ctrl, trNode);
}

BOOL 	MatObjHeadersDlg::OnEditColSize(Control ctrl)
{
	TreeNode		trNode = m_trTheme.Root.Dimensions.X.Size;
	return OnEditDimSize(ctrl, trNode);
}

BOOL 	MatObjHeadersDlg::OnEditDimSize(Control ctrl, TreeNode& trNode)
{
	ASSERT(trNode);
	int				nVal = atoi(ctrl.Text);
	trNode.nVal = nVal;
	setChanged(trNode);
	return TRUE;
}

BOOL 	MatObjHeadersDlg::OnEditXFirst(Control ctrl)
{
	TreeNode		trNode = m_trTheme.Root.Dimensions.X.First;
	return OnEditXYMapping(ctrl, trNode);
}
BOOL 	MatObjHeadersDlg::OnEditXLast(Control ctrl)
{
	TreeNode		trNode = m_trTheme.Root.Dimensions.X.Last;
	return OnEditXYMapping(ctrl, trNode);
}
BOOL 	MatObjHeadersDlg::OnEditYFirst(Control ctrl)
{
	TreeNode		trNode = m_trTheme.Root.Dimensions.Y.First;
	return OnEditXYMapping(ctrl, trNode);
}
BOOL 	MatObjHeadersDlg::OnEditYLast(Control ctrl)
{
	TreeNode		trNode = m_trTheme.Root.Dimensions.Y.Last;
	return OnEditXYMapping(ctrl, trNode);
}

BOOL 	MatObjHeadersDlg::OnEditXYMapping(Control ctrl, TreeNode& trNode)
{
	ASSERT(trNode);
	double			dVal = atof(ctrl.Text);
	trNode.dVal = dVal;
	setChanged(trNode);
	return TRUE;
}

BOOL 	MatObjHeadersDlg::OnEditXYLongName(Control ctrl)
{
	TreeNode		trNode;
	if ( isYAxisActived() )
		trNode = m_trTheme.Root.Dimensions.Y.LongName;
	else
		trNode = m_trTheme.Root.Dimensions.X.LongName;
	return OnEditXYHeaders(ctrl, trNode);
}
BOOL 	MatObjHeadersDlg::OnEditXYUnit(Control ctrl)
{
	TreeNode		trNode;
	if ( isYAxisActived() )
		trNode = m_trTheme.Root.Dimensions.Y.Unit;
	else
		trNode = m_trTheme.Root.Dimensions.X.Unit;
	return OnEditXYHeaders(ctrl, trNode);
}
BOOL 	MatObjHeadersDlg::OnEditXYComment(Control ctrl)
{
	TreeNode		trNode;
	if ( isYAxisActived() )
		trNode = m_trTheme.Root.Dimensions.Y.Comment;
	else
		trNode = m_trTheme.Root.Dimensions.X.Comment;
	return OnEditXYHeaders(ctrl, trNode);
}

BOOL 	MatObjHeadersDlg::OnEditXYHeaders(Control ctrl, TreeNode& trNode)
{
	ASSERT(trNode);
	trNode.strVal = ctrl.Text;
	setChanged(trNode);
	return TRUE;
}

BOOL	MatObjHeadersDlg::OnAxesTabChange(Control cntrl)
{
	TabControl		tabCtrl = cntrl;
	updateControlsOnTabChange(tabCtrl.GetCurSel());
	return TRUE;
}

void	MatObjHeadersDlg::OnGridAfterEdit(Control flxControl, int nRow, int nCol)
{
	UpdateGridCellToHeader(nRow, nCol);
}

void 	MatObjHeadersDlg::OnGridBeforeMouseDown(Control cntrl, short nButton, short nShift, float X, float Y, BOOL* pCancel)
{
	if ( MK_RBUTTON != nButton || m_gridZ.IsMouseOnHeader() )
		return ;

	int nRow, nCol, nX, nY;
	if ( !m_gridZ.GetMousePixel(X, Y, nRow, nCol, nX, nY) )
		return ;

	MenuBase		menu;
	menu.Add(_L("Apply Value to Right"), MenuBase::OnMenuItem);
	menu.Add(_L("Apply Value to Left"), MenuBase::OnMenuItem);
	/// Hong 06/11/10 ORG-131-S1 REMOVE_ENUM_CONTEXT_MENU
	//menu.Add(_L("Enumerate Value to Right"), MenuBase::OnMenuItem);
	//menu.Add(_L("Enumerate Value to Left"), MenuBase::OnMenuItem);
	/// end REMOVE_ENUM_CONTEXT_MENU
	menu.Add("", MenuBase::OnMenuItem, MF_SEPARATOR);
	
	int				nParameterRow = RCLT_PARAM - RCLT_LONG_NAME + m_gridZ.GetRowOffset(); // See GetLabelTypes
	bool			bParameterRowHidden = m_gridZ.IsRowHidden(nParameterRow);
	if ( bParameterRowHidden )
		menu.Add(_L("Show System Parameters"), MenuBase::OnMenuItem);
	else
		menu.Add(_L("Hide System Parameters"), MenuBase::OnMenuItem);
	menu.Add(_L("Add User-Defined Parameter"), MenuBase::OnMenuItem);
	/// Hong 05/27/10 ORG-131-P1 ADD_CONTEXT_MENU_TO_DELETE_UDL
	UINT			nFlag = MF_STRING;
	nFlag |= (RCLT_UDL > GetLabelType(nRow - m_gridZ.GetRowOffset())) ? MF_DISABLED | MF_GRAYED : MF_ENABLED;
	menu.Add(_L("Delete"), MenuBase::OnMenuItem, nFlag);
	/// end ADD_CONTEXT_MENU_TO_DELETE_UDL
	
	menu.Add("", MenuBase::OnMenuItem, MF_SEPARATOR);
	menu.Add(_L("Go to Active Object's Column"), MenuBase::OnMenuItem);
	
	int 			nChoice = menu.DoTrackPopup(nX, nY, m_gridZ.GetDlgSafeHwnd());
	if ( nChoice < 0 )
		return ;

	/// Hong 05/27/10 ORG-131-P1 ADD_CONTEXT_MENU_TO_DELETE_UDL
	if ( CTXT_MENU_DELETE_UDL == nChoice ) // Delete
	{
		int					nType = GetLabelType(nRow - m_gridZ.GetRowOffset());
		ASSERT( RCLT_UDL <= nType );
		TreeNode			trLabel = getLabelNode(nType);
		TreeNode			trLast = trLabel;
		while ( trLast.NextNode )
		{
			TreeNode		trSibling = trLast.NextNode;
			trLast.Data.strVals = trSibling.Data.strVals;
			setChanged(trLast.Type);
			setChanged(trLast.Data);
			trLast = trSibling;
		}
		trLast.Remove();
		vector<string>		vsUDLNames;
		getNumUserDefineParameters(&vsUDLNames);
		string				strUDLName = m_gridZ.GetCell(nRow, 0);
		int					nPos = vsUDLNames.Find(strUDLName);
		ASSERT(nPos >= 0);
		vsUDLNames.RemoveAt(nPos);
		TreeNode		trUDLNames = m_trTheme.Root.Grid.Dimensions.Horizontal.UDLs;
		trUDLNames.strVals = vsUDLNames;
		setChanged(trUDLNames);
		
		m_gridZ.DeleteRow(nRow);
	}
	else
	//// end ADD_CONTEXT_MENU_TO_DELETE_UDL
	if ( CTXT_MENU_ADD_UDL == nChoice )
	{
		AddUserParameter();
	}
	else if ( CTXT_MENU_SHOW_SYS_PARAMS == nChoice )
	{
		bool			bShowParams = bParameterRowHidden;
		ShowParameterRows(bShowParams);
		DWORD			wdVal = bShowParams ? 1 : 0;
		dlg_save_to_registry(STR_DLG_NAME, STR_SHOW_PARAMS_REG_KEY, wdVal);
	}
	else if ( CTXT_MENU_ACTIVE_OBJ == nChoice )
	{
		/// Hong 06/11/10 ORG-131-P15 KEEP_ROW_INDEX_WHEN_GOTO_ACTIVE_OBJ_COL
		//int			nIndex = m_ml.GetActive();
		//int			nCol = nIndex + m_gridZ.GetColOffset();
		//m_gridZ.SelCell(m_gridZ.GetRowOffset(), nCol);
		/// Bill 07/14/2010 ORG-552-S1 BETTER_INDICATION_FOR_ACTIVE_MATRIX
		// int			nX, nY, nRow, nCol;
		// m_gridZ.GetSelCell(nX, nY, nRow, nCol);
		// int			nIndex = m_ml.GetActive();
		// nCol = nIndex + m_gridZ.GetColOffset();
		// m_gridZ.SelCell(nRow, nCol);
		goToActiveMatrixColumn();
		/// End BETTER_INDICATION_FOR_ACTIVE_MATRIX
		/// end KEEP_ROW_INDEX_WHEN_GOTO_ACTIVE_OBJ_COL
	}
	/// Hong 06/11/10 ORG-131-S1 REMOVE_ENUM_CONTEXT_MENU
	//else if ( CTXT_MENU_TO_LEFT <= nChoice && nChoice <= CTXT_MENU_ENUM_TO_RIGHT )
	else if ( CTXT_MENU_TO_LEFT <= nChoice && nChoice <= CTXT_MENU_TO_RIGHT )
	/// end REMOVE_ENUM_CONTEXT_MENU
	{
		bool		bEnumerate = (nChoice > CTXT_MENU_TO_RIGHT);
		bool		bRight = (nChoice & 1) ? FALSE : TRUE;
		int			nStratCol = bRight ? nCol + 1 : nCol - 1;
		int			nEndCol = bRight ? m_gridZ.GetCols() : m_gridZ.GetColOffset() - 1;
		int			nInc = bRight ? 1 : -1;
		string		strCell = m_gridZ.GetCell(nRow, nCol);
		int			nEndNum;
		if ( bEnumerate )
		{
			char 	szNodePrefix[MAXLINE];
			nEndNum = string_to_prefix_end_number(szNodePrefix, strCell);
			if ( lstrlen(szNodePrefix) == strCell.GetLength() )
				nEndNum = 1;
			else
				strCell = szNodePrefix;
		}
		string		strVal = strCell;
		for ( int iCol = nStratCol; iCol != nEndCol && iCol >= m_gridZ.GetColOffset(); iCol += nInc )
		{
			if ( bEnumerate )
				strVal.Format("%s%d", strCell, ++nEndNum);
			m_gridZ.SetCell(nRow, iCol, strVal);
			UpdateGridCellToHeader(nRow, iCol);
		}
	}
}

int		MatObjHeadersDlg::GetLabelType(int nRow)
{
	vector<int>		vnTypes;
	vnTypes = GetLabelTypes();
	ASSERT(nRow >= 0 && nRow < vnTypes.GetSize() );
	return vnTypes[nRow];
}

vector<int>		MatObjHeadersDlg::GetLabelTypes()
{
	vector<int>		vnTypes;
	for ( int iType = RCLT_LONG_NAME; iType < RCLT_PARAM + PARAMS_MAX_NUM; iType++ )
		vnTypes.Add(iType);
	for ( int ii = 0; ii < getNumUserDefineParameters(); ii++ )
		vnTypes.Add(RCLT_UDL + ii);
	return vnTypes;
}

void	MatObjHeadersDlg::UpdateGridCellToHeader(int nRow, int nCol)
{
	int				nType = GetLabelType(nRow - m_gridZ.GetRowOffset());
	TreeNode		trLabel = getLabelNode(nType);
	vector<string>	vsLabels;
	vsLabels = trLabel.Data.strVals;
	int				nObjIndex = nCol - m_gridZ.GetColOffset();
	ASSERT( 0 <= nObjIndex && nObjIndex <= vsLabels.GetSize() );
	vsLabels[nObjIndex] = m_gridZ.GetCell(nRow, nCol);
	trLabel.Data.strVals = vsLabels;
	setChanged(trLabel.Data);
	setChanged(trLabel.Type);
}


///Sophy 7/13/2010 ORG-131-P21 MORE_WORK_ON_CHECK_USER_INPUT
#define	STR_ROWCOL_ERROR	_L("The specified value for %s is not a positive integer and will not apply.\n")
#define	STR_XYMAP_ERROR		_L("The specified value for %s is not numeric data and will not apply.\n")
#define	REMOVE_DIMS_ONE_NODE(_Node, _SubNode)	TreeNode trNode = m_trTheme.Root.Dimensions._Node._SubNode; \
	if ( trNode ) \
		trNode.Remove();
int		MatObjHeadersDlg::CheckUserSettings()
{
	int nErr = 0;
	Control cEdt;
	string str;
	string strErrMsg = "";
	//column size
	cEdt = GetItem(IDC_COL_SIZE);
	if ( atol(cEdt.Text) <= 0 )
	{
		str.Format(STR_ROWCOL_ERROR, _L("Columns"));
		strErrMsg += str;
		nErr++;
		REMOVE_DIMS_ONE_NODE(X, Size)
	}
	//rows
	cEdt = GetItem(IDC_ROW_SIZE);
	if ( atol(cEdt.Text) <= 0 )
	{
		str.Format(STR_ROWCOL_ERROR, _L("Rows"));
		strErrMsg += str;
		nErr++;
		REMOVE_DIMS_ONE_NODE(Y, Size)
	}
	
	//First Column X
	cEdt = GetItem(IDC_AXIS_X_FIRST);
	if ( is_missing_value(atof(cEdt.Text)) )
	{
		str.Format(STR_XYMAP_ERROR, _L("First Column X"));
		strErrMsg += str;
		nErr++;
		REMOVE_DIMS_ONE_NODE(X, First)
	}
	
	//Last Column X
	cEdt = GetItem(IDC_AXIS_X_LAST);
	if ( is_missing_value(atof(cEdt.Text)) )
	{
		str.Format(STR_XYMAP_ERROR, _L("Last Column X"));
		strErrMsg += str;
		nErr++;
		REMOVE_DIMS_ONE_NODE(X, Last)
	}

	//First Row Y
	cEdt = GetItem(IDC_AXIS_Y_FIRST);
	if ( is_missing_value(atof(cEdt.Text)) )
	{
		str.Format(STR_XYMAP_ERROR, _L("First Row Y"));
		strErrMsg += str;
		nErr++;
		REMOVE_DIMS_ONE_NODE(Y, First)
	}
	
	//Last Row Y
	cEdt = GetItem(IDC_AXIS_Y_LAST);
	if ( is_missing_value(atof(cEdt.Text)) )
	{
		str.Format(STR_XYMAP_ERROR, _L("Last Row Y"));
		strErrMsg += str;
		nErr++;
		REMOVE_DIMS_ONE_NODE(Y, Last)
	}
	if ( nErr > 0 )
		warning_msg_box(strErrMsg, false, 'E');
	return nErr;
}
///end MORE_WORK_ON_CHECK_USER_INPUT

/// Bill 07/14/2010 ORG-552-S1 BETTER_INDICATION_FOR_ACTIVE_MATRIX
void	MatObjHeadersDlg::goToActiveMatrixColumn()
{
	int nX, nY, nRow, nCol;
	int nMatIndex = m_ml.GetActive();

	m_gridZ.GetSelCell(nX, nY, nRow, nCol);	
	nCol = nMatIndex + m_gridZ.GetColOffset();
	m_gridZ.SelCell(nRow, nCol);
}
/// End BETTER_INDICATION_FOR_ACTIVE_MATRIX

bool	MatObjHeadersDlg::isYAxisActived()
{
	int				nCurSel = m_tabCtrl.GetCurSel();
	ASSERT( TAB_X_HEADERS == nCurSel || TAB_Y_HEADERS == nCurSel );
	return (TAB_Y_HEADERS == nCurSel);
}

void	MatObjHeadersDlg::updateSharedCtrlValues(bool bYAxisActived)
{
	TreeNode		trNode;
	if ( bYAxisActived )
		trNode = m_trTheme.Root.Dimensions.Y;
	else
		trNode = m_trTheme.Root.Dimensions.X;
	
	GetItem(IDC_AXIS_LONGNAME).Text = trNode.LongName.strVal;
	GetItem(IDC_AXIS_UNIT).Text = trNode.Unit.strVal;
	// Hong, TreeNode have bug for multiline string, it's replace "\r\n" to "\n" in windows OS,
	// so i add it back again here, NOTICE that!!! This will fail if for Unix
	string			strCmts = trNode.Comment.strVal;
	strCmts.Replace("\r\n", "\n");
	strCmts.Replace("\n", "\r\n");
	GetItem(IDC_AXIS_COMMENT).Text = strCmts;
}

int		MatObjHeadersDlg::getNumUserDefineParameters(vector<string>* pvsNames/* = NULL*/)
{
	TreeNode		trUDLNames = m_trTheme.Root.Grid.Dimensions.Horizontal.UDLs;
	if ( pvsNames )
		*pvsNames = trUDLNames.strVals;
	return trUDLNames.strVals.GetSize();
}

TreeNode	MatObjHeadersDlg::getLabelNode(int nType)
{
	TreeNode		trLabels = m_trTheme.Root.Grid.Dimensions.Horizontal.Labels;
	foreach ( TreeNode trLabel in trLabels.Children )
	{
		if ( nType == trLabel.Type.nVal )
			return trLabel;
	}
	ASSERT(FALSE);
	TreeNode		trJunk;
	return trJunk;
}

void	MatObjHeadersDlg::ShowParameterRows(bool bShow)
{
	int				nParameterRow = RCLT_PARAM - RCLT_LONG_NAME + m_gridZ.GetRowOffset(); // See GetLabelTypes
	for ( int ii = 0; ii < PARAMS_MAX_NUM; ii++ )
		m_gridZ.HideRow(nParameterRow + ii, !bShow);
}

void update_control_label(Dialog& dlg, vector<UINT>& vnIDs, vector<string>& vsLabels)
{
	ASSERT( vnIDs.GetSize() == vsLabels.GetSize() );
	Control			ctrl;
	for ( int ii  = 0; ii < vnIDs.GetSize(); ii++ )
	{
		ctrl = dlg.GetItem(vnIDs[ii]);
		ctrl.Text = vsLabels[ii];
	}
}

void	MatObjHeadersDlg::updateControlsOnTabChange(int nCurSel)
{
	vector<UINT>		vnIDs = {IDC_STATIC1, IDC_STATIC2, IDC_STATIC3, IDC_STATIC4};
	vector<UINT>		vnIDXYMapping = {IDC_AXIS_X_FIRST, IDC_AXIS_X_LAST, IDC_AXIS_Y_FIRST, IDC_AXIS_Y_LAST};
	vector<UINT>		vnIDXYHdrs = {IDC_AXIS_LONGNAME, IDC_AXIS_UNIT, IDC_AXIS_COMMENT};
	vector<UINT>		vnIDZHdrs = {IDC_GRID_Z_AXIS, IDC_STATIC_HINT};
	vector<string>		vsLabels;
	switch ( nCurSel )
	{
	case TAB_XY_MAP:
		vsLabels.Add(_L("First Column X"));
		vsLabels.Add(_L("Last Column X"));
		vsLabels.Add(_L("First Row Y"));
		vsLabels.Add(_L("Last Row Y"));
		update_control_label(*this, vnIDs, vsLabels);
		
		ShowControls(vnIDs);
		ShowControls(vnIDXYMapping);
		ShowControls(vnIDXYHdrs, false);
		ShowControls(vnIDZHdrs, false);
		
		break;
	case TAB_X_HEADERS:
	case TAB_Y_HEADERS:
		vsLabels.Add(STR_HDR_LN);
		vsLabels.Add(STR_HDR_UNIT);
		vsLabels.Add(STR_HDR_CMT);
		ASSERT( vsLabels.GetSize() <= vnIDs.GetSize() );
		vnIDs.SetSize(vsLabels.GetSize());
		update_control_label(*this, vnIDs, vsLabels);
		
		ShowControls(vnIDs);
		ShowControls(vnIDXYMapping, false);
		ShowControls(vnIDXYHdrs, true);
		vnIDZHdrs.Add(IDC_STATIC4);
		ShowControls(vnIDZHdrs, false);
		
		updateSharedCtrlValues(TAB_Y_HEADERS == nCurSel);
		break;
	case TAB_Z_HEADERS:
		ShowControls(vnIDs, false);
		ShowControls(vnIDXYMapping, false);
		ShowControls(vnIDXYHdrs, false);
		ShowControls(vnIDZHdrs, true);

		/// Bill 07/14/2010 ORG-552-S1 BETTER_INDICATION_FOR_ACTIVE_MATRIX
		if ( m_bFirstTimeOpenZHeader )
		{
			m_bFirstTimeOpenZHeader = false;
			goToActiveMatrixColumn();
		}
		/// End BETTER_INDICATION_FOR_ACTIVE_MATRIX

		break;
	}
}

void 	MatObjHeadersDlg::setChanged(TreeNode& trNode)
{
	trNode.SetAttribute(STR_CHANGED_ATTRIB, TRUE);
	m_bIsChanged = true;
}

BOOL	MatrixHeaders()
{
	MatrixLayer		ml = Project.ActiveLayer();
	MatObjHeadersDlg	dlg(ml);
	return dlg.DoModalEx(GetWindow());
}
