/*************************************************
File name:	encodeASN.c
Author: 		JianHui Zheng
Version:		9:00:00 
Date:  			2007-11-09
Description:This file defines the encode function to generate NRTRDE files
						before to send them to the remote HPMNs. 
			
			
			
												
History:               
No. 		
Author:		  
Date:		 
Version:	   
Description:
*************************************************/

#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "nrtrde.h"

/******************************************************/
/******           Function Declaration           ******/
/******************************************************/
/********   From encodeASN.c   *******/
int makeNRFile(HpmnServer* server);
int hasCdrForServer(HpmnServer* server);
long codeNRCdrHead(int type,long byteCount,DataNode* pCdrTail);
long codeNRHCallEvents(long byteCount);
long codeNRHTime(long byteCount);
long codeNRHseqNumber(long byteCount,char* squenceNumber);
long codeNRHRecvSend(HpmnServer* server,long byteCount);
long codeNRHRVN(long byteCount);
long codeNRHSVN(long byteCount);
long codeNRHead(long byteCount);
int writeDataToFile(char* filename);
int codeInBCD(char* data,int len,int tag);
int codeInAscii(char* data,int len,int tag);
int codeInInteger(long data,int tag);
int freeData(void);

/********   From nrtrde.c   ********/
extern void printfInColor(char *message,int color);
extern void printfHPMNServer(HpmnServer* server);
extern void logMessage(char *message);
//extern void getSequenceNumber(char* squenceNumber,int type);

/*******   From seq_num_mng.c  *******/
extern int add_seq_obj(seq_buffer *seq_buf,seq_object *add_obj);
extern unsigned long find_seq_obj(seq_buffer *seq_buf,char *keyvalue);
extern int get_seq_num(char *tadig,int type,char *out_seq);
extern int init_seq();
extern int store_seq();

/******************************************************/
/******           Variable Declaration           ******/
/******************************************************/
/********   From nrtrde.c   ********/
/* The tag configuration */
extern TagNode tags[50];
/* The OMC_PUB database connection */
extern MYSQL *g_omcPubConn;
/* The CDR_DB database connection */
extern MYSQL *g_cdrConn;
/* The local UTC timeOffset */
extern char g_local_utc[8];
/* The tadig of local server */
extern char LOCAL_TADIG[8];
/* The source directory to send the file */
extern char SEND_DIR[256];
/* The directory to receive the file */
extern char RECV_DIR[256];
/* The backup directory */
extern char NR_RECV_BAK_DIR[256];
extern char NR_SEND_BAK_DIR[256];
extern char ND_RECV_BAK_DIR[256];
extern char ND_SEND_BAK_DIR[256];
extern char NE_RECV_BAK_DIR[256];
extern char NE_SEND_BAK_DIR[256];
extern char LOCAL_CSV_DIR[256];

/* The version of the NRTRDE Delivery report */
extern char ND_VERSION[8];
/* The version of the NRTRDE Error report */
extern char NE_VERSION[8];
/* The specificationVersionNumber of the NRTRDE file */
extern int NR_SVN;
/* The ReleaseVersionNumber of the NRTRDE file */
extern int NR_RVN;

/*******   From encodeASN.c   *******/
/* Use to create NRTRDE file */
DataNode* pHead=NULL;
DataNode* pTail=NULL;


