#include    "../include/includes.h"
#include    "../include/message.h"
#include    "../include/ppsm.h"
#include    "../include/cdrme.h"
#include    "../include/ramdata.h"
#include    "../include/mfunc.h"
#include    "../include/config.h"
#include    "../include/param.h"
#include    "../include/precard.h"

#include    "../include/plat_inc.h"

/*-----------------------------------------------------*/
_USED_REPAID_CARD_BUFFER usedPrepaidCardBuffer={0,0};
/*-----------------------------------------------------*/
extern _state_machine		*smshm_ptr;
extern _ram_data			*ramshm_ptr;
extern char					prog_name[12];
extern char					alarm_code[2];
extern int					subSystemID;
extern _pps_cdr_buffer		pps_cdr_buffer;
extern _load_file	load_file; /* 0,1,2=user data/tariff data/prepaid card */
extern struct		timeval tvnow;
extern u_long		PPS_OID_PREFIX[];
extern u_long		LOCAL_IP;
extern u_char		logMsgFlag;
extern u_long		peer_server_ip;
extern u_short		debug_messages;
/*-----------------------------------------------------*/
static u_long		card_counter[MAX_VALUE_TYPE]={0,0,0,0};
_free_mem_quence	freeQuence;
_climax_quence		climaxQuence;
extern	PPSParamStruct	ppsParam;
static u_char		replaceCardFlag=0;
/*-----------------------------------------------------*/
int	 	GetClimaxQuenceStorePos(u_char *card_pwd,int start,int end);
int  	AddNewCardIntoClimaxQuence(_recharge_card_info *cardShmp);
int 	searchCardByIndex(int instance);
int	 	GetClimaxQuenceStorePosByCardNo(long long card_no,int start,int end);
int	 	DeleteCardFromClimaxQuence(_recharge_card_info *cardInfo,int store_pos);
int	UpdateCardInfo(_recharge_card_info *cardShmp);
void DeleteCardFaceValue(long face_value);
extern int pps_real_update_card_file(int head, int tail);
extern void ReadSyncMessageForInit();

int StorePrepaidCard(int *head_no, int head)
{
	int loop;
    _card_data    *shmp=&ramshm_ptr->card_data;

	PutLogFunID("StorePrepaidCard");

	for(loop=0;loop<MAX_CARD_SEGMENT-MAX_CLIMAX_CARD_SEGMENT;loop++)
	{
		if((head == shmp->prepaid_card_head[loop]) 
			&& shmp->segment_used_flag[loop])
		{
			*head_no = loop;  
			return 1;
		}
	}
	
	for(loop=0;loop<MAX_CARD_SEGMENT-MAX_CLIMAX_CARD_SEGMENT;loop++)
	{
		if(shmp->segment_used_flag[loop] == 0)
		{
			*head_no = loop;
			return 2;
		}
	}
	return -1;
}

int InquiryPrepaidCardStorePos(long long head)
{
	int loop;
    _card_data    *shmp=&ramshm_ptr->card_data;
   
	PutLogFunID("InquiryPrepaidCardStorePos");

	for(loop=0;loop<MAX_CARD_SEGMENT-MAX_CLIMAX_CARD_SEGMENT;loop++)
	{
		if((head == shmp->prepaid_card_head[loop]) 
			&& shmp->segment_used_flag[loop])
		{
			return loop;
		}
	}
	return -1;
}

void CardHeadInDecrement(int flag)
{
	char buf[32]="";

	PutLogFunID("CardHeadInDecrement"); 
	
	if(flag)
		debugmib.measurement.cardheadnumber ++;
	else
		debugmib.measurement.cardheadnumber --;
	sprintf(buf,"%08ld",debugmib.measurement.cardheadnumber);
	AsciiToBcd(&debugmib.measurement.card_number[4],buf,8);
}

void CardNumberInDecrement(int flag)
{
	char buf[32]="";

	PutLogFunID("CardNumberInDecrement");
	
	if(flag)
		debugmib.measurement.cardnumber ++;
	else
		debugmib.measurement.cardnumber --;
	sprintf(buf,"%08ld",debugmib.measurement.cardnumber);
	AsciiToBcd(&debugmib.measurement.card_number[0],buf,8);
}

void DeletePrepaidCardHead(int head)
{
	int loop;
	char buf[16];

	_card_data    *shmp=&ramshm_ptr->card_data;

	PutLogFunID("DeletePrepaidCardHead");
  
	for(loop=0;loop<MAX_CARD_NUM_PSEG;loop++)
	{
		if(shmp->prepaid_card[head][loop].card_no[MAX_CARD_LENGTH]>=12)
		{
			return;
		}
	}
	shmp->prepaid_card_head[head] = 0;
	shmp->segment_used_flag[head] = 0;
	CardHeadInDecrement(0);
	sprintf(buf,"%08d",0);
	AsciiToBcd(debugmib.measurement.card_prefix[head],buf,8);

}

/*-----------------------------------------------------*/

void SetReplaceCardFlag(u_char flag)
{
	replaceCardFlag = flag;
	DebugMsg(debugmib.display.asciiOut,"replace flag: %d",replaceCardFlag);
}

int ImportPrepaidCardData(char *carddata)
{
    _recharge_card_info	*shmp=NULL, card_info;
    char    buf[BUFSIZE]={""},buftmp[32],*token;
    int    len,retval, i, index=0,instance=0;						
    const  char    delimiter[]=",;";

    PutLogFunID("ImportPrepaidCardData");  

    shmp=&card_info;
    token  = buf;
	
    if(strlen(carddata)<10)
    {
        if(load_file.log_fp[_FILE_ID_PREPAID_CARD] != NULL)
        {
            fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],
                    "Error: Wrong record length : %s\n",carddata);
        }
        return 0;
    }

    while(index<8)
    {
        token = strsep((char **)&(carddata),delimiter);
        if(token == NULL)
        {
            if(load_file.log_fp[_FILE_ID_PREPAID_CARD] != NULL)
            {
                fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],
                        "Error: Wrong record  : %s\n",carddata);
            }
            return 0;	  
        }

        strcpy(buf,token);

        switch(index)
        {
            case 0x00: /* card number */
                len = strlen(buf);
                if(len>MAX_CARD_LENGTH*2 || len<12 || len%2) 
                {
                    if(load_file.log_fp[_FILE_ID_PREPAID_CARD] != NULL)
                    {
                         fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],
                                "Error: Wrong card no length  : %s\n",buf);
                    } 
                   return 0;
                }
                for(i=0;i<len;i++)
                {
                    if(buf[i]>'9' || buf[i]<'0' || buf[0] =='0') 
                    {
                         if(load_file.log_fp[_FILE_ID_PREPAID_CARD] != NULL)
                        {
                             fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],
                                    "Error: Wrong card format:%s\n",buf);
                        } 
                        return 0;
                    }
                }
                AsciiToBcd(shmp->card_no,buf,len);
                shmp->card_no[MAX_CARD_LENGTH] = len;
                strcpy(buftmp,buf);
            break;
            case 0x01: /* PWD */
                if(strlen(buf)!=16)
                    return 0;
                AsciiToBcd(shmp->card_pwd,buf,16);
            break;
            case 0x02: /* face value */
                shmp->face_value = atoi(buf);
            break;
            case 0x03: /* card status */
                shmp->card_status = atoi(buf);
            break;
            case 0x04: /* expiry_date */
                shmp->expiry_date = atol(buf);
            break;
            case 0x05: /* valid_time */
                shmp->valid_time = atoi(buf);
            break;
            case 0x06: /* msisdn_used */
                strcpy(shmp->msisdn_used,buf);
            break;
            case 0x07: /* updated_date */
                //string2ltime(&nowtime,buf);
                //shmp->updated_date = nowtime;
                shmp->updated_date = tvnow.tv_sec;
            break;
            default:
            break;
        }/* switch */
        index++;
    }

    retval = SetPrepaidCardFaceValue(shmp->face_value);

    if(retval == 0)
    {
        if(load_file.log_fp[_FILE_ID_PREPAID_CARD] != NULL)
        {
            fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],
                    "Error: there are 4 types of face value, cann't store any more!\n");
        } 
        return 0;
    }

    if(replaceCardFlag)
    {
        if((instance=GetClimaxQuenceStorePos(shmp->card_pwd, 0 , climaxQuence.counter))>=0)
        {
            if(load_file.log_fp[_FILE_ID_PREPAID_CARD] != NULL)
            {
                fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],
                        "Warning: card %s is inuse, is replaced!\n",buftmp);
            }
            UpdateCardInfo(shmp);
            DeleteCardFaceValue(shmp->face_value);
        }	
        else if(AddNewCardIntoClimaxQuence(shmp)<0)
        {
            if(load_file.log_fp[_FILE_ID_PREPAID_CARD] != NULL)
            {
                fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],
                        "Error: buffer is full,no space to store new card!\n");
            }
            DeleteCardFaceValue(shmp->face_value);
            return 0; 
        }					   
        return 1;
    }

    if((instance=GetClimaxQuenceStorePos(shmp->card_pwd, 0 , climaxQuence.counter))>=0)
    {
        if(load_file.log_fp[_FILE_ID_PREPAID_CARD] != NULL)
        {
            fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],
                    "Warning: card %s is inuse, cann't be replaced!\n",buftmp);
        } 
        DeleteCardFaceValue(shmp->face_value);
        return 0;
    }

    if(AddNewCardIntoClimaxQuence(shmp)<0)
    {
        if(load_file.log_fp[_FILE_ID_PREPAID_CARD] != NULL)
        {
            fprintf(load_file.log_fp[_FILE_ID_PREPAID_CARD],
                "Error: buffer is full,no space to store new card!\n");
        }
        DeleteCardFaceValue(shmp->face_value);
        return 0; 
    }
	 	 
    return 1;
}

