Click here to Skip to main content
15,895,011 members
Articles / Mobile Apps

The StateWizard VC++ Add-in and Engine with Source Code

Rate me:
Please Sign up or sign in to vote.
4.73/5 (24 votes)
26 Mar 2009CPOL12 min read 190.8K   2.8K   132  
A cross-platform state-oriented application framework and a ClassWizard-like round-trip UML dynamic modeling/development tool that runs in popular IDEs. Aims at providing concurrent, distributed, and real-time application development tools for Win32/Linux
/**********************************************************************
UML StateWizard provides its software under the LGPL License and 
zlib/libpng License.

Email us at info@intelliwizard.com for any information, suggestions and 
feature requestions.

Home Page: http://www.intelliwizard.com
*************************************************************************/

#include "stdafx.h"
#include "DSUtils.h"
#include "stringop.h"
#include "..\Common\ParamStore.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

using namespace std;

/*
#ifdef VS2005
	using namespace EnvDTE80;
	extern CComPtr<EnvDTE::DTE2> g_pDTE;
#else
	extern CComPtr<EnvDTE::_DTE> g_pDTE;
#endif
*/

#define START_COL_POS 5

#define OUTPUT_WINDOW_NAME L"StateWizard"

// set g_nMaxLevelNum for limiting level of chart to be shown 
int g_nMaxLevelNum = CParamStore::GetInstance().GetIntValue("StateChart","MaxLevel") == -1  
	? DEF_STATE_CHART_MAX_LEVEL : CParamStore::GetInstance().GetIntValue("StateChart","MaxLevel");

int g_nFileType = CParamStore::GetInstance().GetIntValue("StateChart","FileType") == -1
	? 0 : CParamStore::GetInstance().GetIntValue("StateChart","FileType");//0 means *.cpp,1 means *.c 


//////////////////////////////////////////////////////////////////////////////////////////////////////////
void TrimSpace(CString& sStr)
{
	sStr.TrimLeft();
	sStr.TrimRight();
	sStr.Replace("\t", NULL);
	sStr.Replace(" ", NULL);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
CString BSTR2CString(BSTR bstr)
{
	char* bstrPath = _com_util::ConvertBSTRToString(bstr); 
	CString sResult(bstrPath);
	delete[]bstrPath;

	return sResult;
}


DSUtils::DSUtils()
{
	/*HRESULT re = g_pDTE->get_Solution(&m_pSolution);
	ATLASSERT(SUCCEEDED(re));
	re = m_pSolution->get_Projects(&m_pProjects);
	ATLASSERT(SUCCEEDED(re));
	re = g_pDTE->get_ItemOperations(&m_pItemOperation);
	ATLASSERT(SUCCEEDED(re));
	prjCount = GetProjectCount();*/
}

DSUtils::~DSUtils()
{
	/*m_pSolution = NULL;
	m_pItemOperation = NULL;
	prjCount = -1;*/

}


///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION:Get the full path of the solution 
// INPUT: None
// OUTPUT: The full path 
// NOTE: 
///////////////////////////////////////////////////////////////////////////////////////////
_bstr_t DSUtils::GetSlnPath()
{
    BSTR bstrRet;
	CComPtr<EnvDTE::_Solution> m_pSolution;
	HRESULT re = g_pDTE->get_Solution(&m_pSolution);
	ATLASSERT(SUCCEEDED(re));
	m_pSolution->get_FullName(&bstrRet);
    return _bstr_t(bstrRet,false);
}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get the solution name from its file path name
// INPUT: None
// OUTPUT: The solution name
// NOTE:Using  GetSlnPath get the full path and then cut into filename
///////////////////////////////////////////////////////////////////////////////////////////
_bstr_t DSUtils::GetSlnName()
{
    _bstr_t bstrPath = GetSlnPath();
    _bstr_t bstrRet;

	do
	{
		if (bstrPath.length() < 5) 
        break;
		 wstring strSolution = static_cast<WCHAR*>(bstrPath);

		 StringOp<wchar_t>::ReplaceChr(strSolution,L'/',L'\\');
	 
		StringOp<wchar_t>::size_type idxBegin = strSolution.find_last_of(L'\\');
		StringOp<wchar_t>::size_type idxLast	=  strSolution.find_last_of(L'.');
        if(-1 == idxBegin||-1 == idxLast)
            break;
		strSolution = strSolution.substr(idxBegin+1,idxLast-idxBegin-1);
		bstrRet = _bstr_t(strSolution.c_str());
    } while(false);
	
    return bstrRet;
}
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION:  Retrieve the given project directory name
// INPUT: Project name
// OUTPUT: Project directory name
// NOTE: 

///////////////////////////////////////////////////////////////////////////////////////////
_bstr_t DSUtils::GetProjectDir(const _bstr_t &sProject)
{
    ATLASSERT(g_pDTE != NULL );
    _bstr_t bstrRet = "";
    BSTR bstr = NULL;

	// if don't get the project then return NULL
	if(!sProject)
		return _bstr_t(NULL, false);
	else
	{

		CComPtr<EnvDTE::Project> prj = GetProject(sProject);
		if(prj!= NULL)
		{
			prj->get_FullName(&bstr);
		}
		else
			return _bstr_t(NULL, false);
	}
    wchar_t *p = wcsrchr(bstr, L'\\');
    if(NULL != p)
    {
        BSTR bstrPath = ::SysAllocStringLen(bstr, (UINT)(p-bstr));
        bstrRet = _bstr_t(bstrPath, false);
    }
    ::SysFreeString(bstr);
    ATLASSERT(0 != bstrRet.length());
    return bstrRet;
}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Open file in client window
// INPUT: The file name
// OUTPUT: TRUE:Success FALSE: Failed
// NOTE: 
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::OpenFile(_bstr_t &sFile)
{
	ATLASSERT(g_pDTE != NULL );
	CComPtr<EnvDTE::ItemOperations> m_pItemOperation;
	HRESULT re = g_pDTE->get_ItemOperations(&m_pItemOperation);
	ATLASSERT(SUCCEEDED(re));

	CComBSTR viewTye(EnvDTE::vsViewKindCode);
	CComPtr<EnvDTE::Window> pWindows =NULL;
	re = m_pItemOperation->OpenFile(sFile.GetBSTR(),viewTye,&pWindows);
	return SUCCEEDED(re);
}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION:If has any c/cpp/h file opened in DTE
// INPUT: NO
// OUTPUT: True means there are c/cpp/h file opened in DTE,FALSE means there is not.....
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::HasCodeFileOpen()
{
	long count = 0;
	CComPtr<EnvDTE::Documents> docs;
	g_pDTE->get_Documents(&docs);
	docs->get_Count(&count);
	if(count>0)
	{
		for(long i = 1;i<=count;i++)
		{
			CComVariant var(i);
			CComPtr<EnvDTE::Document> doc;
			docs->Item(var,&doc);
			BSTR fileName;
			doc->get_FullName(&fileName);
			_bstr_t fileNameWapper(fileName,false);
			CString FileName(fileName);
			FileName.MakeLower();
			if(FileName.Right(2)==".c"||FileName.Right(4)==".cpp"||FileName.Right(2)==".h")
			{
				return TRUE; 
			}
		}
		return FALSE;
	}
	return FALSE;
}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get project count in workspace/solution. 
// INPUT: None 
// OUTPUT: The number of projects.
///////////////////////////////////////////////////////////////////////////////////////////
long DSUtils::GetProjectCount()
{
	ATLASSERT(g_pDTE != NULL );
	
	CComPtr<EnvDTE::_Solution> m_pSolution;
	CComPtr<EnvDTE::Projects> m_pProjects; 
	HRESULT re = g_pDTE->get_Solution(&m_pSolution);
	ATLASSERT(SUCCEEDED(re));
	re = m_pSolution->get_Projects(&m_pProjects);
	ATLASSERT(SUCCEEDED(re));

    long lCount = 0;
	re = m_pProjects->get_Count(&lCount);
	ATLASSERT(SUCCEEDED(re));
    return lCount;
}

/*******************************************************************************************
DESCRIPTION: Get project object in workspace/solution. 
INPUT: Project name if bIsFileName is FALSE by default 
	or the relative file name if bIsFileName is TRUE.
OUTPUT: The project object.
*******************************************************************************************/
CComPtr<EnvDTE::Project>  DSUtils::GetProject(const _bstr_t &sProject, BOOL bIsFileName)
{
	CComPtr<EnvDTE::_Solution> m_pSolution;
	CComPtr<EnvDTE::Projects> m_pProjects; 
	HRESULT re = g_pDTE->get_Solution(&m_pSolution);
	ATLASSERT(SUCCEEDED(re));
	re = m_pSolution->get_Projects(&m_pProjects);
	ATLASSERT(SUCCEEDED(re));

	CComPtr<EnvDTE::Project> spFoundProj = NULL;
    ATLASSERT(g_pDTE != NULL );
	ATLASSERT(m_pProjects!=NULL);

	long count = GetProjectCount();
	VARIANT va;
	VariantInit(&va);
	V_VT(&va)= VT_UINT;

	for(long i = 1;i<= count;i++)
	{
		V_UINT(&va) = i;
		CComPtr<EnvDTE::Project> spTempProj;
		m_pSolution->Item(va,&spTempProj);
		BSTR pname = NULL;

		if (bIsFileName)
		{
			spTempProj->get_FullName(&pname);

			CString sFullFileName(pname), sFile(static_cast<wchar_t*>(sProject));
			sFullFileName.MakeLower();
			sFile.MakeLower();
			int nLen = sProject.length();
			if (sFullFileName.Right(nLen) == sFile)
			{
				spFoundProj = spTempProj;
				break;
			}
		}
		else 
		{
			spTempProj->get_Name(&pname);
			_bstr_t s(pname, false);
			if(0 == wcsicmp(s, sProject)) // not case sensitive
			{
				spFoundProj = spTempProj;
				break;
			}
		}
	}
	VariantClear(&va);
	return spFoundProj;
}

/*******************************************************************************************
DESCRIPTION: Get project object in workspace/solution. 
INPUT: The project name 
OUTPUT: The project object.
*******************************************************************************************/
CComPtr<EnvDTE::Project>  DSUtils::GetProjectByFileName(const _bstr_t &sPrjFileName)
{
	return GetProject(sPrjFileName, TRUE);
}

void DSUtils::GetProjectList(vector<_bstr_t>& PrjFullNameList)
{
	CComPtr<EnvDTE::_Solution> m_pSolution;
	CComPtr<EnvDTE::Projects> m_pProjects; 
	HRESULT re = g_pDTE->get_Solution(&m_pSolution);
	ATLASSERT(SUCCEEDED(re));
	re = m_pSolution->get_Projects(&m_pProjects);
	ATLASSERT(SUCCEEDED(re));

	long n = GetProjectCount();
	VARIANT va;
	VariantInit(&va);
	V_VT(&va)= VT_UINT;

	PrjFullNameList.clear();

	for(long count = 1 ; count<= n;count++)
	{
		V_UINT(&va) = count;
		CComPtr<EnvDTE::Project> prj;
		HRESULT re = m_pProjects->Item(va,&prj);
		ATLASSERT(SUCCEEDED(re));
		BSTR sPrjName, sPrjFullName;
		re = prj->get_FullName(&sPrjFullName); 
		re = prj->get_Name(&sPrjName); // Jerry Ding. Use project name intead.

		/* NOTE: In some cases, there is a project named "Miscellaneous Files" in VS.NET English edition. WHY???
		The full path name is empty.
		*/
		if (sPrjFullName == NULL || sPrjFullName[0] == 0) 
			continue;

		if(wcslen(static_cast<wchar_t*>(sPrjName))>0)
		PrjFullNameList.push_back(sPrjName);
	}

	VariantClear(&va);

}


///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get the header or source file full name list 
// INPUT:  
// OUTPUT: 1) Header file list; 2) Source file list.
// NOTE:
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::GetSrcFileList(CComPtr<EnvDTE::Project>& prj, vector<_bstr_t>& HeaderFileList, vector<_bstr_t>& SourceFileList)
{
	ATLASSERT(prj!=NULL);
	SourceFileList.clear();
	HeaderFileList.clear();

	CComPtr<EnvDTE::ProjectItems> prjItems;
	prj->get_ProjectItems(&prjItems);

	if (prjItems==NULL)
		return FALSE;

	return GetFileFromPrjItems(prjItems, HeaderFileList, SourceFileList);
	/*
	long n ;
	prjItems->get_Count(&n);
	for(long count = 1 ; count<= n;count++)
	{
		CComVariant var(count);
		CComPtr<EnvDTE::ProjectItem> prjItem;
		HRESULT re = prjItems->Item(var,&prjItem);
		if(prjItem!=NULL)
		{
		short fileCount;
		BSTR wa;
		prjItem->get_Name(&wa);
	
		_bstr_t fileListName(wa,false);
		TAG_FILELIST_STATE fileListState;
		if(wcsstr(static_cast<wchar_t*>(fileListName),L"Source Files")!=NULL)
		{
			fileListState = TAG_SOURCE_FILE_STATE;
		}
		else if(wcsstr(static_cast<wchar_t*>(fileListName),L"Header Files")!=NULL)
		{
			fileListState = TAG_HEAD_FILE_STATE;
		}
		else
		{
			fileListState = TAG_OTHER_FILE_STATE;
			continue;//to the next item
		}

		prjItem->get_FileCount(&fileCount);
		CComPtr<EnvDTE::ProjectItems> items;
		prjItem->get_ProjectItems(&items);

		for(short i = 1;i<= fileCount; i++)
		{	
			CComPtr<EnvDTE::ProjectItem> itemContainFile;
			items->Item(CComVariant(i),&itemContainFile);
			BSTR fileName;
			itemContainFile->get_FileNames(1,&fileName);

			_bstr_t fileNameWapper(fileName,false);
			if(fileListState==TAG_SOURCE_FILE_STATE)
			{
				SourceFileList.push_back(fileNameWapper);

			}

			if(fileListState ==TAG_HEAD_FILE_STATE)
			{
				HeaderFileList.push_back(fileNameWapper);
			}
		}
		}
	}
	*/
	return TRUE;
}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: By giving the Project Items ,get the head file list & the source file list
// INPUT: Project Items Object
// OUTPUT: 1) Header file list; 2) Source file list.
// NOTE:
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::GetFileFromPrjItems(CComPtr<EnvDTE::ProjectItems> prjItems,vector<_bstr_t>& HeaderFileList, vector<_bstr_t>& SourceFileList)
{
	if (prjItems==NULL)
		return FALSE;

	//ATLASSERT(prjItems!=NULL);
	
	long count;
	HRESULT re = prjItems->get_Count(&count);
	ATLASSERT(SUCCEEDED(re));
	if(count==0) 
	{
		return TRUE;
	}

	for(long i = 1;i<=count;i++)
	{

		CComVariant var(i);
		CComPtr<EnvDTE::ProjectItem> prjItem;

		HRESULT re = prjItems->Item(var,&prjItem);
		if(prjItem!=NULL)
		{
			// leaf
			BSTR fileName;
			prjItem->get_FileNames(1,&fileName);
			CString sFileName(fileName); 
			_bstr_t fileNameWapper(fileName,false);

			sFileName.MakeLower(); 

			size_t len = wcslen(fileName);
			if (sFileName.Right(2) == ".c" || sFileName.Right(4) == ".cpp") 
					SourceFileList.push_back(fileNameWapper);
			else if (sFileName.Right(2) == ".h")
					HeaderFileList.push_back(fileNameWapper);


			CComPtr<EnvDTE::ProjectItems> ChildPrjItems;
			re = prjItem->get_ProjectItems(&ChildPrjItems);
			ATLASSERT(SUCCEEDED(re));
			GetFileFromPrjItems(ChildPrjItems, HeaderFileList, SourceFileList);
		}
	}
	return TRUE;
}



/////////////////////////////////////////////////////////////////////////
// DESCRIPTION:Delete the specific src file&source file from projectitems
// INPUT:  1)prjItems: ProjectItems to be deleted fils.
//         2)srcFile: Header file path where moved item locates
//         3)headFile:   State name of moved item
// OUTPUT: 1)TRUE: SUCCESS
//         2)FALSE: There are no items in the ProjectItems.
// NOTE: srcFile,headFile need to been maked lower before being passed to this function.
//////////////////////////////////////////////////////////////////////////
BOOL DSUtils::DelSrcHldFilesFromPrjItems(CComPtr<EnvDTE::ProjectItems> prjItems,CString& srcFile, CString& headFile/*make sure that the srcFile& headFile has been maked lower.*/)
{
	if (prjItems==NULL)
		return FALSE;
	
	long count;
	HRESULT re = prjItems->get_Count(&count);
	ATLASSERT(SUCCEEDED(re));
	if(count==0) 
	{
		return TRUE;
	}

	for(long i = 1;i<=count;i++)
	{
		CComVariant var(i);
		CComPtr<EnvDTE::ProjectItem> prjItem;

		HRESULT re = prjItems->Item(var,&prjItem);
		if(prjItem!=NULL)
		{
			// leaf
			BSTR fileName;
			prjItem->get_FileNames(1,&fileName);
			CString sFileName(fileName); 
			_bstr_t fileNameWapper(fileName,false);
			sFileName.MakeLower(); 

			if(sFileName==srcFile||sFileName==headFile)
			{
				prjItem->Remove();
				continue;
			}

			CComPtr<EnvDTE::ProjectItems> ChildPrjItems;
			re = prjItem->get_ProjectItems(&ChildPrjItems);
			ATLASSERT(SUCCEEDED(re));
			DelSrcHldFilesFromPrjItems(ChildPrjItems, srcFile, headFile);
		}
	}
	return TRUE;
}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get active project. In VS.NET, return the first startup project.
// INPUT: None
// OUTPUT: Active project object.
// NOTE: DTE::Solution::solutionBuild::StartupProjects[0] 
//  StartupProjects contains a list of projects that "start" when the Run command is issued.
///////////////////////////////////////////////////////////////////////////////////////////
CComPtr<EnvDTE::Project> DSUtils::GetActiveProject()
{
	CComPtr<EnvDTE::Project> prj = GetFirstStartupProject(); 

	if (prj) return prj;

	// IMPORTANT NOTE: Startup project may be empty.
	// ATLASSERT(prj!=NULL);

	// Temp solution: use ActiveSolutionProjects[0] instead. 

	VARIANT actPrjs;

	HRESULT re=g_pDTE->get_ActiveSolutionProjects(&actPrjs);
	ATLASSERT(SUCCEEDED(re));

	SAFEARRAY *a=actPrjs.parray;
	VARIANT tempVariant;
	
	LONG i[1]={a->rgsabound[0].lLbound};
	for(LONG p = i[0];p<static_cast<long>(a->rgsabound[0].cElements);p++)
	{
		HRESULT re = SafeArrayGetElement(a,&p,&tempVariant);
	    if(FAILED(re))break;
		
		IDispatch* idp = tempVariant.pdispVal;
		CComPtr<EnvDTE::Project> tempPrj;
		idp->QueryInterface(__uuidof(EnvDTE::Project), (LPVOID*)&tempPrj);
		if(tempPrj)
		{
			return tempPrj;
		}
	}

	return NULL;
}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get active project. In VS.NET, return the first startup project.
// INPUT: None
// OUTPUT: First startup project object.
// NOTE: DTE::Solution::solutionBuild::StartupProjects[0] 
//  StartupProjects contains a list of projects that "start" when the Run command is issued.
//  Return value may be empty, for example App.vcproj, the project name is App1.
///////////////////////////////////////////////////////////////////////////////////////////
CComPtr<EnvDTE::Project> DSUtils::GetFirstStartupProject()
{
	CComPtr<EnvDTE::_Solution> so;
	HRESULT re = g_pDTE->get_Solution(&so);
	ATLASSERT(SUCCEEDED(re));

	CComPtr<EnvDTE::SolutionBuild> sb;
	re = so->get_SolutionBuild(&sb);
	ATLASSERT(SUCCEEDED(re));
	
	BSTR s;
	so->get_FileName(&s);

	CComVariant variant;
	sb->get_StartupProjects(&variant);
	if(variant.vt == VT_EMPTY)
	return NULL;
	SAFEARRAY* array = variant.parray;
	long ix = 0;
	VARIANT var;
	if(SafeArrayGetElement(array, &ix, &var) != S_OK)
	return NULL;
	//_bstr_t startUpRrjName(var.bstrVal,false);

	// The return startup project is subdir\file.vcproj for example: App\App.vcproj. Remove the file name.
	/*
	CString sFile(var.bstrVal);
	int nBegin = sFile.ReverseFind('\\');
	nBegin ++; 
	int nEnd = sFile.ReverseFind('.');
	if (nEnd==-1) nBegin = 999;
	CString sPrj = sFile.Mid(nBegin,nEnd-nBegin);
	*/
	_bstr_t startUpRrjName(var.bstrVal);

	CComPtr<EnvDTE::Project> prj = GetProjectByFileName(startUpRrjName);
	return prj;

	// IMPORTANT NOTE: Startup project may be empty.
}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get active project name
// INPUT: None
// OUTPUT: The active project name.
///////////////////////////////////////////////////////////////////////////////////////////
_bstr_t DSUtils::GetActiveProjectName()
{
		BSTR bstr = NULL;

		// if don't get the active project then return NULL
		if(!GetActiveProject())
			return _bstr_t(NULL, false);
		else
			GetActiveProject()->get_Name(&bstr);   /* here don't alloc memory to bstr */
	   _bstr_t bstrRet = _bstr_t(bstr, false);
    return bstrRet;
}


/////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get the mapfile full path.
// INPUT: 1)sMapfilePath: a string to record the mapfile path
// OUTPUT: zero or nonzero
// NOTE: 
//////////////////////////////////////////////////////////////////////////
/*BOOL DSUtils::GetRcfilePath(CString &sRcFilePath)
{
	CComPtr<EnvDTE::Project> activeProject = GetActiveProject();

	CComPtr<EnvDTE::ProjectItems> prjItems;
	activeProject->get_ProjectItems(&prjItems);
	long n ;
	prjItems->get_Count(&n);
	for(long count = 1 ; count<= n;count++)
	{
		CComVariant var(count);
		CComPtr<EnvDTE::ProjectItem> prjItem;
		HRESULT re = prjItems->Item(var,&prjItem);
		if(prjItem!=NULL)
		{
			short fileCount;
			BSTR wa;
			prjItem->get_Name(&wa);
			_bstr_t fileListName(wa,false);
			TAG_FILELIST_STATE fileListState;
			if(wcsstr(static_cast<wchar_t*>(fileListName),L"Resource Files")!=NULL)
			{
				fileListState = TAG_RESOURCE_FILE_STATE;
			}
			else
			{
				fileListState = TAG_OTHER_FILE_STATE;
				continue;//to the next item
			}

			prjItem->get_FileCount(&fileCount);
			CComPtr<EnvDTE::ProjectItems> items;
			prjItem->get_ProjectItems(&items);

			for(short i = 1;i<= fileCount; i++)
			{	
				CComPtr<EnvDTE::ProjectItem> itemContainFile;
				items->Item(CComVariant(i),&itemContainFile);
				BSTR fileName;
				itemContainFile->get_FileNames(1,&fileName);
				_bstr_t fileNameWapper(fileName,false);
				if(wcsstr(static_cast<wchar_t*>(fileNameWapper),L".rc")!=NULL)
				{
					sRcFilePath = static_cast<WCHAR*>(fileNameWapper);
					return TRUE;
				}

			}

		}
	}
	return FALSE;
}*/

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get active project file list including head files and source files. 
// INPUT:  1) PrjFileList: a project file list Array.
// OUTPUT: None.
// NOTE: 
///////////////////////////////////////////////////////////////////////////////////////////
void DSUtils::GetProjectFileList(CComPtr<EnvDTE::Project> prj, vector<_bstr_t> &PrjFileList)
{
	CComPtr<EnvDTE::Project> prjTemp = prj;
	if(prj==NULL)
	{
		prjTemp = GetActiveProject();
	}
	vector<_bstr_t> HeadFileList,SourceFileList,TotalFileList;
	GetSrcFileList(prjTemp,HeadFileList,SourceFileList);
	PrjFileList.clear();
	PrjFileList.insert(PrjFileList.begin(),SourceFileList.begin(),SourceFileList.end());
	PrjFileList.insert(PrjFileList.begin(),HeadFileList.begin(),HeadFileList.end());
}


///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Test the given document is opened or not 
// INPUT:  1) sFullPath: a given File full path.
//         2) bAutoSave: Automatically save current file
// OUTPUT: None.
// NOTE: The pattern of function implementation if <FunctionName> ... {
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::TestOpenedDocIsModified(LPCSTR sFullPath, BOOL bAutoSave)
{
	ATLASSERT(g_pDTE!=NULL);
	CComPtr<EnvDTE::Documents> tDocuments;
	g_pDTE->get_Documents(&tDocuments);
	
	CComQIPtr<EnvDTE::Documents,&EnvDTE::IID_Documents> spActiveDocs(tDocuments);
	ATLASSERT(spActiveDocs);

	//record the num of opened documents
    long openedDocNum = 0; 
	
	// get active document num in documents
	spActiveDocs->get_Count(&openedDocNum); 

	// resource file should not be opened
	for (long i = 1L; i <= openedDocNum; i++) 
	{
		BSTR bstr = NULL;
		_bstr_t bstrRet("");
		CComPtr<EnvDTE::Document> spDoc;
		spActiveDocs->Item(_variant_t(i, VT_I4),&spDoc);
		CComQIPtr<EnvDTE::Document,&EnvDTE::IID_Document> pGenericDocQIPtr(spDoc);
		pGenericDocQIPtr->get_FullName(&bstr);
		bstrRet = _bstr_t(bstr, false);


		char* docPath = _com_util::ConvertBSTRToString(bstrRet.GetBSTR());
		CString sOpenedDocPath(docPath);
		delete []docPath;

		VARIANT_BOOL vbSaved;
		if (!sOpenedDocPath.CompareNoCase(sFullPath))
		{
			pGenericDocQIPtr->get_Saved(&vbSaved);
			if (vbSaved == VARIANT_FALSE)
			{
				if (bAutoSave == TRUE)
				{
					EnvDTE::vsSaveStatus  retval; 

					CComBSTR sBfullPath(sFullPath);
					pGenericDocQIPtr->Save(sBfullPath,&retval);
					// Save twice to ensure to save file which is opened by another editor. 
					pGenericDocQIPtr->get_Saved(&vbSaved);
					if (vbSaved == VARIANT_FALSE)
						pGenericDocQIPtr->Save(sBfullPath.m_str,&retval);
				}
				return TRUE;
			}
			else
				return FALSE;
		}
	}

  return false;
}



///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Parse the state of the given line. 
// INPUT:  1) sCleanLine: a given line string. 
//         2) nCommentState: the comment state of the given line.
//         including (NO_COMMENT_STATE,SLASH_COMMENT_STATE,ASTERISK_COMMENT_STATE,SLASH_CODE_STATE).
//         3) CountResultArray: Record the different state line's number.
//         4) nFuncPosLine: Record the function existed linenumber.
// OUTPUT: 
// *) sCleanLine: the code string with comment removed.
// *) nCommentState: the code parsing state.
// *) return: whether mix code and comment. 
// NOTE: 
///////////////////////////////////////////////////////////////////////////////////////////
//***************************** never tested *****************************
BOOL DSUtils::ParseCommentState(CString &sCleanLine, UCHAR &nCommentState, UINT *CountResultArray, UINT *nFuncPosLine)
{
	int pastParseFlag = -1;
	sCleanLine.TrimLeft();
    CString sCurrentLine = sCleanLine;
	sCleanLine= "";
	BOOL bInvokedByTagDB = FALSE;
	BOOL bIsContexJoint = FALSE;

	if (CountResultArray == NULL)
		bInvokedByTagDB = TRUE;
	
	if (bInvokedByTagDB)
		(*nFuncPosLine)++;
	if (sCurrentLine.IsEmpty())
	{
		if (!bInvokedByTagDB)
			CountResultArray[BLANK_LINES]++;
		return FALSE;
	}

	while(true)
	{
		// Case with no comments before or met with matched asterisk comments 
		if (nCommentState == NO_COMMENTS_STATE)
		{
			if (sCurrentLine.IsEmpty())
				break;
			int nSlashPos = sCurrentLine.Find("//");
			int nAsteriskPos = sCurrentLine.Find("/*");

				
			// Calculate relative line attribute
			if (-1 == nSlashPos && nAsteriskPos == -1)
			{
				if (sCurrentLine.GetAt(sCurrentLine.GetLength()-1) == '\\')
				{
					bIsContexJoint = TRUE;
					nCommentState = SLASH_CODES_STATE;
				}
				
				if (!bInvokedByTagDB)
				{
					if ((pastParseFlag != MIXED_LINES) &&
						(pastParseFlag != CODE_LINES))
					{
						CountResultArray[CODE_LINES]++;
						pastParseFlag = CODE_LINES;
					}
				}
				else
				{
					if (bIsContexJoint == TRUE)
						sCurrentLine = sCurrentLine.Left(sCurrentLine.GetLength()-1);
					sCleanLine += sCurrentLine;
				}
			}else if (0 == nSlashPos || nAsteriskPos == 0)
			{
				if (!bInvokedByTagDB)
				{
					if ((pastParseFlag != COMMENT_LINES) &&
						(pastParseFlag != MIXED_LINES))
					{
						CountResultArray[COMMENT_LINES]++;
						pastParseFlag = COMMENT_LINES;
					}
				}
			}
			else 
			{
				if (!bInvokedByTagDB)
				{
					if (pastParseFlag != MIXED_LINES)
					{
						if (pastParseFlag == COMMENT_LINES)
							CountResultArray[COMMENT_LINES]--;
						if (pastParseFlag == CODE_LINES)
							CountResultArray[CODE_LINES]--;
						CountResultArray[COMMENT_LINES]++;
						CountResultArray[CODE_LINES]++;
						CountResultArray[MIXED_LINES]++;
						pastParseFlag = MIXED_LINES;
					}
				}
			}
						////////////////make markup
			if (nSlashPos == 0 ||
				nAsteriskPos > nSlashPos && nSlashPos != -1 ||
				nSlashPos != -1 && nAsteriskPos == -1)
			{
					nCommentState = SLASH_COMMENTS_STATE;
			
				if (bInvokedByTagDB)
					sCleanLine += sCurrentLine.Left(nSlashPos);	
			   	continue;			
			}
			if (nAsteriskPos == 0 ||
				nSlashPos > nAsteriskPos && nAsteriskPos != -1 ||
				nAsteriskPos != -1 && nSlashPos == -1)
			{
				nCommentState = ASTERISK_COMMENTS_STATE;

				if (bInvokedByTagDB)
					sCleanLine += sCurrentLine.Left(nAsteriskPos);
				sCurrentLine = sCurrentLine.Right(sCurrentLine.GetLength() - nAsteriskPos -2);
				sCurrentLine.TrimLeft();
				continue;
			}
			break;
		}
		else if (nCommentState == ASTERISK_COMMENTS_STATE)
		{
			if (sCurrentLine.IsEmpty())
				break;
			int antiAsterIdx = sCurrentLine.Find("*/");
			
			if (!bInvokedByTagDB)
			{
				if ((pastParseFlag != MIXED_LINES) &&
					(pastParseFlag != COMMENT_LINES))
				{
					CountResultArray[COMMENT_LINES]++;
					pastParseFlag = COMMENT_LINES;
				}
			}
			if (antiAsterIdx != -1)
			{	
				nCommentState = NO_COMMENTS_STATE;
				sCurrentLine = sCurrentLine.Right(sCurrentLine.GetLength() - antiAsterIdx -2);
		
				int len = sCurrentLine.GetLength();
				sCurrentLine.TrimLeft();
				if (bInvokedByTagDB)
				{
					int trimSpaceNum = len-sCurrentLine.GetLength();
					for (int i = 0; i < trimSpaceNum; i++)
						sCleanLine += " ";
				}
					continue;
			}
			break;
		}
		else if (nCommentState == SLASH_COMMENTS_STATE)
		{
			if (!bInvokedByTagDB)
			{
				if ((pastParseFlag != MIXED_LINES) &&
					(pastParseFlag != COMMENT_LINES))
					CountResultArray[COMMENT_LINES]++;
			}
			if (sCurrentLine.GetAt(sCurrentLine.GetLength()-1) != '\\')
				nCommentState = NO_COMMENTS_STATE;
			
			break;
		}
		else
		{
			if (!bInvokedByTagDB)
				CountResultArray[CODE_LINES]--;	
			nCommentState = NO_COMMENTS_STATE;
			continue;
		}
		
	}
    sCleanLine.TrimLeft();
	sCleanLine.TrimRight();
	return bIsContexJoint;
}

/////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Deal with code change in source file when moving state item
// INPUT: 1)pTextSrcSelQIPtr: Text selection of source file
//        2)sSrcFilePath: Source file path
//        3)nHdrStateLineNo: Line number of moved state in header file
//        4)nHdrNewParSibLineNo: Line number to be inserted in
//        5)nMoveStateSum: Sum of states under moved state item
//        6)nStartLineNo: Start line number denoting where white space clearing starts
//        7)nEndLineNo: End line number denoting where white space clearing ends
//
// OUTPUT: 1)TRUE: Success
//         2)FALSE: Fail
// NOTE: 
//////////////////////////////////////////////////////////////////////////

BOOL DSUtils::MoveStateDef(CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextSrcSelQIPtr,
						   LPCTSTR sSrcFilePath,
						   LPCTSTR sNewParentName,
						   LPCTSTR sAppName,
						   long nSrcStateLine,
						   long nSrcParSibLine,
						   long nMoveStateSum,
						   long nStartLineNo,
						   long nEndlLineNo)
{      
	if (FAILED(pTextSrcSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//EnvDTE::DsMovementOptions::dsExtend))))//dsMove))))
		return FALSE;
	if (FAILED(pTextSrcSelQIPtr->MoveTo(nSrcStateLine, 1,VARIANT_BOOL(EnvDTE::dsMove))))// CComVariant(dsMove))))
		return FALSE;
	
	if (FAILED(pTextSrcSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsExtend))))//CComVariant(dsExtend))))
		return FALSE;

	// Get the wanted to be modified line 
	BSTR bstrChangeLine;
	//pTextSrcSelQIPtr->SelectLine();
	if(FAILED(pTextSrcSelQIPtr->get_Text(&bstrChangeLine)))
		return FALSE;
	
	char* ChangeLine = _com_util::ConvertBSTRToString(bstrChangeLine);
	CString sLine=ChangeLine;

	delete[]ChangeLine;
	::SysFreeString(bstrChangeLine);

	int idx = sLine.ReverseFind(',');

	if (idx == -1)
	{
		CString sWarningMsg;
		
		sWarningMsg.Format("%s(%d)	error: illegal syntax", (CString)sSrcFilePath, nSrcStateLine);
		return FALSE;
	}

	CString sDefaultState = sLine.Right(sLine.GetLength()-idx);
	sLine=sLine.Left(idx);
	idx = sLine.ReverseFind(',');

		if (idx == -1)
	{
		CString sWarningMsg;
		
		sWarningMsg.Format("%s(%d)	error: illegal syntax", (CString)sSrcFilePath, nSrcStateLine);
		return FALSE;
	}

	sLine = sLine.Left(idx+1);

	if (((CString)sNewParentName).CompareNoCase(sAppName) == 0)
		sLine = sLine+"0"+sDefaultState;
	else
		sLine = sLine+sNewParentName+sDefaultState;

		// Put the modified line text
	if (FAILED(pTextSrcSelQIPtr->put_Text(CComBSTR(sLine))))
        return FALSE;
	
	////////////////////////////////////////////////////////////////////////////////////
	if (FAILED(pTextSrcSelQIPtr->MoveTo(nSrcStateLine, 1, VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
		return FALSE;

	VARIANT_BOOL vbFound;  
	while (true)
	{
		if (nMoveStateSum == 0)
			break;

		//if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR("SME_STATE"), EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
		if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR("SME_STATE"),EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
		{
			//MessageBox(_T((CString)sSrcFilePath+"  error:SME_STATE expected."),MB_ICONERROR|MB_OK);			
			return FALSE;
		}
		else
			nMoveStateSum--;
		if (FAILED(pTextSrcSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
			return FALSE;
	}

	long nMovedStateEndLineNo;
	pTextSrcSelQIPtr->get_CurrentLine(&nMovedStateEndLineNo);
	
	// Select the lines from nSrcStateLine to nMovedStateEndLineNo
	if (FAILED(pTextSrcSelQIPtr->MoveTo(nSrcStateLine, 1, VARIANT_BOOL(EnvDTE::dsMove))))
		return FALSE;
	if (FAILED(pTextSrcSelQIPtr->MoveTo(nMovedStateEndLineNo+1, 1 , VARIANT_BOOL(EnvDTE::dsExtend)))) // 1: Moves the insertion point to the first column.
		return FALSE;

	if (FAILED(pTextSrcSelQIPtr->Cut()))
		return FALSE;

	// Past the selection to the new insert line 
	int nNewInsertLine;
	if (nSrcParSibLine > nSrcStateLine)
		nNewInsertLine= nSrcParSibLine-(nMovedStateEndLineNo-nSrcStateLine+1);
	else
		nNewInsertLine= nSrcParSibLine;
	if (FAILED(pTextSrcSelQIPtr->MoveTo(nNewInsertLine, 1, VARIANT_BOOL(EnvDTE::dsMove))))
		return FALSE;
	if (FAILED(pTextSrcSelQIPtr->Paste()))
		return FALSE;

	// Release the selection.
	pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsMove);

	return TRUE;
}



/////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Deal with state declaration code change in header file when moving state item
// INPUT: 1)pTextHdrSelQIPtr: Text selection of header file
//        2)sHdrFilePath: Header file path
//        3)nHdrStateLineNo: Line number of moved state in header file
//        4)nHdrNewParSibLineNo: Line number to be inserted in
//        5)nMoveStateSum: Sum of states under moved state item
//
// OUTPUT: 1)TRUE: Success
//         2)FALSE: Fail
// NOTE: Cut the lines between nHdrStateLineNo and nInsertEndlineNo to the original line point nHdrNewParSibLineNo.
/////////////////////////////////////////////////////////////////////////
BOOL DSUtils::MoveStateDec(CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextHdrSelQIPtr,
							LPCTSTR sHdrFilePath,
							long nHdrStateLineNo,
							long nHdrNewParSibLineNo,
							long nMoveStateSum)
{
	//////////////////////////////////////////////////////////
	// Move state declaration.
	if (nHdrNewParSibLineNo == nHdrStateLineNo) // Copy/Paste to the same location.
		return TRUE;
	if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
		return FALSE;

	if (FAILED(pTextHdrSelQIPtr->MoveTo(nHdrStateLineNo, 1,VARIANT_BOOL(EnvDTE::dsMove))))// CComVariant(dsMove))))
		return FALSE;

	long nMovedStateEndLineNo;
	
	VARIANT_BOOL vbFound; 
	
	while (true)
	{
		if (nMoveStateSum == 0)
			break;

		if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR("SME_STATE_DECLARE"), EnvDTE::dsMatchForward, &vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
		{
			//AfxMessageBox(_T((CString)sHdrFilePath+"  error:SME_STATE_DECLARE expected."),MB_ICONERROR|MB_OK);
			return FALSE;
		}
		else
			nMoveStateSum--;
		if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
			return FALSE;
	}

	pTextHdrSelQIPtr->get_CurrentLine(&nMovedStateEndLineNo);

	// Select the lines from nHdrStateLineNo to nMovedStateEndLineNo
	if (FAILED(pTextHdrSelQIPtr->MoveTo(nHdrStateLineNo, 1, VARIANT_BOOL(EnvDTE::dsMove))))
		return FALSE;
	if (FAILED(pTextHdrSelQIPtr->MoveTo(nMovedStateEndLineNo+1, 1 , VARIANT_BOOL(EnvDTE::dsExtend)))) // 1: Moves the insertion point to the first column.
		return FALSE;

	if (FAILED(pTextHdrSelQIPtr->Cut()))
		return FALSE;

	// Past the selection to the new insert line 
	int nNewInsertLine;
	if (nHdrNewParSibLineNo > nHdrStateLineNo)
		nNewInsertLine= nHdrNewParSibLineNo-(nMovedStateEndLineNo-nHdrStateLineNo+1);
	else
		nNewInsertLine= nHdrNewParSibLineNo;
	if (FAILED(pTextHdrSelQIPtr->MoveTo(nNewInsertLine, 1,VARIANT_BOOL(EnvDTE::dsMove))))
		return FALSE;

	if (FAILED(pTextHdrSelQIPtr->Paste()))
		return FALSE;

	// Release the selection.
	pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMove);

	return TRUE;
}


/////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Deal with app class code change in header file when moving state item
// INPUT: 1)pTextHdrSelQIPtr: Text selection of header file
//        2)sHdrFilePath: Header file path
//        3)nHdrStateLineNo: Line number of moved state in header file
//        4)nHdrNewParSibLineNo: Line number to be inserted in
//        5)nMoveStateSum: Sum of states under moved state item
//
// OUTPUT: 1)TRUE: Success
//         2)FALSE: Fail
// NOTE: Cut the lines between nHdrStateLineNo and nInsertEndlineNo to the original line point nHdrNewParSibLineNo.
/////////////////////////////////////////////////////////////////////////
BOOL DSUtils::MoveAppClassDec(CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextHdrSelQIPtr,
							LPCTSTR sAppName,
							LPCTSTR sStateName,
							LPCTSTR sNewParent,
							LPCTSTR sNewSibling,
							long nMoveStateSum)
{
	//////////////////////////////////////////////////////////
	// Move application class declaration.
	CString sStartTag = "/*{{";
	CString sEndTag = "/*}}";
	CString sHdrDecTag = "SME_STATE_EVT_HDL_TBL_DEC";
	CString sHdrNewParentDec = sHdrDecTag+"("+sNewParent+")";
	CString sHdrStateDec = sHdrDecTag+"("+sStateName+")";
	CString sHdrSibParDec = sHdrDecTag+"("+sNewSibling+")"; //sNewSibling may be NULL
	CString sHdrStateDecEnd = CString("SME_STATE_TREE_DEC(") + sAppName + ")";

	CString sHdrAppClassHead = CString("/*{{SME_APP_CLASS_DECLARE(") + sAppName + ",";
	VARIANT_BOOL vbFound;  
	if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sHdrAppClassHead), EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
		return TRUE;

	long nHdrStartLineNo;
	pTextHdrSelQIPtr->get_CurrentLine(&nHdrStartLineNo); 
	long nHdrLine=nHdrStartLineNo+1;

	long nHdrStateLineNo, nHdrNewParLineNo, nHdrNewParSibLineNo;
	nHdrStateLineNo=nHdrNewParLineNo=nHdrNewParSibLineNo=-1;

	long nMovedStateEndLineNo=-1;

	while (true)
	{
		if (FAILED(pTextHdrSelQIPtr->MoveTo(nHdrLine, 1, VARIANT_BOOL(EnvDTE::dsMove))))
			return FALSE;
		if (FAILED(pTextHdrSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText, VARIANT_BOOL(EnvDTE::dsMove))))
			return FALSE;
		if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsExtend))))
			return FALSE;
		BSTR bstr = NULL;
		pTextHdrSelQIPtr->get_Text(&bstr);
		CString sResult = BSTR2CString(bstr);
		TrimSpace(sResult);

		if ((!sResult.IsEmpty()) && (sResult == sHdrStateDecEnd))
		{
			if (sNewSibling==NULL)
				nHdrNewParSibLineNo = nHdrLine;
			break;
		}

		if ((sResult.IsEmpty()) || (sResult.Find("SME_STATE_EVT_HDL_TBL_DEC") == -1))
		{
			break;
		}

		if ((!sResult.IsEmpty()) && (sResult == sHdrStateDec))
		{
			nHdrStateLineNo = nHdrLine;
		}
	
		if ((!sResult.IsEmpty()) && (sResult == sHdrNewParentDec))
		{
			nHdrNewParLineNo = nHdrLine;
		}

		if ((nHdrNewParSibLineNo == -1) &&(!sResult.IsEmpty()) && (sResult == sHdrSibParDec))
		{
			nHdrNewParSibLineNo = nHdrLine;
		}

		if (!sResult.IsEmpty() && nHdrStateLineNo!=-1)
		{
			nMoveStateSum--;
			if (nMoveStateSum==0)
				nMovedStateEndLineNo = nHdrLine;
		}

		nHdrLine++;
	}

	if (nHdrStateLineNo==-1 || nMovedStateEndLineNo==-1)
		return FALSE;

	if (nHdrNewParSibLineNo == nHdrStateLineNo) // Copy/Paste to the same location.
		return TRUE;

	// Select the lines from nHdrStateLineNo to nInsertEndLineNo
	if (FAILED(pTextHdrSelQIPtr->MoveTo(nHdrStateLineNo, 1, VARIANT_BOOL(EnvDTE::dsMove))))
		return FALSE;
	if (FAILED(pTextHdrSelQIPtr->MoveTo(nMovedStateEndLineNo+1, 1 , VARIANT_BOOL(EnvDTE::dsExtend)))) // 1: Moves the insertion point to the first column.
		return FALSE;

	if (FAILED(pTextHdrSelQIPtr->Cut()))
		return FALSE;

	// Past the selection to the new insert line 
	int nNewInsertLine;
	if (nHdrNewParSibLineNo > nHdrStateLineNo) // new location is below the original location.
		nNewInsertLine = nHdrNewParSibLineNo-(nMovedStateEndLineNo-nHdrStateLineNo+1);
	else
		nNewInsertLine = nHdrNewParSibLineNo;

	if (FAILED(pTextHdrSelQIPtr->MoveTo(nNewInsertLine, 1, VARIANT_BOOL(EnvDTE::dsMove))))
		return FALSE;
	if (FAILED(pTextHdrSelQIPtr->Paste()))
		return FALSE;

	return TRUE;
}