/*************************************************
Function:        // makeNRFile
Description:     // Generate the NRTRDE file
Calls:           // 
Called By:       // 
Table Accessed:  // cdrFromMSCSend
Table Updated:   // cdrFromMSCSend
Input:           // server:which server to generate NRTRDE file
Output:          // 
Return:          // 
Others:          // 
*************************************************/
int makeNRFile(HpmnServer* server)
{
	MYSQL_RES *res;
	MYSQL_ROW row;
	char sqlstr[10240];
	char message[256];
	char command[256];
	char fileName[512];
	int recordType;
	long byteCount;								//The total count of NRTRDE file bytes
	int cdrCount;									//The total count of CDR
	int cdrByteCount;							//The total count of one CDR bytes
	char tempstr[64];
	char value[64];
	char squenceNumber[8];
	int i,tempi,j,tempCount;
	DataNode* pCdrTail;						//The tail cdr pointer
	long cdrInstanceNo[1024];
	char where[10240];
	long startTime;
	long searchCdrCount=0;
	
	sprintf(sqlstr,"SELECT instance,recordType,mcc,mnc,servedIMSI,servedIMEI,seizureTime,callDuration,calledNumber,callingNumber,servedMSISDN,recordingEntity,basicService,supplServicesUsed,causeForTerm,callReference,serviceCentre,releaseTime FROM CDR_DB.cdrFromMSCSend where mcc='%s' and mnc='%s'",
								server->mcc,server->mnc);
	
	res=mysql_getres(g_cdrConn,sqlstr);
	if(res == NULL)
	{
		sprintf(message,"[ERR %d][makeNRFile]:%s\n",mysql_errno(g_cdrConn),sqlstr);
		logMessage(message);
		return FAIL;
	}
	
	searchCdrCount=mysql_num_rows(res);
	sprintf(message,"Left searchCdrCount=%ld\n",searchCdrCount);
	printfInColor(message,3);
	
	//Select the cdr from cdrFromMSCSend
	cdrCount=0;
	startTime=time(NULL);
	//while(hasCdrForServer(server)==1)
	while(searchCdrCount)
	{
		byteCount=0;
		cdrCount=0;
		pCdrTail=NULL;
		while((row = mysql_fetch_row(res)) != NULL)
		{
			//instanceNo
			//printf("instance=%s\n",row[0]);
			
			cdrInstanceNo[cdrCount]=atol(row[0]);
			//mcc
			//printf("mcc=%s\n",row[2]);
			//mnc
			//printf("mnc=%s\n",row[3]);
			//recordType
			recordType=atoi(row[1]);
			//store the last tail cdr pointer
			if(cdrCount>0)
			{	
				pCdrTail=pTail;
			}
			//MOC CDR
			if(recordType == 0 || recordType == 6)
			{
				cdrByteCount=0;
				//servedIMSI BCDString
				if(row[4] != NULL && strlen(row[4])>0)
				{	
					cdrByteCount+=codeInBCD(row[4],strlen(row[4]),34);
				}
				
				//servedIMEI DCDString
				if(row[5] != NULL && strlen(row[5])>0)
				{	
					cdrByteCount+=codeInBCD(row[5],strlen(row[5]),33);
				}
				
				//seizureTime ASCII String, get rid of the '-' ' ' ':' from the string
				if(recordType == 0)
				{	
					if(row[6] != NULL && strlen(row[6])>0)
					{	
						sprintf(tempstr,"%s",row[6]);
						tempi=0;
						for(i=0;i<strlen(tempstr);i++)
						{
							if(tempstr[i] == 45 || tempstr[i] == 58 || tempstr[i]==32)
								continue;
							value[tempi]=tempstr[i];
							tempi++;
						}
						value[tempi]='\0';
						cdrByteCount+=codeInAscii(value,strlen(value),21);
					}
				}
				else if(recordType == 6)
				{
					if(row[17] != NULL && strlen(row[17])>0)
					{	
						sprintf(tempstr,"%s",row[17]);
						tempi=0;
						for(i=0;i<strlen(tempstr);i++)
						{
							if(tempstr[i] == 45 || tempstr[i] == 58 || tempstr[i]==32)
								continue;
							value[tempi]=tempstr[i];
							tempi++;
						}
						value[tempi]='\0';
						cdrByteCount+=codeInAscii(value,strlen(value),21);
					}
				}	
				
				//UTCTimeOffset ASCII String
				if(g_local_utc != NULL && strlen(g_local_utc)>0)
				{	
					cdrByteCount+=codeInAscii(g_local_utc,strlen(g_local_utc),45);
				}
				
				//callDuration Integer
				if(recordType == 0)
				{	
					if(row[7] != NULL && strlen(row[7])>0)
					{
						cdrByteCount+=codeInInteger(atol(row[7]),19);
					}
				}
				else if(recordType == 6)
				{
					cdrByteCount+=codeInInteger(0,19);
				}	
				
				//causeForTerm
				if(recordType == 0)
				{	
					if(row[14] != NULL && strlen(row[14])>0)
					{	
						cdrByteCount+=codeInInteger(atol(row[14]),24);
					}
				}
				else if(recordType == 6)
				{
					if(row[14] != NULL && strlen(row[14])>0)
					{	
						cdrByteCount+=codeInInteger(atol(row[14]),24);
					}
					else
					{
						cdrByteCount+=codeInInteger(0,24);
					}	
				}		
				
				//basicService
				if(recordType == 0)
				{	
					if(row[12] != NULL && strlen(row[12])>0)
					{	
						cdrByteCount+=codeInAscii(row[12],strlen(row[12]),43);
					}
				}
				else if(recordType == 6)
				{
					cdrByteCount+=codeInAscii("22",2,43);
				}		
				
				//supplServicesUsed,the value must be 29,2A,2B
				if(row[13] == NULL || strcmp(row[13],"0") == 0 || strlen(row[13]) <= 0)
				{
					//no need to code supplServicesUsed
					//printf("supplServicesUsed is zero or null\n");
					;
				}	
				else
				{
					sprintf(value,"%02x",atoi(row[13]));
					//printf("supplServicesUsed=%s\n",value);
					cdrByteCount+=codeInAscii(value,strlen(value),42);
					
				}
				
				//calledNumber(dialledDigits) ASCII String
				if(row[8] != NULL && strlen(row[8])>0)
				{	
					cdrByteCount+=codeInAscii(row[8],strlen(row[8]),30);
				}
				
				//connectedNumber ASCII String,if the dialledDigits start with '00' then discard it
				//msc mo
				if(recordType == 0)
				{	
					if(row[8] != NULL && strlen(row[8])>0)
					{
						char connectedNumber[128];
						int result;
						//printf("pre-callednumber=%s\n",row[8]);
						result=msisdnUnkToInt(row[8],connectedNumber);
						//printf("aft-connectedNumber=%s,result=%d\n",connectedNumber,result);
						/*
						sprintf(tempstr,"%s",row[8]);
						//printf("dialledDigits=%s\n",tempstr);
						
						if(tempstr[0] == 0x30 && tempstr[1] == 0x30)
						{
							sprintf(connectedNumber,"%s",&tempstr[2]);
						}	
						else
						{
							sprintf(connectedNumber,"%s",tempstr);
						}	
						*/
						//printf("connectedNumber=%s\n",connectedNumber);
						cdrByteCount+=codeInAscii(connectedNumber,strlen(connectedNumber),27);
						
					}	
				}
				//sms mo
				else if(recordType == 6)
				{
					//connectedNumber==serviceCentre
					if(row[16] != NULL && strlen(row[16])>0)
					{	
						cdrByteCount+=codeInAscii(row[16],strlen(row[16]),27);
					}
				}		
					
				//servedMSISDN(ThirdPartyNumber),only when supplServicesUsed=0x21,0x29,0x2A,0x2B
				if(row[13] != NULL && strlen(row[13])>0)
				{
					if(strcmp(value,"21") == 0 || strcmp(value,"29") == 0 || 
						    strcmp(value,"2A") == 0 || strcmp(value,"2B") == 0)
					{
						if(row[10] != NULL && strlen(row[10])>0)
						{	
							cdrByteCount+=codeInAscii(row[10],strlen(row[10]),44);
						}
					}			    
				}	
				
				//recordingEntity
				if(row[11] != NULL && strlen(row[11])>0)
				{	
					cdrByteCount+=codeInAscii(row[11],strlen(row[11]),35);
				}
				
				//callReference
				if(row[15] != NULL && strlen(row[15])>0)
				{	
					cdrByteCount+=codeInInteger(atol(row[15]),23);
				}
				
				
				//code the moc cdr header
				byteCount+=codeNRCdrHead(0,cdrByteCount,pCdrTail);
				
				cdrCount++;
			}	
			//MTC CDR
			else if(recordType == 1 || recordType == 7)
			{
				cdrByteCount=0;
				
				//servedIMSI BCDString
				if(row[4] != NULL && strlen(row[4])>0)
				{	
					cdrByteCount+=codeInBCD(row[4],strlen(row[4]),34);
				}
				
				//servedIMEI BCDString
				if(row[5] != NULL && strlen(row[5])>0)
				{	
					cdrByteCount+=codeInBCD(row[5],strlen(row[5]),33);
				}
				
				//seizureTime ASCII String, get rid of the '-' ' ' ':' from the string
				if(recordType == 1)
				{	
					if(row[6] != NULL && strlen(row[6])>0)
					{	
						sprintf(tempstr,"%s",row[6]);
						tempi=0;
						for(i=0;i<strlen(tempstr);i++)
						{
							if(tempstr[i] == 45 || tempstr[i] == 58 || tempstr[i]==32)
								continue;
							value[tempi]=tempstr[i];
							tempi++;
						}
						value[tempi]='\0';
						cdrByteCount+=codeInAscii(value,strlen(value),21);
					}
				}
				else if(recordType == 7)
				{
					if(row[17] != NULL && strlen(row[17])>0)
					{	
						sprintf(tempstr,"%s",row[17]);
						tempi=0;
						for(i=0;i<strlen(tempstr);i++)
						{
							if(tempstr[i] == 45 || tempstr[i] == 58 || tempstr[i]==32)
								continue;
							value[tempi]=tempstr[i];
							tempi++;
						}
						value[tempi]='\0';
						cdrByteCount+=codeInAscii(value,strlen(value),21);
					}
				}	
				
				//UTCTimeOffset ASCII String
				if(g_local_utc != NULL && strlen(g_local_utc)>0)
				{	
					cdrByteCount+=codeInAscii(g_local_utc,strlen(g_local_utc),45);
				}
				
				//callDuration Integer
				if(recordType == 1)
				{	
					if(row[7] != NULL && strlen(row[7])>0)
					{	
						cdrByteCount+=codeInInteger(atol(row[7]),19);
					}
				}
				else if(recordType == 7)
				{
					cdrByteCount+=codeInInteger(0,19);
				}		
				
				//causeForTerm
				if(recordType == 1)
				{	
					if(row[14] != NULL && strlen(row[14])>0)
					{	
						cdrByteCount+=codeInInteger(atol(row[14]),24);
					}
				}
				else if(recordType == 7)
				{
					if(row[14] != NULL && strlen(row[14])>0)
					{	
						cdrByteCount+=codeInInteger(atol(row[14]),24);
					}
					else
					{
						cdrByteCount+=codeInInteger(0,24);
					}	
				}	
				
				//basicService
				if(recordType == 1)
				{	
					if(row[12] != NULL && strlen(row[12])>0)
					{	
						cdrByteCount+=codeInAscii(row[12],strlen(row[12]),43);
					}
				}
				else if(recordType == 7)
				{
					cdrByteCount+=codeInAscii("21",2,43);
				}	
				
				//callingNumber
				//msc mt
				if(recordType == 1)
				{	
					if(row[9] != NULL && strlen(row[9])>0)
					{	
						cdrByteCount+=codeInAscii(row[9],strlen(row[9]),22);
					}
				}
				//sms mt,callingNumber==serviceCentre
				else if(recordType == 7)
				{
					if(row[16] != NULL && strlen(row[16])>0)
					{	
						cdrByteCount+=codeInAscii(row[16],strlen(row[16]),22);
					}
				}	
				
				//recordingEntity
				if(row[11] != NULL && strlen(row[11])>0)
				{	
					cdrByteCount+=codeInAscii(row[11],strlen(row[11]),35);
				}
				
				
				
				//callReference
				if(row[15] != NULL && strlen(row[15])>0)
				{	
					cdrByteCount+=codeInInteger(atol(row[15]),23);
				}
				
				
				
				//code the MTC cdr header
				byteCount+=codeNRCdrHead(1,cdrByteCount,pCdrTail);
				cdrCount++;
			}	

			searchCdrCount--;
			if(cdrCount >= 1000 ||cdrCount == 0)
				break;
		
		}
		if(cdrCount>0)
		{	
			//get the SequenceNumber of the NRTRDE file
			//getSequenceNumber(squenceNumber,0);
			get_seq_num(server->tadig,0,squenceNumber);
			
			byteCount=codeNRHCallEvents(byteCount);
			byteCount=codeNRHTime(byteCount);
			byteCount=codeNRHseqNumber(byteCount,squenceNumber);
			byteCount=codeNRHRecvSend(server,byteCount);
			byteCount=codeNRHRVN(byteCount);
		  byteCount=codeNRHSVN(byteCount);
		  //code the CallEventsCount
		  byteCount+=codeInInteger(cdrCount,20);
			byteCount=codeNRHead(byteCount);
			
			
			sprintf(fileName,"./NR%s%s%s",LOCAL_TADIG,server->tadig,squenceNumber);
			writeDataToFile(fileName);
			
			sprintf(message,"Generate the NRTRDE file=%s size=%ld byte(s),CDR count=%d\n",fileName,byteCount,cdrCount);
			logMessage(message);
			printfInColor(message,5);
			
			//send the NRTRDE file to the send directory for sending
			sprintf(command,"mv %s %s",fileName,SEND_DIR);
			system(command);
			
			sprintf(message,"Backup the NRTRDE file=%s in %s\n",fileName,NR_SEND_BAK_DIR);
			logMessage(message);
			printfInColor(message,5);
			
			//clear the CDRs which have been got
			tempCount=cdrCount/100;
			if(cdrCount%100 != 0)
				tempCount++;
			for(i=0;i<tempCount;i++)
			{
				memset(where,0,8192);
				for(j=0;j<100;j++)
				{
					if((i*100+j)<cdrCount)
					{
						if(j == 99 || (i*100+j)==(cdrCount-1))
							sprintf(tempstr,"instance=%ld ",cdrInstanceNo[i*100+j]);
						else
							sprintf(tempstr,"instance=%ld or ",cdrInstanceNo[i*100+j]);	
						strcat(where,tempstr);
					}	
				}
				sprintf(sqlstr,"DELETE FROM cdrFromMSCSend WHERE %s",where);
				mysql_getnores(g_cdrConn,sqlstr);	
				//printf("%s\n",sqlstr);
			}			
		}
		
/*		
#if NRTRDE_DEBUG
{
	printf("--------------------coded data-------------------\n");
	DataNode* temp;
			
	temp=pHead;
	do
	{
		if(!pHead)
			break;
		printf("%02x ",temp->data);
		temp=temp->next;
	}while(temp != NULL);
	printf("\n--------------------End data-------------------\n");			
}			
#endif
*/	
		//Free the data link
		freeData();
	}	
	sprintf(message,"generate file cost time=%ld\n",time(NULL)-startTime);
	printfInColor(message,4);
	if(cdrCount == 0)
	{
		sprintf(message,"But there is no roaming CDRs in the database\n");
		logMessage(message);
		printfInColor(message,6);
	}	
	
	mysql_free_result(res);
	return SUCCESSFUL;
}