int	CheckCardPWD(char *pin)
{
	char pwd[256],buf[256];
	int	instance;

	strcpy(pwd,pin);
    
	EncryptCardHRN(pin, (u_char *)pwd);
    
	if((instance = GetClimaxQuenceStorePos((u_char *)pwd, 0 , climaxQuence.counter))<0)
	{
		DebugMsg(debugmib.display.asciiOut,
					"Warning: not found card with PWD< %s >!",pin);
		BcdToAscii(buf, (BYTE *)pwd,16);					
		DebugMsg(debugmib.display.asciiOut,"%s-%s",
					pin,buf);
		
	}   
	else
	{
		searchCardByIndex(instance);
	} 
	
	
    return 1;
}

int RechargeCardRequest(u_short proc_id,char *card_hrn,int *result)
{
	char	card_pwd[64]="";
	int	len;
	int	cardsqu=0,cardtail=0;
	_recharge_card_info	*cardshmp=NULL;
	_state_data	*shmp=NULL;

	PutLogFunID("RechargeCardRequest");
	shmp =(_state_data *) &smshm_ptr->state_data;
	shmp += proc_id;

	len = strlen(card_hrn); /* to judge length of pwd,6,8 */


	if(len <10 || len >18  )
	{
#if DEBUG
		if(debug_messages<MAX_DEBUG_MESSAGES)
   		if(logMsgFlag & 0x02 ||
			logMsgFlag & 0x04 ||
			logMsgFlag & 0x10)
   		{
      			debug_messages ++;
      			DebugMsg(debugmib.display.asciiOut,
        			"error recharge card(length): %s",card_hrn);
   		}
#endif
		return 0;
	}

   

	EncryptCardHRN(card_hrn, (u_char *)card_pwd);


	if((cardsqu = GetClimaxQuenceStorePos((u_char *)card_pwd, 0 , climaxQuence.counter))<0)
	{
		#if DEBUG
			if(logMsgFlag & 0x01 || logMsgFlag & 0x02 ||
			  logMsgFlag & 0x04 ||
			  logMsgFlag & 0x10 )
			{
				DebugMsg(debugmib.display.asciiOut,
					"Warning: Error card number< %s >!",card_hrn);
			}
		#endif
		*result = 1; /* no card found */
		return 0;
	}
	cardtail = cardsqu % MAX_CARD_NUM_PSEG;
	cardsqu  = cardsqu / MAX_CARD_NUM_PSEG;
	
	cardshmp=&ramshm_ptr->card_data.prepaid_card[cardsqu][cardtail];


	if(memcmp(card_pwd,cardshmp->card_pwd,MAX_CARD_HRN_BLEN))
	{ /* error password */
#if DEBUG
		if(logMsgFlag & 0x01 || logMsgFlag & 0x02 ||
			logMsgFlag & 0x04 ||
			logMsgFlag & 0x10 )
		{
			char buf[64];
			BcdToAscii(buf,cardshmp->card_pwd,16);
			DebugMsg(debugmib.display.asciiOut,
					"Warning: Error password! %s-%s",card_hrn,buf);
		}
	#endif
		*result = 2; /* error pwd */
		return 0;
   	}
   
	if(cardshmp->card_status != CARD_FRESH && cardshmp->card_status !=CARD_AS_CC_USED)
	{
#if DEBUG
		if(logMsgFlag & 0x01 || logMsgFlag & 0x02 ||
			logMsgFlag & 0x04 || logMsgFlag & 0x10 )
		{
			DebugMsg(debugmib.display.asciiOut,
        			"Warning: This card has been recharged!");
   		}
#endif
		*result = 3; /* card used */
	 	return 0;
	}
	
	if(cardshmp->expiry_date<time(NULL))
   	{
#if DEBUG
		if(logMsgFlag & 0x01 || logMsgFlag & 0x02 ||
	  		logMsgFlag & 0x04 || logMsgFlag & 0x10 )
		{
			DebugMsg(debugmib.display.asciiOut,
				"Warning: This card is expirated!");
		}
#endif
		*result = 4; /* card expired */
	 	return 0;
	}
	shmp->card_info.cardhead = cardsqu;
	shmp->card_info.cardtail = cardtail;
	memcpy(&shmp->context_info.context, cardshmp,sizeof(_recharge_card_info));
	{
		int balance;
		_account_info *account_ptr;

		if(shmp->process_info.rechargeByOther ==1)
		{
			account_ptr = &shmp->recharge_info;
		}
		else
			account_ptr = &shmp->caller_info;

              if(GetAccountPos(account_ptr)==FALSE)
		    balance = 0;
		else
		balance = (int)GetAccountBalance(account_ptr->head,account_ptr->tail);

		balance += GetRechargeCardFaceValue(shmp);
		if(balance >= ppsParam.serviceControl.maxBalance)
		{
			#if DEBUG
			if(logMsgFlag & 0x02 || logMsgFlag & 0x04 || logMsgFlag & 0x10 )
			{
     				DebugMsg(debugmib.display.asciiOut,
					"Recharge failed for balance+card value>maxBalance");
			}
			#endif
			*result = 5; /* too much money */
			return 0;
		}
	}
   
#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)
		if(logMsgFlag & 0x02 || logMsgFlag & 0x04 || logMsgFlag & 0x10 )
   	{
		debug_messages ++;
		DebugMsg(debugmib.display.asciiOut,
		"Face value: %d, valid days: %d",cardshmp->face_value,cardshmp->valid_time);
   	}
#endif

	memcpy(&shmp->context_info.context, cardshmp,sizeof(_recharge_card_info));
	return 1;
}

int SendPrepaidCardRealSync(int instance,int ocode)
{
	_recharge_card_info *cardshmp=NULL;
	snmp_pdu         snmpbuf;
	snmp_addr		 snmpaddr;
	var_list		 *varlist;
	int cardhead,    cardtail;

	PutLogFunID("SendPrepaidCardRealSync");
	cardhead = instance/MAX_CARD_NUM_PSEG;
	cardtail = instance%MAX_CARD_NUM_PSEG;

	cardshmp=&ramshm_ptr->card_data.prepaid_card[cardhead][cardtail];

	snmpbuf.pdu_type = PDU_TRAP; /* trap  */
	snmpbuf.var_num	 = 0x01;

	snmpaddr.remote_ip = peer_server_ip;
	snmpaddr.local_ip  = LOCAL_IP;
	snmpaddr.remote_port = PPS_REALSYNC_PORT;
	snmpaddr.local_port  = PPS_REALSYNC_PORT;
	snmpaddr.broadcast   = 0x00;

	varlist = snmpbuf.var;
	varlist->oidlen   = 17;
	varlist->vartype  = 0x04;

	memcpy(&varlist->oid,PPS_OID_PREFIX,11*4);
	varlist->oid[11] = 0x02; /* configuration */
	varlist->oid[12] = 0x02; /* database */
	varlist->oid[13] = 0x03; /* prepaid card */
	varlist->oid[14] = 0x01; /* prepaid card */
	varlist->oid[15] = instance; 
	varlist->oid[16] = ocode;
	varlist->msglen  = sizeof(_recharge_card_info);
	memcpy(varlist->msg, cardshmp, sizeof(_recharge_card_info));

	if (realSyncTcpSend(PPS_PREPAID_CARD_DB_OID, instance, ocode, varlist->msg, varlist->msglen) < 0)
	{
		snmp_send(&snmpbuf,&snmpaddr);
	}

	if(ocode==4 || ocode == 5)
	{
		snmpaddr.remote_ip = LOCAL_IP;
		snmp_send(&snmpbuf,&snmpaddr);
	}
	
	return 1;
}


static int DeleteCardInfo(_recharge_card_info *cardShmp)
{
	int	instance;
	char	buf[64];
	
	if((instance=GetClimaxQuenceStorePos(cardShmp->card_pwd, 
			0 , climaxQuence.counter))>=0)
	{
		MoveUsedCardToBuffer(instance);
	}
	else 
	{
		BcdToAscii(buf,cardShmp->card_no,cardShmp->card_no[MAX_CARD_LENGTH]%17);
		DebugMsg(debugmib.display.asciiOut,
			  "Update card: %s, card not found!",buf);
	
		return 0;
	}

	return 1;
		
}