///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Whether work space is a normal one according to file extension .dsw
// INPUT: None
// OUTPUT: None
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::IsNormalSln()
{
    _bstr_t bstrPath = GetSlnPath();
    BOOL bRet = FALSE;
	do
    {
        if (bstrPath.length() < 3) 
            break;

		char* filePath = _com_util::ConvertBSTRToString(bstrPath.GetBSTR());
        CString strWorkspace = filePath;
		delete []filePath;
        strWorkspace = strWorkspace.Right(3);
        bRet = (0 == _tcsicmp(strWorkspace, _T("sln")));
    } while(FALSE);
    return bRet;
}



/////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Whether debugger is active.
// INPUT: 
// OUTPUT: zero or nonzero
// NOTE: 
//////////////////////////////////////////////////////////////////////////
BOOL DSUtils::IsDebuggerActive()
{
	CComPtr<EnvDTE::Debugger> pDebuggerIPtr;
	g_pDTE->get_Debugger(&pDebuggerIPtr);

	CComQIPtr<EnvDTE::Debugger, &EnvDTE::IID_Debugger> pDebuggerQIPtr(pDebuggerIPtr);
	//DsExecutionState nDebuggerState;

	EnvDTE::dbgDebugMode nDebuggerState;
	pDebuggerQIPtr->get_CurrentMode(&nDebuggerState);//get_State(&nDebuggerState);
    
	if (nDebuggerState != 1)      //////dbgDesignMode=1//////dte.tlh
	{
		return TRUE;
	}

	return FALSE;
}

/////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get the map file name.
// INPUT: 1)lpFilePath: a point to the dsp full path.
//        2)lpDspName: a point to the dsp name.
//        3)sMapfileName: a refference to the string of the mapfilename
// OUTPUT: zero or nonzero
// NOTE: 
//////////////////////////////////////////////////////////////////////////
BOOL DSUtils::GetMapfileName(LPCTSTR lpFilePath, LPCTSTR lpDspName, LPCTSTR lpDswFullPath, CString &sMapfileName, bool &bUnopen)
{
	return FALSE;
}

/////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get the map file full path.
// INPUT: 1)sMapfilePath: a string to record the mapfile path
// OUTPUT: zero or nonzero
// NOTE: 
//////////////////////////////////////////////////////////////////////////
BOOL DSUtils::GetMapfilePath(CString &sMapfilePath, bool &bUnopen)
{
	// First save all
	g_pDTE->ExecuteCommand(CComBSTR("File.SaveAll"), CComBSTR("")); 


	// Get the sln path 
	char *temp=_com_util::ConvertBSTRToString(GetSlnPath().GetBSTR());
	CString sSlnPath = temp;
	
	delete[] temp;
	sSlnPath = sSlnPath.Left(sSlnPath.ReverseFind('\\'));

	//open map file
	CString strFilter = "mapfile|*.map||";
	CFileDialog dlg(TRUE, NULL, NULL, OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST, strFilter, NULL);
	dlg.m_ofn.lpstrTitle = "Open Mapfile";
	dlg.m_ofn.lpstrInitialDir = sSlnPath;

	if (dlg.DoModal() == IDOK)
		sMapfilePath = dlg.GetPathName();
	else
		bUnopen = TRUE;


	if (!sMapfilePath.IsEmpty())
		return TRUE;


	return FALSE;;
}


/*******************************************************************************************
** DESCRIPTION: Add source file and header file to the specific VC project. 
** INPUT:  
**		1) prj: The project to be added files; 
**		2) srcFile: Source file name 
**		3) headFile: Header file name 
** OUTPUT: TRUE: Insert successfully. FALSE: Failed to insert.
** NOTE: 
Translate Project object to VCProject object.
**   
*******************************************************************************************/
BOOL DSUtils::AddSrcHdrFilesToPrj(CComPtr<EnvDTE::Project>& prj, _bstr_t& srcFile, _bstr_t& headFile, _bstr_t& EventIdFile)
{
	ATLASSERT(g_pDTE != NULL );
	g_pDTE->ExecuteCommand(CComBSTR("File.SaveAll"), CComBSTR("")); //???


	CComPtr<IDispatch> pDispProject;
	if (FAILED(prj->get_Object(&pDispProject))) return FALSE;

#ifdef VS2005
	CComQIPtr<VCProjectEngineLibrary::VCProject> pVCProject;
	if (FAILED(pDispProject->QueryInterface(&pVCProject))) return FALSE;
	pVCProject = pDispProject; ///?? Faile for VS2005
#else
	CComQIPtr<VCProject> pVCProject;
	pVCProject = pDispProject;
#endif

	
	HRESULT ree=S_OK;
	BOOL bAddEventIdFile = FALSE;
	if (EventIdFile.length()!=0)
	bAddEventIdFile = TRUE;

#ifdef VS2005
	CComPtr<IDispatch> spDispFile;

	if(!bAddEventIdFile){
		CComPtr<IDispatch> retSrc,retHead;
		spDispFile=NULL;
		//ree = pVCProject->AddFile(srcFile.GetBSTR(),&spDispFile);
		ree = pVCProject->AddFile(srcFile.GetBSTR());
		if(!SUCCEEDED(ree))MessageBox(NULL,"Failed to add head files to current project!","Error",0);

		spDispFile=NULL;
		//ree = pVCProject->AddFile(headFile.GetBSTR(),&spDispFile);
		ree = pVCProject->AddFile(headFile.GetBSTR());
		if(!SUCCEEDED(ree))MessageBox(NULL,"Failed to add c/cpp files to current project!","Error",0);
	}
	else
	{
		CComPtr<IDispatch> retEventId;
		spDispFile=NULL;
		//ree = pVCProject->AddFile(EventIdFile.GetBSTR(),&spDispFile);
		ree = pVCProject->AddFile(EventIdFile.GetBSTR());
		if(!SUCCEEDED(ree))MessageBox(NULL,"Failed to add eventid files to current project!","Error",0);
	}
#else
	if(!bAddEventIdFile){
		CComPtr<IDispatch> retSrc,retHead;
		ree = pVCProject->AddFile(srcFile.GetBSTR());
		if(!SUCCEEDED(ree))MessageBox(NULL,"Failed to add head files to current project!","Error",0);

		ree = pVCProject->AddFile(headFile.GetBSTR());
		if(!SUCCEEDED(ree))MessageBox(NULL,"Failed to add c/cpp files to current project!","Error",0);
	}
	else
	{
		CComPtr<IDispatch> retEventId;
		ree = pVCProject->AddFile(EventIdFile.GetBSTR());
		if(!SUCCEEDED(ree))MessageBox(NULL,"Failed to add eventid files to current project!","Error",0);
	}
#endif
	return TRUE;
}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Del source file and header file from the specific VC project. 
// INPUT: 1) prj: The project to be deleted files; 
//		2) srcFile: Source file name 
//		3) headFile: Header file name 
// OUTPUT: None.
// NOTE:
//   
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::DelSrcHdrFilesFromPrj(CComPtr<EnvDTE::Project>& prj, _bstr_t& srcFile, _bstr_t& headFile)
{
	ATLASSERT(prj!=NULL);
	g_pDTE->ExecuteCommand(CComBSTR("File.SaveAll"), CComBSTR("")); //???


	CString SrcFile(srcFile.GetBSTR()),HeadFile(headFile.GetBSTR());
	SrcFile.MakeLower();
	HeadFile.MakeLower();
	char ifSuccess = 0;
	CComPtr<EnvDTE::ProjectItems> prjItems;
	prj->get_ProjectItems(&prjItems);
	if(prjItems==NULL)return FALSE;
	return DelSrcHldFilesFromPrjItems(prjItems,SrcFile,HeadFile);

	/*long n ;
	prjItems->get_Count(&n);
	for(long count = 1 ; count<= n;count++)
	{
		CComVariant var(count);
		CComPtr<EnvDTE::ProjectItem> prjItem;
		HRESULT re = prjItems->Item(var,&prjItem);
		if(prjItem!=NULL)
		{
			short fileCount;
			BSTR wa;
			prjItem->get_Name(&wa);
			_bstr_t fileListName(wa,false);
			TAG_FILELIST_STATE fileListState;
			if(wcsstr(static_cast<wchar_t*>(fileListName),L"Source Files")!=NULL)
			{
				fileListState = TAG_SOURCE_FILE_STATE;
			}
			else if(wcsstr(static_cast<wchar_t*>(fileListName),L"Header Files")!=NULL)
			{
				fileListState = TAG_HEAD_FILE_STATE;
			}
			else
			{
				fileListState = TAG_OTHER_FILE_STATE;
				continue;//to the next item
			}

			prjItem->get_FileCount(&fileCount);
			CComPtr<EnvDTE::ProjectItems> items;
			prjItem->get_ProjectItems(&items);

			for(short i = 1;i<= fileCount; i++)
			{	
				CComPtr<EnvDTE::ProjectItem> itemContainFile;
				items->Item(CComVariant(i),&itemContainFile);
				BSTR fileName;
				itemContainFile->get_FileNames(1,&fileName);
				_bstr_t fileNameWapper(fileName,false);
				if(fileListState==TAG_SOURCE_FILE_STATE)
				{
					if(wcsstr(fileNameWapper.GetBSTR(),srcFile.GetBSTR()))
					{
						itemContainFile->Remove();
						ifSuccess++;
						break;

					}

				}

				if(fileListState ==TAG_HEAD_FILE_STATE)
				{
					if(wcsstr(fileNameWapper.GetBSTR(),headFile.GetBSTR()))
					{
						itemContainFile->Remove();
						ifSuccess+=2;
						break;

					}
				}
			}
		}
	}

	if(ifSuccess==3)
	{
		return TRUE;
	}
	else
		if(ifSuccess==1)
		{
			MessageBox(NULL,"Failed when attempting to remove one head file from project.","Error",0);
			return FALSE;
		}
	else 
		if(ifSuccess==2)
		{
			MessageBox(NULL,"Failed when attempting to remove one c/cpp file from project.","Error",0);
			return FALSE;
		}
	else
	{
		MessageBox(NULL,"Failed when attempting to remove one c/cpp file & one head file from project.","Error",0);
		return FALSE;

	}*/
}




