/***************************************************************************
**
**    $Header$
**
**    $Log$
** 
****************************************************************************/

/***************************************************************************
**
** File name :  PERCORE.CPP
**
** Author:      Richard Guo
** Description: CPerCore implemented here.
**
** coding from: Oct 24, 1996
** Finished date:
**
**
**    Copyright (C) 1996 Microtek International, Inc.
**    All Rights Reserved
**                        
****************************************************************************/

#include "stdafx.h"
#include <assert.h>
#include <stdio.h>  
#include <ctype.h>     

#include "perbase.h"
#include "percore.h"
#include "regsvr.h"
#include "cpusvr.h"

#define KC196_WSR_DESCID	2902     
#define KC196_WSR_BASEID	480

#define ROOTINFOFF 5   // first register information site in m_wPerBase

// I do not put this data in string table only because its' information
// may be too long in one string. It also supports modifying as one please
// without caring about rc file string structure.
// It bring us additional codes to do with this difference.

WORD wPer_9X[] = {
 // total register number, control string space, control string start
 // description string space, description string start
 // each register index number
	7, 20, 100, 100, 1000,
	0, 1, 2, 3, 4, 5, 6
};

WORD wPer_196KA[] = {
 // total register number, control string space, control string start
 // description string space, description string start
 // each register index number
	18, 20, 100, 100, 1000,
	0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
	10, 11, 12, 13, 14, 15, 16, 17
};

WORD wPer_196KC[] = {
 // total register number, control string space, control string start
 // description string space, description string start
 // each register index number
	19, 20, 100, 100, 1000,
	0, 1, 2, 3, 4, 5, 6, 7, 8, 19,
	10, 20, 12, 21, 22, 15, 16, 17, 18
};

WORD wPer_196MC[] = {
 // total register number, control string space, control string start
 // description string space, description string start
 // each register index number
	37, 10, 100, 100, 2000,
	0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
	10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
	21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 
	32, 33, 34, 35, 36
};                    

WORD wPer_196MD[] = {
 // total register number, control string space, control string start
 // description string space, description string start
 // each register index number
	45, 10, 100, 100, 2000,
	0, 49, 50, 3, 4, 41, 42, 7, 8, 9,
	10, 11, 12, 13, 14, 15, 16, 17, 47, 48, 20,
	21, 22, 23, 64, 25, 26, 27, 28, 29, 30, 31, 
	32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44,
	45, 46
};                    

WORD wPer_196MH[] = {
 // total register number, control string space, control string start
 // description string space, description string start
 // each register index number
	42, 10, 100, 100, 2000,
	0, 57, 58, 51, 53, 54, 52, 7, 8, /*9,*/
	/*10,*/ 11, 12, 13, 69, 15, 16, 17, 55, 56, 20,
	21, 22, 63, 65, 25, 26, 27, 28, 29, 30, 31, 
	32, 33, 34, 35, 36, 59, 60, 61, 62, 66, 67, 68
};                    


	
CPerCore::CPerCore(WORD wCpuID1, HINSTANCE hPerLib1)
{                 
	m_wCpuID  = wCpuID1;
	hPerLib = hPerLib1;
	
	SetTable();
	
    m_wRootCount = m_wPerBase[0];
    m_wRootBaseSpace = m_wPerBase[1];
    m_wRootBaseStart = m_wPerBase[2];   
    m_wDescBaseSpace = m_wPerBase[3];
    m_wDescBaseStart = m_wPerBase[4];
}

void CPerCore::SetTable()
{
    if (m_wCpuID>=EP9X_CPUID_START && m_wCpuID<=EP9X_CPUID_END)
         m_wPerBase = wPer_9X;
	else if (m_wCpuID>=EP196KA_CPUID_START && m_wCpuID<=EP196KA_CPUID_END)
         m_wPerBase = wPer_196KA;
	else if (m_wCpuID>=EP196KB_CPUID_START && m_wCpuID<=EP196KB_CPUID_END)
         m_wPerBase = wPer_196KA;
	else if (m_wCpuID>=EP196KC_CPUID_START && m_wCpuID<=EP196KC_CPUID_END)
         m_wPerBase = wPer_196KC;   
	else if (m_wCpuID>=EP196MC_CPUID_START && m_wCpuID<=EP196MC_CPUID_END)
         m_wPerBase = wPer_196MC;   
	else if (m_wCpuID>=EP196MD_CPUID_START && m_wCpuID<=EP196MD_CPUID_END)
         m_wPerBase = wPer_196MD; 
	else if (m_wCpuID>=EP196MH_CPUID_START && m_wCpuID<=EP196MH_CPUID_END)
         m_wPerBase = wPer_196MH;   
	else m_wPerBase = NULL;
}