void PrepaidCardTcpRealSyncProc(BYTE *pdata, WORD dataLen, DWORD instance, DWORD ocode)
{
	int  head, tail;
	_recharge_card_info *shmp = NULL, card_info;

	PutLogFunID("PrepaidCardTcpRealSyncProc");  

	if(dataLen != sizeof(_recharge_card_info))
	{
		return;
	}

#if DEBUG
	if ((logMsgFlag & 0x02) && (debug_messages<=MAX_DEBUG_MESSAGES))
	{
		debug_messages ++;
		DebugMsgDelimiter();
		DebugMsg(debugmib.display.asciiOut,
		"prepaid card tcp real sync: instance: %d ocode: %d\n", instance, ocode);
	}
#endif   

	head = instance/MAX_CARD_NUM_PSEG;
	tail = instance%MAX_CARD_NUM_PSEG;

	if (head >= MAX_CARD_SEGMENT || tail >= MAX_CARD_NUM_PSEG)
	{
		return ;
	}
	
	if(ocode==5 || ocode == OMC_OCODE_EDIT) // 2: updated
	{/*
		shmp=&ramshm_ptr->card_data.prepaid_card[head][tail];
		if(shmp->card_no[MAX_CARD_LENGTH] == 0) 
		{
			return ;
		}
		
		memcpy(shmp, pdata, sizeof(_recharge_card_info));
		pps_real_update_card_file(head, tail);*/


		shmp = &card_info;
		memcpy(shmp, pdata, sizeof(_recharge_card_info));
		UpdateCardInfo(shmp);
		return ; 
	}
   
	if (ocode == OMC_OCODE_DEL)// 4: del
	{/*
		shmp=&ramshm_ptr->card_data.prepaid_card[head][tail];
		if(shmp->card_no[MAX_CARD_LENGTH] == 0)
		{
			return ;
		}
		
		memcpy(shmp, pdata, sizeof(_recharge_card_info));
		MoveUsedCardToBuffer(instance);*/

		shmp = &card_info;
		memcpy(shmp, pdata, sizeof(_recharge_card_info));
		DeleteCardInfo(shmp);
	}
	else if (ocode == OMC_OCODE_ADD)// 3: add
	{/* update head  */
		shmp = &card_info;
		memcpy(shmp, pdata, sizeof(_recharge_card_info));
		AddNewCardIntoClimaxQuence(shmp);
	}/* else add prepaid card */
	
	/*
	if(reflag)
	{
		SendPrepaidCardRealSync(oid[15],oid[16]);
	}
	*/
	return;
}


void PrepaidCardRealSyncMessageProc(u_char oidLen,
         DWORD *oid, u_char *pdata, u_short dataLen,int reflag)
{
   int  instance, /*head, tail, */ocode;
 
   _recharge_card_info *shmp=NULL,card_info;

	PutLogFunID("PrepaidCardRealSyncMessageProc");  
   if(oidLen<16) return;
   if(dataLen != sizeof(_recharge_card_info)) return;

   instance = oid[15];/* instance */
   ocode = oid[16];/* ocode */
   
#if DEBUG
   if((logMsgFlag & 0x02) && (debug_messages<=MAX_DEBUG_MESSAGES))
   {
      debug_messages ++;
	DebugMsgDelimiter();
	DebugMsg(debugmib.display.asciiOut,
       "prepaid card real sync: instance: %d ocode: %d\n",instance,ocode);
   }
#endif   
   //head = instance/MAX_CARD_NUM_PSEG;
   //tail = instance%MAX_CARD_NUM_PSEG; 
   if(ocode==5 || ocode == OMC_OCODE_EDIT) //updated
   {/*
     shmp=&ramshm_ptr->card_data.prepaid_card[head][tail];
	 if(shmp->card_no[MAX_CARD_LENGTH] == 0) 
		 return ;
     memcpy(shmp,pdata,sizeof(_recharge_card_info));

     pps_real_update_card_file(head, tail);*/
     
        shmp = &card_info;
        memcpy(shmp, pdata, sizeof(_recharge_card_info));
        UpdateCardInfo(shmp);
     return ; 
   }
   if(ocode==OMC_OCODE_DEL){
     /*shmp=&ramshm_ptr->card_data.prepaid_card[head][tail];
	 if(shmp->card_no[MAX_CARD_LENGTH] == 0) 
		 return ;
     memcpy(shmp,pdata,sizeof(_recharge_card_info));
     MoveUsedCardToBuffer(instance);*/

		shmp = &card_info;
		memcpy(shmp, pdata, sizeof(_recharge_card_info));
		DeleteCardInfo(shmp);
   }
   else
   {/* update head  */
     shmp = &card_info;
	 memcpy(shmp,pdata,sizeof(_recharge_card_info));     
	 AddNewCardIntoClimaxQuence(shmp);
   }/* else add prepaid card */
   /*
   if(reflag){
     SendPrepaidCardRealSync(oid[15],oid[16]);
   }
   */
}

int UpdateRechargeCard(u_short proc_id, int status)
{
	int  cardhead,cardtail;
	_recharge_card_info *cardshmp=NULL;
	_state_data     *shmp=NULL;
	int ocode = 5; /*default to delete card for being recharged */
	
	PutLogFunID("UpdateRechargeCard");
	shmp =(_state_data *) &smshm_ptr->state_data;
	shmp += proc_id;

	cardhead = shmp->card_info.cardhead;
	cardtail = shmp->card_info.cardtail;

	cardshmp=&ramshm_ptr->card_data.prepaid_card[cardhead][cardtail];
   
	cardshmp->card_status = status;
	cardshmp->updated_date  = tvnow.tv_sec;

	strcpy(cardshmp->msisdn_used, (char *)shmp->caller_info.number);

   	if(shmp->process_info.ccc_flag )
		ocode = 2;
	SendPrepaidCardRealSync(cardhead*MAX_CARD_NUM_PSEG+cardtail, ocode);

	pps_real_update_card_file(cardhead, cardtail);

   return 1;
}

int UpdateRechargeCardBalance(_card_info *card_info, float charge)
{
	int  cardhead,cardtail;
	_recharge_card_info *cardshmp=NULL;

	PutLogFunID("UpdateRechargeCardBalance");


	cardhead = card_info->cardhead;
	cardtail = card_info->cardtail;

	cardshmp = &ramshm_ptr->card_data.prepaid_card[cardhead][cardtail];

	cardshmp->face_value += ceil(charge+0.5);
	cardshmp->updated_date  = tvnow.tv_sec;

	SendPrepaidCardRealSync(cardhead*MAX_CARD_NUM_PSEG+cardtail, 2);//modify

	pps_real_update_card_file(cardhead, cardtail);

	return 1;
}

int SetPrepaidCardFaceValue(long face_value)
{
   int i;

	PutLogFunID("SetPrepaidCardFaceValue");  
   if(face_value >1000000) return 0;

   for(i=0;i<MAX_VALUE_TYPE;i++)
   {
     if(face_value==ramshm_ptr->card_data.face_value[i])
	 {
	    card_counter[i] ++;
	    return 1;
	 }
   }

   for(i=0;i<MAX_VALUE_TYPE;i++)
   {
     if(ramshm_ptr->card_data.face_value[i]==0)
	 {
		ramshm_ptr->card_data.face_value[i] = face_value;
		card_counter[i] ++;
		return 1; 
	 }
   }
	return 0;
}

void PrintfCounter()
{
	int i;

	for(i=0;i<MAX_VALUE_TYPE;i++)
	{
	    DebugMsg(debugmib.display.asciiOut,"faceValue:%ld,counter[%d]=%ld",
	        ramshm_ptr->card_data.face_value[i],i, card_counter[i]);
	}
}

int GetCardIndex(long face_value)
{
   int i;

	PutLogFunID("GetCardIndex"); 
   if(face_value == 0) return -1;
   for(i=0;i<MAX_VALUE_TYPE;i++)
   {
     if(ramshm_ptr->card_data.face_value[i]==face_value ){
	   return i;
	 }
   }
   return -1;
}

void DeleteCardFaceValue(long face_value)
{
   int i;

	PutLogFunID("DeleteCardFaceValue");
   if(face_value == 0) return ;
   for(i=0;i<MAX_VALUE_TYPE;i++)
   {

     if(ramshm_ptr->card_data.face_value[i]==face_value )
	 {	 
		card_counter[i] --;
	   if(card_counter[i]<=0)
	   {
			card_counter[i] = 0;
			ramshm_ptr->card_data.face_value[i] = 0;
	   }
	   return ;
	 }
   }

}

static int pps_reuse_recharge_card = 0;

void SetPPSRechargeCardReusable(int flag)
{
	pps_reuse_recharge_card = flag;
}