/////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Check legality of syntax when moving state to another 
// INPUT:  1)sSrcFilePath: Source file path where moved item locates
//         2)sHdrFilePath: Header file path where moved item locates
//         3)sStatename:   State name of moved item
//         4)sNewParent:   Parent state name of moved item
//         5)sNewSibling:  Parent state's sibling 
//         6)sAppName:     Application name
//         7)nState:       Sum of states under moved item(including moved item)
//
// OUTPUT: 1)TRUE: Syntax is legal for coming move action.
//         2)FALSE: Syntax is illegal for coming move action.
// NOTE: sNewSibling == Null when there is no sibling of parent, that is, 
//       the moved item is under the bottom of state tree.
//////////////////////////////////////////////////////////////////////////
//Need an interface for communication !
BOOL DSUtils::CheckMoveStateAtomic(LPCTSTR sSrcFilePath, LPCTSTR sHdrFilePath, LPCSTR sStatename, LPCTSTR sNewParent, 
								   LPCTSTR sNewSibling, LPCTSTR sAppName, UINT nState)
{
					// Open file
	CComPtr<EnvDTE::Documents> pOpenDocsIPtr;
	CComPtr<EnvDTE::Document> pHdrDocIPtr;

	g_pDTE->get_Documents(&pOpenDocsIPtr);
	if (pOpenDocsIPtr == NULL)
		return FALSE;

	//CComQIPtr<EnvDTE::Documents, &EnvDTE::IID_Documents> pOpenDocsQIPtr(pOpenDocsIPtr);
	if (FAILED(pOpenDocsIPtr->Open(CComBSTR(sHdrFilePath), CComBSTR("Text"),VARIANT_FALSE, &pHdrDocIPtr)))
	{
		MessageBox(NULL,_T("Application "+(CString)sAppName+"'s header file failed to open."),NULL , MB_ICONERROR|MB_OK);
		return FALSE;
	}
	
	// Get Text Selection
	//CComQIPtr<EnvDTE::TextDocument, &EnvDTE::IID_TextDocument> pTextHdrDocQIPtr(pHdrDocIPtr);

	//CComPtr<EnvDTE::TextSelection> pTextHdrSelIPtr;
	CComPtr<IDispatch> pDTextHdrSelIPtr;
	if (FAILED(pHdrDocIPtr->get_Selection(&pDTextHdrSelIPtr)))
	{
		return FALSE;   
	}


	CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextHdrSelQIPtr(pDTextHdrSelIPtr);
	//pTextHdrSelQIPtr->SelectAll();
	pTextHdrSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.


	CString sStartTag = "/*{{";
	CString sEndTag = "/*}}";
	CString sHdrDecTag = "SME_STATE_DECLARE";
	CString sHdrStateDecHead = sStartTag+sHdrDecTag+"("+sAppName+")*/";
	CString sHdrStateDecEnd = sEndTag+sHdrDecTag+"*/";
	CString sHdrMaxStateDec = "SME_MAX_STATE(";
	sHdrMaxStateDec = sHdrMaxStateDec + sAppName+")";
	CString sHdrNewParentDec = sHdrDecTag+"("+sNewParent+")";
	CString sHdrStateDec = sHdrDecTag+"("+sStatename+")";
	CString sHdrSibParDec = sHdrDecTag+"("+sNewSibling+")";
	
	VARIANT_BOOL vbFound;  
	// search for the StateHead declaration
	//EnvDTE::vsFindOptions

	if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sHdrStateDecHead), EnvDTE::dsMatchFromStart, &vbFound)) || ! vbFound)// EnvDTE::dsMatchFromStart, &vbFound)) || ! vbFound)
	{
		MessageBox(NULL,_T((CString)sHdrFilePath+"  error:" + sHdrStateDecHead + " expected."),NULL,MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"  error:"+ sHdrStateDecHead + " expected")));
		return FALSE;
	}

	// move the cursor to the end of matching line
    if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
		return FALSE;
	
	long nHdrStartLineNo;
	pTextHdrSelQIPtr->get_CurrentLine(&nHdrStartLineNo); 
	// Search for StateEnd declaration
	if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sHdrStateDecEnd), EnvDTE::dsMatchForward,&vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sHdrFilePath+"  error:" + sHdrStateDecEnd + " expected."),NULL, MB_ICONERROR|MB_OK);
		//OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sHdrStateDecEnd)));
		return FALSE;
	}
	// Move the cursor to the end of matching line
    if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
		return FALSE;

	long nHdrEndLineNo;
	pTextHdrSelQIPtr->get_CurrentLine(&nHdrEndLineNo);
	

	long nHdrStateLineNo = -1;
	long nHdrNewParLineNo = -1;
	long nHdrNewParSibLineNo = -1;
	long nHdrLine = nHdrStartLineNo+1;
	

	// No new sibling state.
	if (sNewSibling == NULL)
	nHdrNewParSibLineNo = nHdrEndLineNo;

	while (true)
	{
		if (nHdrLine >= nHdrEndLineNo)
			break;

		if (FAILED(pTextHdrSelQIPtr->MoveTo(nHdrLine,1,VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
			return FALSE;

		//EnvDTE::vsStartOfLineOptions ss;
		if (FAILED(pTextHdrSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsFirstText), CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsExtend)))//VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsExtend))))
			return FALSE;
		BSTR bstr = NULL;
		//pTextHdrSelQIPtr->SelectLine();
		pTextHdrSelQIPtr->get_Text(&bstr);

		char* bstrPath = _com_util::ConvertBSTRToString(bstr);//////////////////////////////////////***************************************
		CString sResult(bstrPath);
		delete[]bstrPath;

		sResult.TrimLeft();
		sResult.TrimRight();
		sResult.Replace("\t", NULL);
		sResult.Replace(" ", NULL);

		if ((!sResult.IsEmpty()) && (sResult == sHdrStateDec))
		{
			nHdrStateLineNo = nHdrLine;
		}
	
		if ((!sResult.IsEmpty()) && (sResult == sHdrNewParentDec))
		{
			nHdrNewParLineNo = nHdrLine;
		}

		if ((nHdrNewParSibLineNo == -1) &&(!sResult.IsEmpty()) && (sResult == sHdrSibParDec))
		{
			nHdrNewParSibLineNo = nHdrLine;
		}

		// No new sibling state. Insert point is the end of state declaration.
		if ((!sResult.IsEmpty()) && (sResult == sHdrMaxStateDec))
		{
			if (nHdrNewParSibLineNo == nHdrEndLineNo)
				nHdrNewParSibLineNo = nHdrLine;
		}
		nHdrLine++;

	}

	if (nHdrStateLineNo == -1)
	{
		MessageBox(NULL,_T((CString)sHdrFilePath+"  error:" + sHdrStateDec+ " expected."),NULL, MB_ICONERROR|MB_OK);
		//OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sStateDecParent)));
		return FALSE;
	}
	
	if (nHdrNewParLineNo == -1)
	{
		MessageBox(NULL,_T((CString)sHdrFilePath+"  error:" + sHdrNewParentDec+ " expected."), NULL,MB_ICONERROR|MB_OK);
//		OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sStateDecParent)));
		return FALSE;
	}
	
	if (nHdrNewParSibLineNo == -1)
	{
		MessageBox(NULL,_T((CString)sHdrFilePath+"  error:" + sHdrMaxStateDec + " expected."),NULL, MB_ICONERROR|MB_OK);
		//OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sStateDecParent)));
		return FALSE;
	}

	// Check source file all-or-nothing
	CComPtr<EnvDTE::Document> pTextSrcDocIPtr;
	
	if (FAILED(pOpenDocsIPtr->Open(CComBSTR(sSrcFilePath), CComBSTR("Text"), VARIANT_FALSE, &pTextSrcDocIPtr)))
	{
		MessageBox(NULL,_T("Application "+(CString)sAppName+"'s source file failed to open."), NULL,MB_ICONERROR|MB_OK);
		return FALSE;
	}

	// Get Text Selection
	/*CComQIPtr<EnvDTE::TextDocument, &EnvDTE::IID_TextDocument> pTextSrcDocQIPtr(pTextSrcDocIPtr);
	CComPtr<EnvDTE::TextSelection> pTextSrcSelIPtr;
	if (FAILED(pTextSrcDocQIPtr->get_Selection(&pTextSrcSelIPtr)))
	{
		return FALSE;   
	}*/
	CComPtr<IDispatch> pTextSrcSelIPtr;
	if (FAILED(pTextSrcDocIPtr->get_Selection(&pTextSrcSelIPtr)))
	{
		return FALSE;   
	}
	
	CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextSrcSelQIPtr(pTextSrcSelIPtr);

	CString sSeparator="/*{{SME_STATE_STATETREE_SEPARATOR}}*/";
//////////////////////////////////////$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$////////////////////////////
	if(FAILED(pTextSrcSelQIPtr->MoveTo(1,1,EnvDTE::dsMove)))
	{
		return FALSE;
	}
	if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sSeparator), EnvDTE::dsMatchForward, &vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error:" + sSeparator + " expected."),NULL, MB_ICONERROR|MB_OK);
		return FALSE;
	}

	if (FAILED(pTextSrcSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
		return FALSE;

	CString strStateName=CString(sStatename);
	CString strNewParent=CString(sNewParent);
	CString strNewParSibling;
	if (sNewSibling != NULL)
		strNewParSibling=CString(sNewSibling);
	else
		strNewParSibling="";
	CString strAppName=CString(sAppName);

	CString sStateTreeDef = "SME_STATE_TREE_DEF";
	CString sStateTreeDefHead = sStartTag+sStateTreeDef+"("+strAppName+")*/";
	CString sStateTreeDefEnd = sEndTag+sStateTreeDef+"*/";
	CString sStateTreeFind = CString("SME_STATE(")+strAppName+","+strAppName+",";
	CString sStateFind= CString("SME_STATE(")+strAppName+","+strStateName+","; // IMPORTANT: Should end with , to prevent 
	CString sStateNewParentFind=CString("SME_STATE(")+strAppName+","+strNewParent+",";	
	CString sNewParSibFind=CString("SME_STATE(")+strAppName+","+strNewParSibling+",";
	if (strNewParSibling == "")
		sNewParSibFind = "";

	//pTextSrcSelQIPtr->SelectAll();
	pTextSrcSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.

	// Find the state tree definition head
	if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sStateTreeDefHead), EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)// EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error:" + sStateTreeDefHead + " expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sStateTreeDefHead)));
		return FALSE;
	}
	if (FAILED(pTextSrcSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
		return FALSE;
	
	long nSrcStartLineNo = 0;
	if (FAILED(pTextSrcSelQIPtr->get_CurrentLine(&nSrcStartLineNo)))
		return FALSE;
	
	if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sStateTreeDefEnd), EnvDTE::dsMatchForward, &vbFound)) || !vbFound)// EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error:"+sStateTreeDefEnd+" expected."), NULL,MB_ICONERROR|MB_OK);
		return FALSE;
	}
	if (FAILED(pTextSrcSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
		return FALSE;
	long nSrcEndLineNo = 0;
	pTextSrcSelQIPtr->get_CurrentLine(&nSrcEndLineNo);

	long nSrcLine = nSrcStartLineNo+1;
	long nSrcStateLine = -1;
	long nSrcNewParLine = -1;
	long nSrcParSibLine = -1;

	while (true)
	{
		if (nSrcLine >= nSrcEndLineNo)
			break;

		if (FAILED(pTextSrcSelQIPtr->MoveTo(nSrcLine, 1,VARIANT_BOOL(EnvDTE::dsMove))))// CComVariant(dsMove))))
			return FALSE;

		if (FAILED(pTextSrcSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsFirstText), CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSrcSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsExtend))))//CComVariant(dsExtend))))
			return FALSE;
		BSTR bstr = NULL;
		//pTextSrcSelQIPtr->SelectLine();
		pTextSrcSelQIPtr->get_Text(&bstr);
	
		char* bstrPath = _com_util::ConvertBSTRToString(bstr);
		CString sResult(bstrPath);
		delete[]bstrPath;
		
		sResult.TrimLeft();
		sResult.TrimRight();
		sResult.Replace("\t", NULL);
		sResult.Replace(" ", NULL);

		if (!sResult.IsEmpty())
		{
			if ((sResult.Find(sStateFind) != -1))
			{
				CString sTemp = sResult;
				sTemp.Replace(sStateFind, NULL);
				int idx = sTemp.Find(')');
				if (idx == sTemp.GetLength() -1)
				{
					int nCommaNum = 0;
					while (true)
					{
						if (nCommaNum > 1)
							break;
						int commaIdx = sTemp.Find(',');
						if (commaIdx == -1)
							break;
						sTemp.SetAt(commaIdx, ' ');
						nCommaNum++;
					}
					if (nCommaNum == 1)
					{
						//	SME_STATE(MyApp2,State2,0,-1)
						nSrcStateLine = nSrcLine;
					}
					else
						return FALSE;
				}
			}
			if (sResult.Find(sStateTreeFind) != -1)
			{
				CString sTemp = sResult;
				sTemp.Replace(sStateTreeFind, NULL);
				int idx = sTemp.Find(')');
				if (idx == sTemp.GetLength() -1)
				{
					int nCommaNum = 0;
					while (true)
					{
						if (nCommaNum > 1)
							break;
						int commaIdx = sTemp.Find(',');
						if (commaIdx == -1)
							break;
						sTemp.SetAt(commaIdx, ' ');
						nCommaNum++;
					}
					if (nCommaNum != 1)
					{
						return FALSE;
					}
				}
			}
			if (sResult.Find(sStateNewParentFind) != -1)
			{
				CString sTemp = sResult;
				sTemp.Replace(sStateNewParentFind, NULL);
				int idx = sTemp.Find(')');
				if (idx == sTemp.GetLength() -1)
				{
					int nCommaNum = 0;
					while (true)
					{
						if (nCommaNum > 1)
							break;
						int commaIdx = sTemp.Find(',');
						if (commaIdx == -1)
							break;
						sTemp.SetAt(commaIdx, ' ');
						nCommaNum++;
					}
					if (nCommaNum == 1)
					{
						nSrcNewParLine = nSrcLine;
					}
					else
						return FALSE;
				}
			}
			if ((sNewParSibFind != "") && sResult.Find(sNewParSibFind) != -1)
			{
				CString sTemp = sResult;
				sTemp.Replace(sNewParSibFind, NULL);
				int idx = sTemp.Find(')');
				if (idx == sTemp.GetLength() -1)
				{
					int nCommaNum = 0;
					while (true)
					{
						if (nCommaNum > 1)
							break;
						int commaIdx = sTemp.Find(',');
						if (commaIdx == -1)
							break;
						sTemp.SetAt(commaIdx, ' ');
						nCommaNum++;
					}
					if (nCommaNum == 1)
					{
						nSrcParSibLine = nSrcLine;
					}
					else
						return FALSE;
				}
			}
		}
			nSrcLine++;
		
	}
		
	if (nSrcParSibLine < 0)
    	nSrcParSibLine = nSrcEndLineNo;

	if (nSrcNewParLine < 0)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error:" + sStateNewParentFind + " expected."),NULL, MB_ICONERROR|MB_OK);
		return FALSE;
	}

	if (nSrcStateLine < 0)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error:" + sStateFind + " expected."),NULL, MB_ICONERROR|MB_OK);
		return FALSE;
	}

	if (MoveStateDec(pTextHdrSelQIPtr, sHdrFilePath, nHdrStateLineNo, nHdrNewParSibLineNo, nState) == FALSE)
		return FALSE;

	MoveAppClassDec(pTextHdrSelQIPtr, sAppName, sStatename, sNewParent, sNewSibling, nState);

	if (MoveStateDef(pTextSrcSelQIPtr, sSrcFilePath, sNewParent, sAppName, nSrcStateLine, nSrcParSibLine, nState, nSrcStartLineNo, nSrcEndLineNo+nState) == FALSE)
		return FALSE;
	return TRUE;


}