/*************************************************
Function:        // codeNRCdrHead
Description:     // Code the MOC or MTC cdr header
Calls:           // 
Called By:       // makeNRFile
Table Accessed:  // 
Table Updated:   // 
Input:           // type:0-MOC,1-MTC; byteCount:the total byte count;
Output:          // 
Return:          // the total byte count now
Others:          // This is function will change the value 'pHead' and 'pTail'
*************************************************/
long codeNRCdrHead(int type,long byteCount,DataNode* pCdrTail)
{
	DataNode* pH;
	DataNode* pT;
	DataNode* node;
	unsigned char value;
	unsigned char lenByteCount;
	unsigned char vData[16];
	long temp;
	int i;
	
	//MOC tag=3, MTC tag=4
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	if(type)	
		value=0x64;
	else
		value=0x63;										
	node->data=value;
	node->next=NULL;
	pH=node;
	pT=node;
	     
	
	if(byteCount < 128)
	{
		
		//length
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		value=0xFF & byteCount;
		node->data=value;
		node->next=NULL;
		pT->next=node;
		pT=node;
		
		byteCount+=1+1;
		
	}
	else
	{
		lenByteCount=0;
		temp=byteCount;
		do
		{
			if(temp > 0)
			{	
				vData[lenByteCount]=(unsigned char)(temp & 0xFF);
				lenByteCount++;
				temp >>= 8;
			}
			else
				break;	
		}while(1);
		//printf("lenByteCount=%d\n",lenByteCount);
		//length-1
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		value=0x80 | lenByteCount;
		node->data=value;
		node->next=NULL;
		pT->next=node;
		pT=node;
		
		//length-2
		for(i=lenByteCount-1;i>=0;i--)
		{
			node=malloc(sizeof(DataNode));
			if(node == NULL)
				return 0;
			node->data=vData[i];
			node->next=NULL;
			pT->next=node;
			pT=node;	
		}
		byteCount+=2+lenByteCount;
		
	}		

	
	//link the data to pHead
	if(pCdrTail == NULL)
	{	
		pT->next=pHead;
		pHead=pH;
	}
	//link the data after the last cdr tail
	else
	{	
		pT->next=pCdrTail->next;
		pCdrTail->next=pH;
	}
	
	return byteCount;
}