int SetPrepaidCardByOMC(u_char oidlen, DWORD *oid, BYTE *pdata, u_short datalen)
{
	int  instance,ocode;
	int	head,tail,len;
	int  vallen;//chargeFlag=0;
	char buf[1025]={""},workbuf[128]={""};
	char valbuf[128]="";
	//struct tm tmnow;
	long	long cardNo;
	int totalLen=0;
	int loop=0;
	BYTE pdata1[1601],pdata2[1025],pflag;

	u_short ptagcode;
	char tagbuf[32];
	_recharge_card_info    *shmp=NULL;

	ASN_BUF       *asnbuf, asnbuf1;
	ASN_BUF       *asnbuf2, asnbuf3;

	PutLogFunID("SetPrepaidCardByOMC");
	
	memset(pdata1, 0, datalen+1);
	memcpy(pdata1,pdata,datalen);

	asnbuf = &asnbuf1;
	AsnEncode(pdata,1024,asnbuf);
   
	asnbuf2 = &asnbuf3;
	AsnDecode(pdata1, 1024, UNIT_STORE_ACCOUNT, NULL, asnbuf2);
   

#if DEBUG1
	BcdToAscii(buf,pdata1,datalen*2);
	DebugMsg(debugmib.display.asciiOut,"received prepaid card data omc message");
 
	for(i=0;i<oidlen;i++)
	{
		sprintf(workbuf,"%ld.",oid[i]);
		strcat(buf,workbuf);
		memset(workbuf,0,6);
	}

	DebugMsg(debugmib.display.asciiOut,"oid: %s",buf);

	memset(buf,0,1024);

	for(i=0;i<datalen;i++)
		sprintf(&buf[i*3],"%02x ",pdata1[i]);

	DebugMsg(debugmib.display.asciiOut,"data: %s",buf);
#endif
	if(oidlen<17) return 0;
	ocode = oid[16];
	if(ocode>0x04) return 0;
	
	sprintf(buf,"%u",oid[13]);
	sprintf(workbuf,"%08u",oid[14]);
	strcat(buf,workbuf);
	
	cardNo = atoll(buf);
	instance = GetClimaxQuenceStorePosByCardNo(cardNo,0,climaxQuence.counter);
#if DEBUG1
	DebugMsg(debugmib.display.asciiOut,"prepaid card: %lld,ocode: %d,instance:%d",
	  cardNo,ocode,instance);
#endif
	
	if(instance<0)
	{
		#if DEBUG
		if(logMsgFlag & 0x01 || logMsgFlag & 0x02 ||
		  logMsgFlag & 0x04 ||
		  logMsgFlag & 0x10 )
		{
			DebugMsg(debugmib.display.asciiOut,
				"Warning: Error card number %lld, not found,%d!",cardNo,climaxQuence.counter);
		}
		#endif
		return -1;		
	}
	else
	{
		//DebugMsg(debugmib.display.asciiOut,
			//	"Get card  %s, found,%d!",buf,instance);
			
	}
	head = instance / MAX_CARD_NUM_PSEG;
	tail = instance % MAX_CARD_NUM_PSEG;
	
	shmp = &ramshm_ptr->card_data.prepaid_card[head][tail];		

#if DEBUG1
	DebugMsg(debugmib.display.asciiOut,"instance: %d,ocode:%d",instance,ocode);
#endif

	if(ocode ==OMC_OCODE_DEL){ /* delete */
		SendPrepaidCardRealSync(instance,ocode); 
		//MoveUsedCardToBuffer(instance);
		return datalen;
	}

	/*
	if(ocode == 3) 
	{
		sprintf(pdata,"Operation not supported");
		return -2;
	}
	else
	*/
	{/* read */
		for(loop=1;loop<10;loop++)
		{     
			sprintf(tagbuf,"-%d",loop);
			if((vallen=GetAnyTLV(tagbuf,1024,pdata2,&pflag,&ptagcode,asnbuf2))<0){
				break;
			}
			else
			{
				pdata2[vallen]=0;
				sprintf(tagbuf,"%d",ptagcode);
				//printf("tag:%d\n",ptagcode);
				if(ptagcode<=0 || ptagcode>MAX_CARD_NUM_PSEG) continue;
				switch(ptagcode)
				{
					case 0x01: /* card number */
						if(ocode==1){
							BcdToAscii(valbuf,shmp->card_no,MAX_CARD_LENGTH*2);
							len = shmp->card_no[MAX_CARD_LENGTH];
							if(len==0) return -1;
							len = len % 17;
							totalLen = add_tlv(tagbuf,len, (u_char *)valbuf,0x80,asnbuf);
						}
						else if(ocode==2 || ocode ==3)
						{
							/*
							AsciiToBcd(shmp->card_no,pdata2,vallen*2);
							shmp->card_no[MAX_CARD_LENGTH] = vallen;
							*/
				
							vallen = shmp->card_no[MAX_CARD_LENGTH];
							BcdToAscii(valbuf,shmp->card_no,vallen*2);
							if(strcmp(valbuf, (char *)pdata2))
							{
								sprintf((char *)pdata,"can't change card no.");
								return -2;
							}
							else
							{
								totalLen = add_tlv(tagbuf,vallen, (u_char *)valbuf,0x80,asnbuf);
							}
						}
					break;
					case 0x02: /* pwd */
						if(ocode==1){
							len = MAX_CARD_HRN_BLEN;
							memcpy(valbuf,&shmp->card_pwd,MAX_CARD_HRN_BLEN);	   
							totalLen = add_tlv(tagbuf,len, (u_char *)valbuf,0x80,asnbuf);
						}
						else if(ocode==2 || ocode==3){
							if(memcmp(shmp->card_pwd ,pdata2,vallen))
							{
								sprintf((char *)pdata,"password not changed!");
								return -2;
							}
							totalLen = add_tlv(tagbuf,
										MAX_CARD_HRN_BLEN,
										shmp->card_pwd,
										0x80,
										asnbuf);									
						}
					break;
					case 0x03: /* face value */
						if(ocode==1){
							totalLen = AddInteger(tagbuf,shmp->face_value,0x80,asnbuf);
						}else if(ocode==2 || ocode==3){
							totalLen = AddInteger(tagbuf,shmp->face_value,0x80,asnbuf);
						}
					break;
					case 0x04: /* card status */
						if(ocode==1){
							len = 1;
							valbuf[0] = shmp->card_status ;
							totalLen = add_tlv(tagbuf,len, (u_char *)valbuf,0x80,asnbuf);
						}
						else if(ocode==2 || ocode==3)
			  			{
							if(pdata2[0] >2)
							{
								sprintf((char *)pdata,"error field value,should be 0-2.");	
									return -2;
							}

							if(shmp->card_status == 1 && pdata2[0] == 0)
							{
								if(pps_reuse_recharge_card)
								{
									shmp->card_status = pdata2[0] ;
									pps_reuse_recharge_card = 0;
								}
								else
								{
									
									sprintf((char *)pdata,"Operation not supported!");
									return -2;
								}
							}
							else if(shmp->card_status == 0 && pdata2[0] == 2)
							{
								//	chargeFlag = 1;
								shmp->card_status = pdata2[0];
								totalLen = add_tlv(tagbuf,1,&shmp->card_status,0x80,asnbuf);		
							}
							else if(shmp->card_status == 2 && pdata2[0] == 0)
							{
								shmp->card_status = pdata2[0];
								totalLen = add_tlv(tagbuf,1,&shmp->card_status,0x80,asnbuf);		
							}
							else 
							{
								sprintf((char *)pdata,"Operation not supported!");
								return -2;
							}
							
							totalLen = add_tlv(tagbuf,1,&shmp->card_status,0x80,asnbuf);
						}
					break;
					case 0x05:  /* expiry_date */
						if(ocode==1)
						{
							len = 7;
							AsciiTime(buf,shmp->expiry_date);
							AsciiToBcd((BYTE *)valbuf,buf,14);
							totalLen = add_tlv(tagbuf,len, (u_char *)valbuf,0x80,asnbuf);
						}
						else if(ocode==2 || ocode==3)
						{
							/* 
							BcdToAscii(buf,pdata2,vallen*2);
							shmp->expiry_date = MakeTime(&tmnow,buf);
							AsciiTime(buf,shmp->expiry_date);
							AsciiToBcd(valbuf,buf,14);
							len = 7;
							totalLen = add_tlv(tagbuf,len,valbuf,0x80,asnbuf);
							*/
						}
					break;
					case 0x06: /* valid_time */
						if(ocode==1){
							len = 4;
							totalLen = AddInteger(tagbuf,shmp->valid_time,0x80,asnbuf);
						}else if(ocode==2 || ocode==3){
						}
					break;
					case 0x07: /* msisdn_used */
						if(ocode==1){
							len = strlen(shmp->msisdn_used);
							if(len>16) len=16;
							if(shmp->msisdn_used[0]=='0') len=0;
							totalLen = add_tlv(tagbuf,len, (u_char *)shmp->msisdn_used,0x80,asnbuf);
						}
						else if(ocode==2 || ocode==3)
			  			{
			 				if(vallen>18) 
							{
								vallen = 18;
								pdata2[vallen] = 0;
							}
							if(vallen<1)
							memset(shmp->msisdn_used,0,18);
						
							if(pdata2[0] == 'F')
							{
								vallen = 0;
								memset(shmp->msisdn_used,0,18);
							}
							else
							{
								strcpy(shmp->msisdn_used, (char *)pdata2);
							}
							totalLen = add_tlv(tagbuf,vallen, (u_char *)shmp->msisdn_used,0x80,asnbuf);
				
						}
					break;
					case 0x08: /* updated_date */
						if(ocode==1){
							AsciiTime(buf,shmp->updated_date);
							AsciiToBcd((BYTE *)valbuf,buf,14);
							len = 7;
							totalLen = add_tlv(tagbuf,len, (u_char *)valbuf,0x80,asnbuf);
						}
						else if(ocode==2 || ocode==3)
						{
			  				BcdToAscii(buf,pdata2,vallen*2);		  
							shmp->updated_date = MakeTime(NULL,buf);

							AsciiTime(buf,shmp->updated_date);
							AsciiToBcd((BYTE *)valbuf,buf,14);
							len = 7;
							totalLen = add_tlv(tagbuf,len, (u_char *)valbuf,0x80,asnbuf);
				
						}
					break;
					default:
					break;
				}/* switch */
			}/* else */
		}/* for */
		
		if(ocode==1)
		{ /* read */
	  //BcdToAscii(buf,pdata,totalLen*2);
	  //printf("len:%d code:%s\n",totalLen,buf);
			datalen = totalLen;  
		}
		else
		{
	    //if(chargeFlag)
		//{
		//	SendManualRechargeCDR(shmp);
		//}
		       pps_real_update_card_file(head, tail);
	    
			SendPrepaidCardRealSync(instance,ocode); 
		}
	}
	return datalen;
}