/////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Check atomic attribute of editing an event handler
// INPUT:  1) sSrcFilePath: Full path of application source file.
//         2) sHdrFilePath: Full path of application header file.
//         3) sAppName: Application name.
//         4) sStateName: State name which owns to-be-edited event. 
//         5) sOriginEvent: Event's original name.
//         6) sEventName: New event name.
//         7) sDestState: New transition state name if it exists.
//         8) sActionName: New action name if it exists.
//
// OUTPUT: 1)TRUE:  2)FALSE:
// NOTE: 
//
//////////////////////////////////////////////////////////////////////////
BOOL DSUtils::EditEventHdlDec(LPCTSTR sSrcFilePath, 
							  LPCTSTR sHdrFilePath, 
							  LPCTSTR sAppName,
							  LPCTSTR sFuncClassPrefix,
							  LPCTSTR sStateName, 
							  LPCTSTR sOriginEvent, 
							  LPCTSTR sEventName, 
							  LPCTSTR sDestState, 
							  LPCTSTR sActionName)
{
	CComPtr<EnvDTE::Documents>pOpenDocsIPtr;
	CComPtr<EnvDTE::Document>pTextDocIPtr;
	g_pDTE->get_Documents(&pOpenDocsIPtr);

	if (pOpenDocsIPtr == NULL)
	return FALSE;

	CComQIPtr<EnvDTE::Documents, &EnvDTE::IID_Documents> pOpenDocsQIPtr(pOpenDocsIPtr);
	if (FAILED(pOpenDocsQIPtr->Open(CComBSTR(sSrcFilePath), CComBSTR("Text"), VARIANT_FALSE, &pTextDocIPtr)))
	{
		return FALSE;
	}

	/////////////////// Get Text Selection
	//CComQIPtr<EnvDTE::TextDocument, &EnvDTE::IID_TextDocument> pTextDocQIPtr(pTextDocIPtr);
	//CComPtr<EnvDTE::TextSelection> pTextSelIPtr;
	//if (FAILED(pTextDocQIPtr->get_Selection(&pTextSelIPtr)))
	//{
	//	return FALSE;   
	//}	

	CComPtr<IDispatch> pDTextSelIPtr;
	if (FAILED(pTextDocIPtr->get_Selection(&pDTextSelIPtr)))
	{
		return FALSE;   
	}


	CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextSelQIPtr(pDTextSelIPtr);
	//pTextSelQIPtr->SelectAll();
	pTextSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.

	
	CString sStartTag = "/*{{SME_STATE_DEF";
	CString sEndTag = "/*}}SME_STATE_DEF*/";
	CString sStateDefHead = sStartTag+"("+sAppName+","+sStateName+")*/";
	CString sStateDefEnd = sEndTag;
	CString sEvntHead = "SME_ON_EVENT(";
	CString sEditEventDec = sEvntHead + sOriginEvent+",";

	VARIANT_BOOL vbFound;
	// Find the state definition head);
	if (FAILED(pTextSelQIPtr->FindText(CComBSTR(sStateDefHead), EnvDTE::dsMatchFromStart,&vbFound)) || !vbFound)// EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error: " + sStateDefHead + " expected."), NULL,MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sStateDefHead)));
		return FALSE;
	}
	if (FAILED(pTextSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
		return FALSE;
	long nStartLineNo;
	if (FAILED(pTextSelQIPtr->get_CurrentLine(&nStartLineNo)))
		return FALSE;
	//EnvDTE::vsFindOptions
	if (FAILED(pTextSelQIPtr->FindText(CComBSTR(sStateDefEnd), EnvDTE::dsMatchForward, &vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error: " + sStateDefEnd + " expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sStateDefEnd)));
		return FALSE;
	}
	if (FAILED(pTextSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
		return FALSE;

	long nEndLineNo;
	if (FAILED(pTextSelQIPtr->get_CurrentLine(&nEndLineNo)))
		return FALSE;
	
	long nLine = nStartLineNo+1;
	CString sOriginAction;

	while (true)
	{
		if (nLine >= nEndLineNo)
			break;
		
		if (FAILED(pTextSelQIPtr->MoveTo(nLine, 1, VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsFirstText), CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsExtend))))//CComVariant(dsExtend))))
			return FALSE;
		BSTR bstr = NULL;
		//pTextSelQIPtr->SelectLine();
		pTextSelQIPtr->get_Text(&bstr);
	
		char* bstrPath = _com_util::ConvertBSTRToString(bstr);
		CString sResult(bstrPath);
		delete[]bstrPath;
		
		sResult.TrimLeft();
		sResult.TrimRight();
		sResult.Replace("\t", NULL);
		sResult.Replace(" ", NULL);

		if ((!sResult.IsEmpty()) && (sResult.Find(sEditEventDec) != -1))
		{
			sResult.Replace(sEditEventDec, NULL);
			int idx = sResult.Find(')');
			if (idx != sResult.GetLength()-1)
			{
				CString sWarningMsg;

				sWarningMsg.Format("%s(Line %d)	error: %s expected.", (CString)sSrcFilePath, nLine, sEditEventDec);
				AfxMessageBox(_T(sWarningMsg), MB_ICONERROR|MB_OK);
				OutPutStringToPane(_bstr_t(_T(sWarningMsg)));
				return FALSE;
			}
			sResult.Replace(")", NULL);
			idx = sResult.Find(',');
			if (idx == -1)
			{
				CString sWarningMsg;

				sWarningMsg.Format("%s(Line %d)	error: %s expected.", (CString)sSrcFilePath, nLine, sEditEventDec);
				MessageBox(NULL,_T(sWarningMsg), NULL,MB_ICONERROR|MB_OK);
				OutPutStringToPane(_bstr_t(_T(sWarningMsg)));
				return FALSE;
			}
			sOriginAction = sResult.Left(idx);
			sResult.SetAt(idx, ' ');
			idx = sResult.Find(',');
			if (idx != -1)
			{
				CString sWarningMsg;
					
				sWarningMsg.Format("%s(Line %d)	error: %s expected.", (CString)sSrcFilePath, nLine, sEditEventDec);
				MessageBox(NULL,_T(sWarningMsg),NULL, MB_ICONERROR|MB_OK);
				OutPutStringToPane(_bstr_t(_T(sWarningMsg)));
				return FALSE;
			}
			break;	
		}
		nLine++;
	
		// Format:	SME_ON_EVENT(eventid,action,transition state)
	}

	if (nLine >= nEndLineNo)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error: " + sEditEventDec + " expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sEditEventDec)));
		return FALSE;
	}

	long nFuncLineNo=0;
	if ((((CString)sActionName == "SME_NULL") && (sOriginAction != "SME_NULL" && sOriginAction != "0")) ||
		(((CString)sActionName != "SME_NULL") && ((CString)sActionName != sOriginAction)))
	{
		if (EditEventHdlFunc(sHdrFilePath, sAppName, sOriginAction, sActionName) == FALSE)
			return FALSE;
		if(FAILED(pTextSelQIPtr->EndOfDocument(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
			return FALSE;

		pTextSelQIPtr->get_CurrentLine(&nFuncLineNo);

		if (CString(sActionName) != "SME_NULL")
		{
			if(FAILED(pTextSelQIPtr->put_Text(CComBSTR(CString("\nint ")+sFuncClassPrefix+CString(sActionName)+"(struct SME_APP_T *pApp, struct SME_EVENT_T *pEvent)\n{\nreturn 0;\n}\n\n"))))
				return FALSE;
		}

	}
	// Move to the finded line
	if (FAILED(pTextSelQIPtr->MoveTo(nLine, 1, VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
		return FALSE;
	if (FAILED(pTextSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsFirstText), CComVariant(dsMove))))
		return FALSE;
	if (FAILED(pTextSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsExtend))))//CComVariant(dsExtend))))
		return FALSE;
	
	CString sNewText;
	CString sTemp = sDestState;
	sTemp.TrimLeft();
	sTemp.TrimRight();
	if (!sTemp.IsEmpty())
		sNewText = sEvntHead + (CString)sEventName + "," + (CString)sActionName + "," + (CString)sDestState + ")";
	else
		sNewText = sEvntHead + (CString)sEventName + "," + (CString)sActionName + "," + "SME_INTERNAL_TRAN" + ")";
	// delete the finded line
	if (FAILED(pTextSelQIPtr->put_Text(CComBSTR(sNewText))))
        return FALSE;

	// Move to the function.
	if (nFuncLineNo>0)
	if (FAILED(pTextSelQIPtr->MoveTo(nFuncLineNo+3, START_COL_POS, EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;

	return TRUE;
}


/////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Edit handler declaration in application header file
// INPUT: 1) sHdrFilePath: Full path of application header file
//        2) sAppName: Application name.
//        3) sOriginAction: Original action name.
//        4) sNewAction: New action name.
//
// OUTPUT: 1) TRUE: 2)FALSE��
// NOTE: If new action name has existed already, it will notify users. But it
//       will still re-declaration that event handler again at this version.
//
//////////////////////////////////////////////////////////////////////////
BOOL DSUtils::EditEventHdlFunc(LPCTSTR sHdrFilePath, 
							   LPCTSTR sAppName, 
							   LPCTSTR sOriginAction, 
							   LPCTSTR sNewAction)
{

	if (sHdrFilePath == NULL)
		return FALSE;
	
	// Open file
	//CComPtr<IDispatch> pOpenDocsIPtr, pTextDocIPtr;
	CComPtr<EnvDTE::Documents>pOpenDocsIPtr;CComPtr<EnvDTE::Document>pTextDocIPtr;
	g_pDTE->get_Documents(&pOpenDocsIPtr);
	if (pOpenDocsIPtr == NULL)
		return FALSE;

	CComQIPtr<EnvDTE::Documents, &EnvDTE::IID_Documents> pOpenDocsQIPtr(pOpenDocsIPtr);
	if (FAILED(pOpenDocsQIPtr->Open(CComBSTR(sHdrFilePath), CComBSTR("Text"), VARIANT_FALSE, &pTextDocIPtr)))
	{
		MessageBox(NULL,_T("Application "+(CString)sAppName+"'s header file failed to open."),NULL, MB_ICONERROR|MB_OK);
		return FALSE;
	}
    // Get Text Selection
	//CComQIPtr<ITextDocument, &IID_ITextDocument> pTextDocQIPtr(pTextDocIPtr);
	CComPtr<IDispatch> pTextSelIPtr;	
	if (FAILED(pTextDocIPtr->get_Selection(&pTextSelIPtr)))//get_Selection(&pTextSelIPtr)))
	{
		return FALSE;   
	}	
	CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextSelQIPtr(pTextSelIPtr);
	//pTextSelQIPtr->SelectAll();
	pTextSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.


	CString sStartFlag = "/*{{SME_BEGIN_EVENT_HANDLER(";
	sStartFlag = sStartFlag + sAppName +")*/";
	CString sEndFlag = "/*}}SME_END_EVENT_HANDLER*/";
	
	VARIANT_BOOL vbFound;
	// Search for the event handler function name
	//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$/////////////////////
	if (FAILED(pTextSelQIPtr->FindText(CComBSTR(sStartFlag),EnvDTE::dsMatchFromStart,  &vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sHdrFilePath+"  error: " + sStartFlag + " expected."), NULL,MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sStartFlag)));
		return FALSE;
	}

	// move the cursor to the end of matching line
    if (FAILED(pTextSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
		return FALSE;

	long nStartLineNo;
	pTextSelQIPtr->get_CurrentLine(&nStartLineNo); 
	
	// Search for StateEnd declaration
	if (FAILED(pTextSelQIPtr->FindText(CComBSTR(sEndFlag), EnvDTE::dsMatchForward,&vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sHdrFilePath+"  error: "+ sEndFlag+" expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sEndFlag)));
		return FALSE;
	}

	// Move the cursor to the end of matching line
    if (FAILED(pTextSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
		return FALSE;
	
	long nEndLineNo;
	pTextSelQIPtr->get_CurrentLine(&nEndLineNo);
	// Record the line number
	long nFuncStartLinePos = 0;
	long nFuncStartColPos = 0;
	long nFuncEndLinePos = 0;
	long nFuncEndColPos = 0;

	BOOL bOldHdlIsFound = FALSE;
	BOOL bNewHdlIsFound = FALSE;
	long nHdrLineNo = nStartLineNo+1;

	CString sLastLine ="";
	// Initialize the line number and column number
	nFuncStartLinePos = nStartLineNo+1;
	nFuncStartColPos = 1;

	while (true)
	{
		if (nHdrLineNo >= nEndLineNo)
			break;
		
		long nHeadSpaceNo = 0;
		if (FAILED(pTextSelQIPtr->MoveTo(nHdrLineNo, 1,VARIANT_BOOL(EnvDTE::dsMove))))// CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsFirstText), CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSelQIPtr->get_CurrentColumn(&nHeadSpaceNo)))
			return FALSE;
		if (FAILED(pTextSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsExtend))))//CComVariant(dsExtend))))
			return FALSE;
		BSTR bstr = NULL;
		//pTextSelQIPtr->SelectLine();
		pTextSelQIPtr->get_Text(&bstr);
		
		char* bstrTemp = _com_util::ConvertBSTRToString(bstr);
		CString sResult(bstrTemp);
		delete[]bstrTemp;
		
		sResult.TrimLeft();

		//int State2Exit(struct SME_APP_T *pApp, struct SME_EVENT_T *pEvent);
		if (!sResult.IsEmpty())
		{
			while (true)
			{
				int idx = sResult.Find(';');
				if (-1 == idx)
				{
					sLastLine += " ";
					sLastLine += sResult;
					break;
				}
				if (bOldHdlIsFound == FALSE)
				{
					if (nFuncEndLinePos == nHdrLineNo)
						nFuncEndColPos = nFuncEndColPos + idx +1; 
					else
					{
						nFuncEndLinePos = nHdrLineNo;
						nFuncEndColPos = nHeadSpaceNo+idx+1;
					}
				}

				sLastLine += " ";
				CString sCurrentLine = sLastLine + sResult.Left(idx+1);
				
				// Initialize for the next loop
				sLastLine = "";
				sResult = sResult.Right(sResult.GetLength()-idx-1);
				
				idx = sCurrentLine.Find('(');
				// idx == -1 ?????????
				CString sFuncName = sCurrentLine.Left(idx);
				sFuncName.TrimRight();
				sFuncName.Replace('\t', ' ');
				idx = sFuncName.ReverseFind(' ');
				sFuncName = sFuncName.Right(sFuncName.GetLength()-idx-1);
				if ((sFuncName == (CString)sOriginAction) && (CString)sOriginAction != "SME_NULL")
				{
					bOldHdlIsFound = TRUE;
				}
				if (sFuncName == (CString)sNewAction)
				{
					bNewHdlIsFound = TRUE;
				}
				if (bOldHdlIsFound == FALSE)
				{
					nFuncStartLinePos = nHdrLineNo;
					nFuncStartColPos = nFuncEndColPos;
				}
			}
		}
		nHdrLineNo++;
	}
	if (bOldHdlIsFound  == FALSE && (CString)sOriginAction != "SME_NULL")
	{
		MessageBox(NULL,_T((CString)sHdrFilePath+"  Error!  int "+sOriginAction+"(struct SME_APP_T *pApp, struct SME_EVENT_T *pEvent); not found."), NULL,MB_ICONERROR|MB_OK);

		OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"  Error!  int "+sOriginAction+"(struct SME_APP_T *pApp, struct SME_EVENT_T *pEvent); not found.")));
	}

	if (bNewHdlIsFound == TRUE)
	{
		MessageBox(NULL,_T("The action "+(CString)sNewAction+"already exists."), NULL,MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T("Error! The action "+(CString)sNewAction+"already exists.")));
	}

		// This action must do before next, because any delete operations will cause line number changes
	if (CString(sNewAction) != "SME_NULL")
	{
		if (FAILED(pTextSelQIPtr->MoveTo(nEndLineNo, 1, VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
			return FALSE;

		//long nFuncLineNo;
		//pTextSelQIPtr->get_CurrentLine(&nFuncLineNo);

		if(FAILED(pTextSelQIPtr->put_Text(CComBSTR("int "+CString(sNewAction)+STR_HDLER_PROTOTYPE+";\n"))))
			return FALSE;

		// Move to the function.
		//if (FAILED(pTextSelQIPtr->MoveTo(nFuncLineNo+3, START_COL_POS, EnvDTE::dsMove)))//CComVariant(dsMove))))
		//	return FALSE;

	}	

	if (bOldHdlIsFound == TRUE)
	{
		if (FAILED(pTextSelQIPtr->MoveTo(nFuncStartLinePos, nFuncStartColPos, VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSelQIPtr->MoveTo(nFuncEndLinePos, nFuncEndColPos,VARIANT_BOOL(EnvDTE::dsExtend))))//CComVariant(dsExtend))))
			return FALSE;
		//pTextSelQIPtr->SelectLine();//%%
		if (FAILED(pTextSelQIPtr->Delete(1)))//CComVariant(1)))) // delete 2 twice ????maybe
			return FALSE;
	}


	return TRUE;
}



///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Modify the declaration of the event handler function in the head file. 
// INPUT: 1) sHFilePath: head file full path name.	
//	      2) sDelAction: the event handler function's name.
// OUTPUT: TRUE: modified successfully. FALSE: Failed to modify.
// NOTE: 
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::DelEventHdlFunc(CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextHdrSelQIPtr, 
							  long nStartLineNo,
							  long nStartColNo,
							  long nEndLineNo,
							  long nEndColNo)
{	
	if (FAILED(pTextHdrSelQIPtr->MoveTo(nStartLineNo, nStartColNo,VARIANT_BOOL(EnvDTE::dsMove)))) //CComVariant(dsMove))))
		return FALSE;
	if (FAILED(pTextHdrSelQIPtr->MoveTo(nEndLineNo, nEndColNo,VARIANT_BOOL(EnvDTE::dsExtend))))// CComVariant(dsExtend))))
		return FALSE;
	//pTextHdrSelQIPtr->SelectLine();//%%
	if (FAILED(pTextHdrSelQIPtr->Delete(1)))//CComVariant(1))))
		return FALSE;
	return TRUE;
}


///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Delete state declaration and handler declaration from the header file.
// INPUT:  1) pTextHdrSelQIPtr: Text selection of application header file.
//         2) DelHandlerList: List of handler name to be deleted.
//         3) DelStateList: List of state name to be deleted.
//         4) sAppName: Application name.
//         5) nStateTreeDecStart: Line number of state start declaration.
//      
//
// OUTPUT: 1) TRUE: 2)FALSE:
// NOTE:
//
//
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::DeleteStateHandlerDec(CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextHdrSelQIPtr,
									vector<CString> &DelHandlerList,
									vector<CString> &DelStateList,
									LPCTSTR sAppName,
							        long nStateTreeDecStart,
									long nAppClassStateLine)
{
	//////////////////////////////////////////////////////////////////////////
	// Delete state declarations 
	vector<CString> DelStateListForAppClass(DelStateList);

	long nHdrLine = nStateTreeDecStart+1;

	VARIANT_BOOL vbFound;
	BOOL bStateDecFound = FALSE;

	//pTextHdrSelQIPtr->SelectAll();
	pTextHdrSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.


	if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(CString("/*{{SME_STATE_DECLARE(")+sAppName+")*/"), EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)
	{
		return FALSE;
	}
	// search for the first /*}}SME_STATE_DECLARE*/ from the position /*{{SME_STATE_DECLARE(sAppName)
	if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(CString("SME_MAX_STATE(")+sAppName+")"), EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		return FALSE;
	}
	if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMove)))
		return FALSE;
	long nHdrEndLineNo;
	pTextHdrSelQIPtr->get_CurrentLine(&nHdrEndLineNo);

	while (true)
	{
		if (nHdrLine >= nHdrEndLineNo)
			break;
		
		if (FAILED(pTextHdrSelQIPtr->MoveTo(nHdrLine, 1, VARIANT_BOOL(EnvDTE::dsMove))))
			return FALSE;
		if (FAILED(pTextHdrSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstColumn,VARIANT_BOOL(EnvDTE::dsMove))))// StartOfLine(EnvDTE::dsFirstColumn, EnvDTE::dsMove)))
			return FALSE;
		if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsExtend))))
			return FALSE;
		BSTR bstr = NULL;
		pTextHdrSelQIPtr->get_Text(&bstr);

		CString sResult = BSTR2CString(bstr);
		sResult.TrimLeft();
		sResult.TrimRight();
		sResult.Replace("\t", NULL);
		sResult.Replace(" ", NULL);

		if (!sResult.IsEmpty() && sResult.Find("SME_STATE_DECLARE")==-1)
			break;
		
		// Traverse the to-be-deleted state name array
		int nSelSeq = 0;
		while (true)
		{
			if (nSelSeq >= (int) DelStateList.size())
				break;
			
			//Format:	SME_STATE_DECLARE(TestApp)
			CString sDelStateDec = "SME_STATE_DECLARE(";
			CString sStateName = DelStateList[nSelSeq];
			sDelStateDec += sStateName;
			sDelStateDec += ")";
			
			if (sResult == sDelStateDec)
			{
				bStateDecFound = TRUE;
				pTextHdrSelQIPtr->Delete(2); //here delete use twice because we are sure it is a line
				DelStateList.erase(DelStateList.begin()+nSelSeq);//RemoveAt(nSelSeq);
				break;
			}
			nSelSeq++;
		}
		if (bStateDecFound == TRUE)
		{
			bStateDecFound = FALSE;
		} else nHdrLine++;
	}

	//////////////////////////////////////////////////////////////////////////
	// Delete app class declarations 
	if (nAppClassStateLine>0)
	{
		long nHdrLine = nAppClassStateLine+1;

		VARIANT_BOOL vbFound;
		BOOL bStateDecFound = FALSE;

		//pTextHdrSelQIPtr->SelectAll();
		pTextHdrSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.

		if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(CString("/*{{SME_APP_CLASS_DECLARE(")+sAppName+","), EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)
		{
			return FALSE;
		}
		// search for the first /*}}SME_APP_CLASS_DECLARE*/ from the position /*{{SME_APP_CLASS_DECLARE(sAppName)
		if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR("/*}}SME_APP_CLASS_DECLARE*/"), EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
		{
			return FALSE;
		}
		if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))
			return FALSE;
		long nHdrEndLineNo;
		pTextHdrSelQIPtr->get_CurrentLine(&nHdrEndLineNo);

		while (true)
		{
			if (nHdrLine >= nHdrEndLineNo)
				break;
			
			if (FAILED(pTextHdrSelQIPtr->MoveTo(nHdrLine, 1, VARIANT_BOOL(EnvDTE::dsMove))))
				return FALSE;
			if (FAILED(pTextHdrSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstColumn,VARIANT_BOOL(EnvDTE::dsMove))))
				return FALSE;
			if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsExtend))))
				return FALSE;
			BSTR bstr = NULL;
			pTextHdrSelQIPtr->get_Text(&bstr);
			CString sResult = BSTR2CString(bstr);
			sResult.TrimLeft();
			sResult.TrimRight();
			sResult.Replace("\t", NULL);
			sResult.Replace(" ", NULL);

			if (!sResult.IsEmpty() && sResult.Find("SME_STATE_EVT_HDL_TBL_DEC")==-1)
				break;
			
			// Traverse the to-be-deleted state name array
			int nSelSeq = 0;
			while (true)
			{
				if (nSelSeq >= (int) DelStateListForAppClass.size())
					break;
				
				//Format:	SME_STATE_DECLARE(TestApp)
				CString sDelStateDec = "SME_STATE_EVT_HDL_TBL_DEC(";
				CString sStateName = DelStateListForAppClass[nSelSeq];
				sDelStateDec += sStateName;
				sDelStateDec += ")";
				
				if (sResult == sDelStateDec)
				{
					bStateDecFound = TRUE;
					pTextHdrSelQIPtr->Delete(2); //here delete use twice because we are sure it is a line
					DelStateListForAppClass.erase(DelStateListForAppClass.begin()+nSelSeq);// RemoveAt(nSelSeq);
					break;
				}
				nSelSeq++;
			}
			if (bStateDecFound == TRUE)
			{
				bStateDecFound = FALSE;
			} else nHdrLine++;
		}
	}

	//////////////////////////////////////////////////////////////////////////
	// Delete event handlers 

	CString sHandlerDecStartFlag = "/*{{SME_BEGIN_EVENT_HANDLER(";
	sHandlerDecStartFlag += sAppName;
	sHandlerDecStartFlag += ")*/";
	CString sHandlerDecEndFlag = "/*}}SME_END_EVENT_HANDLER*/";	
//////////////////////////////////////////////////////////////////////////
	BOOL bDelete = FALSE;

	//pTextHdrSelQIPtr->SelectAll();
	pTextHdrSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.

	while (true)
	{
		if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sHandlerDecStartFlag), EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)// EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)
		{
			//OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sHandlerDecStartFlag)));
			return FALSE;
		}
		if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
			return FALSE;
		// Get start flag line number of handler declaration
		long nHdrHdlStartLine = 0;
		pTextHdrSelQIPtr->get_CurrentLine(&nHdrHdlStartLine);
		if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sHandlerDecEndFlag), EnvDTE::dsMatchForward,&vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
		{
			//OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sHandlerDecEndFlag)));
			return FALSE;
		}
		if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
			return FALSE;
		long nHdrHdlEndLine = 0;
		pTextHdrSelQIPtr->get_CurrentLine(&nHdrHdlEndLine);
		
		// Record the line number
		long nFuncStartLinePos = 0;
		long nFuncStartColPos = 0;
		long nFuncEndLinePos = 0;
		long nFuncEndColPos = 0;
		long nHdrLineNo = nHdrHdlStartLine+1;
		CString sLastLine ="";
		// Initialize the line number and column number
		nFuncStartLinePos = nHdrHdlStartLine+1;
		nFuncStartColPos = 1;
		while (true)
		{
			if (nHdrLineNo >= nHdrHdlEndLine)
				break;
			
			long nHeadSpaceNo = 0;
			if (FAILED(pTextHdrSelQIPtr->MoveTo(nHdrLineNo, 1,VARIANT_BOOL(EnvDTE::dsMove))))// CComVariant(dsMove))))
				return FALSE;
			if (FAILED(pTextHdrSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsFirstText), CComVariant(dsMove))))
				return FALSE;
			if (FAILED(pTextHdrSelQIPtr->get_CurrentColumn(&nHeadSpaceNo)))
				return FALSE;
			if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsExtend))))//CComVariant(dsExtend))))
				return FALSE;
			BSTR bstr = NULL;
			//pTextHdrSelQIPtr->SelectLine();
			pTextHdrSelQIPtr->get_Text(&bstr);
		
			char* bstrTemp = _com_util::ConvertBSTRToString(bstr);
			CString sResult(bstrTemp);
			delete [] bstrTemp;
			
			sResult.TrimLeft();
				//int State2Exit(struct SME_APP_T *pApp, struct SME_EVENT_T *pEvent);
			if (!sResult.IsEmpty())
			{
				while (true)
				{
					int idx = sResult.Find(';');
					if (-1 == idx)
					{
						sLastLine += " ";
						sLastLine += sResult;
						break;
					}
					if (nFuncEndLinePos == nHdrLineNo)
						nFuncEndColPos = nFuncEndColPos + idx +1; 
					else
					{
						nFuncEndLinePos = nHdrLineNo;
						nFuncEndColPos = nHeadSpaceNo+idx+1;
					}
					
					sLastLine += " ";
					CString sCurrentLine = sLastLine + sResult.Left(idx+1);
					
					// Initialize for the next loop
					sLastLine = "";
					sResult = sResult.Right(sResult.GetLength()-idx-1);
					
					idx = sCurrentLine.Find('(');
					// idx == -1 ?????????
					CString sFuncName = sCurrentLine.Left(idx);
					sFuncName.TrimRight();
					sFuncName.Replace('\t', ' ');
					idx = sFuncName.ReverseFind(' ');
					sFuncName = sFuncName.Right(sFuncName.GetLength()-idx-1);
									
					int nSelSeq = 0;
					while (true)
					{
						if (nSelSeq >=(int) DelHandlerList.size())
							break;

						if (!DelHandlerList.at(nSelSeq).Compare(sFuncName))//if (sFuncName == DelHandlerList.GetAt(nSelSeq))
						{
							bDelete = TRUE;
							DelEventHdlFunc(pTextHdrSelQIPtr, nFuncStartLinePos, nFuncStartColPos, nFuncEndLinePos, nFuncEndColPos);
							DelHandlerList.erase(DelHandlerList.begin()+nSelSeq);
							break;
						}
						nSelSeq++;
					}
					nFuncStartLinePos = nHdrLineNo;
					nFuncStartColPos = nFuncEndColPos;
				}
			}
			if (bDelete == TRUE)
			{
				bDelete = FALSE;
				break;
			}
			nHdrLineNo++;
		}
		if (nHdrLineNo >= nHdrHdlEndLine)
			break;
	}

	// Release the selection
	pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMove);

	return TRUE;

}