/*************************************************
Function:        // codeNRHCallEvents
Description:     // Code the callEvents of the NRTRDE file header
Calls:           // 
Called By:       // makeNRFile;
Table Accessed:  // 
Table Updated:   // 
Input:           // byteCount:the total byte count;
Output:          // 
Return:          // the total byte count now
Others:          // This is function will change the value 'pHead' and 'pTail'
*************************************************/
long codeNRHCallEvents(long byteCount)
{
	DataNode* pH;
	DataNode* pT;
	DataNode* node;
	unsigned char value;
	unsigned char lenByteCount;
	unsigned char vData[16];
	long temp;
	int i;
	
	//tag=2
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x62;									
	node->data=value;
	node->next=NULL;
	pH=node;
	pT=node;
	     
	
	if(byteCount < 128)
	{
		
		//length
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		value=0xFF & byteCount;
		node->data=value;
		node->next=NULL;
		pT->next=node;
		pT=node;
		
		byteCount+=1+1;
		
	}
	else
	{
		lenByteCount=0;
		temp=byteCount;
		do
		{
			if(temp > 0)
			{	
				vData[lenByteCount]=(unsigned char)(temp & 0xFF);
				lenByteCount++;
				temp >>= 8;
			}
			else
				break;	
		}while(1);
		//printf("lenByteCount=%d\n",lenByteCount);
		//length-1
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		value=0x80 | lenByteCount;
		node->data=value;
		node->next=NULL;
		pT->next=node;
		pT=node;
		
		//length-2
		for(i=lenByteCount-1;i>=0;i--)
		{
			node=malloc(sizeof(DataNode));
			if(node == NULL)
				return 0;
			node->data=vData[i];
			node->next=NULL;
			pT->next=node;
			pT=node;	
		}
		byteCount+=2+lenByteCount;
		
	}		
	
	
	
	//link the data the pHead
	pT->next=pHead;
	pHead=pH;
	
	return byteCount;
}