/*--------------------------------------------------*/
void MoveUsedCardToBuffer(int instance)
{
   int head,tail,head0,tail0;
   int	len;
   _recharge_card_info *shmp=NULL;

	PutLogFunID("MoveUsedCardToBuffer");

	head0 = instance/MAX_CARD_NUM_PSEG;
	tail0 = instance%MAX_CARD_NUM_PSEG;
	if(head0>=MAX_CARD_SEGMENT) return;
	shmp = &ramshm_ptr->card_data.prepaid_card[head0][tail0];

	DeleteCardFaceValue(shmp->face_value);

	head = usedPrepaidCardBuffer.ptrHead;
	tail = usedPrepaidCardBuffer.ptrTail%MAX_USED_CARD_STORED;

	memcpy(&usedPrepaidCardBuffer.used_precard[tail],
		  shmp,
		  sizeof(_recharge_card_info));
	tail ++;
	tail = tail %0x80000000;
	if (tail == head )
	{
		head ++;
		head =  head %0x80000000;
	}
	usedPrepaidCardBuffer.ptrHead = head;
	usedPrepaidCardBuffer.ptrTail = tail ;
   
	len = shmp->card_no[MAX_CARD_LENGTH];
	if(len<12 || len%2==1 || len>20)
		return;
  
	if(DeleteCardFromClimaxQuence(shmp,instance)<0) 
	{
		return;
	}
	//CardNumberInDecrement(0);
   
	memset(shmp,0,sizeof(_recharge_card_info));

	pps_real_update_card_file(head0, tail0);

   //DeletePrepaidCardHead(head0);
}

int GetUsedPrepaidCard(u_char oidLen,DWORD *oid, u_char *pdata,BYTE *vartype)
{
   int      instance,totalLen=0,i,len;
   int      index;
   char     valbuf[128]="",tagbuf[4]="",buf[32]="";
   ASN_BUF  *asnbuf,asnbuf1;
   _recharge_card_info *shmp=NULL;

   *vartype = 0x04;

	PutLogFunID("GetUsedPrepaidCard");

   if(oid[13]==0x01)/* head pointer */
   {
     pdata[0] = usedPrepaidCardBuffer.ptrHead>>24;
     pdata[1] = usedPrepaidCardBuffer.ptrHead>>16;
     pdata[2] = usedPrepaidCardBuffer.ptrHead>>8;
     pdata[3] = usedPrepaidCardBuffer.ptrHead;
     *vartype = 0x02;
	 return 4;
   }else if(oid[13]==0x02)/* tail pointer */
   {
     pdata[0] = usedPrepaidCardBuffer.ptrTail>>24;
     pdata[1] = usedPrepaidCardBuffer.ptrTail>>16;
     pdata[2] = usedPrepaidCardBuffer.ptrTail>>8;
     pdata[3] = usedPrepaidCardBuffer.ptrTail;
     *vartype = 0x02;
     return 4;
   }
   instance = oid[14];

   index = instance % MAX_USED_CARD_STORED;

   asnbuf = &asnbuf1;
   AsnEncode(pdata,1024,asnbuf);

   shmp = &usedPrepaidCardBuffer.used_precard[index];
   for(i=1;i<9;i++)
   {
     sprintf(tagbuf,"%d",i);
     switch(i)
	 {
	   case 1:
  		 BcdToAscii(valbuf,shmp->card_no,MAX_CARD_LENGTH*2);
		 len = shmp->card_no[MAX_CARD_LENGTH];
		 if(len>MAX_CARD_LENGTH*2) len = MAX_CARD_LENGTH*2;
		 totalLen = add_tlv(tagbuf,len, (u_char *)valbuf,0x80,asnbuf);
		 if(len==0)
		 {
			//DebugMsg(debugmib.display.asciiOut,"Zero data of used_card: instance=%d",instance);
		 }
	   break;
	   case 2:
		 len = MAX_CARD_HRN_BLEN;
		 memcpy(valbuf,&shmp->card_pwd,MAX_CARD_HRN_BLEN);	   
		 totalLen = add_tlv(tagbuf,len, (u_char *)valbuf,0x80,asnbuf);
	   break;
	   case 3:
		 totalLen = AddInteger(tagbuf,shmp->face_value,0x80,asnbuf);
	   break;
	   case 4:
		 len = 1;
		 valbuf[0] = shmp->card_status ;
		 totalLen = add_tlv(tagbuf,len, (u_char *)valbuf,0x80,asnbuf);
	   break;
	   case 5:
		 len = 7;
		 AsciiTime(buf,shmp->expiry_date);
		 AsciiToBcd((BYTE *)valbuf,buf,14);
		 totalLen = add_tlv(tagbuf,len, (u_char *)valbuf,0x80,asnbuf);
	   break;
	   case 6:
		 len = 4;
		 totalLen = AddInteger(tagbuf,shmp->valid_time,0x80,asnbuf);
	   break;
	   case 7:
		 len = strlen(shmp->msisdn_used);
		 if(shmp->msisdn_used[0]=='0') len=0;
		 totalLen = add_tlv(tagbuf,len, (u_char *)shmp->msisdn_used,0x80,asnbuf);
	   break;
	   case 8:
		 AsciiTime(buf,shmp->updated_date);
		 AsciiToBcd((BYTE *)valbuf,buf,14);
         len = 7;
		 totalLen = add_tlv(tagbuf,len, (u_char *)valbuf,0x80,asnbuf);
	   break;
	 }
   }
   return totalLen;
}

/*--------- store prepaid card test ---------- 06-30 -----*/
/*
int	 GetClimaxQuenceIndex(u_char	*card_pwd,int start,int end)
{
	int index;

	index = start + (end-start)/2;
	if(start == end ) return start;

	if(memcmp(card_pwd,climaxQuence.card_pwd[index],MAX_CARD_HRN_BLEN)==0)
	{
		return index;
	}
	else if(memcmp(card_pwd,climaxQuence.card_pwd[index],MAX_CARD_HRN_BLEN)>0)
	{
		if(start == end-1) return end;
		return GetClimaxQuenceIndex(card_pwd,index,end);
	}
	else
	{
		if(start == end-1) return start;
		return GetClimaxQuenceIndex(card_pwd,start,index);
	}
}

int	 GetClimaxQuenceStorePos(u_char	*card_pwd,int start,int end)
{
	int index;

	index = start + (end-start)/2;
	if(start == end )
	{
		if(strcmp(card_pwd,climaxQuence.card_pwd[start])==0)
			return start;
		else
			return -1;
	}
	if(start == (end-1))
	{
		if(memcmp(card_pwd,climaxQuence.card_pwd[start],MAX_CARD_HRN_BLEN)==0)
		{
			return start;
		}
		else if(memcmp(card_pwd,climaxQuence.card_pwd[end],MAX_CARD_HRN_BLEN)==0)
		{
			return end;
		}
		else
			return -1;
	}

	if(strcmp(card_pwd,climaxQuence.card_pwd[index])==0)
	{
		return index;
	}
	else if(strcmp(card_pwd,climaxQuence.card_pwd[index])>0)
	{
		return GetClimaxQuenceStorePos(card_pwd,index,end);
	}
	else
	{
		return GetClimaxQuenceStorePos(card_pwd,start,index);
	}
}

int	 StoreCardToClimaxQuence(u_char	*card_pwd,int store_pos)
{
	int		index;
	_climax_quence climaxTemp;

	if(climaxQuence.counter == 0)
	{
		memcpy(&climaxQuence.card_pwd[climaxQuence.counter],
				card_pwd,
				MAX_CARD_HRN_BLEN);
		climaxQuence.store_pos[0] = store_pos;
		return 0;
	}
	else
	{
		index = GetClimaxQuenceIndex(card_pwd,0,climaxQuence.counter);
		if(index<climaxQuence.counter)
		{
			memcpy(&climaxTemp.card_pwd[0],
					&climaxQuence.card_pwd[index],
					MAX_CARD_HRN_BLEN*(climaxQuence.counter-index));
			memcpy(&climaxQuence.card_pwd[index+1],
					&climaxTemp.card_pwd,
					MAX_CARD_HRN_BLEN*(climaxQuence.counter-index));
					
		}
		memcpy(&climaxQuence.card_pwd[index],
				card_pwd,
				MAX_CARD_HRN_BLEN);
		climaxQuence.store_pos[index] = store_pos;
	}
	return index;
}
*/
int	 GetClimaxQuenceIndex(u_char *card_pwd,int start,int end)
{
	int index,result=0;

	index = start + (end-start)/2;
	if(start == end ) return start;
	
	result = memcmp(card_pwd,
		climaxQuence.card_pwd[index],
		MAX_CARD_HRN_BLEN);
	if(result == 0)
	{
		return index;
	}
	else if(result > 0)
	{
		if(start == end-1) return end;
		return GetClimaxQuenceIndex(card_pwd,index,end);
	}
	else
	{
		if(start == end-1) return start;
		return GetClimaxQuenceIndex(card_pwd,start,index);
	}
}