///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Delete state definition and corresponding state tree declaration
// INPUT:  1) pTextSrcSelQIPtr: Text selection of application source file.
//         2) DelStateList: List of states name to be deleted.
//         3) sAppName: Application name.
//         4) nStateTreeDefStart: Line number of state tree start flag.
//         5) nStateTreeDefEnd: Line number of state tree end flag.
//      
//
// OUTPUT: 1) TRUE: 2)FALSE:
// NOTE: Delete corresponding information in state tree definition.
//		 Delete corresponding state definition. 
//       Users may delete such information by hand, so it will ignore it.
//
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::DeleteStateFromStateTree(CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextSrcSelQIPtr,
							 vector<CString> &DelStateList,
							 LPCTSTR sAppName,
							 long nStateTreeDefStart)
{
	// Copy a temporarily to-be-deleted state name list
	vector<CString> TmpDelStateList;
	TmpDelStateList.clear();
	//vector <int>::iterator Iter;
    //?the second parameter of assign means the first element beyond the range of elements to be copied?
	//TmpDelStateList.assign(DelStateList.begin(),DelStateList.end());
	//TmpDelStateList.push_back(DelStateList.end());

	int NomOfEle=(int)DelStateList.size();
    for(int i=0;i<NomOfEle;i++)
	{
		CString t=DelStateList.at(i);
		TmpDelStateList.push_back(t);

	}
	long nSrcLine = nStateTreeDefStart+1;
	BOOL bStateFound = FALSE;
	VARIANT_BOOL vbFound;

	while (true)
	{
		if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR("/*}}SME_STATE_TREE_DEF*/"),EnvDTE::dsMatchForward,&vbFound)) || !vbFound)// EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
		{
			return FALSE;
		}
		if (FAILED(pTextSrcSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
			return FALSE;
		long nStateTreeDefEnd;
		pTextSrcSelQIPtr->get_CurrentLine(&nStateTreeDefEnd);

		nSrcLine = nStateTreeDefStart+1;

		while (true)
		{
			if (nSrcLine >= nStateTreeDefEnd)
				break;
			
			if (FAILED(pTextSrcSelQIPtr->MoveTo(nSrcLine, 1,VARIANT_BOOL(EnvDTE::dsMove))))// CComVariant(dsMove))))
				return FALSE;
			if (FAILED(pTextSrcSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstColumn,VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsFirstColumn), CComVariant(dsMove))))
				return FALSE;
			if (FAILED(pTextSrcSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsExtend))))//CComVariant(dsExtend))))
				return FALSE;
			BSTR bstr = NULL;
			//pTextSrcSelQIPtr->SelectLine();
			pTextSrcSelQIPtr->get_Text(&bstr);
		
			char* bstrTemp = _com_util::ConvertBSTRToString(bstr);
			CString sResult(bstrTemp);
			delete[] bstrTemp;

			sResult.TrimLeft();
			sResult.TrimRight();
			sResult.Replace("\t", NULL);
			sResult.Replace(" ", NULL);
			if (!sResult.IsEmpty())
			{
				// Traverse the to-be-deleted state name array
				int nDelSeq = 0;
				while (true)
				{
					if (nDelSeq >= (int)TmpDelStateList.size())
						break;
					
					//Format:	SME_STATE(TestApp,s11,State1,s111)
					CString sDelStateDef = "SME_STATE(";
					CString sStateName = TmpDelStateList.at(nDelSeq);
					sDelStateDef += sAppName;
					sDelStateDef += ",";
					sDelStateDef += sStateName;
					sDelStateDef += ",";
					
					if (sResult.Find(sDelStateDef) != -1)
					{
						bStateFound = TRUE;
						//pTextSrcSelQIPtr->SelectLine();//%%
						pTextSrcSelQIPtr->Delete(2);//CComVariant(2)); //here delete use twice because we are sure
						//it is a line
						break;
					}
					nDelSeq++;
				}
				if (bStateFound == TRUE)
				{
					bStateFound = FALSE;
					break;
				}
			}
			nSrcLine++;
		}
		if (nSrcLine >= nStateTreeDefEnd)
			break;
	}
	while (true)
	{
		if ((int)TmpDelStateList.size() == 0)
			break;
	
		// Get to-be-found flag names
		CString sStateName = TmpDelStateList.at(0);
		CString sStateStartFlag = "/*{{SME_STATE_DEF(";
		sStateStartFlag += sAppName;
		sStateStartFlag += ",";
		sStateStartFlag += sStateName;
		sStateStartFlag += ")";
		CString sStateMacroStart = "";
		CString sStateMacroEnd = "";

		sStateMacroEnd = "SME_END_STATE_DEF";
       // VARIANT_BOOL vcFound;
		//pTextSrcSelQIPtr->SelectAll();////$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$4/////////
		pTextSrcSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.

		if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sStateStartFlag),  EnvDTE::dsMatchFromStart, &vbFound))|| !vbFound)//EnvDTE::dsMatchFromStart, &vbFound))|| !vbFound)
		{
			return FALSE;
		}
		if (FAILED(pTextSrcSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
			return FALSE;
		if (vbFound == -1) //%% Only do such operations when state macro definition exists
		{		
			if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sStateMacroEnd),EnvDTE::dsMatchForward,&vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
			{
			//	OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sStateMacroEnd)));
				return FALSE;
			}			
			if (FAILED(pTextSrcSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
				return FALSE;
			long nDelEndLineNo = 0;
			pTextSrcSelQIPtr->get_CurrentLine(&nDelEndLineNo);

			if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR("SME_BEGIN_STATE_DEF"), EnvDTE::dsMatchBackward, &vbFound)) || !vbFound)//CComVariant(dsMatchBackward), &vbFound)) || !vbFound)
			{
				//OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion SME_BEGIN_STATE_DEF")));
				return FALSE;
			}
			if (FAILED(pTextSrcSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
				return FALSE;
			long nDelStartLineNo = 0;
			pTextSrcSelQIPtr->get_CurrentLine(&nDelStartLineNo);

			// Go to the end of state macro definition
			if (FAILED(pTextSrcSelQIPtr->MoveTo(nDelEndLineNo, 1 ,VARIANT_BOOL(EnvDTE::dsMove))))// CComVariant(dsMove))))
				return FALSE;
			// Move to the end of line
			if (FAILED(pTextSrcSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
				return FALSE;
			// Go to the beginning of state macro definition
			if (FAILED(pTextSrcSelQIPtr->MoveTo(nDelStartLineNo, 1,VARIANT_BOOL(EnvDTE::dsExtend))))// CComVariant(dsExtend))))
				return FALSE;

			// Delete lines from (nDelStartLineNo) to nDelEndLineNo
			pTextSrcSelQIPtr->Delete(2);//CComVariant(2));

			long nLineNo = 0;
			pTextSrcSelQIPtr->get_CurrentLine(&nLineNo);
			ClearSpace(pTextSrcSelQIPtr, nLineNo, nLineNo);

		}
		TmpDelStateList.erase(TmpDelStateList.begin());//.RemoveAt(0); //delete current state from list
	}

	return TRUE;

}

/*****************************************************************************************************
// DESCRIPTION: Whether a text line is blank or not. 
// INPUT:  
//		1) pTextSelQIPtr: Text selection denoting which file is to be cleared
//      2) nLineNo: 
//
// OUTPUT: 1)TRUE  2)FALSE
/*****************************************************************************************************/

BOOL DSUtils::IsLineBlank(CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextSelQIPtr, long nLine)
{
	if (FAILED(pTextSelQIPtr->MoveTo(nLine, 1, EnvDTE::dsMove)))
								   return FALSE;
	if (FAILED(pTextSelQIPtr->SelectLine()))
								   return FALSE;
	
	BSTR bstr = NULL;
	pTextSelQIPtr->get_Text(&bstr);
	CString sResult(static_cast<WCHAR*>(bstr));
	TrimSpace(sResult);

	// Release the selection
	pTextSelQIPtr->EndOfLine(EnvDTE::dsMove);

	return (sResult.IsEmpty());

}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Clear white space in files 
// INPUT:  
//		1) pTextSelQIPtr: Text selection denoting which file is to be cleared
//      2)nStartLineNo: Start line number denoting where white space clearing starts
//      3)nEndLineNo: End line number denoting where white space clearing ends
//
// OUTPUT: 1)TRUE  2)FALSE
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::ClearSpace(CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextSelQIPtr,
						 long nStartLineNo,
						 long nEndLineNo)
{
	while (true)
	{
		if (nStartLineNo > nEndLineNo)
			 break;
		
		if (IsLineBlank(pTextSelQIPtr, nStartLineNo))
		{
			if (FAILED(pTextSelQIPtr->MoveTo(nStartLineNo, 1, EnvDTE::dsMove)))
								   return FALSE;
			if (FAILED(pTextSelQIPtr->SelectLine()))
				return FALSE;
			if (FAILED(pTextSelQIPtr->Delete(1))) // Delete only once because SelectLine() selected whole line.
				return FALSE;
			nStartLineNo--;
			nEndLineNo--;
		}
		nStartLineNo++;
	}

	// Release the selection
	pTextSelQIPtr->EndOfLine(EnvDTE::dsMove);

	return FALSE;
}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Delete handler declaration in the application source file.
// INPUT:  1) pTextSrcSelQIPtr: Text selection of application source file. 
//         2) nDelLineNo: Line number of deleted event handler.
//
// OUTPUT: 1) TRUE: 2) FALSE:
// NOTE: 
//   
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::DelHdlerDec(CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextSrcSelQIPtr,long nDelLineNo)
{
	// Move to the finded line
	if (FAILED(pTextSrcSelQIPtr->MoveTo(nDelLineNo, 1,EnvDTE::dsMove)))// CComVariant(dsMove))))
		return FALSE;
	if (FAILED(pTextSrcSelQIPtr->MoveTo(nDelLineNo+1,1,EnvDTE::dsExtend)))//EndOfLine(EnvDTE::dsExtend)))//CComVariant(dsExtend))))
		return FALSE;
	
	// delete the finded line
	//if (FAILED(pTextSrcSelQIPtr->put_Text(CComBSTR(""))))
 //       return FALSE;
	//if (FAILED(pTextSrcSelQIPtr->Backspace(1)))
 //       return FALSE;
	if(FAILED(pTextSrcSelQIPtr->Delete(1)))
		return FALSE;
	return TRUE;

}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Check atomic attribute of doing deleting state operations. 
// INPUT:  1) DelStateList: List of total to-be-deleted state name.
//         2) DelHanderList: List of total to-be-deleted handler name(without parameters).
//         3) sHdrFilePath: Full path of application header file.
//         4) sSrcFilePath: Full path of application source file.
//         5) sAppName: Application name.
//         6) sParentName: To-be-deleted state's parent name.
//
// OUTPUT: 1) TRUE: 2)FALSE:
// NOTE: Check deleted state's parent state definition in state tree.
//       Check deleted state definition macro start and end flag
//       Check deleted handler declaration start and end flag 
//       Check deleted state declaration macro start and end flag.
//       Not Check deleted state's macro in state tree definition.
//       Not Check deleted state's internal handlers plus entry, exit handlers' completeness.
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::CheckDelStateAtomic(vector<CString> &DelStateList,
								  vector<CString> &DelHanderList,
								  LPCTSTR sHdrFilePath,
								  LPCTSTR sSrcFilePath,
								  LPCTSTR sAppName,
								  LPCTSTR sParentName)
{
	// Copy a temporarily to-be-deleted state name list
	vector<CString> TmpDelStateList;
	TmpDelStateList.clear();
	//vector <int>::iterator Iter;
    //?the second parameter of assign means the first element beyond the range of elements to be copied?
	//TmpDelStateList.assign(DelStateList.begin(),DelStateList.end());
	//TmpDelStateList.push_back(DelStateList.end());
	int NomOfEle=(int)DelStateList.size();
    for(int i=0;i<NomOfEle;i++)
	{
		CString t=DelStateList.at(i);
		TmpDelStateList.push_back(t);

	}

	/////////////////// Open source file
	CComPtr<EnvDTE::Documents> pOpenDocsIPtr;
	CComPtr<EnvDTE::Document>pTextSrcDocIPtr;
	g_pDTE->get_Documents(&pOpenDocsIPtr);
	if (pOpenDocsIPtr == NULL)
		return FALSE;
	CComQIPtr<EnvDTE::Documents, &EnvDTE::IID_Documents> pOpenDocsQIPtr(pOpenDocsIPtr);
	if (FAILED(pOpenDocsQIPtr->Open(CComBSTR(sSrcFilePath), CComBSTR("Text"), VARIANT_FALSE, &pTextSrcDocIPtr)))
	{
		MessageBox(NULL,_T("Application "+(CString)sAppName+"'s source file failed to open."),NULL, MB_ICONERROR|MB_OK);
		return FALSE;
	}

	/////////////////// Get Source File Text Selection
	//CComQIPtr<ITextDocument, &IID_ITextDocument> pTextSrcDocQIPtr(pTextSrcDocIPtr);
	CComPtr<IDispatch> pTextSrcSelIPtr;
	if (FAILED(pTextSrcDocIPtr->get_Selection(&pTextSrcSelIPtr)))
	{
		return FALSE;   
	}	
	CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextSrcSelQIPtr(pTextSrcSelIPtr);

	// Open header file
	CComPtr<EnvDTE::Document> pTextHdrDocIPtr;
	
	if (FAILED(pOpenDocsQIPtr->Open(CComBSTR(sHdrFilePath), CComBSTR("Text"), VARIANT_FALSE, &pTextHdrDocIPtr)))
	{
		MessageBox(NULL,_T("Application "+(CString)sAppName+"'s header file failed to open."),NULL, MB_ICONERROR|MB_OK);
		return FALSE;
	}

	// Get Header Text Selection
	//CComQIPtr<ITextDocument, &IID_ITextDocument> pTextHdrDocQIPtr(pTextHdrDocIPtr);

	CComPtr<IDispatch> pTextHdrSelIPtr;
	if (FAILED(pTextHdrDocIPtr->get_Selection(&pTextHdrSelIPtr)))
	{
		return FALSE;   
	}	
	CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextHdrSelQIPtr(pTextHdrSelIPtr);
	//////////////////////////////////////////////////////////////////////////
	//Format 	
	/*{{SME_STATE_DECLARE(TestApp)*/
	/*}}SME_STATE_DECLARE*/
	/*{{SME_STATE_TREE_DEF(TestApp)*/
	/*}}SME_STATE_TREE_DEF*/
	/*{{SME_STATE_DEF(TestApp,State)*/
	/*}}SME_STATE_DEF*/
	/*{{SME_BEGIN_EVENT_HANDLER(TestApp)*/
	/*}}SME_END_EVENT_HANDLER*/
	//	SME_STATE(TestApp,s11,State1,s111)
	// SME_BEGIN_STATE_DEF(TestApp,State3)
	// SME_END_STATE_DEF
	CString sStateTreeStartFlag;
	CString sStateTreeEndFlag;
	CString sParentFlag; //need check parent state definition in case that default state changes
	
	sStateTreeStartFlag = "/*{{SME_STATE_TREE_DEF(";
	sStateTreeStartFlag += sAppName;
	sStateTreeStartFlag += ")*/";
	sStateTreeEndFlag = "/*}}SME_STATE_TREE_DEF*/";
	sParentFlag = "SME_STATE(";
	sParentFlag += sAppName;
	sParentFlag += ",";
	sParentFlag += sParentName;
	sParentFlag += ",";

	VARIANT_BOOL vbFound;
	// Find the state definition head
	//pTextSrcSelQIPtr->SelectAll();//////////$$$$$$$$$$$$$$$////////////
	pTextSrcSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.

	if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sStateTreeStartFlag),EnvDTE::dsMatchFromStart,&vbFound)) || !vbFound)// EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error: "+sStateTreeStartFlag+" expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sStateTreeStartFlag)));
		return FALSE;
	}
	// Move to the end of line to do the next fine operation
	// or it will fail in continuous find operations
	if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;
	long nSrcStateTreeStart = 0;
	pTextSrcSelQIPtr->get_CurrentLine(&nSrcStateTreeStart);

	if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sStateTreeEndFlag), EnvDTE::dsMatchForward, &vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error: "+ sStateTreeEndFlag + " expected."), NULL,MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sStateTreeEndFlag)));
		return FALSE;
	}

	if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;
	long nSrcStateTreeEnd = 0;
	pTextSrcSelQIPtr->get_CurrentLine(&nSrcStateTreeEnd);

	long nSrcStateTreeLine = nSrcStateTreeStart+1;
	while (true)
	{
		if (nSrcStateTreeLine >= nSrcStateTreeEnd)
			break;

		if (FAILED(pTextSrcSelQIPtr->MoveTo(nSrcStateTreeLine,1, EnvDTE::dsMove)))//CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSrcSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,EnvDTE::dsMove)))//CComVariant(dsFirstText), CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsExtend)))//CComVariant(dsExtend))))
			return FALSE;
		// Get selection line
		BSTR bstr = NULL;
		//pTextSrcSelQIPtr->SelectLine();
		pTextSrcSelQIPtr->get_Text(&bstr);
		
		char* bstrTemp = _com_util::ConvertBSTRToString(bstr);
		CString sResult(bstr);
		delete[]bstrTemp;
		
		sResult.TrimLeft();
		sResult.TrimRight();
		sResult.Replace("\t", NULL);
		sResult.Replace(" ", NULL);
			// Check syntax of parent state in state tree in case that deletion of state will 
		// effect its parent state
		if (sResult.Find(sParentFlag) == 0)
		{
			// 	SME_STATE(TestApp,State2,0,s21)
			sResult.Replace(sParentFlag, NULL);
			int idx = sResult.Find(')');
			if (idx == sResult.GetLength() -1 )
			{
				sResult.Replace(")", NULL);
				idx = sResult.Find(',');
				if (idx != -1)
				{
					sResult.Replace(",", NULL);
					idx = sResult.Find(' ');
					if (idx == -1)
						break;
				}
			}
		}
		nSrcStateTreeLine++;
	}
	if (nSrcStateTreeLine >= nSrcStateTreeEnd)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error: " + sParentFlag + " expected."), NULL,MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sParentFlag)));
		return FALSE;
	}

	// Check deleted state definition syntax if they exist
	while (true)
	{
		if (0 == (int)TmpDelStateList.size())
			break;

		//	SME_STATE(TestApp,s11,State1,s111)
		// SME_BEGIN_STATE_DEF(TestApp,State3)
		// SME_END_STATE_DEF

		// Get to-be-found flag names
		CString sStateName = TmpDelStateList.at(0);
		CString sStateStartFlag = "/*{{SME_STATE_DEF(";
		sStateStartFlag += sAppName;
		sStateStartFlag += ",";
		sStateStartFlag += sStateName;
		sStateStartFlag += ")";
		CString sStateEndFlag = "/*}}SME_STATE_DEF*/";
		CString sStateMacroStart = "";
		CString sStateMacroEnd = "";

		sStateMacroStart = "SME_BEGIN_STATE_DEF(";
		sStateMacroStart += sAppName;
		sStateMacroStart += ",";
		sStateMacroStart += sStateName;
		sStateMacroStart += ")";
		sStateMacroEnd = "SME_END_STATE_DEF";

		//pTextSrcSelQIPtr->SelectAll();//////$$$$$$$$$$$$$$$$$$$$//////////////
		pTextSrcSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.

		if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sStateStartFlag), EnvDTE::dsMatchFromStart,&vbFound)) || !vbFound)//EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)
		{
			OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		Warning: macro expansion " + sStateStartFlag+" not found")));
		}
		// Move to the end of line to do the next fine operation
		// or it will fail in continuous find operations
		if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
			return FALSE;

		// Check if users has deleted them already , there is no need to delete at all
		if (vbFound == -1)//%%
		{
			if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sStateEndFlag), EnvDTE::dsMatchForward, &vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
			{
				MessageBox(NULL,_T((CString)sSrcFilePath+"  error: "+sStateEndFlag+" expected."),NULL, MB_ICONERROR|MB_OK);
				OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sStateEndFlag)));
				return FALSE;
			}			
			// Move to the end of line to do the next fine operation
			// or it will fail in continuous find operations
			if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
				return FALSE;

			if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sStateMacroEnd),EnvDTE::dsMatchForward,&vbFound)) || !vbFound)// EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
			{
				MessageBox(NULL,_T((CString)sSrcFilePath+"  error: " + sStateMacroEnd + " expected."),NULL, MB_ICONERROR|MB_OK);
				OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sStateMacroEnd)));
				return FALSE;
			}
			
			if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
				return FALSE;
			
			if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR("SME_BEGIN_STATE_DEF"), EnvDTE::dsMatchBackward, &vbFound)) || !vbFound)//CComVariant(dsMatchBackward), &vbFound)) || !vbFound)
			{
				MessageBox(NULL,_T((CString)sSrcFilePath+"  error: SME_BEGIN_STATE_DEF expected."),NULL, MB_ICONERROR|MB_OK);
				OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion SME_BEGIN_STATE_DEF")));
				return FALSE;
			}
			
			if (FAILED(pTextSrcSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,EnvDTE::dsMove)))//CComVariant(dsFirstText), CComVariant(dsMove))))
				return FALSE;
			if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsExtend)))//CComVariant(dsExtend))))
				return FALSE;
			// Get selection line
			BSTR bstr = NULL;
			//pTextSrcSelQIPtr->SelectLine();
			pTextSrcSelQIPtr->get_Text(&bstr);
			
			char* bstrTemp = _com_util::ConvertBSTRToString(bstr);
			CString sResult(bstr);
			delete[] bstrTemp;
	
			sResult.TrimLeft();
			sResult.TrimRight();
			sResult.Replace("\t", NULL);
			sResult.Replace(" ", NULL);
			// Match the wanted line to the beginning macro definition 
			if (sResult != sStateMacroStart)
			{
				MessageBox(NULL,_T((CString)sSrcFilePath+"  error: "+sStateMacroStart+" expected."),NULL, MB_ICONERROR|MB_OK);
				OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion "+sStateMacroStart)));
				return FALSE;
			}

		}
		TmpDelStateList.erase(TmpDelStateList.begin());
	}

	CString sStateDecStartFlag = "/*{{SME_STATE_DECLARE(";
	sStateDecStartFlag += sAppName;
	sStateDecStartFlag += ")*/";
	CString sStateDecEndFlag = CString("SME_MAX_STATE(") + sAppName + ")"; //"/*}}SME_STATE_DECLARE*/";
	CString sHandlerDecStartFlag = "/*{{SME_BEGIN_EVENT_HANDLER(";
	sHandlerDecStartFlag += sAppName;
	sHandlerDecStartFlag += ")*/";
	CString sHandlerDecEndFlag = "/*}}SME_END_EVENT_HANDLER*/";
	CString sAppClassDecStartFlag=CString("/*{{SME_APP_CLASS_DECLARE(")+sAppName+",";
	// Note: we can not located "/*}}SME_APP_CLASS_DECLARE*/" as the end of app class declaration, because if there are more than 1
	// app header is located at a same file
	CString sAppClassDecEndFlag=CString("SME_STATE_TREE_DEC(")+sAppName+")";
	// CString sAppClassDecEndFlag="/*}}SME_APP_CLASS_DECLARE*/";
	

	///////////////////////////////////////////////////////////
	// Search for the state declaration header.

	//pTextHdrSelQIPtr->SelectAll();
	pTextHdrSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.

	if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sStateDecStartFlag),EnvDTE::dsMatchFromStart , &vbFound)) || !vbFound)//EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sHdrFilePath+"  error: " + sStateDecStartFlag + " expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sStateDecStartFlag)));
		return FALSE;
	}
	if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;
	// Get Start Line No
	long nHdrStartLineNo = 0;
	pTextHdrSelQIPtr->get_CurrentLine(&nHdrStartLineNo);

	if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sStateDecEndFlag),EnvDTE::dsMatchForward , &vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sHdrFilePath+"  error: "+sStateDecEndFlag+" expected."), NULL,MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sStateDecEndFlag)));
		return FALSE;
	}
	if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;
//	long nHdrEndLineNo = 0;
//	pTextHdrSelQIPtr->get_CurrentLine(&nHdrEndLineNo);

	///////////////////////////////////////////////////////////
	// Search for the app class declaration header.
	//pTextHdrSelQIPtr->SelectAll();
	pTextHdrSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.

	long nAppClassStateLine=-1;
	if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sAppClassDecStartFlag), EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)
	{
	} else
	{
		if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove)))) //CComVariant(dsMove)
			return FALSE;
		pTextHdrSelQIPtr->get_CurrentLine(&nAppClassStateLine);

		if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sAppClassDecEndFlag), EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
		{
			AfxMessageBox(_T((CString)sHdrFilePath+"  error: "+sAppClassDecEndFlag+" expected."), MB_ICONERROR|MB_OK);
			return FALSE;
		}
	}


	///////////////////////////////////////////////////////////
	// Search for the event handler header.
	//pTextHdrSelQIPtr->SelectAll();
	pTextHdrSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.

	if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sHandlerDecStartFlag),EnvDTE::dsMatchFromStart , &vbFound)) || !vbFound)//EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sHdrFilePath+"  error: "+sHandlerDecStartFlag+" expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sHandlerDecStartFlag)));
		return FALSE;
	}
	if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;
	
	if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sHandlerDecEndFlag),EnvDTE::dsMatchForward , &vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sHdrFilePath+"  error: "+sHandlerDecEndFlag+" expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sHandlerDecEndFlag)));
		return FALSE;
	}
	if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;


	DeleteStateFromStateTree(pTextSrcSelQIPtr, DelStateList, sAppName, nSrcStateTreeStart);
	DeleteStateHandlerDec(pTextHdrSelQIPtr, DelHanderList, DelStateList, sAppName, nHdrStartLineNo, nAppClassStateLine);
	return TRUE;
}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Add state tree declaration to application source file.
// INPUT:  1) pTextSelQIPtr: Text selection of application source file
//         2) sStatename: State name. 
//         3) sParent: Current state's parent's name.
//		   4) sAppName: Application name. 
//         5) sDefChild: Default child state name.
//		   6) nSkippedLinNumFromApp: Number of states above the state to be inserted.
//         7) nParStateTreeDecLineNo: Line number of inserted state's parent state tree declaration
//         8) nAppStateTreeDecLineNo: Line number of inserted state's application declation in
//                                    state tree.
// 
// OUTPUT: 1) TRUE: 2)FALSE
// NOTE: Do this operation after checking atomic attribute operations
//
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::DeclareStateTree(CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextSrcSelQIPtr, 
							   LPCTSTR sStatename, 
							   LPCSTR sParent, 
							   LPCTSTR sAppname,
							   LPCTSTR sDefChild, 
							   UINT nSkippedLinNumFromApp,
							   long nParStateTreeDecLineNo,
							   long nAppStateTreeDecLineNo)
{
	CString strStateName=CString(sStatename);
	CString strParent=CString(sParent);
	CString strAppName=CString(sAppname);
	CString strDefChild=CString(sDefChild);
	CString strParetname;
	CString sStateTreeDef = "SME_STATE";
	CString sStateTreeFind = sStateTreeDef+"("+strAppName+","+strAppName;
    CString sStateParentFind=sStateTreeDef+"("+strAppName+","+strParent;

	if (!strDefChild.IsEmpty())
	{
		if (FAILED(pTextSrcSelQIPtr->MoveTo(nParStateTreeDecLineNo, 1, EnvDTE::dsMove)))//CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSrcSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,EnvDTE::dsMove)))//CComVariant(dsFirstText), CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsExtend)))//CComVariant(dsExtend))))
			return FALSE;

		BSTR bstr = NULL;		
		pTextSrcSelQIPtr->get_Text(&bstr);
		CString sResult(bstr);
		sResult.TrimLeft();
		sResult.TrimRight();
		sResult.Replace("\t", NULL);
		sResult.Replace(" ", NULL);
		sResult.Replace("-1",LPCTSTR(strDefChild));

		if (FAILED(pTextSrcSelQIPtr->put_Text(CComBSTR(sResult))))
			return FALSE;
	}

	UINT nItemNum = 0;
	long nInsertLineNo = nAppStateTreeDecLineNo;
	while (true)
	{
		if (nItemNum >= nSkippedLinNumFromApp)
			break;
		
		if (FAILED(pTextSrcSelQIPtr->MoveTo(nInsertLineNo, 1,EnvDTE::dsMove)))// CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSrcSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,EnvDTE::dsMove)))//CComVariant(dsFirstText), CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsExtend)))//CComVariant(dsExtend))))
			return FALSE;
		BSTR bstr = NULL;
		//pTextSrcSelQIPtr->SelectLine();
		pTextSrcSelQIPtr->get_Text(&bstr);
		CString sResult(bstr);
		sResult.TrimLeft();
		sResult.TrimRight();
		sResult.Replace("\t", NULL);
		sResult.Replace(" ", NULL);
		
		if (!sResult.IsEmpty())
		{
			nItemNum++;
		}
		nInsertLineNo++;
	}

	// Move the cursor to the end of matching line
	if (FAILED(pTextSrcSelQIPtr->MoveTo(nInsertLineNo, 1,EnvDTE::dsMove)))// CComVariant(dsMove))))
		return FALSE;

	if (FAILED(pTextSrcSelQIPtr->Indent(1)))//EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;

	// Set the parent name
	if (!strAppName.Compare(LPCTSTR(strParent)))
	{
		strParetname="0";
	}
	else
		strParetname=strParent;

	// Put a item of the state to the state tree definition
	if (FAILED(pTextSrcSelQIPtr->put_Text(CComBSTR(sStateTreeDef+"("+strAppName+","+strStateName+","+strParetname+","+"-1"+")"))))
		return FALSE; 

	if (FAILED(pTextSrcSelQIPtr->NewLine(1)))//EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;

	return TRUE;
}


///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Declare new state and add declaration to the application header files 
// INPUT:  1) pTextHdrSelQIPtr: Text selection of application header file
//         2) sStatename: State name.
//		   3) sEntryFuncName: Entry function name.
//         4) sExitFuncName: Exit function name.
//		   5) nSkippedLinNumFromApp: Number of states above the state to be inserted. 
//         6) nStateDecInsertLine: Line number of state declaration insert point 
//         *) nAppClassInsertLine: SME_STATE_EVT_HDL_TBL_DEC() insert point
//         *) nHdrHdlDecLine: Line number of handler declaration start flag
//  
// OUTPUT: 1) TRUE: Add declaration successfully. 2) FALST:
// NOTE: Do this operation after checking atomic attribute of adding state operations 
//
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::DeclareNewState(CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextHdrSelQIPtr,
							  LPCSTR sStatename, 
							  LPCTSTR sEntryFuncName, 
							  LPCTSTR sExitFuncName,
							  UINT nSkippedLinNumFromApp,
							  long nStateDecInsertLine,
							  long nAppClassInsertLine,
							  long nHdrHdlDecLine)
{	
	CString strEntryFunc = "";
	CString strExitFunc = "";

	// Adjust insert point line for 3 new insert lines because operation above has added some additional new lines to the original text
	int nFuncNum=0;
	if (strEntryFunc != "")
		nFuncNum++;
	if (strExitFunc != "")
		nFuncNum++;

	int nOffsetStateDec = ((nStateDecInsertLine>nAppClassInsertLine && nAppClassInsertLine>0) ?1:0) + (nStateDecInsertLine>nHdrHdlDecLine?nFuncNum:0);
	int nOffsetAppClassDec = (nAppClassInsertLine>nStateDecInsertLine?1:0) + (nAppClassInsertLine>nHdrHdlDecLine?nFuncNum:0);
	int nOffsetHdlDec = (nHdrHdlDecLine>nStateDecInsertLine?1:0) + ((nHdrHdlDecLine>nAppClassInsertLine && nAppClassInsertLine>0)?1:0);
	nStateDecInsertLine+=nOffsetStateDec;
	nAppClassInsertLine+=nOffsetAppClassDec;
	nHdrHdlDecLine+=nOffsetHdlDec;
	
	if (strcmp(sEntryFuncName, "SME_NULL") != 0)
		strEntryFunc="int "+CString(sEntryFuncName)+ STR_HDLER_PROTOTYPE + ";\n";
	if (strcmp(sExitFuncName, "SME_NULL") != 0)
		strExitFunc="int "+CString(sExitFuncName)+ STR_HDLER_PROTOTYPE + ";\n";

	// Insert SME_STATE_DECLARE([state])
	if (FAILED(pTextHdrSelQIPtr->MoveTo(nStateDecInsertLine, 1, VARIANT_BOOL(EnvDTE::dsMove))))
		return FALSE;
	// make the tab line 
	if (FAILED(pTextHdrSelQIPtr->Indent(1))) 
		return FALSE;
	
	if (FAILED(pTextHdrSelQIPtr->put_Text(CComBSTR(CString("SME_STATE_DECLARE(")+sStatename+")"))))
		return FALSE;
	
	if (FAILED(pTextHdrSelQIPtr->NewLine(1)))
		return FALSE;

    if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))
		return FALSE;

	// Insert SME_STATE_EVT_HDL_TBL_DEC([state])
	if (nAppClassInsertLine>0)
	{
		if (FAILED(pTextHdrSelQIPtr->MoveTo(nAppClassInsertLine, 1, VARIANT_BOOL(EnvDTE::dsMove))))
			return FALSE;
		// make the tab line 
		if (FAILED(pTextHdrSelQIPtr->Indent(1))) 
			return FALSE;
		
		if (FAILED(pTextHdrSelQIPtr->put_Text(CComBSTR(CString("SME_STATE_EVT_HDL_TBL_DEC(")+sStatename+")"))))
			return FALSE;
		
		if (FAILED(pTextHdrSelQIPtr->NewLine(1)))
			return FALSE;

		if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMatchForward)))
			return FALSE;
	};
	

	if (strEntryFunc != "" || (strExitFunc != ""))
	if (FAILED(pTextHdrSelQIPtr->MoveTo(nHdrHdlDecLine,1,EnvDTE::dsMatchForward)))
		return FALSE;

	if (strEntryFunc != "")
	{
		// Put the declaration of the entry function
		if (FAILED(pTextHdrSelQIPtr->put_Text(CComBSTR(strEntryFunc))))
			return FALSE;
	}

	if (strExitFunc != "")
	{
		// Put the declaration of the exit function
		if (FAILED(pTextHdrSelQIPtr->put_Text(CComBSTR(strExitFunc))))
			return FALSE;		
	}
	return TRUE;
}


///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Declare event handler to application header file.
// INPUT:  1) pTextHdrSelQIPtr: Text selection of application header file
//         2) sAppName: Application name.
//		   3) sHandlerName: Event handler name(without parameters).
//         4) nHdlDecLineNo: Event handler declaration start flag.
// OUTPUT: 1) TRUE: 2)FALSE
// NOTE: 
//
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::DeclareEventHandler(CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextHdrSelQIPtr,
								  LPCTSTR sAppname,
								  LPCTSTR sFuncClassPrefix,
								  LPCTSTR sHandlerName,
								  long nHdlDecLineNo)
{
		// Move the curse to the finded number
		// No function class prefix in header file.
		if (FAILED(pTextHdrSelQIPtr->MoveTo(nHdlDecLineNo, 1, EnvDTE::dsMove)))//CComVariant(dsMove))))
			return FALSE;
		if(FAILED(pTextHdrSelQIPtr->put_Text(CComBSTR("int "+CString(sHandlerName)+STR_HDLER_PROTOTYPE + ";\n"))))
			return FALSE;
		return TRUE;
}