/*************************************************
Function:        // codeNRHTime
Description:     // Code the fileAvailableTimeStamp and UTCTimeOffset
										of the NRTRDE file header
Calls:           // 
Called By:       // makeNRFile;
Table Accessed:  // 
Table Updated:   // 
Input:           // byteCount:the total byte count;
Output:          // 
Return:          // the total byte count now
Others:          // This is function will change the value 'pHead' and 'pTail'
*************************************************/
long codeNRHTime(long byteCount)
{
	DataNode* pH;
	DataNode* pT;
	DataNode* node;
	unsigned char value;
	struct tm *now;
	time_t t;
	char timestr[64];
	int i;
	
	//fileAvailableTimeStamp
	//tag=31
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x5F;
	node->data=value;
	node->next=NULL;
	pH=pT=node;
	
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x1F;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;	
	
	//length,the value is constant=0x0E
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x0E;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;	
	
	//value
	t=time(NULL);
	now=localtime(&t);
	sprintf(timestr,"%04d%02d%02d%02d%02d%02d",
	      		now->tm_year+1900,
	      		now->tm_mon+1,
	      		now->tm_mday,
	      		now->tm_hour,
	      		now->tm_min,
	      		now->tm_sec);
	
	for(i=0;i<strlen(timestr);i++)
	{
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		value=(unsigned char)(timestr[i]);
		node->data=value;
		node->next=NULL;
		pT->next=node;
		pT=node;
	}      		
	byteCount+=2+1+strlen(timestr);
	
	//UTCTimeOffset
	//tag=45
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x5F;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;
	
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x2D;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;
	
	//length=5
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x05;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;
	
	//value
	for(i=0;i<strlen(g_local_utc);i++)
	{
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		value=(unsigned char)(g_local_utc[i]);
		node->data=value;
		node->next=NULL;
		pT->next=node;
		pT=node;
	}
	
	byteCount+=2+1+strlen(g_local_utc);
	
	//link the data the pHead
	pT->next=pHead;
	pHead=pH;
	
	return byteCount;
}

/*************************************************
Function:        // codeNRHseqNumber
Description:     // Code the sequenceNumber of the NRTRDE file header
Calls:           // 
Called By:       // makeNRFile;
Table Accessed:  // 
Table Updated:   // 
Input:           // byteCount:the total byte count; squenceNumber:squenceNumber of the NRTRDE file
Output:          // 
Return:          // the total byte count now
Others:          // This is function will change the value 'pHead' and 'pTail'
*************************************************/
long codeNRHseqNumber(long byteCount,char* squenceNumber)
{
	DataNode* pH;
	DataNode* pT;
	DataNode* node;
	unsigned char value;
	int i;
	
	//printf("NR squenceNumber=%s\n",squenceNumber);
	//tag=39
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x5F;
	node->data=value;
	node->next=NULL;
	pH=pT=node;
	
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x27;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;
	
	//length=7,constant
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x07;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;
	
	//value
	for(i=0;i<strlen(squenceNumber);i++)
	{
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		value=(unsigned char)(squenceNumber[i]);
		node->data=value;
		node->next=NULL;
		pT->next=node;
		pT=node;
	}
	
	//link the data to the pHead
	pT->next=pHead;
	pHead=pH;
	
	i=2+1+strlen(squenceNumber);
	byteCount+=2+1+strlen(squenceNumber);
	
	return byteCount;
}

/*************************************************
Function:        // codeNRHRecvSend
Description:     // Code the Sender and Recipient of the NRTRDE file header
Calls:           // 
Called By:       // makeNRFile;
Table Accessed:  // 
Table Updated:   // 
Input:           // byteCount:the total byte count;
Output:          // 
Return:          // the total byte count now
Others:          // This is function will change the value 'pHead' and 'pTail'
*************************************************/
long codeNRHRecvSend(HpmnServer* server,long byteCount)
{
	DataNode* pH;
	DataNode* pT;
	DataNode* node;
	unsigned char value;
	char sender[8];
	int i;
	
	//Sender
	//tag=38
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x5F;
	node->data=value;
	node->next=NULL;
	pH=pT=node;

	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x26;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;
	
	//length=5,constant
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x05;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;
	
	//value
	sprintf(sender,"%s",LOCAL_TADIG);
	for(i=0;i<strlen(sender);i++)
	{
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		value=(unsigned char)(sender[i]);
		node->data=value;
		node->next=NULL;
		pT->next=node;
		pT=node;
	}
	
	//Recipient
	//tag=36
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x5F;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;
	
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x24;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;
	
	//length=5,constant
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x05;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;
	
	//value
	for(i=0;i<strlen(server->tadig);i++)
	{
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		value=(unsigned char)(server->tadig[i]);
		node->data=value;
		node->next=NULL;
		pT->next=node;
		pT=node;
	}
	
	//link the data the pHead
	pT->next=pHead;
	pHead=pH;
	
	byteCount+=16;
	
	return byteCount;
}