int	 GetClimaxQuenceStorePos(u_char *card_pwd,int start,int end)
{
	int index,result=0;

	if(climaxQuence.counter == 0) return -1;
	if(start>end) return -1;
	index = start + (end-start)/2;

	if(start == end )
	{
		if(memcmp(card_pwd,climaxQuence.card_pwd[start],MAX_CARD_HRN_BLEN)==0)
			return climaxQuence.store_pos[start];
		else
			return -1;
	}

	if(start == (end-1))
	{
		if(memcmp(card_pwd , climaxQuence.card_pwd[start],MAX_CARD_HRN_BLEN)==0)
		{
			return climaxQuence.store_pos[start];
		}
		else if(memcmp(card_pwd , climaxQuence.card_pwd[end],8)==0)
		{
			return climaxQuence.store_pos[end];
		}
		else
			return -1;
	}

	result = memcmp(card_pwd,
				climaxQuence.card_pwd[index],
				MAX_CARD_HRN_BLEN);
	if(result == 0 )
	{
		return climaxQuence.store_pos[index];
	}
	else if(result > 0)
	{
		return GetClimaxQuenceStorePos(card_pwd,index,end);
	}
	else
	{
		return GetClimaxQuenceStorePos(card_pwd,start,index);
	}
}


int	 GetClimaxQuenceIndexByCardNo(long long card_no,int start,int end)
{
	int index;

	index = start + (end-start)/2;
	if(start == end ) return start;

	//printf("start: %d,end: %d, index: %d, card_no: %lld - %lld\n",
	//	start,end,index,card_no,climaxQuence.card_no[index]);
	
	if(card_no == climaxQuence.card_no[index])
	{
		return index;
	}
	else if(card_no > climaxQuence.card_no[index])
	{
		if(start == end-1) return end;
		return GetClimaxQuenceIndexByCardNo(card_no,index,end);
	}
	else
	{
		if(start == end-1) return start;
		return GetClimaxQuenceIndexByCardNo(card_no,start,index);
	}
}

int	 GetClimaxQuenceStorePosByCardNo(long long card_no,int start,int end)
{
	int index;

	if(climaxQuence.counter == 0) return -1;
	if(start>end) return -1;
	index = start + (end-start)/2;
	
//	printf("start: %d,end: %d, index: %d, card_no: %lld - %lld\n",
	//	start,end,index,card_no,climaxQuence.card_no[index]);
		
	if(start == end )
	{
		if(card_no==climaxQuence.card_no[start])
			return climaxQuence.store_pos_card_no[start];
		else
			return -1;
	}

	if(start == (end-1))
	{
		if(card_no == climaxQuence.card_no[start])
		{
			return climaxQuence.store_pos_card_no[start];
		}
		else if(card_no == climaxQuence.card_no[end])
		{
			return climaxQuence.store_pos_card_no[end];
		}
		else
			return -1;
	}

	if(card_no == climaxQuence.card_no[index] )
	{
		return climaxQuence.store_pos_card_no[index];
	}
	else if(card_no > climaxQuence.card_no[index])
	{
		return GetClimaxQuenceStorePosByCardNo(card_no,index,end);
	}
	else
	{
		return GetClimaxQuenceStorePosByCardNo(card_no,start,index);
	}
}

int		AssignFreeQuenceMem()
{
	int	pos;

	if(freeQuence.pWriteSub>0)
	{		
		pos = freeQuence.free_pos[freeQuence.pWriteSub-1];
		freeQuence.pWriteSub --;
		if(freeQuence.pWriteSub<0)
			freeQuence.pWriteSub = 0;
		debugmib.measurement.cardheadnumber = 
				freeQuence.pWriteSub;
				
		return pos;
	}
	return -1;
}

int	 AddCardIntoClimaxQuence(_recharge_card_info *cardInfo,int store_pos)
{
	int		index=0;
	_climax_quence climaxTemp;
	long	long cardNo=0;
	char	buf[64];
	
	if(climaxQuence.counter == 0)
	{
		memcpy(climaxQuence.card_pwd[climaxQuence.counter] , 
			cardInfo->card_pwd, 
			MAX_CARD_HRN_BLEN);
			
		BcdToAscii(buf,cardInfo->card_no,cardInfo->card_no[MAX_CARD_LENGTH]%17);
		buf[cardInfo->card_no[MAX_CARD_LENGTH]%17] = 0;
		//len = strlen(buf);
		cardNo = atoll(buf);
		climaxQuence.card_no[climaxQuence.counter] = cardNo; 
		/*
		printf("%lld - %s store at %d-%d, total: %d\n",
			cardNo,buf,			
			index,store_pos,
			climaxQuence.counter);
		*/
		climaxQuence.store_pos[0] = store_pos;
		climaxQuence.store_pos_card_no[0] = store_pos;
		index = 0;
		
		climaxQuence.counter++;
		//climaxQuence.counter %= MAX_CARD_SEGMENT*MAX_CARD_NUM_PSEG;
		CardNumberInDecrement(1);
		debugmib.watch_dog[16] = climaxQuence.counter ;
	}
	else if(climaxQuence.counter< MAX_CARD_RECORD)
	{
		index = GetClimaxQuenceIndex(cardInfo->card_pwd,0,climaxQuence.counter);
		//printf("index: %d to store new card\n",index);
		if(index<=climaxQuence.counter)
		{
			memcpy(&climaxTemp.card_pwd[0],
					&climaxQuence.card_pwd[index],
					MAX_CARD_HRN_BLEN*(climaxQuence.counter-index));
			memcpy(&climaxQuence.card_pwd[index+1],
					&climaxTemp.card_pwd,
					MAX_CARD_HRN_BLEN*(climaxQuence.counter-index));					
			memcpy(&climaxTemp.store_pos[0],
					&climaxQuence.store_pos[index],
					sizeof(int)*(climaxQuence.counter-index));
			memcpy(&climaxQuence.store_pos[index+1],
					&climaxTemp.store_pos,
					sizeof(int)*(climaxQuence.counter-index));					

		}
		memcpy(climaxQuence.card_pwd[index],cardInfo->card_pwd,MAX_CARD_HRN_BLEN);
		climaxQuence.store_pos[index] = store_pos;
		
		BcdToAscii(buf,cardInfo->card_no,cardInfo->card_no[MAX_CARD_LENGTH]%17);
		buf[cardInfo->card_no[MAX_CARD_LENGTH]%17] = 0;
		cardNo = atoll(buf);
		
		index = GetClimaxQuenceIndexByCardNo(cardNo,0,climaxQuence.counter);
		/*
		printf("%lld - %s store at %d-%d, total: %d\n",
			cardNo,buf,			
			index,store_pos,
			climaxQuence.counter);
		*/
		if(index<=climaxQuence.counter)
		{
			memcpy(&climaxTemp.card_no[0],
					&climaxQuence.card_no[index],
					sizeof(long long)*(climaxQuence.counter-index));
			memcpy(&climaxQuence.card_no[index+1],
					&climaxTemp.card_no,
					sizeof(long long)*(climaxQuence.counter-index));					
					
			memcpy(&climaxTemp.store_pos_card_no[0],
					&climaxQuence.store_pos_card_no[index],
					sizeof(int)*(climaxQuence.counter-index));
			memcpy(&climaxQuence.store_pos_card_no[index+1],
					&climaxTemp.store_pos_card_no,
					sizeof(int)*(climaxQuence.counter-index));					
					
			climaxQuence.card_no[index]= cardNo;
			climaxQuence.store_pos_card_no[index] = store_pos;
			
		}				
		climaxQuence.counter++;
		//climaxQuence.counter %= MAX_CARD_SEGMENT*MAX_CARD_NUM_PSEG;
		CardNumberInDecrement(1);
		debugmib.watch_dog[16] = climaxQuence.counter ;
	}
		
	return index;
}

