/***************************************************************************
**
**    $Header:   D:/EPSLDV1/SRC/LOG/ALIAS.CPP   1.7   20 Jun 1996 09:24:42   ZJRD  $
**
**    $Log:   D:/EPSLDV1/SRC/LOG/ALIAS.CPP  $
** 
**    Rev 1.7   20 Jun 1996 09:24:42   ZJRD
** EasyPack/SLD Version 1.20a
** 
**    Rev 1.5   10 Jun 1996 10:19:20   ZJRD
** EasyPack/SLD Version 1.20
** 
**    Rev 1.3   29 May 1996 09:28:22   ZJRD
** No change.
** 
**    Rev 1.2   16 May 1996 09:08:44   ZJRD
** No change.
** 
**    Rev 1.1   10 May 1996 09:08:14   ZJRD
** EasyPack/SLD Version 1.93
** 
**    Rev 1.0   02 May 1996 10:25:46   ZJRD
** Initial revision.
** 
****************************************************************************/

#include "stdafx.h"                                                      
#include <afxcoll.h>
#include "alias.h"     
#include "hosterrs.h"

#include <limits.h>
#define SIZE_T_MAX  UINT_MAX            /* max size for a size_t */


#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

#define COMMANDROOT(i) 		((CCommandRoot*)m_pData[i])     
#define COMMAND(i) 			((CCommand*)ComArray[i])     
#define ALIAS(i) 			((CAlias*)AliasArray[i])     

#define COM_NAME(i) 		ComArray[i]->strCommandName
#define COM_HINTS(i) 		((CCommand*)ComArray[i])->strHints
#define COM_PARA(i) 		((CCommand*)ComArray[i])->arrArgv
#define COM_PARA_NAME(i,j)  COM_PARA(i)[j]->strCommandName

#define ALIAS_NAME(i) 		AliasArray[i]->strCommandName    
#define ALIAS_COM(i) 		((CAlias*)AliasArray[i])->wCommandIndex
#define ALIAS_COM_NAME(i) 	COM_NAME(ALIAS_COM(i))
#define ALIAS_COM_HINTS(i) 	COM_HINTS(ALIAS_COM(i))


IMPLEMENT_SERIAL(CCommandArray, CObArray, 0)
IMPLEMENT_SERIAL(CCommandRoot, CObject, 0)
IMPLEMENT_SERIAL(CCommand, CCommandRoot, 0)
IMPLEMENT_SERIAL(CAlias, CCommandRoot, 0)

void ShowLine(char* pszBuffer);
extern char szAppPath[_MAX_PATH+1];
//extern char *szAppPath;

// array of command, alias or commandroot item
// all items are sorted by strCommandName, case insensitive


/////////////////////////////////////////////////////////////////////////////
//
//  Name:  CCommandArray()  
//
//  Description: Constructor, call base class constructor
//
//  Input:  
//
//  Output: 
//
//  Return: 
//
/////////////////////////////////////////////////////////////////////////////

CCommandArray::CCommandArray() : CObArray()
{
}
            

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  ~CCommandArray()  
//
//  Description: destructor, free item object memory 
//
//  Input:  
//
//  Output: 
//
//  Return: 
//
/////////////////////////////////////////////////////////////////////////////
            
CCommandArray::~CCommandArray()
{  
	for(int i=0; i<m_nSize; i++)
		delete m_pData[i];  // free command or alias or commandroot object
}              


/////////////////////////////////////////////////////////////////////////////
//
//  Name:  FirstMatch()  
//
//  Description: find first match item index from nFrom item to nTo item.
//  			 strlen(pszAbbr) no need to larger or equal bMinKeyword.
//
//  Input:  nFrom, nTo, pszAbbr
//
//  Output: 
//
//  Return: the first match item index,
//  if not found , return CCommandRoot::NOT_EXIST
//
/////////////////////////////////////////////////////////////////////////////

