
#include "stdafx.h"                                                      
#include <afxcoll.h>
#include "alias.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);
    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.dat 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[40];                
//    int  nErrId;

    switch(m_nArgc){
        case 1:  // show all alias.
        {                                          
            ASSERT(m_pszArgv[0] != NULL);
            char szbuf[50];
            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_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) == GOODD)
  //      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);
    
    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------------------------------*/