int	 DeleteCardFromClimaxQuence(_recharge_card_info *cardInfo,int store_pos)
{
	int		index,totalIndex=MAX_CARD_SEGMENT*MAX_CARD_NUM_PSEG;
	_climax_quence climaxTemp;
	long	long cardNo=0;
	char	buf[64];
	
	if(climaxQuence.counter == 0)
	{
//		climaxQuence.card_no[climaxQuence.counter] = card_no;
//		climaxQuence.store_pos[0] = store_pos;
		return -1;
	}
	else
	{
		index = GetClimaxQuenceIndex(cardInfo->card_pwd,0,climaxQuence.counter);
		if(memcmp(climaxQuence.card_pwd[index], 
				cardInfo->card_pwd,
				MAX_CARD_HRN_BLEN) !=0)
			 return -1;
		if(index<climaxQuence.counter)
		{
			memcpy(&climaxTemp.card_pwd[0],
					&climaxQuence.card_pwd[index+1],
					MAX_CARD_HRN_BLEN*(totalIndex-index-1));
			memcpy(&climaxQuence.card_pwd[index],
					&climaxTemp.card_pwd,
					MAX_CARD_HRN_BLEN*(totalIndex-index-1));
			memcpy(climaxTemp.store_pos,
					&climaxQuence.store_pos[index+1],
					sizeof(int)*(totalIndex-index-1));
			memcpy(&climaxQuence.store_pos[index],
					climaxTemp.store_pos,
					sizeof(int)*(totalIndex-index-1));
			
			//DebugMsg(debugmib.display.asciiOut,"delete card: %d, totoal: %d",
			//	store_pos,freeQuence.pWriteSub);
			
			freeQuence.free_pos[freeQuence.pWriteSub] = store_pos;
			freeQuence.pWriteSub ++;
			freeQuence.pWriteSub %= (totalIndex+1);
			
			
		}
		BcdToAscii(buf,cardInfo->card_no,cardInfo->card_no[MAX_CARD_LENGTH]%17);
		buf[cardInfo->card_no[MAX_CARD_LENGTH]%17] = 0;
		cardNo = atoll(buf);
		index = GetClimaxQuenceIndexByCardNo(cardNo,0,climaxQuence.counter);
		if(index<climaxQuence.counter)
		{
			memcpy(&climaxTemp.card_no[0],
					&climaxQuence.card_no[index+1],
					sizeof(long long)*(totalIndex-index-1));
			memcpy(&climaxQuence.card_no[index],
					&climaxTemp.card_no,
					sizeof(long long)*(totalIndex-index-1));
					
			memcpy(climaxTemp.store_pos_card_no,
					&climaxQuence.store_pos_card_no[index+1],
					sizeof(int)*(totalIndex-index-1));
			memcpy(&climaxQuence.store_pos_card_no[index],
					climaxTemp.store_pos_card_no,
					sizeof(int)*(totalIndex-index-1));

		}
			
		climaxQuence.counter --;
		CardNumberInDecrement(0);
	
		debugmib.measurement.cardheadnumber = 
				freeQuence.pWriteSub;
				
		if(climaxQuence.counter<0) 
			climaxQuence.counter = 0;
		debugmib.watch_dog[16] = climaxQuence.counter ;
	}
	return index;
}

void CreateQuenceList()
{
	int		rear_ptr=0;
	int		i,j,len ;
	
	_card_data	*card_data;

	card_data = &ramshm_ptr->card_data;
	rear_ptr = freeQuence.pWriteSub = 0;	

	for(i=MAX_CARD_SEGMENT-1;i>=0;i--)
	{
	       if(i%10 == 0)
	           ReadSyncMessageForInit();
	       
		for(j=MAX_CARD_NUM_PSEG-1;j>=0;j--)
		{
			len = card_data->prepaid_card[i][j].card_no[MAX_CARD_LENGTH];
			if(len<=0 || len<MAX_CARD_LENGTH || len>(MAX_CARD_LENGTH*2))
			{
				memset(&card_data->prepaid_card[i][j],
					0,
					sizeof(_recharge_card_info));
				freeQuence.free_pos[rear_ptr] = i*MAX_CARD_NUM_PSEG + j;
				rear_ptr ++;
				rear_ptr %= (MAX_CARD_SEGMENT*MAX_CARD_NUM_PSEG+1);
				continue;
			}			
			AddCardIntoClimaxQuence(&card_data->prepaid_card[i][j],
				i*MAX_CARD_NUM_PSEG+j);			
			SetPrepaidCardFaceValue(card_data->prepaid_card[i][j].face_value);
		}
	}
	freeQuence.pWriteSub = rear_ptr;
	debugmib.watch_dog[16] = climaxQuence.counter ;
	
	debugmib.measurement.cardheadnumber = 
				freeQuence.pWriteSub;
		
	DebugMsg(debugmib.display.asciiOut,"rear ptr: %d, counter: %d",
				rear_ptr,climaxQuence.counter);


}

int	UpdateCardInfo(_recharge_card_info *cardShmp)
{
	int	instance,head,tail;
	char	buf[64];
	
	if((instance=GetClimaxQuenceStorePos(cardShmp->card_pwd, 
			0 , climaxQuence.counter))>=0)
	{
		head = instance / MAX_CARD_NUM_PSEG;
		tail = instance % MAX_CARD_NUM_PSEG;
	
		memcpy(&ramshm_ptr->card_data.prepaid_card[head][tail],
				cardShmp,
				sizeof(_recharge_card_info));
	}
	else 
	{
		BcdToAscii(buf,cardShmp->card_no,cardShmp->card_no[MAX_CARD_LENGTH]%17);
		DebugMsg(debugmib.display.asciiOut,
			  "Update card: %s, card not found!",buf);
	
		return 0;
	}
	
	pps_real_update_card_file(head, tail);

	return 1;
		
}

int  AddNewCardIntoClimaxQuence(_recharge_card_info *cardShmp)
{
	int		freePos = -1;
	unsigned int	head,tail;
		
	freePos = AssignFreeQuenceMem();
	
	
	
	if(freePos<0 || freePos>= MAX_CARD_SEGMENT*MAX_CARD_NUM_PSEG)
	{
		return -1;
	}
	
	head = freePos / MAX_CARD_NUM_PSEG;
	tail = freePos % MAX_CARD_NUM_PSEG;
	
	memcpy(&ramshm_ptr->card_data.prepaid_card[head][tail],
				cardShmp,
				sizeof(_recharge_card_info));

	pps_real_update_card_file(head, tail);
	
	return AddCardIntoClimaxQuence(cardShmp,freePos);
		
}


int GetRechargeCardByIndex(int index, char *card_no)
{
	if(index<0 || index>=climaxQuence.counter)
		return 0;
	
	sprintf(card_no,"%lld",climaxQuence.card_no[index]);
	return 1;
}
/*--------------- Debug func --------------------------------------*/
void printfClimaxQuenceIndex()
{
	int	i;

	DebugMsg(debugmib.display.asciiOut,"Total quenced :%d",climaxQuence.counter);

	for (i=0;i<climaxQuence.counter ;i++ )
	{
			DebugMsg(debugmib.display.asciiOut,"[%04d] :%06lld @ %d",
				i,climaxQuence.card_pwd[i],climaxQuence.store_pos[i]);
	}
}

void searchCardInfoByPWD(char *pwd)
{
	int		len;
	int		storePos=-1;
	char	card_pwd[32];
	struct	timeval tmstart,tmend;
	

	gettimeofday(&tmstart,NULL);

	len = strlen(pwd);
	if(len<10 || len>20 || len%2)
	{
		DebugMsg(debugmib.display.asciiOut,"Error card pwd:%s",pwd);
		return ;
	}
	EncryptCardHRN(pwd, (u_char *)card_pwd);
	if((storePos = GetClimaxQuenceStorePos((u_char *)card_pwd, 0 , climaxQuence.counter))<0)
	{
		DebugMsg(debugmib.display.asciiOut,"card [%s] not found in DB!",pwd);
			return ;
	}
	DebugMsg(debugmib.display.asciiOut,"card [%s] stored @ [%d] in DB second area!",
			pwd,storePos);
	
	gettimeofday(&tmend,NULL);
	searchCardByIndex(storePos);
	DebugMsg(debugmib.display.asciiOut,"search time: %ld.%06ld-%ld.%06ld",
		tmend.tv_sec,tmend.tv_usec,
		tmstart.tv_sec,tmstart.tv_usec);
}