///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Add state definition to application source
//              file.
// INPUT:  1) pTextSrcSelQIPtr: Text selection of application source file.
//         2) sStateName: State name. 
//         3) sAppName: Application name. 
//		   4) sEntryFuncName: Entry function name. 
//         5) sExitFuncName: Exit function name.
//            sAppClassPrefix: App class with :: if app is a class. 
// OUTPUT: 1) TRUE: 2)FALSE
// NOTE: Do this operation after checking atomic attribute of adding a new state operations
//
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::CreateStateDef(CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextSrcSelQIPtr, 
							 LPCTSTR sStateName, 
							 LPCTSTR sAppName, 
							 LPCTSTR sFuncClassPrefix,
							 LPCTSTR sEntryFuncName, 
							 LPCTSTR sExitFuncName)
{
	CString sText;
	CString sSeparator="/*{{SME_STATE_STATETREE_SEPARATOR}}*/";

	//sText =CComBSTR("\nSME_BEGIN_STATE_DEF("+CString(sAppName)+","+CString(sStateName)+")\n\t/*{{SME_STATE_DEF("+sAppName+","+sStateName+
	//	")*/\n\tSME_STATE_ENTRY_FUNC("+sEntryFuncName+")\n\tSME_STATE_EXIT_FUNC("+sExitFuncName+
	//	")\n\t/*}}SME_STATE_DEF*/\nSME_END_STATE_DEF\n");
	sText = "\nSME_BEGIN_STATE_DEF("+CString(sAppName)+","+CString(sStateName)+")\n\t/*{{SME_STATE_DEF("+sAppName+","+sStateName+
	")*/\nSME_STATE_ENTRY_FUNC("+sEntryFuncName+")\nSME_STATE_EXIT_FUNC("+sExitFuncName+
	")\n/*}}SME_STATE_DEF*/\n";
	CString sTextEnd="SME_END_STATE_DEF\n";

	CString strEntryFunc = "";
	CString strExitFunc = "";

	VARIANT_BOOL vbFound;
	if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sSeparator),EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)
	{
		return FALSE;
	}
	if (FAILED(pTextSrcSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
		return FALSE;

	long nStateTreeSepNo = 0;
	pTextSrcSelQIPtr->get_CurrentLine(&nStateTreeSepNo);
	if (strcmp(sEntryFuncName, "SME_NULL") != 0)
		strEntryFunc=CString("\nint ") + sFuncClassPrefix + CString(sEntryFuncName) + STR_HDLER_PROTOTYPE + "\n{\n\treturn 0;\n}\n\n";
	if (strcmp(sExitFuncName, "SME_NULL") != 0)
		strExitFunc=CString("\nint ") + sFuncClassPrefix + CString(sExitFuncName)+ STR_HDLER_PROTOTYPE + "\n{\n\treturn 0;\n}\n\n";
	CString strEntryExit=strEntryFunc+strExitFunc;

	if (IsLineBlank(pTextSrcSelQIPtr, nStateTreeSepNo-1))
	{
		if (FAILED(pTextSrcSelQIPtr->MoveTo(nStateTreeSepNo-1, 1, EnvDTE::dsMove)))
			return FALSE;
	} else
		if (FAILED(pTextSrcSelQIPtr->MoveTo(nStateTreeSepNo, 1, EnvDTE::dsMove)))
			return FALSE;

	// Put a state definition
	if (FAILED(pTextSrcSelQIPtr->put_Text(CComBSTR(sText))))
		return FALSE;

	if(FAILED(pTextSrcSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstColumn,EnvDTE::dsMove)))
		return FALSE;

	if (FAILED(pTextSrcSelQIPtr->put_Text(CComBSTR(sTextEnd))))
		return FALSE;

	if (FAILED(pTextSrcSelQIPtr->EndOfDocument(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;

	long nEntryOrExitLineNo;
	pTextSrcSelQIPtr->get_CurrentLine(&nEntryOrExitLineNo);
	// Put the entry function and the exit function declaration of the state
	if (strEntryExit != "")
	{
		if (FAILED(pTextSrcSelQIPtr->put_Text(CComBSTR(strEntryExit))))
			return FALSE;
	}

	// Move to the entry function.
	if (FAILED(pTextSrcSelQIPtr->MoveTo(nEntryOrExitLineNo+3, START_COL_POS, EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;

	return TRUE;

}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Create service file for storing event id list if necessary
// INPUT:  
// OUTPUT: 1)TRUE 2)FALSE
// NOTE:  
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::CreateServiceFile(LPCTSTR sFilePath)
{

	CString sFileName = sFilePath;
	int idx = sFileName.ReverseFind('\\');
	sFileName = sFileName.Right(sFileName.GetLength()-idx-1);
	CString sPreProcFileName = sFileName;
	sPreProcFileName.Replace('.', '_');
	sPreProcFileName.MakeUpper();

	CStdioFile ServiceFile; // .c file to be created
	
	// Create the head file 
	if(! ServiceFile.Open(LPCTSTR(sFilePath),CFile::modeCreate|CFile::modeReadWrite|CFile::typeText))
	{
#ifdef _DEBUG
		afxDump<<"Service file could not be opened"<<"\n";
#endif
		return FALSE;//exit(1);
	}

	char *sNote = "NOTE: The StateWizard will add mapping macros between /*{{ and /*}}. Do NOT modify manually.";

	CString sHeaderFormat = "/*\nFILE:";
	sHeaderFormat += sFileName;
	sHeaderFormat += "\n%s\n*/\n\n#ifndef ";
	sHeaderFormat += sPreProcFileName;
	sHeaderFormat += "\n#define ";
	sHeaderFormat += sPreProcFileName;
	sHeaderFormat += "\n\n#include \"sme.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
	CString sHeader; 
	sHeader.Format(sHeaderFormat, sNote);
	
	CString sServiceDeclare;
	sServiceDeclare = "enum\n{\n\t/*{{SME_EVENT_ID_LIST_DECLARE*/\n";
	CString sEnd = "\t/*}}SME_EVENT_ID_LIST_DECLARE*/\n};\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n";
	sServiceDeclare += sEnd;

	ServiceFile.WriteString(LPCTSTR(sHeader));
	ServiceFile.WriteString(LPCTSTR(sServiceDeclare));
	ServiceFile.Close();
	return TRUE;
}


///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Add handler implementation and macro definition to application source file.
// INPUT:  1) pTextSrcSelQIPtr: Text selection of application source file.
//         2) sAppName: Application name.
//         3) sSrcState: Current state name.
//         4) sDestState: Transition state name.
//         5) sEventID: Event name.
//         6) sHandlerName: Event handler name.
//         7) nStateDefEndFlag: Line number of state definition macro start flag which owns 
//                              current event handler.
//
// OUTPUT: 1)TRUE 2)FALSE
// NOTE:
//
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::CreateHandlerDef(CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextSrcSelQIPtr,
							   LPCTSTR sAppname,
							   LPCTSTR sFuncClassPrefix,
							   LPCTSTR sSrcState, 
							   LPCTSTR sDestState,
							   LPCTSTR sEventID, 
							   LPCTSTR sHandlerName,
							   long nStateDefEndFlag)
{
	CString sEventDef = "SME_ON_EVENT";

	if (FAILED(pTextSrcSelQIPtr->MoveTo(nStateDefEndFlag, 1,EnvDTE::dsMove)))// CComVariant(dsMove))))
		return FALSE;
	if (FAILED(pTextSrcSelQIPtr->Indent(1)))//EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;

	//if(sDestState==NULL)
	if ( CComBSTR(sDestState) == "")	
		sDestState = "SME_INTERNAL_TRAN";
	
	// Add the event handler definition to a state declaration
	if (FAILED(pTextSrcSelQIPtr->put_Text(CComBSTR(sEventDef+"("+sEventID+","+sHandlerName+
		","+sDestState+")"))))
		return FALSE;
	if (FAILED(pTextSrcSelQIPtr->NewLine(1)))//EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;


	// Add a handler function implementation to source file
	// If handler has been used by some other events ,it will not
	// redefine the handler function 
	if (strcmp(sHandlerName, "SME_NULL") != 0)
	{
		if(FAILED(pTextSrcSelQIPtr->EndOfDocument(EnvDTE::dsMove)))//CComVariant(dsMove))))
			return FALSE;

		long nFuncLineNo;
		pTextSrcSelQIPtr->get_CurrentLine(&nFuncLineNo);
		if(FAILED(pTextSrcSelQIPtr->put_Text(CComBSTR(CString("\nint ")+ sFuncClassPrefix + CString(sHandlerName)+"(struct SME_APP_T *pApp, struct SME_EVENT_T *pEvent)\n{\nreturn 0;\n}\n\n"))))
			return FALSE;

		// Move to the function.
		if (FAILED(pTextSrcSelQIPtr->MoveTo(nFuncLineNo+3, START_COL_POS, EnvDTE::dsMove)))//CComVariant(dsMove))))
			return FALSE;
	}


	return TRUE;
}


///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Calculator the code line number of the given file. 
// INPUT:  1) sFilePath: File full path. 
//         2) CountResultArray: Record the different state line's number.
// OUTPUT: None.
// NOTE: The pattern of function implementation if <FunctionName> ... {
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::CodeLineCalculator(CString sFilePath, UINT *CountResultArray)
{
	UCHAR nCommentState = NO_COMMENTS_STATE;
	CStdioFile stdFile;

	// Open the given file for read only
	if (!stdFile.Open(sFilePath, CFile::modeRead | CFile::typeText ))
	{
        if (!stdFile.Open(sFilePath, CFile::modeCreate | CFile::modeWrite | CFile::typeText ))
	       return FALSE;
		
		return TRUE;
	}	
		
	CString sCurrentLine;
	
	while (true)
	{
		// Read in a line from the file.
		if (!stdFile.ReadString(sCurrentLine))
			break;
		ParseCommentState(sCurrentLine, nCommentState, CountResultArray, NULL);
	}
	stdFile.Close();		
	return TRUE;
}


/////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Check atomic attribute of deleting an event handler
// INPUT:  1) sSrcFilePath: Full path of application source file.
//         2) sHdrFilePath: Full path of application header file.
//         3) appName: Application name.
//         4) stateName: State name which owns to-be-deleted event. 
//         5) eventName: Event name to be deleted.
//         6) sDelAction: Action name to be deleted.
//
// OUTPUT: 1)TRUE:  2)FALSE:
// NOTE: If the event handler to be deleted has been deleted by users already,
//       it will notify users about this.
//
//////////////////////////////////////////////////////////////////////////
BOOL DSUtils::CheckDelEventAtomic(LPCTSTR sSrcFilePath,
									 LPCTSTR sHdrFilePath, 
									 LPCTSTR appName, 
									 LPCTSTR stateName, 
									 LPCTSTR eventName, 
									 LPCTSTR sDelAction)
{

	CString sAppName = appName;
	CString sStateName = stateName;
	
	/////////////////// Open file
	CComPtr<EnvDTE::Documents> pOpenDocsIPtr;
	CComPtr<EnvDTE::Document> pTextSrcDocIPtr;
	g_pDTE->get_Documents(&pOpenDocsIPtr);
	if (pOpenDocsIPtr == NULL)
		return FALSE;
	
	CComQIPtr<EnvDTE::Documents, &EnvDTE::IID_Documents> pOpenDocsQIPtr(pOpenDocsIPtr);
	if (FAILED(pOpenDocsQIPtr->Open(CComBSTR(sSrcFilePath), CComBSTR("Text"), VARIANT_FALSE, &pTextSrcDocIPtr)))
	{
		MessageBox(NULL,_T("Application "+(CString)sAppName+"'s source file failed to open."),NULL, MB_ICONERROR|MB_OK);
		return FALSE;
	}

	/////////////////// Get Text Selection
	//CComQIPtr<ITextDocument, &IID_ITextDocument> pTextSrcDocQIPtr(pTextSrcDocIPtr);
	CComPtr<IDispatch> pTextSrcSelIPtr;
	if (FAILED(pTextSrcDocIPtr->get_Selection(&pTextSrcSelIPtr)))
	{
		return FALSE;   
	}	
	CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextSrcSelQIPtr(pTextSrcSelIPtr);
	//pTextSrcSelQIPtr->SelectAll();
	pTextSrcSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.

	CString sStartTag = "/*{{SME_STATE_DEF";
	CString sEndTag = "/*}}SME_STATE_DEF*/";
	CString sStateDefHead = sStartTag+"("+sAppName+","+sStateName+")*/";
	CString sStateDefEnd = sEndTag;
	CString sEvntHead = "SME_ON_EVENT(";
	CString sDelEventDec = sEvntHead + eventName+",";

	VARIANT_BOOL vbFound;
	// Find the state definition head
	if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sStateDefHead),EnvDTE::dsMatchFromStart,&vbFound)) || !vbFound)// EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error: " + sStateDefHead + " expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sStateDefHead)));
		return FALSE;
	}

	if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;
	long nStartLineNo;
	if (FAILED(pTextSrcSelQIPtr->get_CurrentLine(&nStartLineNo)))
		return FALSE;

	if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sStateDefEnd), EnvDTE::dsMatchForward,&vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error: " + sStateDefEnd + " expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sStateDefEnd)));
		return FALSE;
	}
	if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;
	long nEndLineNo;
	if (FAILED(pTextSrcSelQIPtr->get_CurrentLine(&nEndLineNo)))
		return FALSE;

	long nLine = nStartLineNo+1;
	BOOL bIsFound = FALSE;
	while (true)
	{
		if (nLine >= nEndLineNo)
			break;
		
		if (FAILED(pTextSrcSelQIPtr->MoveTo(nLine, 1,EnvDTE::dsMove)))// CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSrcSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,EnvDTE::dsMove)))//CComVariant(dsFirstText), CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsExtend)))//CComVariant(dsExtend))))
			return FALSE;
		BSTR bstr = NULL;
		//pTextSrcSelQIPtr->SelectLine();
		pTextSrcSelQIPtr->get_Text(&bstr);

		char* bstrTemp = _com_util::ConvertBSTRToString(bstr);
		CString sResult(bstrTemp);
		delete[]bstrTemp;
		
		sResult.TrimLeft();
		sResult.TrimRight();
		sResult.Replace("\t", NULL);
		sResult.Replace(" ", NULL);

		// Format: 	SME_ON_EVENT(event2,OnState1event2,State2)
		if ((!sResult.IsEmpty()) && (sResult.Find(sDelEventDec) != -1))
		{
			bIsFound = TRUE;

			sResult.Replace(sDelEventDec, NULL);
			int idx = sResult.Find(')');
			if (idx != sResult.GetLength()-1)
			{
				CString sWarningMsg;
				
				sWarningMsg.Format("%s(Line %d)	error: %s expected.", (CString)sSrcFilePath, nLine, sDelEventDec);
				MessageBox(NULL,_T(sWarningMsg),NULL, MB_ICONERROR|MB_OK);
				OutPutStringToPane(_bstr_t(_T(sWarningMsg)));
				return FALSE;
			}
			sResult.Replace(")", NULL);
			idx = sResult.Find(',');
			if (idx == -1)
			{
				CString sWarningMsg;
				
				sWarningMsg.Format("%s(Line %d)	error: %s expected.", (CString)sSrcFilePath, nLine, sDelEventDec);
				MessageBox(NULL,_T(sWarningMsg), NULL,MB_ICONERROR|MB_OK);
				OutPutStringToPane(_bstr_t(_T(sWarningMsg)));
				return FALSE;
			}
			sResult.SetAt(idx, ' ');
			idx = sResult.Find(',');
			if (idx != -1)
			{
				CString sWarningMsg;
				
				sWarningMsg.Format("%s(Line %d)	error: %s expected.", (CString)sSrcFilePath, nLine, sDelEventDec);
				MessageBox(NULL,_T(sWarningMsg), NULL,MB_ICONERROR|MB_OK);
				OutPutStringToPane(_bstr_t(_T(sWarningMsg)));
				return FALSE;
			}
			break;	
		}
		nLine++;
	}

	if (nLine >= nEndLineNo)
	{
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"  Warning: " + sDelEventDec+" not found")));
	}

	// Modify the declaration of the event handler function in the head file
	if (strcmp(sDelAction, "SME_NULL") != 0)
	{	
		// Open file
		CComPtr<EnvDTE::Document> pTextHdrDocIPtr;

		if (FAILED(pOpenDocsQIPtr->Open(CComBSTR(sHdrFilePath), CComBSTR("Text"),VARIANT_FALSE, &pTextHdrDocIPtr)))
		{
			MessageBox(NULL,_T("Application "+(CString)sAppName+"'s header file failed to open."),NULL, MB_ICONERROR|MB_OK);
			return FALSE;
		}

		// Get Text Selection
		//CComQIPtr<ITextDocument, &IID_ITextDocument> pTextHdrDocQIPtr(pTextHdrDocIPtr);
		CComPtr<IDispatch> pTextHdrSelIPtr;
		if (FAILED(pTextHdrDocIPtr->get_Selection(&pTextHdrSelIPtr)))
		{
			return FALSE;   
		}	
		CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextHdrSelQIPtr(pTextHdrSelIPtr);

		CString sEventHdlStartFlag = "/*{{SME_BEGIN_EVENT_HANDLER(";
		sEventHdlStartFlag = sEventHdlStartFlag + sAppName +")*/";
		CString sEventHdlEndFlag = "/*}}SME_END_EVENT_HANDLER*/";
		
		// Search for the event handler function name
		if(FAILED(pTextHdrSelQIPtr->MoveTo(1,1,EnvDTE::dsMove)))
		{
			return FALSE;
		}
		if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sEventHdlStartFlag),EnvDTE::dsMatchForward, &vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
		{
			MessageBox(NULL,_T((CString)sHdrFilePath+"  error: "+ sEventHdlStartFlag + " expected."),NULL, MB_ICONERROR|MB_OK);
			OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sEventHdlStartFlag)));
			return FALSE;
		}

		// move the cursor to the end of matching line
		if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
			return FALSE;
		
		long nHdrStartLineNo;
		pTextHdrSelQIPtr->get_CurrentLine(&nHdrStartLineNo); 
		
		// Search for StateEnd declaration
		if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sEventHdlEndFlag),EnvDTE::dsMatchForward , &vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
		{
			MessageBox(NULL,_T((CString)sHdrFilePath+"  error: "+ sEventHdlEndFlag + " expected."),NULL, MB_ICONERROR|MB_OK);
			OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sEventHdlEndFlag)));
			return FALSE;
		}
		// Move the cursor to the end of matching line
		if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
			return FALSE;
		
		long nHdrEndLineNo;
		pTextHdrSelQIPtr->get_CurrentLine(&nHdrEndLineNo);

		//////////////////////////////////////////////////////////////////////////
		// Record the line number
		long nFuncStartLinePos = 0;
		long nFuncStartColPos = 0;
		long nFuncEndLinePos = 0;
		long nFuncEndColPos = 0;

		long nHdrLineNo = nHdrStartLineNo+1;
		BOOL bHdlIsFound = FALSE;
		CString sLastLine ="";
		// Initialize the line number and column number
		nFuncStartLinePos = nHdrStartLineNo+1;
		nFuncStartColPos = 1;

		while (true)
		{
			if (nHdrLineNo >= nHdrEndLineNo)
				break;
	
			long nHeadSpaceNo = 0;
			if (FAILED(pTextHdrSelQIPtr->MoveTo(nHdrLineNo, 1,EnvDTE::dsMove)))// CComVariant(dsMove))))
				return FALSE;
			if (FAILED(pTextHdrSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,EnvDTE::dsMove)))//CComVariant(dsFirstText), CComVariant(dsMove))))
				return FALSE;
			if (FAILED(pTextHdrSelQIPtr->get_CurrentColumn(&nHeadSpaceNo)))
				return FALSE;
			if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsExtend)))//CComVariant(dsExtend))))
				return FALSE;
			BSTR bstr = NULL;
			//pTextHdrSelQIPtr->SelectLine();
			pTextHdrSelQIPtr->get_Text(&bstr);

			char* bstrTemp = _com_util::ConvertBSTRToString(bstr);
			CString sResult(bstrTemp);
			delete[]bstrTemp;
			
			sResult.TrimLeft();

			//int State2Exit(struct SME_APP_T *pApp, struct SME_EVENT_T *pEvent);
			if (!sResult.IsEmpty())
			{
				while (true)
				{
					int idx = sResult.Find(';');
					if (-1 == idx)
					{
						sLastLine += " ";
						sLastLine += sResult;
						break;
					}
					if (nFuncEndLinePos == nHdrLineNo)
						nFuncEndColPos = nFuncEndColPos + idx +1; 
					else
					{
						nFuncEndLinePos = nHdrLineNo;
						nFuncEndColPos = nHeadSpaceNo+idx+1;
					}

					sLastLine += " ";
					CString sCurrentLine = sLastLine + sResult.Left(idx+1);
				
					// Initialize for the next loop
					sLastLine = "";
					sResult = sResult.Right(sResult.GetLength()-idx-1);

					idx = sCurrentLine.Find('(');
					// idx == -1 ?????????
					CString sFuncName = sCurrentLine.Left(idx);
					sFuncName.TrimRight();
					sFuncName.Replace('\t', ' ');
					idx = sFuncName.ReverseFind(' ');
					sFuncName = sFuncName.Right(sFuncName.GetLength()-idx-1);
					if (sFuncName == (CString)sDelAction)
					{
						bHdlIsFound = TRUE;
						break;	
					}
					nFuncStartLinePos = nHdrLineNo;
					nFuncStartColPos = nFuncEndColPos;
				}
				if (bHdlIsFound == TRUE)
					break;
			}
			nHdrLineNo++;
		}
		if (bHdlIsFound == FALSE)
		{
			OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		Warning:  int "+sDelAction+"(struct SME_APP_T *pApp, struct SME_EVENT_T *pEvent); not found")));
		}
		else
		{
			if (DelEventHdlFunc(pTextHdrSelQIPtr, nFuncStartLinePos, nFuncStartColPos ,nFuncEndLinePos, nFuncEndColPos) == FALSE)
				return FALSE;
		}

	}

	if (bIsFound == TRUE)
		DelHdlerDec(pTextSrcSelQIPtr, nLine);

	return TRUE;


}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Check atomic attribute of adding state operations.
// INPUT:  1) sSrcFilePath: Full path of application source file.
//         2) sHdrFilePath: Full path of application header file.
//         3) sStatename: State name.
//         4) sParent: Current state's parent's name.
//		   5) sAppName: Application name. 
//         6) sDefChild: Default child state name.
//		   7) nSkippedLinNumFromApp: Num of sibling child state of the same parent 
//		   8) sEntryFuncName: Entry function name. 
//         9) sExitFuncName: Exit function name.
// OUTPUT: 1) TRUE:  2) FALSE: Error in any key word or macro definition 
// NOTE: 
//
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::CheckAddStateAtomic(LPCTSTR sSrcFilePath, LPCTSTR sHdrFilePath, LPCSTR sStatename,
								  LPCTSTR sParent, LPCTSTR sAppName, LPCTSTR sFuncClassPrefix, LPCTSTR sDefChild, 
								  UINT nSkippedLinNumFromApp, LPCTSTR sEntryFuncName, LPCTSTR sExitFuncName)
{
	// Open file
	CComPtr<EnvDTE::Documents> pOpenDocsIPtr;
	CComPtr<EnvDTE::Document>pTextHdrDocIPtr;
	g_pDTE->get_Documents(&pOpenDocsIPtr);
	if (pOpenDocsIPtr == NULL)
		return FALSE;
	
	CComQIPtr<EnvDTE::Documents, &EnvDTE::IID_Documents> pOpenDocsQIPtr(pOpenDocsIPtr);
	if (FAILED(pOpenDocsQIPtr->Open(CComBSTR(sHdrFilePath), CComBSTR("Text"),VARIANT_FALSE, &pTextHdrDocIPtr)))
	{
		MessageBox(NULL,_T("Application "+(CString)sAppName+"'s header file failed to open."),NULL, MB_ICONERROR|MB_OK);
		return FALSE;
	}

	// Get Text Selection
	//CComQIPtr<ITextDocument, &IID_ITextDocument> pTextHdrDocQIPtr(pTextHdrDocIPtr);
	CComPtr<IDispatch> pTextHdrSelIPtr;
	if (FAILED(pTextHdrDocIPtr->get_Selection(&pTextHdrSelIPtr)))
	{
		return FALSE;   
	}
	
	CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextHdrSelQIPtr(pTextHdrSelIPtr);
	//pTextHdrSelQIPtr->SelectAll();
	pTextHdrSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.


	CString sStateDecHead = CString("/*{{SME_STATE_DECLARE(")+sAppName+")*/";
	CString sStateDecEnd = "/*}}SME_STATE_DECLARE*/";
	CString sStateDecParent = CString("SME_STATE_DECLARE(")+sAppName+")";
	CString sClassDecHead = CString("/*{{SME_APP_CLASS_DECLARE(")+sAppName+","; // IMPORTANT: should define a tail.
	CString sClassDecEnd = CString("SME_STATE_TREE_DEC(") + sAppName + ")"; //"/*}}SME_APP_CLASS_DECLARE*/";
	CString sEventHandlerEnd = "/*}}SME_END_EVENT_HANDLER*/";
	
    VARIANT_BOOL vbFound; 
	// search for the state enumeration declaration
	if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sStateDecHead), EnvDTE::dsMatchFromStart , &vbFound)) || ! vbFound)//EnvDTE::dsMatchFromStart, &vbFound)) || ! vbFound)
		// EnvDTE::dsMatchFromStart
	{
		MessageBox(NULL,_T((CString)sHdrFilePath+"  error:" + sStateDecHead + " expected."),NULL,MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"  error:"+ sStateDecHead + " expected")));
		return FALSE;
	}
	
	// move the cursor to the end of matching line
	if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;
	
	long nStartLineNo;
	pTextHdrSelQIPtr->get_CurrentLine(&nStartLineNo); 

	// Search for StateEnd declaration
	if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sStateDecEnd),EnvDTE::dsMatchForward , &vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sHdrFilePath+"  error:" + sStateDecEnd + " expected."), NULL,MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sStateDecEnd)));
		return FALSE;
	}
	// Move the cursor to the end of matching line
	if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;
	
	long nEndLineNo;
	pTextHdrSelQIPtr->get_CurrentLine(&nEndLineNo);

	// Search for the parent state and record down the line of insert point
	unsigned int nItemNum = 0;
	long nHdrStateDecLine = nStartLineNo+1;
	long nStateDecInsertLine = nHdrStateDecLine;
	BOOL bParentStateFound=FALSE;

	while (true)
	{
		if (nHdrStateDecLine >= nEndLineNo)
			break;

		if (nItemNum >= nSkippedLinNumFromApp && bParentStateFound==TRUE)
			break;

		if (FAILED(pTextHdrSelQIPtr->MoveTo(nHdrStateDecLine, 1,EnvDTE::dsMove))) //CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextHdrSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,EnvDTE::dsMove)))//CComVariant(dsFirstText), CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsExtend)))//CComVariant(dsExtend))))
			return FALSE;
		BSTR bstr = NULL;
		//pTextHdrSelQIPtr->SelectLine();
		pTextHdrSelQIPtr->get_Text(&bstr);

		char* bstrTemp = _com_util::ConvertBSTRToString(bstr);
		CString sResult(bstrTemp);
		delete[]bstrTemp;
		
		sResult.TrimLeft();
		sResult.TrimRight();
		sResult.Replace("\t", NULL);
		sResult.Replace(" ", NULL);

		if (!sResult.IsEmpty())
		{
			nItemNum++;
			if (nItemNum == nSkippedLinNumFromApp )
				nStateDecInsertLine = nHdrStateDecLine+1;

		}
		if ((!sResult.IsEmpty()) && (sResult == sStateDecParent))
			bParentStateFound=TRUE;	
		nHdrStateDecLine++;
	}

	if (bParentStateFound==FALSE)
	{
		MessageBox(NULL,_T((CString)sHdrFilePath+"  error:" + sStateDecParent+ " expected."), NULL,MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sStateDecParent)));
		return FALSE;
	}

	if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;

	///////////////////////////////////////////////////////////////////////////
	// Search for the app class declaration
	BOOL bExistClassDec=FALSE;
	long nAppClassDecStartLine = -1;
	long nAppClassDecEndLine = -1;
	long nAppClassInserLine =-1;
	//pTextHdrSelQIPtr->SelectAll();
	pTextHdrSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.
	if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sClassDecHead), EnvDTE::dsMatchFromStart, &vbFound)) || ! vbFound)
	{
		bExistClassDec = FALSE;
	} else 
	{
		bExistClassDec = TRUE;
		// move the cursor to the end of matching line
		if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))
			return FALSE;
		pTextHdrSelQIPtr->get_CurrentLine(&nAppClassDecStartLine);

		if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sClassDecEnd), EnvDTE::dsMatchForward, &vbFound)) || ! vbFound)
		{
			AfxMessageBox(_T((CString)sHdrFilePath+"  error:" + sClassDecEnd+ " expected."), MB_ICONERROR|MB_OK);
			return FALSE;
		}
		if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))
			return FALSE;
		// Record the line no of the /*}}SME_STATE_DECLARE*/
		pTextHdrSelQIPtr->get_CurrentLine(&nAppClassDecEndLine);

		// Locate the insert point of SME_STATE_DECLARE.
		nItemNum = 0;
		long nDecLine = nAppClassDecStartLine+1;
		nAppClassInserLine = nDecLine;
		bParentStateFound=FALSE;
		while (true)
		{
			if (nDecLine >= nAppClassDecEndLine)
				break;

			if (FAILED(pTextHdrSelQIPtr->MoveTo(nDecLine, 1, VARIANT_BOOL(EnvDTE::dsMove))))
				return FALSE;
			if (FAILED(pTextHdrSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,VARIANT_BOOL(EnvDTE::dsMove))))
				return FALSE;
			if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsExtend)))) //EndOfLine(CComVariant(dsExtend))))
				return FALSE;
			BSTR bstr = NULL;
			pTextHdrSelQIPtr->get_Text(&bstr);
			CString sResult = BSTR2CString(bstr);
			sResult.TrimLeft();
			sResult.TrimRight();
			sResult.Replace("\t", NULL);
			sResult.Replace(" ", NULL);

			if (!sResult.IsEmpty())
			{
				nItemNum++;
				if (nItemNum == nSkippedLinNumFromApp )
				{
					nAppClassInserLine = nDecLine+1;
					break;
				}
			}
			nDecLine++;
		}
	}

	///////////////////////////////////////////////////////////////////////////
	// Search for the end of event handler tables
	if (!bExistClassDec)
		if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sStateDecHead), EnvDTE::dsMatchFromStart , &vbFound)) || ! vbFound)
			return FALSE;

	if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sEventHandlerEnd),EnvDTE::dsMatchForward, &vbFound)) || !vbFound)// EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sHdrFilePath+"  error:" + sEventHandlerEnd+" expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sEventHandlerEnd)));
		return FALSE;
	}
	if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
		return FALSE;

	long nHdrHdlDecLine = 0;
	pTextHdrSelQIPtr->get_CurrentLine(&nHdrHdlDecLine);
	
	///////////////////////////////////////////////////////////////////////////
	// Check source file all-or-nothing
	CComPtr<EnvDTE::Document> pTextSrcDocIPtr;

	if (FAILED(pOpenDocsQIPtr->Open(CComBSTR(sSrcFilePath), CComBSTR("Text"),VARIANT_FALSE, &pTextSrcDocIPtr)))
	{
		MessageBox(NULL,_T("Application "+(CString)sAppName+"'s source file failed to open."),NULL, MB_ICONERROR|MB_OK);
		return FALSE;
	}

	// Get Text Selection
	//CComQIPtr<ITextDocument, &IID_ITextDocument> pTextSrcDocQIPtr(pTextSrcDocIPtr);
	CComPtr<IDispatch> pTextSrcSelIPtr;
	if (FAILED(pTextSrcDocIPtr->get_Selection(&pTextSrcSelIPtr)))
	{
		return FALSE;   
	}
	
	///////////////////////////////////////////////////////////////////////////
	// Search for the state tree definition

	CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextSrcSelQIPtr(pTextSrcSelIPtr);
	CString sSeparator="/*{{SME_STATE_STATETREE_SEPARATOR}}*/";

	//pTextSrcSelQIPtr->SelectAll();
	pTextSrcSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.

	if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sSeparator),EnvDTE::dsMatchFromStart,  &vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error:" + sSeparator + " expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in seperater flag " + sSeparator)));
		return FALSE;
	}

	if (FAILED(pTextSrcSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
		return FALSE;

	CString strStateName=CString(sStatename);
	CString strParent=CString(sParent);
	CString strAppName=CString(sAppName);
	CString strDefChild=CString(sDefChild);

	CString sStateTreeDefHead = CString("/*{{SME_STATE_TREE_DEF(")+strAppName+")*/";
	CString sStateTreeDefEnd = "/*}}SME_STATE_TREE_DEF*/";
	CString sStateTreeFind = CString("SME_STATE(")+strAppName+","+strAppName+","; // SHOULD add , as separator
    CString sStateParentFind=CString("SME_STATE(")+strAppName+","+strParent+","; // SHOULD add , as separator

	//pTextSrcSelQIPtr->SelectAll();
	pTextSrcSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.

	// Find the state tree definition head
	if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sStateTreeDefHead),EnvDTE::dsMatchFromStart , &vbFound)) || !vbFound)//EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error:" + sStateTreeDefHead + " expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sStateTreeDefHead)));
		return FALSE;
	}
	if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;


	nStartLineNo = 0;
	if (FAILED(pTextSrcSelQIPtr->get_CurrentLine(&nStartLineNo)))
		return FALSE;

	if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sStateTreeDefEnd),EnvDTE::dsMatchForward , &vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error:"+sStateTreeDefEnd+" expected."), NULL,MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sStateTreeDefEnd)));
		return FALSE;
	}
	if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;
	nEndLineNo = 0;
	pTextSrcSelQIPtr->get_CurrentLine(&nEndLineNo);

	BOOL bUpdateDfltChild = FALSE;
	long nLine = nStartLineNo+1;
	long nFlagLineNo = -1;
	long nParentLineNo = 0;
	while (true)
	{
		if (nLine >= nEndLineNo)
			break;
		
		if (FAILED(pTextSrcSelQIPtr->MoveTo(nLine, 1,EnvDTE::dsMove))) //CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSrcSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,EnvDTE::dsMove)))//CComVariant(dsFirstText), CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsExtend)))//CComVariant(dsExtend))))
			return FALSE;
		BSTR bstr = NULL;
		//pTextSrcSelQIPtr->SelectLine();
		pTextSrcSelQIPtr->get_Text(&bstr);

	char* bstrTemp = _com_util::ConvertBSTRToString(bstr);
		CString sResult(bstrTemp);
		delete[]bstrTemp;

		sResult.TrimLeft();
		sResult.TrimRight();
		sResult.Replace("\t", NULL);
		sResult.Replace(" ", NULL);

		if (!sResult.IsEmpty())
		{
			if (!strDefChild.IsEmpty()&& (sResult.Find(sStateParentFind) != -1))
			{
				//	SME_STATE(MyApp2,State2,0,-1)
				bUpdateDfltChild = TRUE;
				nParentLineNo = nLine;
			}
			if (sResult.Find(sStateTreeFind) != -1)
			{
				nFlagLineNo = nLine;
			}
		}
		nLine++;
	}

	if (nFlagLineNo < 0)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error:" + sStateTreeFind + " expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sStateTreeFind)));
		return FALSE;
	}

	if ((!strDefChild.IsEmpty()) && (bUpdateDfltChild == FALSE))
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error:"+ sStateParentFind+" expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sStateParentFind)));
		return FALSE;
	}

	DeclareNewState(pTextHdrSelQIPtr, sStatename, sEntryFuncName, sExitFuncName, nSkippedLinNumFromApp
		, nStateDecInsertLine, nAppClassInserLine, nHdrHdlDecLine);
	DeclareStateTree(pTextSrcSelQIPtr, sStatename, sParent, sAppName, sDefChild, nSkippedLinNumFromApp
		, nParentLineNo, nFlagLineNo);
	CreateStateDef(pTextSrcSelQIPtr, sStatename, sAppName, sFuncClassPrefix, sEntryFuncName, sExitFuncName);


	return TRUE;
}