/*************************************************
Function:        // codeNRHRVN
Description:     // Code the ReleaseVersionNumber of the NRTRDE file header
Calls:           // 
Called By:       // makeNRFile;
Table Accessed:  // 
Table Updated:   // 
Input:           // byteCount:the total byte count;
Output:          // 
Return:          // the total byte count now
Others:          // This is function will change the value 'pHead' and 'pTail'
*************************************************/
long codeNRHRVN(long byteCount)
{
	DataNode* pH;
	DataNode* pT;
	DataNode* node;
	unsigned char value;
	
	//tag=37
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x5F;
	node->data=value;
	node->next=NULL;
	pH=pT=node;

	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x25;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;
	
	//length=1,constant
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x01;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;
	
	//value=0x01
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0xFF & NR_RVN;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;
	
	//link the data the pHead
	pT->next=pHead;
	pHead=pH;
	
	byteCount+=4;
	
	
	return byteCount;
}

/*************************************************
Function:        // codeNRHSVN
Description:     // Code the specificationVersionNumber of the NRTRDE file header
Calls:           // 
Called By:       // makeNRFile;
Table Accessed:  // 
Table Updated:   // 
Input:           // byteCount:the total byte count;
Output:          // 
Return:          // the total byte count now
Others:          // This is function will change the value 'pHead' and 'pTail'
*************************************************/
long codeNRHSVN(long byteCount)
{
	DataNode* pH;
	DataNode* pT;
	DataNode* node;
	unsigned char value;
	
	//tag=41
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x5F;
	node->data=value;
	node->next=NULL;
	pH=pT=node;

	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x29;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;
	
	//length=1,constant
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0x01;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;
	
	//value=0x02
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	value=0xFF & NR_SVN;
	node->data=value;
	node->next=NULL;
	pT->next=node;
	pT=node;
	
	//link the data the pHead
	pT->next=pHead;
	pHead=pH;
	
	byteCount+=4;
	
	return byteCount;
}

/*************************************************
Function:        // codeNRHead
Description:     // Code the NRTRDE file head
Calls:           // 
Called By:       // 
Table Accessed:  // 
Table Updated:   // 
Input:           // byteCount:the callEvents byte count;
Output:          // 
Return:          // the total byte count now
Others:          // This is function will change the value 'pHead' and 'pTail'
*************************************************/
long codeNRHead(long byteCount)
{
	DataNode* pH;
	DataNode* pT;
	DataNode* node;
	unsigned char value;
	unsigned char lenByteCount;
	unsigned char vData[16];
	long temp;
	int i;
	
	//nrtrde
	//tag=1
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return FAIL;
	value=0x61;									
	node->data=value;
	node->next=NULL;
	pH=node;
	pT=node;
	
	
	     
	
	if(byteCount < 128)
	{
		
		//length
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return FAIL;
		value=0xFF & byteCount;
		node->data=value;
		node->next=NULL;
		pT->next=node;
		pT=node;
		
		byteCount+=2;
		
	}
	else
	{
		lenByteCount=0;
		temp=byteCount;
		do
		{
			if(temp > 0)
			{	
				vData[lenByteCount]=(unsigned char)(temp & 0xFF);
				lenByteCount++;
				temp >>= 8;
			}
			else
				break;	
		}while(1);
		//printf("lenByteCount=%d\n",lenByteCount);
		//length-1
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return FAIL;
		value=0x80 | lenByteCount;
		node->data=value;
		node->next=NULL;
		pT->next=node;
		pT=node;
		
		byteCount+=2;
		
		//length-2
		for(i=lenByteCount-1;i>=0;i--)
		{
			node=malloc(sizeof(DataNode));
			if(node == NULL)
				return FAIL;
			node->data=vData[i];
			node->next=NULL;
			pT->next=node;
			pT=node;	
			byteCount+=1;
		}		
	}		
	

	//link the data the pHead
	pT->next=pHead;
	pHead=pH;

	return byteCount;
}

/*************************************************
Function:        // freeData
Description:     // To free the resource of the link
Calls:           // 
Called By:       // 
Table Accessed:  // 
Table Updated:   // 
Input:           // 
Output:          // 
Return:          // 0;failed; 1:successful
Others:          // Use for creating NRTRDE file, change the value 'pHead' and 'pTail'
*************************************************/
int freeData()
{
	DataNode* node;
	DataNode* temp;
	
	node=pHead;
	while(node != NULL)
	{
		temp=node->next;
		//printf("free %d\n",node->data);
		//free(node->next);
		free(node);
		node=temp;
	}
	pHead=NULL;
	pTail=NULL;
	return SUCCESSFUL;
}