int searchCardByIndex(int instance)
{
	int					head,tail,len;
	char				buf[32];
	_recharge_card_info *shmp=NULL;
	_card_data			*card_data;
	

	if(instance>=MAX_CARD_SEGMENT*MAX_CARD_NUM_PSEG || instance<0)
	{
		DebugMsg(debugmib.display.asciiOut,"Error index %d, should be 0-%d!",
			instance,MAX_CARD_SEGMENT*MAX_CARD_NUM_PSEG);
		return 0;
	}
	head = instance / MAX_CARD_NUM_PSEG;
	tail = instance % MAX_CARD_NUM_PSEG;
	card_data = &ramshm_ptr->card_data;	
	shmp = &card_data->prepaid_card[head][tail];
	len = shmp->card_no[MAX_CARD_LENGTH];
	if(len<=0 || len<MAX_CARD_LENGTH || len>(MAX_CARD_LENGTH*2))
	{
		DebugMsg(debugmib.display.asciiOut,"Index %d not used.",
			instance);
		return 0;
	}
	BcdToAscii(buf,shmp->card_no,len);
	DebugMsg(debugmib.display.asciiOut,"Card info. of index %d .",
			instance);
	DebugMsg(debugmib.display.asciiOut,"	no: %s",
			buf);
	BcdToAscii(buf,shmp->card_pwd,16);
	DebugMsg(debugmib.display.asciiOut,"	card pwd: %s",
			buf);	
	DebugMsg(debugmib.display.asciiOut,"	faceValue: %d",
			shmp->face_value);
	DebugMsg(debugmib.display.asciiOut,"	status: %d",
			shmp->card_status);
	return 1;
}


int ppsCleanCardFaceValue(int faceValue)
{
        static int pps_clean_card_face_value=0;
        register int i,j;

        _recharge_card_info *shmp=NULL;
        _card_data      *card_data;

        if(faceValue == 0)
        {
                pps_clean_card_face_value = faceValue;
                return 0;
        }
        if(pps_clean_card_face_value == 0)
        {
                pps_clean_card_face_value = faceValue;
                return 0;
        }
        if(pps_clean_card_face_value != faceValue)
        {
                pps_clean_card_face_value = 0;
                return 0;
        }
        
		DebugMsg(debugmib.display.asciiOut,"\nBefore clean command:");
        PrintfCounter();
        
		card_data = &ramshm_ptr->card_data;
        for(i=0;i<MAX_CARD_SEGMENT;i++)
        for(j=0;j<MAX_CARD_NUM_PSEG;j++)
        {
                shmp = &card_data->prepaid_card[i][j];
                if(shmp->face_value == faceValue)
                        MoveUsedCardToBuffer(i*MAX_CARD_NUM_PSEG + j);
        }
        
        pps_clean_card_face_value = 0;
        
        DebugMsg(debugmib.display.asciiOut,"\nAfter clean command:");
        PrintfCounter();
        
		for(i=0;i<MAX_VALUE_TYPE;i++)
        {
            if(ramshm_ptr->card_data.face_value[i]== faceValue && card_counter[i])
                                card_counter[i] = 0;
        }
        return 1;
}

float ocs_get_calling_card_left_balance(int head, int tail)
{
	_recharge_card_info *shmp=NULL;

	if(head >=MAX_CARD_SEGMENT || tail >= MAX_CARD_NUM_PSEG)
		return 0;

       shmp = &ramshm_ptr->card_data.prepaid_card[head][tail];

	return shmp->face_value;
}
/****----------------------------------------------------*/

DWORD    RCM_OID_PREFIX_UPDATE_CARD[18]={1,3,6,1,4,1,1373,2,3,3,26,5,10};

int send_scf_update_card_data(u_short portid)
{
    int    len,oidlen=13;
    _scf_rcm_msg *scf_update_msg, msg;
    char	encrypt_pwd[32];

    snmp_pdu         snmpbuf;
    snmp_addr		 snmpaddr;
    var_list		 *varlist;

    _state_data *shmp;

    PutLogFunID("send_scf_update_card_data");

    shmp = (_state_data *)&smshm_ptr->state_data;

    if(portid>=MAX_FSM_PROCESS)
        return -1;
    shmp += portid;

    len =  sizeof(_scf_rcm_msg);
    
    scf_update_msg = &msg;
    memset(scf_update_msg,0x00,len);
    
    scf_update_msg->ocode = OC_UPDATE_CARD;
    scf_update_msg->invoke_id = portid;
    
    EncryptCardHRN((char *)shmp->called_info.number, (u_char *)encrypt_pwd );
    memcpy(scf_update_msg->card_pwd, encrypt_pwd, MAX_CARD_HRN_BLEN);
    strcpy(scf_update_msg->msisdn, (char *)shmp->caller_info.number);
    
    snmpbuf.pdu_type = PDU_SET; 
    snmpbuf.var_num	 = 0x01;
 
    snmpaddr.remote_ip = ppsParam.rcm_ip;
    snmpaddr.remote_port = HEART_BEATING_PORT;
    snmpaddr.local_port  = HEART_BEATING_PORT;
    snmpaddr.broadcast   = 0x00;

    varlist = snmpbuf.var;
    varlist->oidlen   = oidlen;
    varlist->vartype  = 0x04;

    memcpy(&varlist->oid, RCM_OID_PREFIX_UPDATE_CARD, oidlen*4);
    varlist->msglen  = sizeof(_scf_rcm_msg);

    memcpy(varlist->msg, (u_char *)scf_update_msg, 
		sizeof(_scf_rcm_msg));
    snmp_send(&snmpbuf,&snmpaddr);

   debugmib.msgstatistics.update_card_request ++;

 #if DEBUG
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
    {  
        DebugMsg(debugmib.display.asciiOut,"[%04d] send update card data to RCM %08x @ %ld",portid, ppsParam.rcm_ip,tvnow.tv_sec);
        DebugMsg(debugmib.display.asciiOut,"[%04d] CARD PWD: %s",	portid, shmp->called_info.number);
    }
#endif
    return 1;
}


int scf_update_rcm_card_data_ack(snmp_pdu *pdu, snmp_addr *addr)
{
    u_short portid;
    
   _state_data *shmp;
    _scf_rcm_msg *scf_update_msg;

    PutLogFunID("scf_update_rcm_card_data_ack");

    if(pdu->var[0].msglen != sizeof(_scf_rcm_msg))
    {
        debugmib.msgstatistics.update_card_error_msg ++;
        return 0;
    }

    if(pdu->error_status)
    {
        debugmib.msgstatistics.update_card_error_msg ++;
        return 0;
    }

    scf_update_msg = (_scf_rcm_msg *)pdu->var[0].msg;
    portid = scf_update_msg->invoke_id;

    if(portid>=MAX_FSM_PROCESS)
    {
        debugmib.msgstatistics.update_card_error_msg ++;
        return 0;
    }
    shmp = (_state_data *)&smshm_ptr->state_data;
    shmp += portid;

    /*
    if(shmp->process_info.sub_state != S_REC_CHECK_CARD_WITH_RCM && shmp->process_info.sub_state_2 != 1)
    {
        if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
        {  
            DebugMsg(debugmib.display.asciiOut,"\n[%04d] receive update card ack, but state not in waiting ack: %d-%d @ %ld",
            		portid, shmp->process_info.sub_state ,shmp->process_info.sub_state_2, tvnow.tv_sec);
        }   
        debugmib.msgstatistics.update_card_error_msg ++;
        return 0;
    }
    */
    
    shmp->process_info.update_card_ack = 1;
    shmp->process_info.update_card_result = scf_update_msg->result;

    memcpy(&shmp->context_info.context, &scf_update_msg->card_data,sizeof(_recharge_card_info));

    switch(scf_update_msg->result)
    {
        case OC_RESULT_OK:
        	debugmib.msgstatistics.update_card_ok++;
        break;
        case OC_RESULT_NO_CARD:
        	debugmib.msgstatistics.update_card_no_card++;
        break;
        case OC_RESULT_CARD_USED:
        	debugmib.msgstatistics.update_card_used ++;
        break;
        case OC_RESULT_CARD_EXPIRED:
        	debugmib.msgstatistics.update_card_expired ++;
        break;
        case OC_RESULT_SYSTEM_FAILURE:
        	debugmib.msgstatistics.update_card_sys_failure ++;
        break;
        default:
        	debugmib.msgstatistics.update_card_error_msg ++;
        break;
    }
    return 1;
}

extern int smppSendMsg(u_char *peerNumber, u_char *msg, u_char serviceNumPosition);
int sendSMSRechargeNegativeResponse(_state_data *shmp, u_char error_code )
{
    char sms[512];

    if(shmp == NULL)
    	return 0;

    PutLogFunID("sendSMSRechargeNegativeResponse");
    
    switch(error_code)
    {
        case OC_RESULT_NO_CARD:
        	sprintf(sms, "%s", getSmsSentenceNative(0,SMS_RECHARGE_FAILED_NO_CARD));
        break;
        case OC_RESULT_CARD_USED:
        	sprintf(sms, "%s", getSmsSentenceNative(0,SMS_RECHARGE_FAILED_CARD_USED));
        break;
        case OC_RESULT_CARD_EXPIRED:
        	sprintf(sms, "%s", getSmsSentenceNative(0,SMS_RECHARGE_FAILED_CARD_EXPIRED));
        break;
        case OC_RESULT_SYSTEM_FAILURE:
        	sprintf(sms, "%s", getSmsSentenceNative(0,SMS_RECHARGE_FAILED_SYS_FAILURE));
        default:
        break;
    }

    smppSendMsg(shmp->caller_info.number, (u_char *)sms, ScratchCardRechargeNumberPosition);
    return 1;
}

int initRCMReponse()
{
    inquire_rspmsg(13,RCM_OID_PREFIX_UPDATE_CARD,(void *)scf_update_rcm_card_data_ack);
    return 1;
}