WORD CPerCore::RootItemCount()
{
	return m_wRootCount;
}

inline WORD CPerCore::RootChildToIndex(WORD wChild)
{
	if (wChild >= m_wRootCount) wChild = m_wRootCount - 1;
	return m_wPerBase[ROOTINFOFF+wChild];
}
                                 
WORD CPerCore::RootIndexToChild(WORD wIndex)
{
	for (WORD i=0; i<m_wRootCount; i++){
		if (wIndex== m_wPerBase[ROOTINFOFF+i])
			return i;
	}
	assert(0);
	return 0;
}
                                 
/* wIndex is zero based */          
/* if wIndex is larger than the largest index, return the last one base ID */
inline WORD CPerCore::RootIndexBaseID(WORD wIndex)
{
//	if (wIndex >= m_wRootCount) wIndex = m_wRootCount - 1;  
	return m_wRootBaseStart + m_wRootBaseSpace*wIndex;
}       

WORD CPerCore::RootChildBaseID(WORD wChild)
{
	return RootIndexBaseID(RootChildToIndex(wChild));	
}

/* wIndex is zero based */
inline WORD CPerCore::RootIndexDescID(WORD wIndex)
{
	return m_wDescBaseStart + m_wDescBaseSpace*(WORD)wIndex;
}                       

WORD CPerCore::RootChildDescID(WORD wIndex)
{
	return RootIndexDescID(RootChildToIndex(wIndex));
}
                                                  
inline WORD CPerCore::RootBaseToIndex(WORD wBaseID)
{                                                                 
	return (wBaseID-m_wRootBaseStart)/m_wRootBaseSpace;
}                          

WORD CPerCore::RootBaseToChild(WORD wBaseID)
{
	return RootIndexToChild(RootBaseToIndex(wBaseID));
}
                                                  