///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Check atomic attribute of adding an event operations.
// INPUT:  1) sSrcFilePath: Full path of application source file.
//         2) sHdrFilePath: Full path of application header file.
//		   3) sAppName: Application name. 
//         4) sSrcState: Current state name.
//         5) sDestState: Transition state name.
//		   6) sEventID: Event ID of new event.
//         7) sHandlerName: Handler name of event handler(without parameters)
// 
// OUTPUT: 1) TRUE: 2)FALSE
// Note:
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::CheckAddEventAtomic(LPCTSTR sSrcFilePath, 
									 LPCTSTR sHdrFilePath,
									 LPCTSTR sAppname,
									 LPCTSTR sFuncClassPrefix,
									 LPCTSTR sSrcState, 
									 LPCTSTR sDestState,
									 LPCTSTR sEventID, 
									 LPCTSTR sHandlerName)
{

	CComPtr<EnvDTE::Documents> pOpenDocsIPtr;
	g_pDTE->get_Documents(&pOpenDocsIPtr);
	if (pOpenDocsIPtr == NULL)
		return FALSE;

	CComPtr<EnvDTE::Document>  pTextHdrDocIPtr, pTextSrcDocIPtr;
	CComQIPtr<EnvDTE::Documents, &EnvDTE::IID_Documents> pOpenDocsQIPtr(pOpenDocsIPtr);

	// Open Header file
	if (FAILED(pOpenDocsQIPtr->Open(CComBSTR(sHdrFilePath), CComBSTR("Text"), VARIANT_FALSE, &pTextHdrDocIPtr)))
	{
		MessageBox(NULL,_T("Application "+(CString)sAppname+"'s header file failed to open."),NULL, MB_ICONERROR|MB_OK);
		return FALSE;
	}

	// Get Text Selection
	//CComQIPtr<ITextDocument, &IID_ITextDocument> pTextHdrDocQIPtr(pTextHdrDocIPtr);
	CComPtr<IDispatch> pTextHdrSelIPtr;
	if (FAILED(pTextHdrDocIPtr->get_Selection(&pTextHdrSelIPtr)))
	{
		return FALSE;   
	}	
	CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextHdrSelQIPtr(pTextHdrSelIPtr);

	if(FAILED(pTextHdrSelQIPtr->MoveTo(1,1,EnvDTE::dsMove)))
	{
		return FALSE;
	}

	BOOL bHdlIsNULL = TRUE;
	long nHdrHdlDecLine = 0;

	if (strcmp(sHandlerName, "SME_NULL") != 0)
	{
		bHdlIsNULL = FALSE;
		CString sStartFlag = "/*{{SME_BEGIN_EVENT_HANDLER(";
		sStartFlag = sStartFlag + sAppname +")*/";
		CString sEndFlag = "/*}}SME_END_EVENT_HANDLER*/";
		

		VARIANT_BOOL vbFound;
		// Search for the event handler function name
		if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sStartFlag),EnvDTE::dsMatchForward , &vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
		{
			MessageBox(NULL,_T((CString)sHdrFilePath+"  error:" + sStartFlag + " expected."),NULL, MB_ICONERROR|MB_OK);
			OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sStartFlag)));
			return FALSE;
		}
		
		// move the cursor to the end of matching line
		if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
			return FALSE;

		long nStartLineNo;
		pTextHdrSelQIPtr->get_CurrentLine(&nStartLineNo); 
		
		// Search for StateEnd declaration
		if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR(sEndFlag),EnvDTE::dsMatchForward, &vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
		{
			MessageBox(NULL,_T((CString)sHdrFilePath+"  error:"+sEndFlag+" expected."),NULL, MB_ICONERROR|MB_OK);
			OutPutStringToPane(_bstr_t(_T((CString)sHdrFilePath+"		error: unexpected composition in macro expansion " + sEndFlag)));
			return FALSE;
		}
		// Move the cursor to the end of matching line
		if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
			return FALSE;

		long nEndLineNo;
		pTextHdrSelQIPtr->get_CurrentLine(&nEndLineNo);
		// Record the line number
		long nLineNo = nStartLineNo+1;
		CString sLastLine ="";
		while (true)
		{
			if (nLineNo >= nEndLineNo)
			{
				sLastLine.TrimLeft();
				sLastLine.TrimRight();
				
				if (!sLastLine.IsEmpty())
				{
					int idx = sLastLine.Find('(');
					
					CString sFuncName = sLastLine.Left(idx);
					sFuncName.TrimRight();
					idx = sFuncName.ReverseFind(' ');
					sFuncName = sFuncName.Right(sFuncName.GetLength()-idx-1);
					if (sFuncName == (CString)sHandlerName)
					{
						bHdlIsNULL = TRUE;
					}
				}
				break;
			}

			if (FAILED(pTextHdrSelQIPtr->MoveTo(nLineNo, 1, EnvDTE::dsMove)))//CComVariant(dsMove))))
				return FALSE;
			if (FAILED(pTextHdrSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,EnvDTE::dsMove)))//CComVariant(dsFirstText), CComVariant(dsMove))))
				return FALSE;
			if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsExtend)))//CComVariant(dsExtend))))
				return FALSE;
			BSTR bstr = NULL;
			//pTextHdrSelQIPtr->SelectLine();
			pTextHdrSelQIPtr->get_Text(&bstr);

	char* bstrTemp = _com_util::ConvertBSTRToString(bstr);
			CString sResult(bstrTemp);
			delete[]bstrTemp;

			sResult.TrimLeft();
			sResult.TrimRight();
			sResult.Replace('\t', ' ');
			CString sTemp = " ";
			sTemp+=sResult;
			sResult = sTemp;

			//int State2Exit(struct SME_APP_T *pApp, struct SME_EVENT_T *pEvent);
			if (!sResult.IsEmpty())
			{
				int idx = sResult.Find(';');
				if (idx == -1)
				{
					sLastLine += sResult;
					nLineNo++;
					continue;
				}
				CString sCurrentLine = sLastLine + sResult.Left(idx+1);
				sLastLine = sResult.Right(sResult.GetLength()-idx-1);
				idx = sCurrentLine.Find('(');
				CString sFuncName = sCurrentLine.Left(idx);
				sFuncName.TrimRight();
				idx = sFuncName.ReverseFind(' ');
				sFuncName = sFuncName.Right(sFuncName.GetLength()-idx-1);
				if (sFuncName == (CString)sHandlerName)
				{
					bHdlIsNULL = TRUE;
					break;
				}
			}
			nLineNo++;
		}
		// Check the name of the event handler whether is already existed
		//	CString sDupli = "int "+CString(sHandlerName)+"(struct SME_APP_T *pApp, struct SME_EVENT_T *pEvent)";		
		if (bHdlIsNULL == TRUE)
		{
			MessageBox(NULL,_T("Error! The action "+(CString)sHandlerName+"already exists."),NULL, MB_ICONERROR|MB_OK);
//			return FALSE;
			OutPutStringToPane(_bstr_t(_T("Error! The action "+(CString)sHandlerName+" already exists.")));
		}
		nHdrHdlDecLine = nEndLineNo;
	}

	// Open file
	if (FAILED(pOpenDocsQIPtr->Open(CComBSTR(sSrcFilePath), CComBSTR("Text"),VARIANT_FALSE, &pTextSrcDocIPtr)))
	{
		MessageBox(NULL,_T("Application "+(CString)sAppname+"'s source file failed to open."),NULL, MB_ICONERROR|MB_OK);
		return FALSE;
	}
	
	// Get Text Selection
	//CComQIPtr<ITextDocument, &IID_ITextDocument> pTextSrcDocQIPtr(pTextSrcDocIPtr);
	CComPtr<IDispatch> pTextSrcSelIPtr;
	if (FAILED(pTextSrcDocIPtr->get_Selection(&pTextSrcSelIPtr)))
	{
		return FALSE;   
	}	
	CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextSrcSelQIPtr(pTextSrcSelIPtr);
	//pTextSrcSelQIPtr->SelectAll();
	pTextSrcSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.

	CString sStartTag = "/*{{SME_STATE_DEF";
	CString sEndTag = "/*}}SME_STATE_DEF*/";
	CString sStateDefHead = sStartTag+"("+sAppname+","+sSrcState+")*/";
	CString sStateDefEnd = sEndTag;

	VARIANT_BOOL vbFound;
	if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sStateDefHead), EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)//EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error:" + sStateDefHead + " expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sStateDefHead)));
		return FALSE;
	}
	if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;
	if (FAILED(pTextSrcSelQIPtr->FindText(CComBSTR(sStateDefEnd),EnvDTE::dsMatchForward , &vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error:" + sStateDefHead + " expected."),NULL, MB_ICONERROR|MB_OK);
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"		error: unexpected composition in macro expansion " + sStateDefHead)));
		return FALSE;
	}
	if (FAILED(pTextSrcSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;

	long nStateDefEndFlag = 0;
	if (FAILED(pTextSrcSelQIPtr->get_CurrentLine(&nStateDefEndFlag)))
		return FALSE;
	
	// Add code to header file
	if (bHdlIsNULL == FALSE)
	{
	DeclareEventHandler(pTextHdrSelQIPtr, sAppname, sFuncClassPrefix, sHandlerName, nHdrHdlDecLine);
	}
	CreateHandlerDef(pTextSrcSelQIPtr, sAppname, sFuncClassPrefix, sSrcState, sDestState, sEventID, sHandlerName, nStateDefEndFlag);
	return TRUE;
}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Delete one state declaration from the head file. 
// INPUT:  1) sApp: an application name.
//         2) sParent: the name of a parent of the selected item.
//         3) sSelected: the selected item's name.
// OUTPUT: None.
// NOTE: The pattern of function implementation if <FunctionName> ... {
//
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::ChangeDefaultState(LPCTSTR sSrcFilePath, LPCTSTR sApp, LPCTSTR sParent, LPCTSTR sSelected)
{
	CString sAppName=CString(sApp);
	CString sParentName=CString(sParent);
	CString sSelectedName=CString(sSelected);

	/////////////////// Open file
	CComPtr<EnvDTE::Documents> pOpenDocsIPtr;
	CComPtr<EnvDTE::Document>pTextDocIPtr;
	g_pDTE->get_Documents(&pOpenDocsIPtr);
	if (pOpenDocsIPtr == NULL)
		return FALSE;
	
	CComQIPtr<EnvDTE::Documents, &EnvDTE::IID_Documents> pOpenDocsQIPtr(pOpenDocsIPtr);
	if (FAILED(pOpenDocsQIPtr->Open(CComBSTR(sSrcFilePath), CComBSTR("Text"),VARIANT_FALSE, &pTextDocIPtr)))
	{
		return FALSE;
	}

	/////////////////// Get Text Selection
	//CComQIPtr<ITextDocument, &IID_ITextDocument> pTextDocQIPtr(pTextDocIPtr);
	CComPtr<IDispatch> pTextSelIPtr;
	if (FAILED(pTextDocIPtr->get_Selection(&pTextSelIPtr)))
	{
		return FALSE;   
	}	
	CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextSelQIPtr(pTextSelIPtr);
	//pTextSelQIPtr->SelectAll();
	pTextSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.

		
	CString sStartTag = "/*{{";
	CString sEndTag = "/*}}";
	CString sStateTreeDef = "SME_STATE_TREE_DEF";
	CString sStateTreeDefHead = sStartTag+sStateTreeDef+"("+sAppName+")*/";
	CString sStateTreeDefEnd = sEndTag+sStateTreeDef+"*/";
    CString sStateParentFind=sStateTreeDef.Left(9)+"("+sAppName+","+sParentName+",";
	
    VARIANT_BOOL vbFound;
	// Fine the state tree definition head
	if (FAILED(pTextSelQIPtr->FindText(CComBSTR(sStateTreeDefHead),EnvDTE::dsMatchFromStart , &vbFound)) || !vbFound)//EnvDTE::dsMatchFromStart, &vbFound)) || !vbFound)
	{
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"  error: "+ sStateTreeDefHead + " expected" )));
		return FALSE;
	}
	if (FAILED(pTextSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;

	long nStartLineNo;
	if (FAILED(pTextSelQIPtr->get_CurrentLine(&nStartLineNo)))
		return FALSE;

	if (FAILED(pTextSelQIPtr->FindText(CComBSTR(sStateTreeDefEnd),EnvDTE::dsMatchForward, &vbFound)) || !vbFound)// EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		OutPutStringToPane(_bstr_t(_T((CString)sSrcFilePath+"  error: "+ sStateTreeDefEnd + " expected")));
		return FALSE;
	}
	if (FAILED(pTextSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;

	long nEndLineNo;
	if (FAILED(pTextSelQIPtr->get_CurrentLine(&nEndLineNo)))
		return FALSE;

	long nLineNo = nStartLineNo+1;

	while (true)
	{
		if (nLineNo >= nEndLineNo)
			break;

		if (FAILED(pTextSelQIPtr->MoveTo(nLineNo, 1, EnvDTE::dsMove)))//CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,EnvDTE::dsMove)))//CComVariant(dsFirstText), CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextSelQIPtr->EndOfLine(EnvDTE::dsExtend)))//CComVariant(dsExtend))))
			return FALSE;
		BSTR bstr = NULL;
		//pTextSelQIPtr->SelectLine();
		pTextSelQIPtr->get_Text(&bstr);

	char* bstrTemp = _com_util::ConvertBSTRToString(bstr);
		CString sResult(bstrTemp);
		delete[]bstrTemp;

		sResult.TrimLeft();
		sResult.TrimRight();
		sResult.Replace("\t", NULL);
		sResult.Replace(" ", NULL);

		if ((!sResult.IsEmpty()) && (sResult.Find(sStateParentFind) == 0))
		{
			sResult.Replace(sStateParentFind, NULL);
			int idx = sResult.Find(')');
			if (idx == sResult.GetLength()-1)
			{
				sResult.Replace(")", NULL);
				idx = sResult.Find(',');
				if (idx != -1)	
				{
					break;
				}
			}
		}
		nLineNo++;
	}

	if (nLineNo >= nEndLineNo)
	{
		MessageBox(NULL,_T((CString)sSrcFilePath+"  error: "+ sStateParentFind + " expected."),NULL,MB_ICONERROR|MB_OK);
		return FALSE;
	}

	
	// Move to the finded line
	if (FAILED(pTextSelQIPtr->MoveTo(nLineNo, 1,EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;

	if (FAILED(pTextSelQIPtr->EndOfLine(EnvDTE::dsExtend)))//CComVariant(dsExtend))))
		return FALSE;
	
	// Get the wanted to be modified line 
	BSTR bstrChangeLine;
	if(FAILED(pTextSelQIPtr->get_Text(&bstrChangeLine)))
		return FALSE;

	CString sLine=CString(bstrChangeLine);
	int idx = sLine.ReverseFind(',');

	if (idx == -1)
	{
		CString sWarningMsg;

		sWarningMsg.Format("%s(%d)	error: illegal syntax", (CString)sSrcFilePath, nLineNo);
		OutPutStringToPane(_bstr_t(_T(sWarningMsg)));
		return FALSE;
	}
	sLine=sLine.Left(idx);
	sLine=sLine+","+sSelectedName+")";

	// Put the modified line text
	if (FAILED(pTextSelQIPtr->put_Text(CComBSTR(sLine))))
        return FALSE;


	return  TRUE;
}


BOOL DSUtils::CheckAddAppAtomic(LPCTSTR sPrjName/*no path just the name*/, LPCTSTR sAppName)
{
		char *sNote = "NOTE: The StateWizard will add mapping macros between /*{{ and /*}}. Do NOT modify manually.";
	_bstr_t bstrPath = GetProjectDir(_bstr_t(sPrjName));


	CString strPrjPath = _com_util::ConvertBSTRToString(bstrPath.GetBSTR());
    CString strAppName = sAppName;
 	CString sFileHFullPath = strPrjPath + "\\"+sAppName+".h";
		CString sFileCFullPath;
	if(g_nFileType==APPTYPE_CLASS || g_nFileType==APPTYPE_CPP_FILE)
		sFileCFullPath = strPrjPath + "\\"+sAppName+".cpp";
	else 
		sFileCFullPath = strPrjPath + "\\"+sAppName+".c";

	CString sPrjFullPath;
	vector<_bstr_t>  sPrjFileList;
	sPrjFileList.clear();
	
	CComPtr<EnvDTE::Project> prj = NULL;
	prj = GetProject(_bstr_t(sPrjName));
	if(prj==NULL)
		return FALSE;
	GetProjectFileList(prj, sPrjFileList);
	int nFileNum = 0;
	while (true)
	{
		if (nFileNum == sPrjFileList.size())
			break;

		_bstr_t sFilePath = sPrjFileList[nFileNum];
		char* filePath = _com_util::ConvertBSTRToString(sFilePath.GetBSTR());
		if (sFileHFullPath.CompareNoCase(filePath) == 0)
		{
			delete [] filePath;
			AfxMessageBox(_T("A file with the name you specified already exists."), MB_ICONERROR|MB_OK);
			return FALSE;
		}
		if (sFileCFullPath.CompareNoCase(filePath) == 0)
		{
			delete [] filePath;
			AfxMessageBox(_T("A file with the name you specified already exists."), MB_ICONERROR|MB_OK);
			return FALSE;
		}
		delete [] filePath;
		nFileNum++;
	}
	CStdioFile AppHFile; // .h file to be created 
	CStdioFile AppCFile; // .c file to be created

	if (AppHFile.Open(LPCTSTR(sFileHFullPath),CFile::modeRead | CFile::typeText ))
	{
		AppHFile.Close();
		AfxMessageBox(_T("The file: "+(CString)sFileHFullPath + " already exists."), MB_ICONERROR|MB_OK);
		return FALSE;
	}
	
	if (AppCFile.Open(LPCTSTR(sFileCFullPath),CFile::modeRead | CFile::typeText ))
	{
		AppCFile.Close();
		AfxMessageBox(_T("The file: "+(CString)sFileCFullPath + " already exists."), MB_ICONERROR|MB_OK);
		return FALSE;
	}

	/* 
	// Create the head file 
	if(! AppHFile.Open(LPCTSTR(sFileHFullPath),CFile::modeCreate|CFile::modeReadWrite|CFile::typeText))
	{
		AfxMessageBox(_T("Application "+(CString)sAppName+"'s header file failed to open."), MB_ICONERROR|MB_OK);
		return FALSE; //exit(1);
	}
	AppHFile.Close();
    // Create the source file	
	if(! AppCFile.Open(LPCTSTR(sFileCFullPath),CFile::modeCreate|CFile::modeReadWrite|CFile::typeText))
	{
		AfxMessageBox(_T("Application "+(CString)sAppName+"'s source file failed to open."), MB_ICONERROR|MB_OK);
#ifdef _DEBUG
		afxDump<<"AppCFile could not be opened"<<"\n";
#endif
		return FALSE; // exit(1)
	}
	AppCFile.Close();
	*/
	
	CString sSrcFileName;
	if(g_nFileType==APPTYPE_CLASS || g_nFileType==APPTYPE_CPP_FILE)
		sSrcFileName = ".\\"+strAppName+".cpp";
	else 
		sSrcFileName = ".\\"+strAppName+".c";
		

	CString sHdrFileName=".\\"+strAppName+".h";

	if (AddSrcHdrFilesToPrj(prj, _bstr_t(sSrcFileName), _bstr_t(sHdrFileName), _bstr_t("")))
	{
		return TRUE;
	}
	   
	// Delete relative files when ops failed
	/*
	::DeleteFile(sFileHFullPath);
	::DeleteFile(sFileCFullPath);
	*/

	return FALSE;
}

/////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get Event id list by calling ParseEventIdList function
// INPUT: 1)sServiceHdrPath: Text selection of header file
//        2)EventIdList: Header file path
//
// OUTPUT: 1)TRUE: Success
//         2)FALSE: Fail
//
// Note: If the document is opened already, there is no necessary to open again.
//       Otherwise, open it right now.
/////////////////////////////////////////////////////////////////////////
BOOL DSUtils::GetEventIdList(LPCTSTR sServiceHdrPath,vector<_bstr_t> &EventIdList)
{
	// Open file
	CComPtr<EnvDTE::Documents> pOpenDocsIPtr;
	CComPtr<EnvDTE::Document>pTextHdrDocIPtr;
	g_pDTE->get_Documents(&pOpenDocsIPtr);
	if (pOpenDocsIPtr == NULL)
		return FALSE;

	CComQIPtr<EnvDTE::Documents,&EnvDTE::IID_Documents> spActiveDocs(pOpenDocsIPtr);
	ATLASSERT(spActiveDocs);

	//record the num of opened documents
    long openedDocNum = 0; 
	
	// get active document num in documents
	spActiveDocs->get_Count(&openedDocNum); 

	// resource file should not be opened
	for (long i = 1L; i <= openedDocNum; i++) 
	{
		CComPtr<EnvDTE::Document> pGenericDocIPtr;
		BSTR bstr = NULL;
		_bstr_t bstrRet("");
		spActiveDocs->Item(_variant_t(i, VT_I4), &pGenericDocIPtr);
 		pGenericDocIPtr->get_FullName(&bstr);
		bstrRet = _bstr_t(bstr, false);

		char* docPath = _com_util::ConvertBSTRToString(bstrRet.GetBSTR());
		CString sOpenedDocPath = docPath;
		delete[] docPath;

		// Confirm whether service file has already opened
		if (!sOpenedDocPath.CompareNoCase(sServiceHdrPath))
		{
			//CComQIPtr<ITextDocument, &IID_ITextDocument> pTextHdrDocQIPtr(pGenericDocIPtr);
			CComPtr<IDispatch> pTextHdrSelIPtr;
			if (FAILED(pGenericDocIPtr->get_Selection(&pTextHdrSelIPtr)))
			{
				return FALSE;   
			}
			
			CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextHdrSelQIPtr(pTextHdrSelIPtr);
			ParseEventIdListFromWnd(pTextHdrSelQIPtr, sServiceHdrPath, EventIdList);
			return TRUE;
		}
	}
	ParseEventIdListFromFile(sServiceHdrPath, EventIdList);

	size_t size = EventIdList.size();
	return TRUE;

}

/////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get Event id list by calling ParseEventIdList function
// INPUT: 1)sServiceHdrPath: Text selection of header file
//        2)EventIdList: Header file path
//
// OUTPUT: 1)TRUE: Success
//         2)FALSE: Fail
//
// Note: If the document is opened already, there is no necessary to open again.
//       Otherwise, open it right now.
/////////////////////////////////////////////////////////////////////////
BOOL DSUtils::CreateAppFiles(LPCTSTR sPrjName, LPCTSTR sAppName, LPCTSTR sEntryFuncName, LPCSTR sExitFuncName)
{
	char *sNote = "NOTE: The StateWizard will add mapping macros between /*{{ and /*}}. Do NOT modify manually.";
	_bstr_t bstrPath = GetProjectDir(sPrjName);
	char* tempPath = _com_util::ConvertBSTRToString(bstrPath.GetBSTR());
	CString strPrjPath = tempPath;
	delete []tempPath;
		
    CString strAppName = sAppName;
 	CString sFileHFullPath = strPrjPath + "\\"+sAppName+".h";
	CString sFileCFullPath;
	
	
	if(g_nFileType==APPTYPE_CLASS || g_nFileType==APPTYPE_CPP_FILE)
	 sFileCFullPath = strPrjPath + "\\"+sAppName+".cpp";
	else 
	 sFileCFullPath = strPrjPath + "\\"+sAppName+".c";

	CStdioFile AppHFile; // .h file to be created 
	CStdioFile AppCFile; // .c file to be created


	CString sAppClass="C" + strAppName;
	CString sFuncClassPrev;
	if (g_nFileType==APPTYPE_CLASS)
		sFuncClassPrev = sAppClass + "::";

	// Create the head file 
	if(! AppHFile.Open(LPCTSTR(sFileHFullPath),CFile::modeCreate|CFile::modeReadWrite|CFile::typeText))
	{
#ifdef _DEBUG
		afxDump<<"AppHFile could not be opened"<<"\n";
#endif
		return FALSE;// exit(1);
	}
	else
	{
		CString sUpperAppName = strAppName;
		sUpperAppName.MakeUpper();

		CString sHeaderFormat = "/*\nFILE:%s.h\n%s\n*/\n\n#ifndef %s_H\n#define %s_H\n\n#include \"sme.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
		CString sHeader; 
		sHeader.Format(sHeaderFormat, strAppName, sNote, sUpperAppName, sUpperAppName);

		CString sStateDeclare;
		sStateDeclare = "SME_BEGIN_STATE_DECLARE("+strAppName+")\n\t/*{{SME_STATE_DECLARE("+strAppName+
			   ")*/\n\tSME_STATE_DECLARE("+strAppName+")\n\tSME_MAX_STATE("+strAppName+
			   ")\n\t/*}}SME_STATE_DECLARE*/\nSME_END_STATE_DECLARE\n\n";

		CString sBegin = "/*{{SME_BEGIN_EVENT_HANDLER("+strAppName+")*/\n";
		CString sEndHdndler = "/*}}SME_END_EVENT_HANDLER*/\n\n";
		CString sEndHdr = "#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n";

		CString sBaseClass="SME_APP_T";

		CString sAppClassHdr;
		sAppClassHdr="class " + sAppClass+": public SME_APP_T\n{\npublic:\n\t" + sAppClass 
			+ "(const char* _sAppName, const struct SME_STATE_TREE_TABLE_T *_pStateTree):" + sBaseClass + "(_sAppName, _pStateTree) {};\n\n";

		CString sAppClassDeclare;
		sAppClassDeclare = "SME_BEGIN_APP_CLASS_DECLARE("+sAppClass+","+sBaseClass+")\n\t/*{{SME_APP_CLASS_DECLARE("+strAppName+","+sAppClass+","+sBaseClass+
			   ")*/\n\tSME_STATE_EVT_HDL_TBL_DEC("+strAppName+")\n\tSME_STATE_TREE_DEC("+strAppName+
			   ")\n\t/*}}SME_APP_CLASS_DECLARE*/\nSME_END_APP_CLASS_DECLARE\n\n";

		CString sEntryFunc = "";
		CString sExitFunc = "";


		// No function class prefix in header file.
		if (strcmp(sEntryFuncName, "SME_NULL") != 0)
			sEntryFunc = "int "+ CString(sEntryFuncName)+STR_HDLER_PROTOTYPE + ";\n";
		if (strcmp(sExitFuncName, "SME_NULL") != 0)
			sExitFunc = "int "+ CString(sExitFuncName)+STR_HDLER_PROTOTYPE + ";\n";

		AppHFile.WriteString(LPCTSTR(sHeader));
		if (g_nFileType==APPTYPE_CLASS)
			AppHFile.WriteString(LPCTSTR(sAppClassHdr));
		AppHFile.WriteString(LPCTSTR(sStateDeclare));
		if (g_nFileType==APPTYPE_CLASS)
			AppHFile.WriteString(LPCTSTR(sAppClassDeclare));
		AppHFile.WriteString(LPCTSTR(sBegin));
		if (sEntryFunc != "")
			AppHFile.WriteString(LPCTSTR(sEntryFunc));
		if (sExitFunc != "")
			AppHFile.WriteString(LPCTSTR(sExitFunc));
		AppHFile.WriteString(LPCTSTR(sEndHdndler));

		if (g_nFileType==APPTYPE_CLASS)
			AppHFile.WriteString("};\n\n");

		AppHFile.WriteString(LPCTSTR(sEndHdr));

		AppHFile.Close();
	}

	// Create the source file	
	if(! AppCFile.Open(LPCTSTR(sFileCFullPath),CFile::modeCreate|CFile::modeReadWrite|CFile::typeText))
	{
#ifdef _DEBUG
		afxDump<<"AppCFile could not be opened"<<"\n";
#endif
		return FALSE; //exit(1);
	}
	else
	{
		CString sText;
		sText.Format("/*\nFILE: %s.c/cpp\n%s\n*/\n\n#include \"sme.h\"\n#include \"%s.h\"\n\n", strAppName, sNote, strAppName);	

		CString sHandlerClass;
		if (g_nFileType==APPTYPE_CLASS)
			sHandlerClass.Format("SME_HANDLER_CLASS_DEF(%s)\n\n", strAppName); 


		CString sAppDef = "SME_BEGIN_STATE_DEF("+strAppName+ ","+strAppName+")\n\t/*{{SME_STATE_DEF("+strAppName+","+strAppName+
		")*/\n\tSME_STATE_ENTRY_FUNC("+sEntryFuncName+")\n\tSME_STATE_EXIT_FUNC("+sExitFuncName+
		")\n\t/*}}SME_STATE_DEF*/\nSME_END_STATE_DEF\n\n";
		sAppDef =sText+sHandlerClass+sAppDef;

		CString sSeparator1="/*{{SME_STATE_STATETREE_SEPARATOR}}*/\n\n";

		CString sStateTreeDEF;
		sStateTreeDEF="SME_BEGIN_STATE_TREE_DEF("+strAppName+
			          ")\n\t/*{{SME_STATE_TREE_DEF("+strAppName+")*/\n\tSME_STATE("+strAppName+","+
					  strAppName+",SME_INVALID_STATE,-1)\n\t/*}}SME_STATE_TREE_DEF*/\nSME_END_STATE_TREE_DEF\n\n";
        
		CString sSepatator2;
		sSepatator2.Format("/*{{SME_DEC_IMP_SEPARATOR}}*/\n\nSME_APPLICATION_DEF(%s, \"%s\")\n\n", strAppName, strAppName);

		CString sEntryFunc = "";
		CString sExitFunc = "";

		if (strcmp(sEntryFuncName, "SME_NULL") != 0)
			sEntryFunc="int "+ sFuncClassPrev + CString(sEntryFuncName)+STR_HDLER_PROTOTYPE + "\n{\n\treturn 0;\n}\n\n";
		if (strcmp(sExitFuncName, "SME_NULL") != 0)
			sExitFunc="int "+ sFuncClassPrev + CString(sExitFuncName)+STR_HDLER_PROTOTYPE + "\n{\n\treturn 0;\n}\n\n";


		AppCFile.WriteString(LPCTSTR(sAppDef));
		AppCFile.WriteString(LPCTSTR(sSeparator1));
		AppCFile.WriteString(LPCTSTR(sStateTreeDEF));
		AppCFile.WriteString(LPCTSTR(sSepatator2));
		if (sEntryFunc != "")
			AppCFile.WriteString(LPCTSTR(sEntryFunc));
		if (sExitFunc != "")
			AppCFile.WriteString(LPCTSTR(sExitFunc));
		
		AppCFile.Close();
	}
	return TRUE;

}

BOOL DSUtils::ExecuteCommand(_bstr_t &commandName)
{
	HRESULT re = g_pDTE->ExecuteCommand(commandName.GetBSTR(),CComBSTR(""));
	if(SUCCEEDED(re))
		return TRUE;
	else
		return FALSE;

}
BOOL DSUtils::IsFileOpen(_bstr_t& FileName)
{
	ATLASSERT(g_pDTE != NULL );
	CComPtr<EnvDTE::ItemOperations> m_pItemOperation;
	HRESULT re = g_pDTE->get_ItemOperations(&m_pItemOperation);
	ATLASSERT(SUCCEEDED(re));

	CComBSTR viewTye(EnvDTE::vsViewKindCode);
	VARIANT_BOOL  ifOpen;
	re = m_pItemOperation->IsFileOpen(FileName.GetBSTR(),viewTye,&ifOpen);
	ATLASSERT(SUCCEEDED(re));
	return ifOpen==-1 ? TRUE:FALSE ;
	
}

// If lineNumber is -1; just activate the file only.
BOOL DSUtils::OpenFileAndMoveLineTo(_bstr_t& FilePath,long lineNumber)
{
	if(!IsFileOpen(FilePath))
	{
		if(!OpenFile(FilePath))
			return FALSE;
	}

	CComPtr<EnvDTE::Documents> docs = NULL;
	g_pDTE->get_Documents(&docs);

	long docCount;
	docs->get_Count(&docCount);
	for(long i=1;i<=docCount;i++)
	{
		CComVariant var(i);
		CComPtr<EnvDTE::Document> doc;
		docs->Item(var,&doc);
		BSTR fileFullName;
		doc->get_FullName(&fileFullName);
		if(wcscmp(FilePath.GetBSTR(),fileFullName)==0)
		{
			doc->Activate();
			if (lineNumber!=-1)
			{
			CComPtr<IDispatch> docDispatch;
			doc->get_Selection(&docDispatch);
			CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> textSel(docDispatch);
			//Edited By Fengxin
			textSel->GotoLine(lineNumber,VARIANT_FALSE);
			//textSel->MoveTo(lineNumber,0,VARIANT_BOOL(EnvDTE::dsMove));
			}
			return TRUE; //??????? Memory Leaks
		}
		::SysFreeString(fileFullName); //?????????????????????

	}
	return FALSE;
}

///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Store the parameter to the ini file
// INPUT: 1).The section name 2)The key name 3) The value according to the key
// OUTPUT: True:Success False: Failed
// NOTE: 
///////////////////////////////////////////////////////////////////////////////////////////
BOOL DSUtils::PutParamStoreValue(LPCTSTR sSection, LPCTSTR sKey, LPCTSTR Value)
{
	return CParamStore::GetInstance().PutValue(sSection,sKey,Value);
}
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get the max level of displaying the state tree
// INPUT: 
// OUTPUT: The max level
// NOTE: 
///////////////////////////////////////////////////////////////////////////////////////////
int DSUtils::GetGMaxLevelNul()
{
	return g_nMaxLevelNum;
}
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION:Get the file Type 
// INPUT: 
// OUTPUT: 0 means *.cpp,1 means *.c 
// NOTE: 
///////////////////////////////////////////////////////////////////////////////////////////
int DSUtils::GetGFileType()
{
	return g_nFileType;
}



/////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Parse file syntax to get list of event id
// INPUT: 1)pTextHdrSelQIPtr: Text selection of header file
//        2)sServiceHdrPath: Header file path
//        3)EventIdList: Array to store event id
//
// OUTPUT: 1)TRUE: Success
//         2)FALSE: Fail
//
// Note: Key word to match is /*{{SME_EVENT_ID_LIST_DECLARE*/ and 
//       /*}}SME_EVENT_ID_LIST_DECLARE*/. They give the boundary of declared
//       event id list.
/////////////////////////////////////////////////////////////////////////
BOOL DSUtils::ParseEventIdListFromWnd(CComQIPtr<EnvDTE::TextSelection, &EnvDTE::IID_TextSelection> pTextHdrSelQIPtr, 
							   LPCTSTR sServiceHdrPath,
							   vector<_bstr_t> &EventIdList)
{ 
	
	long nOriginLineNo;
	pTextHdrSelQIPtr->get_CurrentLine(&nOriginLineNo); 
	long nOriginColNo;
	pTextHdrSelQIPtr->get_CurrentColumn(&nOriginColNo); 
	
	VARIANT_BOOL vbFound;  
	// search for the StateHead declaration
	//pTextHdrSelQIPtr->SelectAll();
	pTextHdrSelQIPtr->EndOfDocument(VARIANT_FALSE);// NOTE: ? Move to the end of document, FindText() will take effect.

	if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR("/*{{SME_EVENT_ID_LIST_DECLARE*/"), EnvDTE::dsMatchFromStart, &vbFound)) || ! vbFound)//EnvDTE::dsMatchFromStart, &vbFound)) || ! vbFound)
	{
		MessageBox(NULL,_T((CString)sServiceHdrPath+"  error:/*{{SME_EVENT_ID_LIST_DECLARE*/ expected."),NULL,MB_ICONERROR|MB_OK);
		return FALSE;
	}
	
	// move the cursor to the end of matching line
	if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;
	
	long nBeginLine;
	pTextHdrSelQIPtr->get_CurrentLine(&nBeginLine); 
	
	// Search for StateEnd declaration
	if (FAILED(pTextHdrSelQIPtr->FindText(CComBSTR("/*}}SME_EVENT_ID_LIST_DECLARE*/"), EnvDTE::dsMatchForward,&vbFound)) || !vbFound)//EnvDTE::dsMatchForward, &vbFound)) || !vbFound)
	{
		MessageBox(NULL,_T((CString)sServiceHdrPath+"  error:/*}}SME_EVENT_ID_LIST_DECLARE*/ expected."),NULL, MB_ICONERROR|MB_OK);
		return FALSE;
	}
	// Move the cursor to the end of matching line
	if (FAILED(pTextHdrSelQIPtr->EndOfLine(EnvDTE::dsMove)))//CComVariant(dsMove))))
		return FALSE;
	
	long nEndLine;
	pTextHdrSelQIPtr->get_CurrentLine(&nEndLine);

	long nHdrLine = nBeginLine+1;

	CString sText = "";
	BOOL bStillComment = FALSE; // Mark whether it is backslash at the end of line. If it is, then need to concatenate two lines

	// Eliminate // comments
	while (true)
	{
		if (nHdrLine >= nEndLine)
			break;
		
		if (FAILED(pTextHdrSelQIPtr->MoveTo(nHdrLine, 1,VARIANT_BOOL(EnvDTE::dsExtend)))) //CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextHdrSelQIPtr->StartOfLine(EnvDTE::vsStartOfLineOptionsFirstText,EnvDTE::dsMove)))//CComVariant(dsFirstText), CComVariant(dsMove))))
			return FALSE;
		if (FAILED(pTextHdrSelQIPtr->EndOfLine(VARIANT_BOOL(EnvDTE::dsExtend))))//CComVariant(dsExtend))))
			return FALSE;
		BSTR bstr = NULL;
		pTextHdrSelQIPtr->get_Text(&bstr);
		CString sResult(bstr);
		sResult.TrimLeft();
		sResult.TrimRight();
		sResult.Replace("\t", NULL);
		sResult.Replace(" ", NULL);
		
		if (!sResult.IsEmpty())
		{
			int idx = sResult.Find("//");
			int slashIdx = sResult.ReverseFind('\\');

			if (bStillComment == TRUE)
			{
				if (slashIdx != (sResult.GetLength()-1))
					bStillComment = FALSE;
			}
			else
			{
				if (idx != -1)
				{
					sText += (sResult.Left(idx));
					if (slashIdx == (sResult.GetLength()-1))
						bStillComment = TRUE;
				}
				else
				{
					if (slashIdx == (sResult.GetLength()-1))
						sResult=sResult.Left(sResult.GetLength()-1);
					sText = sText + sResult;
				}
			}
		}
		nHdrLine++;
	}

	// Eliminate /**/ comments
	while (true)
	{
		int idx1 = sText.Find("/*");
		if (idx1 != -1)
		{
			int idx2 = sText.Find("*/", idx1+1);
			ATLASSERT(idx2 != -1);
			
			CString sTemp = sText.Left(idx1);
			sTemp += sText.Right(sText.GetLength()-idx2-2);
			sText = sTemp;
		}
		else
			break;
	}

	// Parse to get event id which is separated by comma
	EventIdList.clear();//.RemoveAll();
	while (true)
	{
		int idx = sText.Find(",");
		if (idx == -1)
		{
			sText.TrimLeft();
			sText.TrimRight();
			if (!sText.IsEmpty())
			{
				idx = sText.Find("=");
				if (idx != -1)
				{
					sText = sText.Left(idx);
					sText.TrimRight();
				}
				EventIdList.insert(EventIdList.end(),(_bstr_t)sText);//Add(sText);
			}
			break;
		}
		else
		{
			CString sEventId = sText.Left(idx);
			sText = sText.Right(sText.GetLength()-idx-1);
			sEventId.TrimLeft();
			sEventId.TrimRight();
			if (!sEventId.IsEmpty())
			{
				idx = sEventId.Find("=");
				if (idx != -1)
				{
					sEventId = sEventId.Left(idx);
					sEventId.TrimRight();
				}				
				EventIdList.insert(EventIdList.end(),(_bstr_t)sEventId);//Add(sEventId);
			}
		}
	}

	if (FAILED(pTextHdrSelQIPtr->MoveTo(nOriginLineNo, nOriginColNo, VARIANT_BOOL(EnvDTE::dsMove))))//CComVariant(dsMove))))
		return FALSE;
	return TRUE;
}


///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Get eventid List from eventid.h file
// INPUT: the full path of eventid.h file 
// OUTPUT: EventIdList
// NOTE: 
///////////////////////////////////////////////////////////////////////////////////////////

BOOL DSUtils::ParseEventIdListFromFile(LPCTSTR sServiceHdrPath,
									  vector<_bstr_t> &EventIdList)
{
	CStdioFile OpenedFile;		
	if (OpenedFile.Open(sServiceHdrPath, CFile::modeRead | CFile::typeText ) == 0)
	{
		// File exists in dsp file but does not exist in disk
		//				DSUtils(m_pApp).OutPutStringToPane("failure in create tag db: open a file\n");
		OutPutStringToPane(_bstr_t(_T((CString)sServiceHdrPath+"		error: unexpected failure to open this file. \n")));
		return FALSE;
	}
	
	CString sCurrentLine = "";
	CString sText = "";
	BOOL bIsFound = FALSE;
	BOOL bStillComment = FALSE;

	while (true)
	{
		// Read a line from the file.
		if (!OpenedFile.ReadString(sCurrentLine))
		{
			bIsFound = FALSE;
			break;
		}
		
		sCurrentLine.TrimLeft();
		sCurrentLine.TrimRight();
		if (sCurrentLine.IsEmpty())
			continue;

		if (bIsFound == TRUE)
		{
			int idx = sCurrentLine.Find("//");
			int slashIdx = sCurrentLine.ReverseFind('\\');
		    int nLen = sCurrentLine.GetLength();			
				
			if (bStillComment == TRUE)
			{
				if (slashIdx != (nLen-1))
					bStillComment = FALSE;
			}
			else
			{
				if (idx != -1)
				{
					sText += (sCurrentLine.Left(idx));
					if (slashIdx == (nLen-1))
						bStillComment = TRUE;
				}
				else
				{
					if (slashIdx == (nLen-1))
						sCurrentLine = sCurrentLine.Left(nLen-1);
					sText = sText + sCurrentLine;
				}
			}
		}
		if (sCurrentLine.Compare("/*{{SME_EVENT_ID_LIST_DECLARE*/") == 0)
			bIsFound = TRUE;
		if (sCurrentLine.Compare("/*}}SME_EVENT_ID_LIST_DECLARE*/") == 0)
			break;		
	}
	if (bIsFound == FALSE)
		return FALSE;

	OpenedFile.Close();

	// Eliminate /**/ comments
	while (true)
	{
		int idx1 = sText.Find("/*");
		if (idx1 != -1)
		{
			int idx2 = sText.Find("*/", idx1+1);
			ATLASSERT(idx2 != -1);
			
			CString sTemp = sText.Left(idx1);
			sTemp += sText.Right(sText.GetLength()-idx2-2);
			sText = sTemp;
		}
		else
			break;
	}

	// Parse to get event id which is separated by comma
	EventIdList.clear();//RemoveAll();
	while (true)
	{
		int idx = sText.Find(",");
		if (idx == -1)
		{
			sText.TrimLeft();
			sText.TrimRight();
			if (!sText.IsEmpty())
			{
				idx = sText.Find("=");
				if (idx != -1)
				{
					sText = sText.Left(idx);
					sText.TrimRight();
				}
				EventIdList.insert(EventIdList.end(),(_bstr_t)sText);//Add(sText);
			}
			break;
		}
		else
		{
			CString sEventId = sText.Left(idx);
			sText = sText.Right(sText.GetLength()-idx-1);
			sEventId.TrimLeft();
			sEventId.TrimRight();
			if (!sEventId.IsEmpty())
			{
				idx = sEventId.Find("=");
				if (idx != -1)
				{
					sEventId = sEventId.Left(idx);
					sEventId.TrimRight();
				}				
				EventIdList.insert(EventIdList.end(),(_bstr_t)sEventId);//Add(sEventId);
			}
		}
	}
	return TRUE;
}


/////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Output string to output window
// INPUT: 1)bstrText: string needs to be output
//      
// OUTPUT: 1)TRUE: Success
//         2)FALSE: Fail
/////////////////////////////////////////////////////////////////////////
BOOL DSUtils::OutPutStringToPane(_bstr_t bstrText)
{

	CComPtr<EnvDTE::Windows> wins = NULL;
	HRESULT re =  g_pDTE->get_Windows(&wins);
	if (FAILED(re) || wins == NULL)
		return FALSE;

	CComPtr<EnvDTE::Window> win;
	re = wins->Item(CComVariant(CComBSTR(EnvDTE::vsWindowKindOutput)),&win);

	if (FAILED(re) || win == NULL)
		return FALSE;

	CComPtr<IDispatch> spOutputWindowDisp;
	re = win->get_Object(&spOutputWindowDisp);
	if (FAILED(re) || spOutputWindowDisp == NULL)
		return FALSE;

	CComQIPtr<EnvDTE::OutputWindow> spOutputWindow = spOutputWindowDisp;
	if (spOutputWindow == NULL)
		return FALSE;

	CComPtr<EnvDTE::OutputWindowPanes> spOutputWindowPanes;
	re = spOutputWindow->get_OutputWindowPanes(&spOutputWindowPanes);
	if (FAILED(re) || spOutputWindowPanes == NULL)
		return FALSE;

	//first we should find if the out put window has exits
	long wincount = 0;
	BOOL IfNeedCreate = TRUE;
	spOutputWindowPanes->get_Count(&wincount);
	CComPtr<EnvDTE::OutputWindowPane> pan = NULL;
	
	if(wincount>0)
	{
		for(long i = 1;i<=wincount;i++)
		{
			CComVariant var(i);
			CComPtr<EnvDTE::OutputWindowPane> Pane;
			spOutputWindowPanes->Item(var,&Pane);

			BSTR paneName;
			Pane->get_Name(&paneName);
			_bstr_t fileNameWapper(paneName,false);
			if(fileNameWapper==_bstr_t(CComBSTR(OUTPUT_WINDOW_NAME),false))
			{
				IfNeedCreate = FALSE;
				pan = Pane;
				break;
			}
			
		}
	}
	if(IfNeedCreate==TRUE)
	{
		CComPtr<EnvDTE::OutputWindowPane> spOutputWindowPane;
		re = spOutputWindowPanes->Add(CComBSTR(OUTPUT_WINDOW_NAME), &spOutputWindowPane);
		if (FAILED(re) || spOutputWindowPane == NULL)
			return FALSE;

		spOutputWindowPane->OutputString(bstrText.GetBSTR());
		spOutputWindowPane->OutputString(CComBSTR(L"\r\n"));
	}
	else
	{
		pan->OutputString(bstrText.GetBSTR());
		pan->OutputString(CComBSTR(L"\r\n"));
	}
	return TRUE;

}

BOOL DSUtils::CleanPane()
{
	CComPtr<EnvDTE::Windows> wins = NULL;
	HRESULT re =  g_pDTE->get_Windows(&wins);
	if (FAILED(re) || wins == NULL)
		return FALSE;

	CComPtr<EnvDTE::Window> win;
	re = wins->Item(CComVariant(CComBSTR(EnvDTE::vsWindowKindOutput)),&win);

	if (FAILED(re) || win == NULL)
		return FALSE;

	CComPtr<IDispatch> spOutputWindowDisp;
	re = win->get_Object(&spOutputWindowDisp);
	if (FAILED(re) || spOutputWindowDisp == NULL)
		return FALSE;

	CComQIPtr<EnvDTE::OutputWindow> spOutputWindow = spOutputWindowDisp;
	if (spOutputWindow == NULL)
		return FALSE;

	CComPtr<EnvDTE::OutputWindowPanes> spOutputWindowPanes;
	re = spOutputWindow->get_OutputWindowPanes(&spOutputWindowPanes);
	if (FAILED(re) || spOutputWindowPanes == NULL)
		return FALSE;

	//first we should find if the out put window has exits
	long wincount = 0;
	BOOL IfNeedCreate = TRUE;
	spOutputWindowPanes->get_Count(&wincount);
	CComPtr<EnvDTE::OutputWindowPane> pan = NULL;
	
	if(wincount>0)
	{
		for(long i = 1;i<=wincount;i++)
		{
			CComVariant var(i);
			CComPtr<EnvDTE::OutputWindowPane> Pane;
			spOutputWindowPanes->Item(var,&Pane);

			BSTR paneName;
			Pane->get_Name(&paneName);
			_bstr_t fileNameWapper(paneName,false);
			if(fileNameWapper==_bstr_t(CComBSTR(OUTPUT_WINDOW_NAME),false))
			{
				IfNeedCreate = FALSE;
				pan = Pane;
				break;
			}
			
		}
	}
	if(IfNeedCreate==TRUE)
	{
		CComPtr<EnvDTE::OutputWindowPane> spOutputWindowPane;
		re = spOutputWindowPanes->Add(CComBSTR(OUTPUT_WINDOW_NAME), &spOutputWindowPane);
		if (FAILED(re) || spOutputWindowPane == NULL)
			return FALSE;
	}
	else
	{
		pan->Clear();
	}
	return TRUE;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
Alex "Question is more important than the answer."

Comments and Discussions