int 
CCommandArray::FirstMatch(int nFrom, int nTo, const char* pszAbbr)
{   
	if ( (m_nSize <= 0) || (nFrom > nTo) || (nFrom < 0) || (nTo > m_nSize-1)) 
		return CCommandRoot::NOT_EXIST;  
		
	int nFlag;	
		
	nFlag = COMMANDROOT(nFrom)->InCommand(pszAbbr);
		     
    if (nFlag > 0 ) // if First command is behind pszAbbr
    	return CCommandRoot::NOT_EXIST;
    else if (nFlag == 0)
    	return nFrom;

   	switch(nTo-nFrom)
   	{
   		case 0:    // only one item.
   			return CCommandRoot::NOT_EXIST;
   		case 1:  // only two items.
   			return COMMANDROOT(nTo)->InCommand(pszAbbr) == 0 ?
   				nTo : CCommandRoot::NOT_EXIST;
		default:  // larger than two items.
			if (COMMANDROOT(nTo)->InCommand(pszAbbr) < 0) // large than the last item
				return CCommandRoot::NOT_EXIST;
			else
			{
				int nIndex;
				if ((nIndex = FirstMatch(nFrom,(nTo+nFrom)/2,pszAbbr))>=0)
					return nIndex;
				else 
					return FirstMatch((nTo+nFrom)/2+1, nTo,pszAbbr);
			}
	} // end of switch
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  LastMatch()  
//
//  Description: find the last match item index from nFrom item to nTo item.
//  			 strlen(pszAbbr) no need to larger or equal bMinKeyword.
//
//  Input:  nFrom, nTo, pszAbbr
//
//  Output: 
//
//  Return: the last match item index,
//  if not found , return CCommandRoot::NOT_EXIST
//
/////////////////////////////////////////////////////////////////////////////
                                                  
int 
CCommandArray::LastMatch(int nFrom, int nTo, const char* pszAbbr)
{
   	if ( (m_nSize <= 0) || (nFrom > nTo) || (nFrom < 0) || (nTo > m_nSize-1)) 
		return CCommandRoot::NOT_EXIST;  
		
	int nFlag;	
		
	nFlag = COMMANDROOT(nTo)->InCommand(pszAbbr);
		     
    if (nFlag < 0 ) // if Last command is before pszAbbr
    	return CCommandRoot::NOT_EXIST;
    else if (nFlag == 0)
    	return nTo;

   	switch(nTo-nFrom)
   	{
   		case 0:    // only one item.
   			return CCommandRoot::NOT_EXIST;
   		case 1:  // only two items.
   			return COMMANDROOT(nFrom)->InCommand(pszAbbr) == 0 ?
   				nFrom : CCommandRoot::NOT_EXIST;
		default:  // larger than two items.
			if (COMMANDROOT(nFrom)->InCommand(pszAbbr) > 0) // less than first item
				return CCommandRoot::NOT_EXIST;
			else
			{
				int nIndex;
				if ((nIndex = LastMatch((nTo+nFrom)/2,nTo,pszAbbr)) >= 0)
					return nIndex;
				else 
					return LastMatch(nFrom, (nTo+nFrom)/2-1,pszAbbr);
			}
	} // end of switch
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  Expand()  
//
//  Description: expand pszAbbr to the complete command.
//
//  Input:  pszAbbr
//
//  Output: 
//
//  Return: the command index in ComArray
//  if not found , return CCommandRoot::NOT_EXIST
//
/////////////////////////////////////////////////////////////////////////////
               
int                                                  
CCommandArray::Expand(const char* pszAbbr)
{   
	if (m_nSize <= 0) return CCommandRoot::NOT_EXIST;
	
	int nFirst, nLast;                             
	
	if ((nFirst = FirstMatch(0,m_nSize-1,pszAbbr)) != CCommandRoot::NOT_EXIST)
		nLast = LastMatch(nFirst,m_nSize-1,pszAbbr);
	else return CCommandRoot::NOT_EXIST;
		
	
    int nAbbr = strlen(pszAbbr);        
    for(int i=nFirst; i<=nLast; i++)
    	if (nAbbr==COMMANDROOT(i)->bMinKeyword)  return i;
    	
    for(i=nFirst; i<=nLast; i++)
    	if (nAbbr>=COMMANDROOT(i)->bMinKeyword)  return i;
    
    return CCommandRoot::NOT_EXIST;
} 

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  InsertIndex()  
//
//  Description: find the index to insert a new item.
//				 the array is sorted 
//
//  Input:  pszCommand
//
//  Output: 
//
//  Return: the command index to insert pszCommand
//  if the command already exist, return CCommandRoot::EXIST
//
/////////////////////////////////////////////////////////////////////////////

int 
CCommandArray::InsertIndex(const char* pszCommand)
{
	if (m_nSize == 0) return 0; // if the array have zero item.
	if (CommandExist(pszCommand) != CCommandRoot::NOT_EXIST) 
		return CCommandRoot::EXIST;
	
	// nCurIndex is assigned in CommandExist function 
	if (nCurIndex != CCommandRoot::NOT_EXIST) 
		return nCurIndex;
	else  return (nCurIndex = LastLess(0,m_nSize-1,pszCommand));
}   
                                                     

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  MatchNum()  
//
//  Description: find the total match index .
//				 the array is sorted 
//
//  Input:  nFrom, nTo, pszAbbr
//
//  Output: nFrom is the first match index
//			nTo is the last match index
//
//  Return: TRUE if find one item at least.
//  		FALSE if no item was found.
//
/////////////////////////////////////////////////////////////////////////////
                                                     
BOOL 
CCommandArray::MatchNum(int& nFrom, int &nTo,const char* pszAbbr)
{
	if ((nFrom=FirstMatch(0,m_nSize-1,pszAbbr)) != CCommandRoot::NOT_EXIST)
	{   // if find first match item
		nTo = LastMatch(nFrom,m_nSize-1,pszAbbr); // nTo must equal or larger than nFrom
		return TRUE;
	}
	return FALSE;
}
	
	      
/////////////////////////////////////////////////////////////////////////////
//
//  Name:  LastLess()  
//
//  Description: find the last item sorted before pszCommand
//				 search from nForm to nTo
//				 the array is sorted 
//
//  Input:  nFrom, nTo ,pszCommand
//
//  Output: 
//
//  Return: the item index 
//
/////////////////////////////////////////////////////////////////////////////

int
CCommandArray::LastLess(int nFrom, int nTo, const char* pszCommand)
{                   
	if (m_nSize <= 0) return 0;
	if (nFrom < 0) nFrom = 0;
	if (nTo >= m_nSize) nTo = m_nSize-1;
	if (nFrom > nTo ) nFrom = nTo;      
		
	if (COMMANDROOT(nFrom)->strCommandName.CompareNoCase(pszCommand) > 0)
		return nFrom;       // less than the first item.
	if (COMMANDROOT(nTo)->strCommandName.CompareNoCase(pszCommand) < 0)
		return nTo+1;  // larger than the last item                                    
	
	if (nTo-nFrom<=1) return nTo; //only one or two items.
	
   	nCurIndex = LastLess((nFrom+nTo)/2,nTo-1,pszCommand); // first search in larger half array
	if (nCurIndex == (nFrom+nTo)/2 )  // search in the lower half array.
			return LastLess(0,(nFrom+nTo)/2 -1,pszCommand);
	else
			return nCurIndex;
} 
     

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  CommandExist()  
//
//  Description: find the pszCommand in the array, not expand pszCommand 
//
//  Input:  pszCommand
//
//  Output: 
//
//  Return: the command index in the array
//  if not find pszCommand, return CCommandRoot::NOT_EXIST
//
/////////////////////////////////////////////////////////////////////////////

int 
CCommandArray::CommandExist(const char* pszCommand)
{   
	
	if (m_nSize <= 0) return CCommandRoot::NOT_EXIST;
	nCurIndex = FirstMatch(0,m_nSize-1,pszCommand);

	if (nCurIndex == CCommandRoot::NOT_EXIST) return nCurIndex;
	else 
		return COMMANDROOT(nCurIndex)->strCommandName.CompareNoCase(pszCommand) == 0 ?
			nCurIndex : CCommandRoot::NOT_EXIST;
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  AbbrCommandExist()  
//
//  Description: find the pszCommand in the array, expand pszCommand 
//
//  Input:  pszCommand
//
//  Output: 
//
//  Return: the command index in the array
//  if not find pszCommand, return CCommandRoot::NOT_EXIST
//
/////////////////////////////////////////////////////////////////////////////

int 
CCommandArray::AbbrCommandExist(const char* pszAbbr)
{
	return (FirstMatch(0,m_nSize-1,pszAbbr) != CCommandRoot::NOT_EXIST);
}
               
/////////////////////////////////////////////////////////////////////////////
//
//  Name:  Add()  
//
//  Description: add newElement.
//				 if newElement already exist in the arrray, do nothing
//
//  Input:  newElement
//
//  Output: 
//
//  Return: the command index in the array
//  if newElement already exist, return CCommandRoot::EXIST
//
/////////////////////////////////////////////////////////////////////////////

int 
CCommandArray::Add(CCommandRoot* newElement)
{
	if ((nCurIndex = InsertIndex(newElement->strCommandName)) != CCommandRoot::EXIST)
	{
		InsertAt(nCurIndex,newElement); 
		return nCurIndex;
	}
	else return CCommandRoot::EXIST;
	
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  ShowCommand()  
//
//  Description: show all items in the array
//
//  Input:  
//
//  Output: 
//
//  Return: 
//  
//
/////////////////////////////////////////////////////////////////////////////

void
CCommandArray::ShowCommand()
{
	for(int i=0; i<m_nSize; i++)
		((CCommandRoot*)m_pData)->ShowCommand();
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  operator[]()  
//
//  Description: define operator [] to support general array operation 
//
//  Input:  nIndex
//
//  Output: 
//
//  Return: the specify item in the array
//  		return NULL if nIndex is invalid
//
/////////////////////////////////////////////////////////////////////////////

CCommandRoot* CCommandArray::operator[](int nIndex) const
{
	if ((nIndex >= 0) && (nIndex < m_nSize))
		return (CCommandRoot*)m_pData[nIndex];
	else return (CCommandRoot*)NULL;
}
			                                
/////////////////////////////////////////////////////////////////////////////
//
//  Name:  CCommandRoot()  
//
//  Description: default constructor of CCommandRoot 
//
//  Input: 
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////
			                                                  
CCommandRoot::CCommandRoot() : strCommandName()
{                                             
	bMinKeyword = 0;
}                   
    
/////////////////////////////////////////////////////////////////////////////
//
//  Name:  CCommandRoot()  
//
//  Description: constructor of CCommandRoot 
//
//  Input:  pszName, bNum
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////
    
CCommandRoot::CCommandRoot(const char* pszName, BYTE bNum) 
	: strCommandName(pszName)
{                                             
	bMinKeyword = bNum;
}                   

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  CCommandRoot()  
//
//  Description: constructor of CCommandRoot 
//
//  Input:  commandroot
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

CCommandRoot::CCommandRoot(const CCommandRoot& commandroot)
{                            
	strCommandName = commandroot.strCommandName;
	bMinKeyword = commandroot.bMinKeyword;
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  ~CCommandRoot()  
//
//  Description: destructor of CCommandRoot 
//
//  Input:  
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////
         
CCommandRoot::~CCommandRoot()
{
	strCommandName.Empty();
}      

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  operator=()  
//
//  Description: support operator assign operation 
//
//  Input:  
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

const CCommandRoot& 
CCommandRoot::operator=(const CCommandRoot& commandroot)
{
	strCommandName = commandroot.strCommandName;
	bMinKeyword = commandroot.bMinKeyword;  
	return *this;
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  InCommand()  
//
//  Description: compare strCommandName and pszAbbr at least strlen(pszAbbr) 
//				 @ and $ are different to compare
//
//  Input:  pszAbbr
//
//  Output: 
//
//  Return: same as strnicmp()
//  
//
/////////////////////////////////////////////////////////////////////////////

int
CCommandRoot::InCommand(const char* pszAbbr)
{                                          
	ASSERT(pszAbbr);            
//Modify for 1.2
/*	
	if ((strCommandName[0] == '@') || (strCommandName[0] == '$') )
		return (strCommandName[0] - tolower(pszAbbr[0]));
*/		
	return strnicmp(strCommandName,pszAbbr,strlen(pszAbbr));
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  ShowCommand()  
//
//  Description: 
//
//  Input:  
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

void
CCommandRoot::ShowCommand()
{
	// ShowLine(strCommandName);
}


/////////////////////////////////////////////////////////////////////////////
//
//  Name:  Serialize()  
//
//  Description: to store data to or load data from ar
//
//  Input: ar
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

void 
CCommandRoot::Serialize(CArchive& ar)
{
	if(ar.IsStoring())
		ar << strCommandName << bMinKeyword;
	else
		ar >> strCommandName >> bMinKeyword;
} 

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  CCommand()  
//
//  Description: Constructor of CCommand
//
//  Input:  
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////
                                           
CCommand::CCommand() : CCommandRoot(), strHints()
{               
	Init();                              
}                   

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  CCommand()  
//
//  Description: Constructor
//
//  Input:  pszName, bNum, pszHints
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

CCommand::CCommand(const char* pszName, BYTE bNum,const char* pszHints) 
	: CCommandRoot(pszName,bNum), strHints(pszHints)
{          
	Init();                                   
}
                                   
/////////////////////////////////////////////////////////////////////////////
//
//  Name:  CCommand()  
//
//  Description: constructor of CCommand
//
//  Input:  command
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////
                                   
CCommand::CCommand(const CCommand& command)
	: CCommandRoot(command.strCommandName,command.bMinKeyword),
	  strHints(command.strHints)
{                                        
	Init();
}                   

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  ~CCommand()  
//
//  Description: deconstructor of CCommand
//
//  Input:  
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

CCommand::~CCommand()
{
	strHints.Empty(); 
}      

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  operator=  
//
//  Description: support assign operation
//
//  Input:  
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////
         
const CCommand& 
CCommand::operator=(const CCommand& command)
{
	strCommandName = command.strCommandName;
	bMinKeyword = command.bMinKeyword;
	strHints = command.strHints; 
	
	arrArgv.SetSize(0);
	arrArgv.InsertAt(0,(CObArray*)&command.arrArgv);
	  
	return *this;
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  ShowCommand()  
//
//  Description: show command name and  hints
//
//  Input:  
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

void
CCommand::ShowCommand()
{
	 char buf[300];
	 
	 strcpy(buf,strCommandName);
	 if ((strCommandName[0] != '@') &&
		(strCommandName[0] != '$'))
			strcat(buf," ");
	 strcat(buf,strHints);	 
	 ShowLine(buf);
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  CompleteHints()  
//
//  Description: get this command commpete hints
//
//  Input:  pszHints
//
//  Output: store complete hints in pszHints
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

void 
CCommand::CompleteHints(char* pszHints)
{
	ASSERT(pszHints);
	
	strcpy(pszHints,strCommandName);
	
	if ( (strCommandName[0] != '@') && 
	   (strCommandName[0] != '$') )
		strcat(pszHints," "); //add a blank.
	
	strcat(pszHints, strHints);
}	

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  Serialize()  
//
//  Description: store data to ar or load data from ar
//
//  Input:  
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

void 
CCommand::Serialize(CArchive& ar)
{
	CCommandRoot::Serialize(ar);
	if(ar.IsStoring())
		ar << strHints;
	else
		ar >> strHints;
	arrArgv.Serialize(ar);
} 
                                           
/////////////////////////////////////////////////////////////////////////////
//
//  Name:  CAlias()  
//
//  Description: default constructor of CAlias
//
//  Input:  
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

CAlias::CAlias() : CCommandRoot()
{               
	wCommandIndex = WORD(-1);                           
}                   

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  CAlias()  
//
//  Description: Constructor of CAlias
//
//  Input:  pszName, bNum, wIndex
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

CAlias::CAlias(const char* pszName, BYTE bNum, WORD wIndex) 
	: CCommandRoot(pszName,bNum)
{          
	wCommandIndex = wIndex;
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  CAlias()  
//
//  Description: Constructor of CAlias
//
//  Input:  alias
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

CAlias::CAlias(const CAlias& alias)
	: CCommandRoot(alias.strCommandName, alias.bMinKeyword)
{                                        
	wCommandIndex = alias.wCommandIndex;
}                   
                 
/////////////////////////////////////////////////////////////////////////////
//
//  Name:  ~CAlias()  
//
//  Description: destructor of CAlias
//
//  Input:  
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////
                 
CAlias::~CAlias()
{
}      

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  operator=  
//
//  Description: support assign operation 
//
//  Input:  alias
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

const CAlias& 
CAlias::operator=(const CAlias& alias)
{
	strCommandName = alias.strCommandName;
	bMinKeyword = alias.bMinKeyword;
	wCommandIndex = alias.wCommandIndex;
	  
	return *this;
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  ShowCommand()  
//
//  Description: 
//
//  Input:  
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

void
CAlias::ShowCommand()
{
	// ShowLine(strCommandName); 
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  Serialize()  
//
//  Description: store object to ar or load object from ar 
//
//  Input:  
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

void 
CAlias::Serialize(CArchive& ar)
{
	CCommandRoot::Serialize(ar);
	if(ar.IsStoring())
		ar << wCommandIndex;
	else
		ar >> wCommandIndex;
	
} 

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  CCommandSet()  
//
//  Description: Constructor of CCommandSet
//				 load data from command.lst to initialize ComArray	               
//
//  Input:  
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////
                                           
CCommandSet::CCommandSet()
{

	CString pFileName = CString(::szAppPath)+"command.dat";
	
	CFile f;
	char buf[512];
	if( !f.Open( pFileName, CFile::modeRead ) ) {
   		#ifdef _DEBUG
    	  afxDump << "Unable to open file" << "\n";
      	#endif                        
      	AfxMessageBox("Command.dat file not find");
      	return;
    }
	CArchive ar( &f, CArchive::load, 512, buf );
	ComArray.Serialize(ar);			                  
	HiddenComArray.Serialize(ar);
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  ~CCommandSet()  
//
//  Description: Destructor of CCommandSet
//
//  Input:  
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

CCommandSet::~CCommandSet()
{
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  AliasCmd()  
//
//  Description: list all alias or add a new alias
//
//  Input:  
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

void 
CCommandSet::AliasCmd(int m_nArgc, char* m_pszArgv[])
{
	char ErrBuf[100];                
	unsigned long  nErrId;

	switch(m_nArgc){
		case 1:  // show all alias.
		{                                          
			ASSERT(m_pszArgv[0] != NULL);
			char szbuf[60];
			for(int i=0; i<AliasArray.GetSize();i++)
			{   
				strcpy(szbuf,ALIAS_COM_NAME(i));  // command name
				strcat(szbuf," ");
				strcat(szbuf,ALIAS_NAME(i)); // alias name
				ShowLine(szbuf);
			}
			return;
		}
		case 3:  // add a new alias.         
		{
			int  nCommandIndex;
			
			ASSERT(m_pszArgv[0] != NULL);
			ASSERT(m_pszArgv[1] != NULL);
			ASSERT(m_pszArgv[2] != NULL);
			
			if ((nCommandIndex = ComArray.CommandExist(
				(const char*)m_pszArgv[1])) == CCommandRoot::NOT_EXIST)
			{  // old command not find.
				nErrId = ER_SYN_COMMAND_NOT_FIND;
				break;
			}
			
			if ((COM_NAME(nCommandIndex)[0] == '@') || 
				(COM_NAME(nCommandIndex)[0] == '$'))
			{ // user want give @ or $ a alias name
				nErrId = ER_SYN_NOT_HAVE_ALIAS;
				break;
			}
			
			if (strlen(m_pszArgv[2]) > 20)
			{  // alias name is more than 20 characters.
				nErrId = ER_SYN_ALIAS_LEN_20;
				break;
			}
			
			if (ComArray.CommandExist(
					(const char*)m_pszArgv[2]) != CCommandRoot::NOT_EXIST)
			{  // alias name is same as one command name
			    nErrId = ER_SYN_ALIAS_DIFFERENT;
				break;
			}
			
			CAlias *alias;                              
			alias = new CAlias((const char*)m_pszArgv[2],
						(BYTE)strlen(m_pszArgv[2]), (WORD)nCommandIndex); 	
			if( AliasArray.Add(alias) == CCommandRoot::EXIST){
				nErrId = ER_SYN_ALIAS_EXIST;  // alias already exist
				delete alias; // free the object.
				break;
			}
			
			return;   
			
		} // end of case 3
	  default:
			return;
	} // end of switch
	                 
	// display error message.	                 
	if (ErrGetErrorText(nErrId, ErrBuf) == GOOD)
		ShowLine(ErrBuf);
	
}
                                       
/////////////////////////////////////////////////////////////////////////////
//
//  Name:  HelpCmd()  
//
//  Description: show all command or show one command
//
//  Input: m_nArgc, m_pszArgv[] 
//
//  Output: 
//
//  Return:
//  
//
/////////////////////////////////////////////////////////////////////////////

void 
CCommandSet::HelpCmd(int m_nArgc, char* m_pszArgv[])
{
	switch(m_nArgc){
		case 1:  // show all command help.
		{                                          
			ASSERT(m_pszArgv[0] != NULL);
			
			for(int i=0; i<ComArray.GetSize();i++)
			{   
				ComArray[i]->ShowCommand();
			}
			break;
		}
		case 2:  //  show one command help.         
		{
			int nCommandIndex;                
			
			ASSERT(m_pszArgv[0] != NULL);
			ASSERT(m_pszArgv[1] != NULL);
						
			if ((nCommandIndex = ComArray.CommandExist(
				(const char*)m_pszArgv[1])) == CCommandRoot::NOT_EXIST)
			{  // old command not find.
				ShowLine("no this command");
				return;
			}                            
			else
				ComArray[nCommandIndex]->ShowCommand();
			break;
		}
	}
}	
				

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  GetCommandId()  
//
//  Description: find index of the command in command array
//
//  Input:  pszCommand
//
//  Output: 
//
//  Return: index of the command
//			return CCommandSet::NO_COMMAND if the command is not found  
//
/////////////////////////////////////////////////////////////////////////////

int 
CCommandSet::GetCommandId(const char* pszCommand)
{                                          
	ASSERT(pszCommand);
	
	int nIndex;
	nIndex = ComArray.CommandExist(pszCommand);
	return (nIndex != CCommandRoot::NOT_EXIST) ? nIndex : NO_COMMAND;
}   

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  GetTotalCommandId()  
//
//  Description: find index of the command in command array and hiden command array
//
//  Input:  pszCommand
//
//  Output: 
//
//  Return: index of the command
//			return CCommandSet::NO_COMMAND if the command is not found  
//
/////////////////////////////////////////////////////////////////////////////

int 
CCommandSet::GetTotalCommandId(const char* pszCommand)
{                                          
	ASSERT(pszCommand);
	
	int nIndex;       
	
	if ( (nIndex = GetCommandId(pszCommand)) != NO_COMMAND)
		return nIndex;
		
	nIndex = HiddenComArray.CommandExist(pszCommand);    
	
	return (nIndex != CCommandRoot::NOT_EXIST) ? 
		nIndex + ComArray.GetSize() : NO_COMMAND;
}   

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  SearchCommand()  
//
//  Description: search all match alias and command
//				 store nArgc command at least
//
//  Input:  pszCommand, nArgc, pszArgv[]
//
//  Output: store match number in nArgc
//			store match command name in pszArgv
//
//  Return: TRUE at least one item was found
//  		FALSE no item was found
//
/////////////////////////////////////////////////////////////////////////////
                                       
BOOL
CCommandSet::SearchCommand(const char* pszCommand, int &nArgc, char* pszArgv[])
{               
    ASSERT(pszCommand);             
    ASSERT(nArgc > 0);

//Modify for 1.2
/*	
	if ((pszCommand[0] == '@') || (pszCommand[0] == '$') ){
	   	ExpandCommand(pszCommand, (char*)NULL, pszArgv[0]);
	   	nArgc = 1;
	   	return TRUE;
	  }
*/	
	int nFirst, nLast;                             
	int nMaxCom = nArgc;
	
	nArgc = 0;	
	if(AliasArray.MatchNum(nFirst, nLast, pszCommand))
	{ // find in alias table.
		nArgc = (nLast-nFirst+1 > nMaxCom) ? nMaxCom : nLast-nFirst+1;
		for(int i=0; i<nArgc; i++){
			ASSERT(pszArgv[i]);
			strcpy(pszArgv[i], ALIAS_NAME(nFirst+i));
		}                                                             
		if (nArgc >= nMaxCom) return TRUE;
	}
	
	if(ComArray.MatchNum(nFirst,nLast,pszCommand))
	{ // find in command table
		int nTotal = (nArgc+nLast-nFirst+1 > nMaxCom) ? 
			nMaxCom : nArgc+nLast-nFirst+1;
		
		for(int i=nArgc; i<nTotal; i++){
			ASSERT(pszArgv[i]);
			strcpy(pszArgv[i], COM_NAME(nFirst+i-nArgc));
		}
		nArgc = nTotal;
	}               
	return (nArgc != 0);
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  ExpandCommand()  
//
//  Description: expand pszCommand 
//
//  Input:  pszCommand, pszExpand, pszHints
//
//  Output: store complete command name or alias name in pszExpand
//			store command hints in pszHints
//
//  Return: return CCommandSet::ALIAS if pszCommand is alias name
//			return CCommandSet::COMMAND if pszCommand is command name
//  		return CCommandSet::NO_COMMAND if pszCommand is not alias name or command name
//
/////////////////////////////////////////////////////////////////////////////

int 
CCommandSet::ExpandCommand(const char* pszCommand,
	 char* pszExpand, char* pszHints)
{ 
	ASSERT(pszCommand);
		
	int nCurIndex; 
	
	if ((nCurIndex = AliasArray.Expand(pszCommand)) != CCommandRoot::NOT_EXIST)
	{   // first find in alias table.
		if (pszExpand != NULL) // if user need complete command name
			strcpy(pszExpand, ALIAS_COM_NAME(nCurIndex));
		if(pszHints != NULL)  // if user need hints    
			COMMAND(ALIAS_COM(nCurIndex))->CompleteHints(pszHints);
			
		return ALIAS;    // an alias name
	}

	if ((nCurIndex = ComArray.Expand(pszCommand)) != CCommandRoot::NOT_EXIST)
	{ // find in command table
		if (pszExpand != NULL) // if user need complete command name
			strcpy(pszExpand, COM_NAME(nCurIndex));
		if(pszHints != NULL){ // if user need hints
			COMMAND(nCurIndex)->CompleteHints(pszHints);
		}
		return COMMAND; // a command name
	}

	return NO_COMMAND;
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  ExpandParameter()  
//
//  Description: expand pszParameter of pszCommand 
//
//  Input: pszCommand, pszParameter, pszExpand 
//
//  Output: store complete parameter in pszExpand
//
//  Return: TRUE if find the parameter
//			FALSE if not find the parameter
//  
//
/////////////////////////////////////////////////////////////////////////////

BOOL
CCommandSet::ExpandParameter(const char* pszCommand,
	 const char* pszParameter, char* pszExpand)
{                 
  	ASSERT(pszCommand);
	ASSERT(pszParameter);
	ASSERT(pszExpand);
	
	int nCurIndex;   // command index in ComArray       
	
	if ((nCurIndex = AliasArray.Expand(pszCommand)) 
		!= CCommandRoot::NOT_EXIST)  // if pszCommand is an alias name
		nCurIndex = ALIAS_COM(nCurIndex);
	else nCurIndex = ComArray.Expand(pszCommand);  // see if a command name
	
	if (nCurIndex == CCommandRoot::NOT_EXIST)
		return FALSE; // not find pszCommand
		
	if ( (COM_NAME(nCurIndex).CompareNoCase("Help") == 0)
		 || (COM_NAME(nCurIndex).CompareNoCase("Alias") == 0) )
	// if command is help or alias , expand parameter according to command method
		return (ExpandCommand(pszParameter,pszExpand, (char*)NULL) == 
			CCommandSet::COMMAND);
							
	int nParaIndex;
	if ((nParaIndex = COM_PARA(nCurIndex).Expand(pszParameter)) 
				!= CCommandRoot::NOT_EXIST) 
	{
		strcpy(pszExpand,COM_PARA_NAME(nCurIndex,nParaIndex));
		return TRUE;
	}
	
	return FALSE;
}                            

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  GetEventName()  
//
//  Description: distinguish EV1, EV2, EV3 
//
//  Input: pszCommand
//
//  Output: store complete event name in EventName
//
//  Return: TRUE if successful
//			FALSE if failure
//  
//
/////////////////////////////////////////////////////////////////////////////

BOOL 
CCommandSet::GetEventName(CString& EventName,const char* pszCommand)
{
	int nEventId;                           
	nEventId = pszCommand[strlen(pszCommand)-1] - '0'; // get event id
	
	switch(nEventId){
		case 1:    
			EventName = "EV1";
			break;
		case 2:               
			EventName = "EV2";
			break;
		case 3:
			EventName = "EV3";
			break;
		default:
			return FALSE;         
		}       
		  
	return TRUE;     
}


/////////////////////////////////////////////////////////////////////////////
//
//  Name:  GetEventHints()  
//
//  Description: get pszCommand hints
// 				 special for Event 1|2|3
//
//  Input:  pszCommand, pszHints
//
//  Output: store command hints in pszHints
//
//  Return: return TRUE if sucessful
//  		return FALSE if fail
//
/////////////////////////////////////////////////////////////////////////////

BOOL
CCommandSet::GetEventHints(const char* pszCommand, char* pszHints)
{
	ASSERT(pszCommand);
	ASSERT(pszHints);
		
	CString EventName;
	                           
	if (!GetEventName(EventName,pszCommand) ) return FALSE;
	
	int nIndex;
	if ((nIndex = ComArray.CommandExist(EventName)) 
		!= CCommandRoot::NOT_EXIST)
	{
		strcpy(pszHints, pszCommand);
		strcat(pszHints, " ");
		strcat(pszHints, COM_HINTS(nIndex));
		return TRUE; 
	}

	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  ExpandEventPara()  
//
//  Description: expand pszParameter of pszCommand 
//
//  Input: pszCommand, pszParameter, pszExpand 
//
//  Output: store complete parameter in pszExpand
//
//  Return: TRUE if find the parameter
//			FALSE if not find the parameter
//  
//
/////////////////////////////////////////////////////////////////////////////

BOOL
CCommandSet::ExpandEventPara(const char* pszCommand, 
	const char* pszParameter, char* pszExpand)
{   
	ASSERT(pszCommand);
	ASSERT(pszParameter);
	ASSERT(pszExpand);
		
	CString EventName;
	
	if (!GetEventName(EventName,pszCommand) ) return FALSE;
                           
	return ExpandParameter(EventName,pszParameter,pszExpand);
}
	 
/*-------------------------end of file------------------------------*/