WORD CPerCore::RegSerialNo(WORD wBaseID)
{             
	char szBuf[256];
	char *szTemp;
	char *szToken;
	                                   
	int nReturn = LoadString(hPerLib, wBaseID, szBuf, 255);
	assert(nReturn != 0);
	
	szTemp = szBuf;
	
	gstrtok(szTemp, ","); // bypass father base ID

	szToken	= gstrtok(szTemp, ",");
	assert(szToken != NULL);
	
	return (WORD)atoi(szToken);
}


                     
/*
 return value is zero based
*/ 
WORD CPerCore::WhichIndex(WORD wBaseID)
{
	WORD wFatherBase = FatherBaseID(wBaseID);
	
	if (wFatherBase==wBaseID)   // top level
		return RootBaseToIndex(wBaseID);
	else{
		char szBuf[256];
		char *szTemp;
		char *szToken;
		int  nReturn;

		nReturn = LoadString(hPerLib, wFatherBase, szBuf, 255);
		assert(nReturn != 0);
		szTemp = szBuf;		

		gstrtok(szTemp, ","); // bypass father base string
		gstrtok(szTemp, ","); // bypass register serial number
		gstrtok(szTemp, ","); // bypass byte flag
		gstrtok(szTemp, ","); // bypass total number   
		
		szToken = gstrtok(szTemp, ","); 
		WORD wSpace = (WORD)atoi(szToken);
		assert(wSpace != 0);		

		szToken = gstrtok(szTemp, ",");
		assert(szToken != 0);
		
		WORD wBaseBegin = (WORD)atoi(szToken);
		
		return (wBaseID - wBaseBegin)/wSpace;
	
	}
}
                            
                            
WORD CPerCore::WhichChild(WORD wBaseID)
{              

	WORD wFatherBase = FatherBaseID(wBaseID);                             
	
	if (wFatherBase==wBaseID)  // top level
		return RootBaseToChild(wBaseID);
	else{
		char szBuf[256];
		char *szTemp;
		char *szToken;
		int  nReturn;
	
		nReturn = LoadString(hPerLib, wFatherBase, szBuf, 255);
		assert(nReturn != 0);
		szTemp = szBuf;		

		gstrtok(szTemp, ","); // bypass father base string
		gstrtok(szTemp, ","); // bypass register serial number
		gstrtok(szTemp, ","); // bypass byte flag
		gstrtok(szTemp, ","); // bypass total number   
		
		szToken = gstrtok(szTemp, ","); 
		WORD wSpace = (WORD)atoi(szToken);
		assert(wSpace != 0);
		
		szToken = gstrtok(szTemp, ",");
		assert(szToken != NULL);
		
		WORD wBaseBegin = (WORD)atoi(szToken);
		
		return (wBaseID - wBaseBegin)/wSpace;
	
	}
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  GetChildNum()  
//
//  Description: get all children of this item
//
//  Input: wBaseID  this SFR string ID in hPerLib library
//
//  Output: 
//
//  Return:  number of offspring
//
/////////////////////////////////////////////////////////////////////////////
WORD CPerCore::GetChildNum(WORD wBaseID)
{
	char szBuf[256];          
	char *szTemp;
	if (LoadString(hPerLib, wBaseID, szBuf, 255)==0)
		return 0;
	szTemp = szBuf;	

	char *szData;
	
	gstrtok(szTemp, ",");   //bypass father string id
	gstrtok(szTemp, ",");   // bypass register serial number
	gstrtok(szTemp, ",");  // bypass bit flag
	
	szData = gstrtok(szTemp, ",");
	assert(szData != NULL);
	
	return (WORD)atoi(szData);	
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  GetOffspringNum()  
//
//  Description: get all offspring of this item, include this item.
//
//  Input: wBaseID  this SFR string ID in hPerLib library
//
//  Output: 
//
//  Return:  number of offspring
//
/////////////////////////////////////////////////////////////////////////////
WORD CPerCore::GetOffspringNum(WORD wBaseID)
{                              
	char szBuf[256];     
	char *szTemp;
	if (LoadString(hPerLib, wBaseID, szBuf, 255)==0)
		return 0;
	szTemp = szBuf;	

	WORD wNum;   
	char *szData;
	
	gstrtok(szTemp, ","); // bypass father string ID
	gstrtok(szTemp, ","); // bypass register serial number
	
	szData = gstrtok(szTemp, ",");
	assert(szData != NULL);
	wNum = (WORD)atoi(szData);   // get bit flag
	
	WORD wOffspringNum = 1;
	if (wNum==0){ // may be a word or dword
	  szData = gstrtok(szTemp, ",");     
	  assert(szData != NULL);
	  wNum = (WORD)atoi(szData);  // get total register number
	  if (wNum != 0){
	  	WORD wSpace;   // per register string space   
	  	WORD wCurStrAddr; // each register string id
	  	
	  	szData = gstrtok(szTemp, ",");
	  	assert(szData != NULL);
	  	wSpace = (WORD)atoi(szData);  // get string space     
	  	assert(wSpace != 0);
	  	
	  	szData = gstrtok(szTemp, ",");
	  	assert(szData != NULL);
	  	wCurStrAddr = (WORD)atoi(szData); // first string id
	  	
	  	for (WORD i=0; i<wNum; i++){   
	  		wOffspringNum += GetOffspringNum(wCurStrAddr + i*wSpace);
	  	}
	  }
	}
	else{  // be a byte	
		szData = gstrtok(szTemp, ",");
		wOffspringNum += (WORD)atoi(szData);
	}
	
	return wOffspringNum;	
}
 
/////////////////////////////////////////////////////////////////////////////
//
//  Name:  GetRegStrNum()  
//
//  Description: get all description string number belong to this item
//
//  Input: wBaseID  this SFR string ID in hPerLib library
//
//  Output: 
//
//  Return:  number of string 
//
/////////////////////////////////////////////////////////////////////////////
WORD CPerCore::GetRegStrNum(WORD wBaseID)
{
	char *szTemp;   
	char szDesc[256];
	if (LoadString(hPerLib, wBaseID, szDesc, 255)==0)
		return 0;                           
	szTemp = szDesc;
	
	WORD wNum;   
	char *szData;
	gstrtok(szTemp, ","); //bypass father string id
	gstrtok(szTemp, ","); //bypass register serial number
	
	szData = gstrtok(szTemp, ",");
	assert(szData != NULL);
	wNum = (WORD)atoi(szData); //get bit flag
	
	WORD wStrNum = 1;    // itself has description also
	if (wNum==0){ // may be a word or dword
	  szData = gstrtok(szTemp, ",");     
	  assert(szData != NULL);
	  wNum = (WORD)atoi(szData);  // get total register number
	  if (wNum != 0){
	  	WORD wSpace;   // per register string space   
	  	WORD wCurStrAddr; // each register string id
	  	szData = gstrtok(szTemp, ",");
	  	assert(szData != NULL);
	  	wSpace = (WORD)atoi(szData);  // get string space  
	  	szData = gstrtok(szTemp, ",");
	  	assert(szData != NULL);
	  	wCurStrAddr = (WORD)atoi(szData); // first string id
	  	for (WORD i=0; i<wNum; i++)   
	  		wStrNum += GetRegStrNum(wCurStrAddr + i*wSpace);
	  }
	}
	else{  // be a byte	
		szData = gstrtok(szTemp, ",");  
		wNum = (WORD)atoi(szData); // get bit number
		for(WORD i=0; i<wNum; i++){ 
			wStrNum++;    // general description
		    szData = gstrtok(szTemp, ",");
		    assert(szData != NULL); 
		    WORD wStart, wLen;
		    RegBitStartLen(szData, wStart, wLen); 
		    szData = gstrtok(szTemp, ",");
		    int nInfFlag = atoi(szData);
		    if(nInfFlag == 1) // each one have its' own description string
				wStrNum += (WORD)1 << wLen;
			else  // only have one description string, need merge
				wStrNum++;
		}
	}
	
	return wStrNum;
}	


/////////////////////////////////////////////////////////////////////////////
//
//  Name:  GetRegStrID()  
//
//  Description: get current register descrpition string id 
//
//  Input: lpFatherPer  father item information in peripheral listbox
//		   lpPer		current item information in peripheral listbox
//
//  Output: result stored in lpPer->StringID
//
//  Return:  return 0
//
/////////////////////////////////////////////////////////////////////////////
BOOL CPerCore::GetRegStrID(PERI_DRAWDATA* lpFatherPer, PERI_DRAWDATA* lpPer)
{                    
	
	lpPer->StringID = lpFatherPer->StringID + 1;                
	if(lpPer->offset == 0) return TRUE;

	char szBuf[256];
	char* szTemp;
	char *szData;
	int nReturn;

	if (lpPer->isBit){ // is bit

		nReturn = LoadString(hPerLib, lpPer->BaseID, szBuf, 255);
		assert(nReturn != 0);    
		szTemp = szBuf;
		
		gstrtok(szTemp, ",");  // bypass father string ID
		gstrtok(szTemp, ",");  // bypass register serial no
		gstrtok(szTemp, ",");  // bypass bit flag
		gstrtok(szTemp, ",");  // bypass total item number
		
		for(BYTE i=0; i<lpPer->offset-1; i++)
		{
			lpPer->StringID++;
			szData = gstrtok(szTemp, ",");  
			WORD wStart, wLen;
		    RegBitStartLen(szData, wStart, wLen); 
		    szData = gstrtok(szTemp, ",");
		    int nInfFlag = atoi(szData); 
		    
		    if ( (m_wCpuID >= EP196KC_CPUID_START) && 
		         (m_wCpuID <= EP196KC_CPUID_END) &&
		    	(lpPer->BaseID == KC196_WSR_BASEID) && (i==0)) // for WSR
		    	lpPer->StringID += 19;
		    else{
		    	if(nInfFlag == 1)
					lpPer->StringID += (WORD)1 << wLen;
				else 
					lpPer->StringID++;
				}
		}                        
	}
	else{ // not bit  
		nReturn = LoadString(hPerLib, lpFatherPer->BaseID, szBuf, 255);
		assert(nReturn != 0); 
		szTemp = szBuf;
		
		gstrtok(szTemp, ","); // bypass father base ID      
		gstrtok(szTemp, ","); // bypass register serial number
		
		WORD wSpace; // each register information string space
		WORD wCurStrAddr; // each register string id
		szData = gstrtok(szTemp, ",");   //bypass bit flag
		szData = gstrtok(szTemp, ",");   //bypass total number
		
		szData = gstrtok(szTemp, ",");
		wSpace = (WORD)atoi(szData);       // get string space
		szData = gstrtok(szTemp, ","); 
		wCurStrAddr = (WORD)atoi(szData);   // get string id
		
		for(BYTE i=0; i<lpPer->offset-1;	i++)
		{
			lpPer->StringID += GetRegStrNum(wCurStrAddr+wSpace*i);
		}
	}								
		
	return TRUE;	

}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  GetRegStrID()  
//
//  Description: get current register descrpition string id 
//
//  Input: wBaseID		the SFR string ID in hPerLib library
//
//  Output: 
//
//  Return:  return string ID
//
/////////////////////////////////////////////////////////////////////////////
WORD CPerCore::GetRegStrID(WORD wBaseID)
{                                                               
	
	WORD wFatherBase = FatherBaseID(wBaseID);
	
	WORD wOffset = WhichIndex(wBaseID);
	
	WORD wStrID = 0;

	if (wFatherBase==wBaseID)
		wStrID = RootIndexDescID(wOffset);
	else{
		char szBuf[256] = "";
		char *szTemp;
		char *szData;
	
		int nReturn;

		nReturn = LoadString(hPerLib, wFatherBase, szBuf, 255);
		assert(nReturn != 0);                                  
		szTemp = szBuf;
	
		gstrtok(szTemp, ",");  // bypass father base id
		gstrtok(szTemp, ",");  // bypass register serial number        
		
		szData = gstrtok(szTemp, ","); // bypass byte flag
		gstrtok(szTemp, ","); // bypass total item number
		
		szData = gstrtok(szTemp, ","); 
		WORD wSpace = (WORD)atoi(szData);                      
		assert(wSpace != 0);
		
		szData = gstrtok(szTemp, ",");
		WORD wStartID = (WORD)atoi(szData);
		
		for(WORD i=0; i<wOffset; i++)
			wStrID += GetRegStrNum(wStartID+i*wSpace);
			
		wStrID += GetRegStrID(wFatherBase) + 1;   
	}
	
	return wStrID;	
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:  GetRegStrID()  
//
//  Description: get current register descrpition string id 
//
//  Input: wBaseID		the SFR string ID in hPerLib library
//		   byOffset     which child
//
//  Output: 
//
//  Return:  return string ID
//
/////////////////////////////////////////////////////////////////////////////
WORD CPerCore::GetRegStrID(WORD wFatherStrID, WORD wBaseID, WORD wOffset)
{
	
	if (wOffset==0) return wFatherStrID+1;
	
	char szBuf[256] = "";
	char *szTemp;
	char *szData;
	
	WORD wStrID = wFatherStrID + 1;
	
	int nReturn = LoadString(hPerLib, wBaseID, szBuf, 255);
	assert(nReturn != 0);                           
	szTemp = szBuf;
	
	gstrtok(szTemp, ",");  // bypass father string ID
	gstrtok(szTemp, ",");  // bypass register serial number
	
	szData = gstrtok(szTemp, ","); 
	assert(szData != NULL);
	int nByteFlag = atoi(szData); // get byte flag
	
	gstrtok(szTemp, ","); //bypass totol number
	
	if (nByteFlag){          
		
		for(WORD i=0; i<wOffset-1; i++)
		{
			wStrID++; // Itself general description string
			szData = gstrtok(szTemp, ",");  
			
			WORD wStart, wLen;
		    RegBitStartLen(szData, wStart, wLen); 
		    szData = gstrtok(szTemp, ",");
		    int nInfFlag = atoi(szData); 
		    
		    if(nInfFlag == 1)
				wStrID += (WORD)1 << wLen;
			else 
				wStrID++;

		} 
		wStrID++; // add register own description id.
	}
	else{ // not bit  
		WORD wSpace; // each register information string space
		WORD wCurStrAddr; // each register string id
		
		szData = gstrtok(szTemp, ",");
		wSpace = (WORD)atoi(szData);       // get string space
		assert(wSpace != 0);
		
		szData = gstrtok(szTemp, ","); 
		wCurStrAddr = (WORD)atoi(szData);   // get string id
		
		for(WORD i=0; i<wOffset-1; i++)
		{
			wStrID += GetRegStrNum(wCurStrAddr+wSpace*i);
		}
	}	
	
	return wStrID;	
}

BOOL CPerCore::GetBitDescStr(WORD wDescID, WORD wValue, 
	BOOL bNeedMerge, char* szDesc)
{         
	if (bNeedMerge){ 
		if (LoadString(hPerLib, wDescID, szDesc, 255) == 0)
			return FALSE;
		char szValue[15];
		wsprintf(szValue, " 0X%X.", wValue);
		strcat(szDesc, szValue);
	}
	else{
		if ((m_wCpuID >= EP196KC_CPUID_START) && 
		    (m_wCpuID <= EP196KC_CPUID_END) &&
		    (wDescID==KC196_WSR_DESCID)){ // for 196KC WSR
		 	if ((wValue & 0xf0) != 0)
		 	{ // vertical window
		 		if ((wValue & 0x70) == 0x40) // 32-Byte window
		 			wValue = 16;
		 		else if ((wValue & 0x78) ==  0x20) // 64-Byte window
		 			wValue = 17;              
		 		else if ((wValue & 0x7C) == 0x10) // 128-Byte window
		 			wValue = 18;
		 		else wValue = 0x6; // no meaning
		 	}
		 }

		if (LoadString(hPerLib, wDescID+wValue, szDesc, 255) ==0 )
			return FALSE;    
	}
	return TRUE;
}

BOOL CPerCore::GetDescStr(PERI_DRAWDATA* lpItem, char* szDesc)
{   
	if (lpItem->isBit)
		GetBitDescStr(lpItem->StringID+1, (WORD)(lpItem->dwVal), 
			!lpItem->isExpanded, szDesc);
	else
		LoadString(hPerLib, lpItem->StringID, szDesc, 255); 
	return TRUE;
}                     


/* If there are not any children, return wBaseID */
/* If there are byOffset+1 children, return the last children base ID */ 
/* If its' children are bit, return wBaseID */
WORD CPerCore::ChildBaseID(WORD wBaseID, WORD wOffset)
{
	char szBuf[256];
	char *szTemp;
	char *szToken;
	
	LoadString(hPerLib, wBaseID, szBuf, 255);
	szTemp = szBuf;

	gstrtok(szTemp, ","); // bypass father base string      
	gstrtok(szTemp, ","); // bypass register serial number
	
	szToken = gstrtok(szTemp, ","); // byte flag
	if (atoi(szToken)) return wBaseID; // no children
	
	szToken = gstrtok(szTemp, ","); // total number   
	WORD wTotal = (WORD)atoi(szToken);
	
	if (wTotal==0) return wBaseID; // no children
	if (wOffset > wTotal-1) wOffset = wTotal-1;
			
	szToken = gstrtok(szTemp, ","); 
	WORD wSpace = (WORD)atoi(szToken);
		
	szToken = gstrtok(szTemp, ",");
	WORD wBaseBegin = (WORD)atoi(szToken);
	
	return wBaseBegin + wSpace*wOffset;
}                       

                                        
WORD CPerCore::ChildFirstOffspringBase(WORD wBaseID, WORD wChild)
{
	WORD wDescendantBase = ChildBaseID(wBaseID, wChild);
	while(wBaseID != wDescendantBase){
		wBaseID = wDescendantBase;
		wDescendantBase = ChildBaseID(wBaseID, 0);
	}
	return wDescendantBase;
}                          

WORD CPerCore::ChildLastOffspringBase(WORD wBaseID, WORD wChild)
{
	WORD wDescendantBase = ChildBaseID(wBaseID, wChild);
	while(wBaseID != wDescendantBase){
		wBaseID = wDescendantBase;
		wDescendantBase = ChildBaseID(wBaseID, 20);
	}
	return wDescendantBase;
}	

                                        
WORD CPerCore::LeftBrotherBase(WORD wBaseID)
{
	
	WORD wFatherBase = FatherBaseID(wBaseID);
	
	if (wFatherBase == wBaseID){ // top level
		WORD wOffset = RootBaseToChild(wBaseID);
		wOffset = (wOffset + m_wRootCount -1) % m_wRootCount;
		
		return ChildLastOffspringBase(RootChildBaseID(wOffset), 20);  // get the last one child
	}
	else {          
		char szBuf[256];
		char *szTemp;
		char *szToken;

		LoadString(hPerLib, wFatherBase, szBuf, 255);
		szTemp = szBuf;                
		
		gstrtok(szTemp, ","); //bypass father base string ID     
		gstrtok(szTemp, ","); //bypass register serial number
		gstrtok(szTemp, ","); //bypass byte flag
		
		szToken = gstrtok(szTemp, ",");
		WORD wTotal = (WORD)atoi(szToken);                   
		
		szToken = gstrtok(szTemp, ",");
		WORD wSpace = (WORD)atoi(szToken);
		assert(wSpace != 0);
		
		szToken = gstrtok(szTemp, ",");
		WORD wStart = (WORD)atoi(szToken);
		
		WORD wOffset = (wBaseID - wStart) / wSpace;  
		if (wOffset==0) // not belong to the same father, 
			return LeftBrotherBase(wFatherBase);
		else 
			return ChildLastOffspringBase(wStart + (wOffset-1) * wSpace, 20);
	}
}
		
WORD CPerCore::RightBrotherBase(WORD wBaseID)
{
	
	WORD wFatherBase = FatherBaseID(wBaseID);
	
	if (wFatherBase == wBaseID){ //top level
		WORD wOffset = RootBaseToChild(wBaseID);
		wOffset = (wOffset + 1) % m_wRootCount;
		
		return ChildFirstOffspringBase(RootChildBaseID(wOffset), 0);
	}
	else {
		char szBuf[256];
		char *szTemp;
		char *szToken;

		LoadString(hPerLib, wFatherBase, szBuf, 255);
		szTemp = szBuf;                
		
		gstrtok(szTemp, ","); //bypass father base string ID
		gstrtok(szTemp, ","); //bypass register serial number
		gstrtok(szTemp, ","); //bypass byte flag
		
		szToken = gstrtok(szTemp, ",");
		WORD wTotal = (WORD)atoi(szToken);                   
		
		szToken = gstrtok(szTemp, ",");
		WORD wSpace = (WORD)atoi(szToken);
		
		szToken = gstrtok(szTemp, ",");
		WORD wStart = (WORD)atoi(szToken);
		
		WORD wOffset = (wBaseID - wStart) / wSpace;
		if (wOffset==wTotal-1)
			return RightBrotherBase(wFatherBase);
		else 
			return ChildFirstOffspringBase(wStart + (wOffset+1) * wSpace, 0);
	}
}

WORD CPerCore::FatherBaseID(WORD wBaseID)
{
	char szBuffer[256];
	char *szTemp;

	if (LoadString(hPerLib, wBaseID, szBuffer, 256) == 0)
	{
		assert(0);
		return  WORD(-1);
	}
	
	szTemp = szBuffer;
	
	char *szData = gstrtok(szTemp, ",");
	WORD wFatherID = (WORD)atoi(szData);
	
	return wFatherID==0? wBaseID : wFatherID;
}
	
	                                                                  
WORD CPerCore::AncestorBaseID(WORD wBaseID)
{
	WORD wForeFatherID = wBaseID;
	do{                         
		wBaseID = wForeFatherID;
		wForeFatherID = FatherBaseID(wBaseID);
		assert (wForeFatherID != WORD(-1));
	}while(wForeFatherID != wBaseID);
	
	return wForeFatherID;	 
}
                                                                 
/******************************end of file***********************/    
    
            
            