/*************************************************
Function:        // writeDataToFile
Description:     // Write the link data to the specific file
Calls:           // 
Called By:       // makeNRFile;
Table Accessed:  // 
Table Updated:   // 
Input:           // filename:the specific file to write
Output:          // 
Return:          // 0:failed; 1:successful;
Others:          // Use for creating NRTRDE file,  use the value 'pHead' and 'pTail'
*************************************************/
int writeDataToFile(char* filename)
{
	DataNode* node;
	FILE* fp;
	int fi;
	
	node=pHead;
	if(node)
	{
		fp=fopen(filename,"wb+");
		fi=fileno(fp);
		do
		{
			write(fi,&node->data,1);
			//printf("%d\n",temp->data);
			node=node->next;
		}while(node != NULL);
		close(fi);
		fclose(fp);
		return SUCCESSFUL;
	}
	else
	{
		return FAIL;
	}		
}

/*************************************************
Function:        // codeInBCD
Description:     // Code the data to BSD string
Calls:           // 
Called By:       // makeNRFile
Table Accessed:  // 
Table Updated:   // 
Input:           // data:the data to code; len:the length of the data; tag:the tag value
Output:          // 
Return:          // The count of the result byte
Others:          // This function will change the value 'pHead' and 'pTail'
*************************************************/
int codeInBCD(char* data,int len,int tag)
{
	DataNode* pH;
	DataNode* pT;
	DataNode* node;
	int vLen;
	int tLen;
	int lLen;
	unsigned char value;
	int i,a,b;
	
	//code the tag
	tLen=0;
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	
		
	value=0x00;
	//If the tag is struct, the 2th bit is 1, else is 0, the tag is application
	if(tags[tag].isStructed)
	{
		value |= 0x60;
	}	
	else
	{
		value |= 0x40;
	}	
	
	//If the tag value is small then 31, the tag byte count is 1, else is 2
	if(tag < 31)
	{
		value |= tag;
		node->data=value;
		node->next=NULL;
		pH=pT=node;
		
		tLen=1;
	}	
	else
	{
		value |= 0x1F;
		node->data=value;
		node->next=NULL;
		pH=pT=node;
		
		value=(unsigned char)(tag & 0xFF);
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		node->data=value;
		pT->next=node;
		pT=node;
		node->next=NULL;
		
		tLen=2;
	}	
	
	//code the length
	vLen=(int)((len+1)/2);
	lLen=0;
	//If the result data length is small then 128
	if(vLen < 128)
	{
		value=(unsigned char)(vLen & 0xFF);
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		node->data=value;
		pT->next=node;
		pT=node;
		node->next=NULL;
		
		lLen=1;
	}	
	else
	{
		//The data length will be smaller then 128 in this program
		;
	}		
	
	//code the value
	value=0;
	for(i=0;i<len;i++)
	{
		a=((i+1)%2)*16*(data[i]-'0');
		b=(i%2)*(data[i]-'0');
		value+=a+b;
		
		if(i == (len-1) && len%2)
		{	
				value+=0x0f;
				
				value=(unsigned char)(value & 0xFF);
				node=malloc(sizeof(DataNode));
				if(node == NULL)
					return 0;
				node->data=value;
				pT->next=node;
				pT=node;
				node->next=NULL;
				//printf("code=%02x\n",temp);
		}
		if(i%2 && i!=0)
		{	
			value=(unsigned char)(value & 0xFF);
			node=malloc(sizeof(DataNode));
			if(node == NULL)
				return 0;
			node->data=value;
			pT->next=node;
			pT=node;
			node->next=NULL;
			
			value=0;
		}	
	}

	//link the TLV to the pTail
	if(pHead == NULL || pTail == NULL)
	{
		pHead=pH;
		pTail=pT;
	}
	else
	{		
		pTail->next=pH;
		pTail=pT;	
	}
	
	return vLen+tLen+lLen;
}

/*************************************************
Function:        // codeInAscii
Description:     // Code the data to ASCII string
Calls:           // 
Called By:       // makeNRFile
Table Accessed:  // 
Table Updated:   // 
Input:           // data:the data to code; len:the length of the data; tag:the tag value
Output:          // 
Return:          // The count of the result byte
Others:          // This function will change the value 'pHead' and 'pTail'
*************************************************/
int codeInAscii(char* data,int len,int tag)
{
	DataNode* pH;
	DataNode* pT;
	DataNode* node;
	int tLen;
	int lLen;
	unsigned char value;
	int i;
	
	//code the tag
	tLen=0;
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	
	value=0x00;
	//If the tag is struct, the 2th bit is 1, else is 0, the tag is application
	if(tags[tag].isStructed)
	{
		value |= 0x60;
	}	
	else
	{
		value |= 0x40;
	}	
	
	//If the tag value is small then 31, the tag byte count is 1, else is 2
	if(tag < 31)
	{
		value |= tag;
		node->data=value;
		node->next=NULL;
		pH=pT=node;
		
		tLen=1;
	}	
	else
	{
		value |= 0x1F;
		node->data=value;
		node->next=NULL;
		pH=pT=node;
		
		value=(unsigned char)(tag & 0xFF);
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		node->data=value;
		pT->next=node;
		pT=node;
		node->next=NULL;
		
		tLen=2;
	}	
	
	//code the length
	lLen=0;
	//If the data length is small then 128
	if(len < 128)
	{
		value=(unsigned char)(len & 0xFF);
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		node->data=value;
		pT->next=node;
		pT=node;
		node->next=NULL;
		
		lLen=1;
	}	
	else
	{
		//The data length will be smaller then 128 in this program
		;
	}		
	
	//code the value
	for(i=0;i<len;i++)
	{
		value=(unsigned char)data[i];
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		node->data=value;
		pT->next=node;
		pT=node;
		node->next=NULL;
	}
	
	//if the tag=43(TeleServiceCode),it must be surrounded by the serverCode choice,tag=46(7f 2e 05)
	if(tag == 43)
	{
		value=0x05;
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		node->data=value;
		node->next=pH;
		pH=node;	
		
		value=0x2E;
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		node->data=value;
		node->next=pH;
		pH=node;
		
		value=0x7F;
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		node->data=value;
		node->next=pH;
		pH=node;
		
		tLen=tLen+3;
		
	}	
	
	//link the TLV to the pTail
	if(pHead == NULL || pTail == NULL)
	{
		pHead=pH;
		pTail=pT;
	}
	else
	{		
		pTail->next=pH;
		pTail=pT;	
	}
	
	return len+tLen+lLen;
}

/*************************************************
Function:        // codeInInteger
Description:     // Code the data to Integer
Calls:           // 
Called By:       // makeNRFile
Table Accessed:  // 
Table Updated:   // 
Input:           // data:the data to code; tag:the tag value;
Output:          // 
Return:          // The count of the result byte
Others:          // This function will change the value 'pHead' and 'pTail'
*************************************************/
int codeInInteger(long data,int tag)
{
	DataNode* pH;
	DataNode* pT;
	DataNode* node;
	int tLen;
	int lLen;
	int vLen;
	unsigned char value;
	int i;
	int addZeroByte;
	unsigned char vData[16];
	long tmpData;
	
	//code the tag
	tLen=0;
	node=malloc(sizeof(DataNode));
	if(node == NULL)
		return 0;
	
	value=0x00;
	//If the tag is struct, the 2th bit is 1, else is 0, the tag is application
	if(tags[tag].isStructed)
	{
		value |= 0x60;
	}	
	else
	{
		value |= 0x40;
	}	
	
	//If the tag value is small then 31, the tag byte count is 1, else is 2
	if(tag < 31)
	{
		value |= tag;
		node->data=value;
		node->next=NULL;
		pH=pT=node;
		
		tLen=1;
	}	
	else
	{
		value |= 0x1F;
		node->data=value;
		node->next=NULL;
		pH=pT=node;
		
		value=(unsigned char)(tag & 0xFF);
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		node->data=value;
		pT->next=node;
		pT=node;
		node->next=NULL;
		
		tLen=2;
	}	
	
	//code the length
	vLen=0;
	memset(vData,0,16*sizeof(unsigned char));
	tmpData=data;
	do
	{
		if(tmpData)
		{
			vData[vLen]=(unsigned char)(tmpData & 0xFF);
			//printf("vData[%d]=%d\n",vLen,vData[vLen]);
			vLen++;
		}	
		else
		{
			break;
		}		
		tmpData=tmpData >> 8;
	}while(1);
	
	//get the 8th bit of the highest byte
	tmpData=data;
	for(i=0;i<vLen-1;i++)
	{
		tmpData=tmpData >> 8;
	}
	//If the bit is 1, then must add 0x00 to the lLen
	addZeroByte=0;
	if(tmpData & 0x80)
	{
		vLen++;
		addZeroByte=1;
	}	
	if(data == 0)
	{
		vLen=1;
	}
	
	lLen=0;
	//If the data length is small then 128
	if(vLen < 128)
	{
		value=(unsigned char)(vLen & 0xFF);
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		node->data=value;
		pT->next=node;
		pT=node;
		node->next=NULL;
		
		lLen=1;
	}	
	else
	{
		//The data length will be smaller then 128 in this program
		;
	}		
	
	//code the value
	if(addZeroByte || data == 0)
	{
		value=0x00;
		node=malloc(sizeof(DataNode));
		if(node == NULL)
			return 0;
		node->data=value;
		pT->next=node;
		pT=node;
		node->next=NULL;
	}	
	
	//printf("vLen=%d,addZeroByte=%d\n",vLen,addZeroByte);
	if(data > 0)
	{	
		for(i=vLen-1-addZeroByte;i>=0;i--)
		{
			//printf("byte-%d=%d\n",i,vData[i]);
			value=vData[i];
			node=malloc(sizeof(DataNode));
			if(node == NULL)
				return 0;
			node->data=value;
			pT->next=node;
			pT=node;
			node->next=NULL;
		}
	}
	
	//link the TLV to the pTail
	if(pHead == NULL || pTail == NULL)
	{
		pHead=pH;
		pTail=pT;
	}
	else
	{		
		pTail->next=pH;
		pTail=pT;	
	}
	
	
	return lLen+vLen+tLen;
}

/*************************************************
Function:        // hasCdrForServer
Description:     // Check whether there have CDRs for the server in cdrFromMSCSend table
Calls:           // 
Called By:       // makeNRFile
Table Accessed:  // CDR_DB.cdrFromMSCSend
Table Updated:   // 
Input:           // server:which server to check
Output:          // 
Return:          // 1-there have CDRs, 0-no CDRs
Others:          // 
*************************************************/
int hasCdrForServer(HpmnServer* server)
{
	MYSQL_RES *res;
	char sqlstr[256];
	char message[256];
	int cdrCount;
	
	
	
	sprintf(sqlstr,"SELECT * FROM cdrFromMSCSend WHERE mcc='%s' and mnc='%s' ",
				               server->mcc,server->mnc);
	
	res=mysql_getres(g_cdrConn,sqlstr);
	if(res == NULL)
	{
		sprintf(message,"[ERR %d][hasCdrForServer]:%s\n",mysql_errno(g_cdrConn),sqlstr);
		logMessage(message);
		return FAIL;
	}
					 
	cdrCount=0;				               
	cdrCount=mysql_num_rows(res);
	mysql_free_result(res);
	
	if(cdrCount)
		return 1;
	else
		return 0;	
}
