
#include    "../include/includes.h"
#include    "../include/ppsm.h"
#include    "../include/ramdata.h"
#include    "../include/ppsinf.h"
#include    "../include/message.h"
#include    "../include/iofunc.h"
#include    "../include/version.h"
#include    "../include/pps_public.h"
#include    "../include/cdrme.h"
#include 	"../include/param.h"

#include    "../include/plat_inc.h"
#include "../../../../plat/scf/src/include/scfmsg.h"
#include "../../../../plat/scf/src/include/scfdef.h"


#include "../include/ppsMibTable.h"
#include "../include/mfunc.h"

extern	PPSParamStruct	ppsParam;
extern	struct timeval 	tvnow;
extern _ram_data    	*ramshm_ptr;
extern 	_state_machine	*smshm_ptr;;

extern u_short		debug_messages;
extern int		  	logMsgFlag;


extern int checkTransferedPartialFee(_account_info   *callerInfo,float feeTransfered);

extern	int	StuffCapMessage(CapArg capArg, PCAP_Message pcap_message);
extern 	int ppsDebugCapMsg(CAP_Message *cap_message,int flag);
extern void FeeTransferTransaction(_state_data *shmp);
static int getParentNumber(_prepaid_info *prepaidInfo,u8 *parentNumber);
static int getMaxCalls(_prepaid_info *prepaidInfo);
static int getMaxSMS(_prepaid_info *prepaidInfo);
static int getMaxConsume(_prepaid_info *prepaidInfo);
static int getCallsMadeToday(_prepaid_info *prepaidInfo);
static int getSMSToday(_prepaid_info *prepaidInfo);
static int getConsumeFee(_prepaid_info *prepaidInfo);
static int checkMasterFee(u_short portid);
static int RealTransferToSlave(_state_data *shmp);
static int smppNotifyMasterADD(u_char *masterNumber,u_char *slaveNumber);
static int smppNotifyMasterDEL(u_char *masterNumber,u_char *slaveNumber);
static int smppNotifySlaveADD(u_char *masterNumber,u_char *slaveNumber);
static int smppNotifySlaveDEL(u_char *masterNumber,u_char *slaveNumber);
static int getAddSlaveCharge(_account_info *accountInfo);
static int getAddingSlaveCosId(_state_data *shmp,MASTER_SLAVE_ADD	*add);
static u_char getChildNum(u_short portid);
static void setChildNum(u_short portid,u_char childNum);
extern BOOL isPromotionCanBeTransfered(_account_info      *accountInfo);

int masterChangeSlaveCharge(_state_data *shmp,_account_info *slaveInfo);
int IncreasePoolAccountChangeCounter(int head, int tail);

void ppsgetdaytime_readFormat(char *daytime_buf);


enum{
	S_MASTER_ADD_IDLE,
	S_MASTER_ADD_WAIT_SLAVE,
	S_MASTER_ADD_WAIT_COS,	
	S_MASTER_ADD_PLAY_CONFIRM,
	S_MASTER_ADD_WAIT_PLAY_CONFIRM,
	S_MASTER_ADD_WAIT_CONFIRM,
	S_MASTER_ADD_PROCESSING,
	S_MASTER_ADD_WAIT_PLAY_DONE,
	S_MASTER_ADD_EXIT,
};


/******************************	enquiry	***********************************************/
 _prepaid_info 	*getPrepaidInfo(_account_info *account)
{
	int				head,tail;

	if(account == NULL)
		return NULL;
	head = account->head;
	tail = account->tail;
	if (account->head < MSISDN_HEAD_NUM && account->tail < UNIT_STORE_ACCOUNT) 
	{
		return &ramshm_ptr->prepaid_data.prepaid_info[head][tail];		
		//return 1;
	}
	return NULL;
}

int getHowManyChildren(_prepaid_info *prepaidInfo)
{
	if(prepaidInfo == NULL)
		return -1;
	return prepaidInfo->poolAccount.roleParty.parent.childNumber;
}

int increMasterChildren(_prepaid_info *prepaidInfo)
{
	if(prepaidInfo == NULL)
		return 0;
	prepaidInfo->poolAccount.roleParty.parent.childNumber++;
	if(prepaidInfo->poolAccount.roleParty.parent.childNumber > POOL_MAX_CHILD)
		prepaidInfo->poolAccount.roleParty.parent.childNumber = POOL_MAX_CHILD;
	return prepaidInfo->poolAccount.roleParty.parent.childNumber;
}

int decMasterChildren(_prepaid_info *prepaidInfo)
{
	if(prepaidInfo == NULL)
		return 0;
	if(prepaidInfo->poolAccount.roleParty.parent.childNumber <= 0)
		prepaidInfo->poolAccount.roleParty.parent.childNumber = 0;
	else
		prepaidInfo->poolAccount.roleParty.parent.childNumber--;	
	return prepaidInfo->poolAccount.roleParty.parent.childNumber;
}

static int getChildNumber(_prepaid_info *prepaidInfo,u8 childIndex,u_char *childNumber)
{
	u8	*bcdNumber,len;
	
	if(prepaidInfo == NULL)
		return -1;
	if(childIndex <= 0 || childIndex > POOL_MAX_CHILD)
		return -1;	
	bcdNumber = prepaidInfo->poolAccount.roleParty.parent.childMsisdn[childIndex - 1];
	len = bcdNumber[MAX_MSISDN_BLEN-1];
	/*
	if(len > MAX_MSISDN_ALEN || len < 3)
		return -1;
	*/
	BcdToAscii((char *)childNumber,bcdNumber,(MAX_MSISDN_BLEN-1)*2);
	childNumber[len] = 0;
	return len;	
}


static void SendDesignatedVoiceAndCollectInfo(u_short portid)
{
   int			dlgid,invokeid=0,len;
   u_char		u_msisdn[12];
   char			buf[32];
   CAP_Message	cap_message;
   CapArg		capArg;
   CapPromptAndCollectUserInformation	*pPCUI;
   CapMessageID							*pMID;

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

	PutLogFunID("SendFavPromptAndCollectUserInfo");

	shmp += portid;   
	AddPPSStatistics(MIBPPS_PCUI,shmp->process_info.dir);
   
	dlgid  = shmp->context_info.dialogue_id;
   
	capArg.ocode = CAP_OC_PromptAndCollectUserInformation;
	capArg.message_flag = REQUEST;
	capArg.port_id = portid;
	capArg.dialogue_id = dlgid;
	capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;

	pPCUI = &capArg.msg_list.promptAndCollectUserInformationArg;

    pPCUI->collectedInfo.choice_id = 0x00;
	pPCUI->collectedInfo.collectedDigits.minimumNbOfDigits = 1;
	pPCUI->collectedInfo.collectedDigits.maximumNbOfDigits = 
		shmp->process_info.maxPCUInfoLen;
	pPCUI->collectedInfo.collectedDigits.optional_flag = 0x79;
	memcpy(pPCUI->collectedInfo.collectedDigits.endOfReplyDigit,
			shmp->process_info.endOfReplyDigit,3);
	pPCUI->collectedInfo.collectedDigits.firstDigitTimeOut = 10;
	pPCUI->collectedInfo.collectedDigits.interDigitTimeOut = 10;
	pPCUI->collectedInfo.collectedDigits.errorTreatment = repeatPrompt;
	pPCUI->collectedInfo.collectedDigits.interruptableAnnInd = 1;

	pPCUI->optional_flag = 0x03;
	pPCUI->disconnectFromIPForbidden = 0x01;
	pPCUI->informationToSend.choice_id = 0x00;
	pPCUI->informationToSend.inbandInfo.messageID.choice_id = 0x03;

	pMID = &pPCUI->informationToSend.inbandInfo.messageID;
	pMID->variableMessage.elementaryMessageID =
		GetAccountVoiceID(shmp->caller_info.head,shmp->caller_info.tail)*65536 +
			+shmp->process_info.voiceID;
	pMID->variableMessage.variableParts.num = 2;


	pMID->variableMessage.variableParts.variablePart[0].choice_id = 1;	
	strcpy(buf,shmp->process_info.tmpDigits);
	len = strlen(buf);
	if(len>18) 
		len = 18;
	ppsAsciiToBcdR(u_msisdn,buf,((len+1)/2)*2);
	pMID->variableMessage.variableParts.variablePart[0].number[0] = (len+1)/2+1;
	if(len%2==0)
		pMID->variableMessage.variableParts.variablePart[0].number[1] = 0x04;
	else
		pMID->variableMessage.variableParts.variablePart[0].number[1] = 0x24;
	memcpy(&pMID->variableMessage.variableParts.variablePart[0].number[2],
			u_msisdn,
			(len+1)/2);	

	pMID->variableMessage.variableParts.variablePart[1].choice_id = 0;	
	pMID->variableMessage.variableParts.variablePart[1].integer	= getChildNum(portid);
	
	pPCUI->informationToSend.inbandInfo.optional_flag = 0x07;
	pPCUI->informationToSend.inbandInfo.numberOfRepetitions = 0x01;
	pPCUI->informationToSend.inbandInfo.duration = 0x00;
	pPCUI->informationToSend.inbandInfo.interval = 0x01;

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);


#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif
}

static void SendSlaveParentNumber(u_short portid)
{
	u8						parentNumber[MAX_MSISDN_BLEN]={0},parentNumberAscci[MAX_MSISDN_BLEN*2]={0},u_msisdn[32]={0};
	_prepaid_info 			*prepaidInfo;
	int						len;
	_state_data 			*shmp;

	int						dlgid,invokeid=0;
	CAP_Message				cap_message;
	CapArg					capArg;
	CapPlayAnnouncement		*pPlayAnnouncement;
	CapMessageID			*pMID;
	CapVariablePart			*pV;
	u8						index=0;
	
	PutLogFunID("SendSlaveParentNumber");		

	
	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	AddPPSStatistics(MIBPPS_PLAY_ANNOUNCEMENT,shmp->process_info.dir);	
	if((prepaidInfo = getPrepaidInfo(&shmp->caller_info)) == NULL)
		return;			
   
	dlgid  = shmp->context_info.dialogue_id;
   
	capArg.ocode = CAP_OC_PlayAnnouncement;
	capArg.message_flag = REQUEST;
	capArg.port_id = portid;
	capArg.dialogue_id = dlgid;
	capArg.invoke_id = invokeid;
    capArg.version = shmp->context_info.acn_ver;

	pPlayAnnouncement = &capArg.msg_list.playAnnouncementArg;

	pPlayAnnouncement->optional_flag = 0x03;
	pPlayAnnouncement->disconnectFromIPForbidden = 0x01;
	pPlayAnnouncement->requestAnnouncementComplete = 0x01;

	pPlayAnnouncement->informationToSend.choice_id = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.messageID.choice_id = 0x03;
	
	pMID = &pPlayAnnouncement->informationToSend.inbandInfo.messageID;

	pMID->variableMessage.elementaryMessageID = 
		GetAccountVoiceID(shmp->caller_info.head,shmp->caller_info.tail)*65536 + SLAVE_ENQUIRY_PARENT_NUMBER;
	pMID->variableMessage.variableParts.num = 1;

	getParentNumber(prepaidInfo,parentNumber);	
	/*********************************	parent number ************************************/
	index = 0;
	len = parentNumber[MAX_MSISDN_BLEN-1];
	BcdToAscii((char *)parentNumberAscci,parentNumber,18);
	StringCut((char *)parentNumberAscci,'F');
	parentNumberAscci[len] = 0;		
	ppsAsciiToBcdR(u_msisdn, (char *)parentNumberAscci,len);
	if(len>(MAX_MSISDN_BLEN-1)*2) 
		len = (MAX_MSISDN_BLEN - 1 )*2;
	
	pV = &pMID->variableMessage.variableParts.variablePart[index];
	pV->choice_id = 1;
	
	pV->number[0] = (len+1)/2+1;
	if(len%2==0)
	{
		pV->number[1] = 0x04;
		memcpy(&pV->number[2],u_msisdn,(len+1)/2);
	}
	else
	{
		pV->number[1] = 0x24;
		memcpy(&pV->number[2],u_msisdn,(len+1)/2);
		pV->number[2+(len+1)/2] &=0x0F;
	}
	/*********************************	parent number ************************************/
	
	
	pPlayAnnouncement->informationToSend.inbandInfo.optional_flag = 0x07;
	pPlayAnnouncement->informationToSend.inbandInfo.numberOfRepetitions = 0x01;
	pPlayAnnouncement->informationToSend.inbandInfo.duration = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.interval = 0x01;

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);


#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif
	return;
}

static void SendSlaveLimits(u_short portid)
{
  	int						maxConsumePerDay,maxCallsPerDay,maxSMSPerDay,balance,centbalance,hth_b,th_b,h_b,b_b;;
	u8						buf[256]={0};
	_prepaid_info 			*prepaidInfo;
	int						resolution=100;
	//int						len;
	_state_data 			*shmp;

	int						dlgid,invokeid=0;
	CAP_Message				cap_message;
	CapArg					capArg;
	CapPlayAnnouncement		*pPlayAnnouncement;
	CapMessageID			*pMID;
	CapVariablePart			*pV;
	u8						index=0;
	
	PutLogFunID("SendSlaveLimits");		

	
	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	AddPPSStatistics(MIBPPS_PLAY_ANNOUNCEMENT,shmp->process_info.dir);	
	if((prepaidInfo = getPrepaidInfo(&shmp->caller_info)) == NULL)
		return;			
   
	dlgid  = shmp->context_info.dialogue_id;
   
	capArg.ocode = CAP_OC_PlayAnnouncement;
	capArg.message_flag = REQUEST;
	capArg.port_id = portid;
	capArg.dialogue_id = dlgid;
	capArg.invoke_id = invokeid;
    capArg.version = shmp->context_info.acn_ver;

	pPlayAnnouncement = &capArg.msg_list.playAnnouncementArg;

	pPlayAnnouncement->optional_flag = 0x03;
	pPlayAnnouncement->disconnectFromIPForbidden = 0x01;
	pPlayAnnouncement->requestAnnouncementComplete = 0x01;

	pPlayAnnouncement->informationToSend.choice_id = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.messageID.choice_id = 0x03;
	
	pMID = &pPlayAnnouncement->informationToSend.inbandInfo.messageID;

	pMID->variableMessage.elementaryMessageID = 
		GetAccountVoiceID(shmp->caller_info.head,shmp->caller_info.tail)*65536 + SLAVE_ENQUIRY_LIMITS;
	pMID->variableMessage.variableParts.num = 3;

	maxCallsPerDay = getMaxCalls(prepaidInfo);
	maxSMSPerDay = getMaxSMS(prepaidInfo);
	maxConsumePerDay = getMaxConsume(prepaidInfo);
	resolution = getSystemCurrencyResolution();

	/*********************************	 max calls per day  ************************************/
	index = 0;
	pV = &pMID->variableMessage.variableParts.variablePart[index];
	pV->choice_id = 0;
	pV->integer = maxCallsPerDay;
	/*********************************	 max calls per day  ************************************/


	/*********************************	 max SMS per day  ************************************/
	index = 1;
	pV = &pMID->variableMessage.variableParts.variablePart[index];
	pV->choice_id = 0;
	pV->integer = maxSMSPerDay;
	/*********************************	 max SMS per day  ************************************/

	/*********************************	max consumption per day ************************************/
	index = 2;
	balance = maxConsumePerDay;
	centbalance = (balance % resolution);
	balance		= (balance / resolution);
    hth_b		= (balance / 10000)%100;
    th_b		= (balance / 1000)%10;
	h_b			= (balance / 100)%10;
	b_b			= (balance % 100); 

	pV = &pMID->variableMessage.variableParts.variablePart[index];
	pV->choice_id = 4;
	sprintf((char *)buf,"%02d",hth_b);

	ppsAsciiToBcdR(&pV->price[0], (char *)buf,2);
	sprintf((char *)buf,"%d%d",th_b,h_b);

	ppsAsciiToBcdR(&pV->price[1], (char *)buf,2);
	sprintf((char *)buf,"%02d",b_b);

	ppsAsciiToBcdR(&pV->price[2], (char *)buf,2);
	sprintf((char *)buf,"%02d",centbalance);

	ppsAsciiToBcdR(&pV->price[3], (char *)buf,2);	
	/*********************************	max consumption per day ************************************/
	
	pPlayAnnouncement->informationToSend.inbandInfo.optional_flag = 0x07;
	pPlayAnnouncement->informationToSend.inbandInfo.numberOfRepetitions = 0x01;
	pPlayAnnouncement->informationToSend.inbandInfo.duration = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.interval = 0x01;

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);


#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif
	return;
}

static void SendSlaveToday(u_short portid)
{
  	int						chargedToday,balance,centbalance,hth_b,th_b,h_b,b_b;
	int						dailedToday,smsToday;
	u8						buf[256]={0};
	_prepaid_info 			*prepaidInfo;
	int						resolution=100;
	//int						len;
	_state_data 			*shmp;

	int						dlgid,invokeid=0;
	CAP_Message				cap_message;
	CapArg					capArg;
	CapPlayAnnouncement		*pPlayAnnouncement;
	CapMessageID			*pMID;
	CapVariablePart			*pV;
	u8						index=0;
	
	PutLogFunID("SendSlaveEnquiryResult");		
	
	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	AddPPSStatistics(MIBPPS_PLAY_ANNOUNCEMENT,shmp->process_info.dir);	
	if((prepaidInfo = getPrepaidInfo(&shmp->caller_info)) == NULL)
		return;			
   
	dlgid  = shmp->context_info.dialogue_id;
   
	capArg.ocode = CAP_OC_PlayAnnouncement;
	capArg.message_flag = REQUEST;
	capArg.port_id = portid;
	capArg.dialogue_id = dlgid;
	capArg.invoke_id = invokeid;
    capArg.version = shmp->context_info.acn_ver;

	pPlayAnnouncement = &capArg.msg_list.playAnnouncementArg;

	pPlayAnnouncement->optional_flag = 0x03;
	pPlayAnnouncement->disconnectFromIPForbidden = 0x01;
	pPlayAnnouncement->requestAnnouncementComplete = 0x01;

	pPlayAnnouncement->informationToSend.choice_id = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.messageID.choice_id = 0x03;
	/* account balance */
	pMID = &pPlayAnnouncement->informationToSend.inbandInfo.messageID;

	pMID->variableMessage.elementaryMessageID = 
		GetAccountVoiceID(shmp->caller_info.head,shmp->caller_info.tail)*65536 + SLAVE_ENQUIRY_TODAY;
	pMID->variableMessage.variableParts.num = 3;
	
	dailedToday = getCallsMadeToday(prepaidInfo);
	smsToday = getSMSToday(prepaidInfo);
	chargedToday = getConsumeFee(prepaidInfo);		
	resolution = getSystemCurrencyResolution();	

	/*********************************	 calls  today  ************************************/
	index = 0;
	pV = &pMID->variableMessage.variableParts.variablePart[index];
	pV->choice_id = 0;
	pV->integer = dailedToday;	
	/*********************************	 calls today  ************************************/
	

	/*********************************	 SMS  today  ************************************/
	index = 1;
	pV = &pMID->variableMessage.variableParts.variablePart[index];
	pV->choice_id = 0;
	pV->integer = smsToday;	
	/*********************************	 SMS today  ************************************/


	/*********************************	 consumption today ************************************/
	index = 2;
	balance = chargedToday;
	centbalance = (balance % resolution);
	balance		= (balance / resolution);
    hth_b		= (balance / 10000)%100;
    th_b		= (balance / 1000)%10;
	h_b			= (balance / 100)%10;
	b_b			= (balance % 100); 
	
	pV = &pMID->variableMessage.variableParts.variablePart[index];
	pV->choice_id = 4;
	sprintf((char *)buf,"%02d",hth_b);

	ppsAsciiToBcdR(&pV->price[0], (char *)buf,2);
	sprintf((char *)buf,"%d%d",th_b,h_b);

	ppsAsciiToBcdR(&pV->price[1], (char *)buf,2);
	sprintf((char *)buf,"%02d",b_b);

	ppsAsciiToBcdR(&pV->price[2], (char *)buf,2);
	sprintf((char *)buf,"%02d",centbalance);

	ppsAsciiToBcdR(&pV->price[3], (char *)buf,2);	
	/*********************************	 consumption today  ************************************/

	
	pPlayAnnouncement->informationToSend.inbandInfo.optional_flag = 0x07;
	pPlayAnnouncement->informationToSend.inbandInfo.numberOfRepetitions = 0x01;
	pPlayAnnouncement->informationToSend.inbandInfo.duration = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.interval = 0x01;

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);


#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif
	return;
}



static void SendSlaveInfo(u_short portid)
{
   int			dlgid,invokeid=0;
   //u_char		u_msisdn[12];
   //char			buf[32];
   CAP_Message	cap_message;
   CapArg		capArg;
   CapPromptAndCollectUserInformation	*pPCUI;
   CapMessageID							*pMID;

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

	PutLogFunID("SendFavPromptAndCollectUserInfo");

	shmp += portid;   
	AddPPSStatistics(MIBPPS_PCUI,shmp->process_info.dir);
   
	dlgid  = shmp->context_info.dialogue_id;
   
	capArg.ocode = CAP_OC_PromptAndCollectUserInformation;
	capArg.message_flag = REQUEST;
	capArg.port_id = portid;
	capArg.dialogue_id = dlgid;
	capArg.invoke_id = invokeid;
   capArg.version = shmp->context_info.acn_ver;

	pPCUI = &capArg.msg_list.promptAndCollectUserInformationArg;

    pPCUI->collectedInfo.choice_id = 0x00;
	pPCUI->collectedInfo.collectedDigits.minimumNbOfDigits = 1;
	pPCUI->collectedInfo.collectedDigits.maximumNbOfDigits = 1;
	pPCUI->collectedInfo.collectedDigits.optional_flag = 0x78;
	pPCUI->collectedInfo.collectedDigits.firstDigitTimeOut = 10;
	pPCUI->collectedInfo.collectedDigits.interDigitTimeOut = 10;
	pPCUI->collectedInfo.collectedDigits.errorTreatment = repeatPrompt;
	pPCUI->collectedInfo.collectedDigits.interruptableAnnInd = 1;

	pPCUI->optional_flag = 0x03;
	pPCUI->disconnectFromIPForbidden = 0x01;
	pPCUI->informationToSend.choice_id = 0x00;
	pPCUI->informationToSend.inbandInfo.messageID.choice_id = 0x03;

	pMID = &pPCUI->informationToSend.inbandInfo.messageID;
	pMID->variableMessage.elementaryMessageID =
		GetAccountVoiceID(shmp->caller_info.head,shmp->caller_info.tail)*65536 + MASTER_CARD_HOW_MANY_CHILDREN;
	pMID->variableMessage.variableParts.num = 2;


	pMID->variableMessage.variableParts.variablePart[0].choice_id = 0;	
	pMID->variableMessage.variableParts.variablePart[0].integer	= getChildNum(portid);

	pMID->variableMessage.variableParts.variablePart[1].choice_id = 0;	
	pMID->variableMessage.variableParts.variablePart[1].integer	= getChildNum(portid);
	
	pPCUI->informationToSend.inbandInfo.optional_flag = 0x07;
	pPCUI->informationToSend.inbandInfo.numberOfRepetitions = 0x01;
	pPCUI->informationToSend.inbandInfo.duration = 0x00;
	pPCUI->informationToSend.inbandInfo.interval = 0x01;

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);

#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif
}

static void playChildNumber(u_short portid,u_char *childNumber)
{
	_state_data 			*shmp;

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	shmp->process_info.voiceID = MASTER_CARD_CHILD_NUMBER;
	strcpy(shmp->process_info.tmpDigits, (char *)childNumber);
	SendDesignatedVoiceAndCollectInfo(portid);
}

#define changeEnquirySlaveState(portid,val) do { \
	enquiry = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.enquiry;\
	enquiry->state = val;\
	shmp->process_info.serviceInput = 0;\
	shmp->process_info.funnel = 0;	\
	pps_print_event(shmp->process_info.logMsisdn,"[%05d]\33[32m%s\33[0m transfer to state \33[36m%s\33[0m", portid, __FUNCTION__, #val); \
} while(0)


static  u8 getEnquirySlaveState(u_short portid)
{
	_state_data 			*shmp;
	MASTER_SLAVE_ENQUIRY	*enquiry;
	
	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	enquiry = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.enquiry;
	return enquiry->state;
}


static int WaitForEnquirySalveSelect(_state_data *shmp)
{				
	u_char					input_msg[64] = {0};
	int						result;
	MASTER_SLAVE_ENQUIRY	*enquiry;	
	
	memset(input_msg,0,64);
	result = WaitingForInput(shmp,input_msg);
	if(result != INPUT_SUCCESS)
		return result;
	enquiry = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.enquiry;			
	if(strlen((char *)input_msg) != 1
		|| (input_msg[0] < '0' || input_msg[0] > enquiry->childNum +'0'))
	{
		if(shmp->process_info.serviceInput++ >= SERVICE_INPUT_NUM)
		{
			return (result = INPUT_ERROR_EXIT);
		}
		else
			return (result = INPUT_ERROR_REINPUT);
	}
	
	enquiry->choice = input_msg[0] - '0';	
	return result;		
}


static int WaitForSlaveEnquiryFunc(_state_data *shmp)
{				
	u_char					input_msg[64] = {0};
	int						result;
	MASTER_SLAVE_ENQUIRY	*enquiry;	
	
	PutLogFunID("WaitForChoice");

	memset(input_msg,0,64);
	result = WaitingForInput(shmp,input_msg);
	if(result != INPUT_SUCCESS)
		return result;

	if(strlen((char *)input_msg) != 1
		|| (input_msg[0] < '0' || input_msg[0] > '3'))
	{
		if(shmp->process_info.serviceInput++ >= SERVICE_INPUT_NUM)
		{
			return (result = INPUT_ERROR_EXIT);
		}
		else
			return (result = INPUT_ERROR_REINPUT);
	}
	enquiry = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.enquiry;
	enquiry->choice = input_msg[0] - '0';	
	return result;		
}

static int WaitForMasterEnquiryFunc(_state_data *shmp)
{				
	u_char					input_msg[64] = {0};
	int						result;
	MASTER_SLAVE_ENQUIRY	*enquiry;	
	
	PutLogFunID("WaitForChoice");

	memset(input_msg,0,64);
	result = WaitingForInput(shmp,input_msg);
	if(result != INPUT_SUCCESS)
		return result;

	if(strlen((char *)input_msg) != 1
		|| (input_msg[0] < '0' || input_msg[0] > '3'))
	{
		if(shmp->process_info.serviceInput++ >= SERVICE_INPUT_NUM)
		{
			return (result = INPUT_ERROR_EXIT);
		}
		else
			return (result = INPUT_ERROR_REINPUT);
	}
	enquiry = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.enquiry;
	enquiry->choice = input_msg[0] - '0';	
	return result;		
}


static int getEnquiryChoice(_state_data *shmp)
{					
	MASTER_SLAVE_ENQUIRY	*enquiry;

	enquiry = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.enquiry;
	return enquiry->choice;	
}

static void clearEnquirySlaveInfo(u_short portid)
{
	_state_data 			*shmp;
	MASTER_SLAVE_ENQUIRY	*enquiry;
	PutLogFunID("clearEnquirySlaveInfo");

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

	enquiry = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.enquiry;
	memset(enquiry,0,sizeof(MASTER_SLAVE_ENQUIRY));
}

static void setChildNum(u_short portid,u_char childNum)
{
	_state_data 			*shmp;
	MASTER_SLAVE_ENQUIRY	*enquiry;
	PutLogFunID("clearEnquirySlaveInfo");

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

	enquiry = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.enquiry;
	enquiry->childNum = childNum;
}

static u_char getChildNum(u_short portid)
{
	_state_data 			*shmp;
	MASTER_SLAVE_ENQUIRY	*enquiry;
	PutLogFunID("clearEnquirySlaveInfo");

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

	enquiry = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.enquiry;
	return enquiry->childNum;
}

static int getParentNumber(_prepaid_info *prepaidInfo,u8 *parentNumber)
{
	u8	*bcdNumber;
	
	if(prepaidInfo == NULL)
		return -1;
	bcdNumber = prepaidInfo->poolAccount.roleParty.child.parentMsisdn;
	memcpy(parentNumber,bcdNumber,MAX_MSISDN_BLEN);
	return 1;	
}

static int getMaxCalls(_prepaid_info *prepaidInfo)
{
	COSTable			*cosTableItem;
	u8					cos_id;
	COS_Pool_Account	*pA;
	
	cos_id = prepaidInfo->cos_id%MaxCosTableItem;
	cosTableItem = &ppsParam.ppsTables.cosTable[cos_id];
	pA = &cosTableItem->poolAccount[0];
	return pA->roleParty.child.maxCallsPerDay;	
}

static int getMaxSMS(_prepaid_info *prepaidInfo)
{
	COSTable			*cosTableItem;
	u8					cos_id;
	COS_Pool_Account	*pA;
	
	cos_id = prepaidInfo->cos_id%MaxCosTableItem;
	cosTableItem = &ppsParam.ppsTables.cosTable[cos_id];
	pA = &cosTableItem->poolAccount[0];
	return pA->roleParty.child.maxSMSPerDay;	
}

static int getMaxConsume(_prepaid_info *prepaidInfo)
{
	COSTable			*cosTableItem;
	u8					cos_id;
	COS_Pool_Account	*pA;
	
	cos_id = prepaidInfo->cos_id%MaxCosTableItem;
	cosTableItem = &ppsParam.ppsTables.cosTable[cos_id];
	pA = &cosTableItem->poolAccount[0];
	return pA->roleParty.child.maxFeePerDay;	
}

static int getCallsMadeToday(_prepaid_info *prepaidInfo)
{
	return prepaidInfo->poolAccount.roleParty.child.callsToday;
}
static int getSMSToday(_prepaid_info *prepaidInfo)
{
	return prepaidInfo->poolAccount.roleParty.child.smsToday;
}

static int getConsumeFee(_prepaid_info *prepaidInfo)
{
	return abs(prepaidInfo->poolAccount.roleParty.child.chargedToday);
}


enum SLAVE_ENQUIRY_STATE
{
	S_SLAVE_ENQUIRY_IDLE = 0,
	S_SLAVE_ENQUIRY_PARENT,
	S_SLAVE_ENQUIRY_LIMITS,
	S_SLAVE_ENQUIRY_TODAY,
	S_SLAVE_PLAY_INFO,	
	S_SLAVE_PLAY_DONE,
};

static int slaveEnquiryProc(u_short portid)
{
	_state_data 	*shmp;
	int 			result = SERVICE_KEEP_STATE,rst,choice;
	//u_char			childNumber[MAX_MSISDN_BLEN*2] = {0};
	_prepaid_info 	*prepaidInfo;
	MASTER_SLAVE_ENQUIRY	*enquiry;
	
	PutLogFunID("slaveEnquiryProc");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
		
	switch(getEnquirySlaveState(portid))
	{
		case S_SLAVE_ENQUIRY_IDLE:
			if((prepaidInfo = getPrepaidInfo(&shmp->caller_info)) == NULL)
				return (result = SERVICE_EXIT_PPS);			
			clearEnquirySlaveInfo(portid);			
			playPromptAndCollectVoice(portid,SLAVE_ENQUIRY_MENU,1);
			changeEnquirySlaveState(portid,S_SLAVE_PLAY_DONE);
		break;		
		case S_SLAVE_ENQUIRY_PARENT:
			SendSlaveParentNumber(portid);
			changeEnquirySlaveState(portid,S_SLAVE_PLAY_INFO);
		break;
		case S_SLAVE_ENQUIRY_LIMITS:
			SendSlaveLimits(portid);
			changeEnquirySlaveState(portid,S_SLAVE_PLAY_INFO);
		break;
		case S_SLAVE_ENQUIRY_TODAY:
			SendSlaveToday(portid);
			changeEnquirySlaveState(portid,S_SLAVE_PLAY_INFO);
		break;
		case S_SLAVE_PLAY_INFO:
			rst = CallingCardWaitingForSpecialResourceReport(shmp);
			if(rst == SERVICE_KEEP_STATE)
				break;					
			else if(rst == 1)					
			{								
				playPromptAndCollectVoice(portid,SLAVE_ENQUIRY_MENU,1);
				changeEnquirySlaveState(portid,S_SLAVE_PLAY_DONE);
			}
			else
				result = SERVICE_EXIT_PPS;
		break;
		case S_SLAVE_PLAY_DONE:			
			rst = WaitForSlaveEnquiryFunc(shmp);
			switch(rst)
			{
				case NO_INPUT:
				break;
				case INPUT_SUCCESS:
					choice = getEnquiryChoice(shmp);
					switch(choice)
					{						
						case 0:
							result = SERVICE_RETURN_TO_PARENT;
						break;
						case 1:						
							changeEnquirySlaveState(portid,S_SLAVE_ENQUIRY_PARENT);
						break;
						case 2:
							changeEnquirySlaveState(portid,S_SLAVE_ENQUIRY_LIMITS);
						break;
						case 3:
						default:
							changeEnquirySlaveState(portid,S_SLAVE_ENQUIRY_TODAY);
						break;
					}
				break;
				case INPUT_ERROR_REINPUT:
					playPromptAndCollectVoice(portid,SLAVE_ENQUIRY_MENU,1);
				break;
				case INPUT_ERROR_EXIT:
					result = SERVICE_EXIT_PPS;
				break;
			}
		break;				
	}
	return result;
}

enum MASTER_ENQUIRY_STATE
{
	S_MASTER_ENQUIRY_IDLE = 0,	
	S_MASTER_ENQUIRY_SELECT_INDEX,
	S_MASTER_ENQUIRY_SELECT_FUNC,
	S_MASTER_ENQUIRY_WAIT_PLAY_DONE,
};

static int masterEnquiryProc(u_short portid)
{
	_state_data 	*shmp;
	int 			result = SERVICE_KEEP_STATE,rst,choice;
	u_char			childNumber[MAX_MSISDN_BLEN*2] = {0};
	_prepaid_info 	*prepaidInfo;
	MASTER_SLAVE_ENQUIRY	*enquiry;
	
	PutLogFunID("masterEnquiryProc");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
		
	switch(getEnquirySlaveState(portid))
	{
		case S_MASTER_ENQUIRY_IDLE:
			if((prepaidInfo = getPrepaidInfo(&shmp->caller_info)) == NULL)
				return (result = SERVICE_EXIT_PPS);			
			clearEnquirySlaveInfo(portid);
			rst = getHowManyChildren(prepaidInfo);
			if(rst <= 0)
			{
				playPromptVoice(portid,ENQUIRY_EMPTY);
				changeEnquirySlaveState(portid,S_MASTER_ENQUIRY_WAIT_PLAY_DONE);
			}
			else
			{
				setChildNum(portid,rst);
				SendSlaveInfo(portid);
				changeEnquirySlaveState(portid,S_MASTER_ENQUIRY_SELECT_INDEX);
			}
		break;
		case S_MASTER_ENQUIRY_SELECT_INDEX:
			rst = WaitForEnquirySalveSelect(shmp);
			switch(rst)
			{
				case NO_INPUT:
				break;
				case INPUT_SUCCESS:
					if((prepaidInfo = getPrepaidInfo(&shmp->caller_info)) == NULL)
						return (result = SERVICE_EXIT_PPS);
					choice = getEnquiryChoice(shmp);
					switch(choice)
					{
						case 0:
							result = SERVICE_RETURN_TO_PARENT;
						break;
						default:
							rst = getChildNumber(prepaidInfo,choice,childNumber);
							if(rst > 0)
							{
								playChildNumber(portid,childNumber);
								changeEnquirySlaveState(portid,S_MASTER_ENQUIRY_SELECT_INDEX);
							}
							else
							{
								playPromptAndCollectVoice(portid,NO_CHILD_NUMBER_RELATED,1);
								changeEnquirySlaveState(portid,S_MASTER_ENQUIRY_SELECT_INDEX);						
							}
						break;
					}
				break;
				case INPUT_ERROR_REINPUT:
					changeEnquirySlaveState(portid,S_MASTER_ENQUIRY_IDLE);	
				break;
				case INPUT_ERROR_EXIT:
					result = SERVICE_EXIT_PPS;
				break;
			}
		break;			
		case S_MASTER_ENQUIRY_WAIT_PLAY_DONE:
			rst = CallingCardWaitingForSpecialResourceReport(shmp);
			if(rst == SERVICE_KEEP_STATE)
				break;					
			else if(rst == 1)	
			{																		
				result = SERVICE_RETURN_TO_PARENT;
			}
			else
				result = SERVICE_EXIT_PPS;
		break;
	}
	return result;
}
/******************************	enquiry	***********************************************/



/******************************	add	***********************************************/
#define changeMasterAddState(portid,val) do { \
	add = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.add;\
	add->state = val;\
	shmp->process_info.serviceInput = 0;\
	shmp->process_info.funnel = 0;\
	pps_print_event(shmp->process_info.logMsisdn,"[%05d]\33[32m%s\33[0m transfer to state \33[36m%s\33[0m", portid, __FUNCTION__, #val); \
} while(0)


static u8 getMasterAddState(u_short portid)
{
	_state_data 			*shmp;
	MASTER_SLAVE_ADD		*add;
	
	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	add = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.add;
	return add->state;
}

static void clearMasterAddInfo(u_short portid)
{
	_state_data 			*shmp;
	MASTER_SLAVE_ADD		*add;

	PutLogFunID("clearAddSlaveInfo");

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

	add = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.add;
	memset(add,0,sizeof(MASTER_SLAVE_ADD));
}

static int isMasterFullSlave(u_short portid)
{
	_prepaid_info 	*prepaidInfo;
	u8				result;
	_state_data 	*shmp;

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	if((prepaidInfo = getPrepaidInfo(&shmp->caller_info)) == NULL)
		return TRUE;			
	result = getHowManyChildren(prepaidInfo);	
	if(result >= POOL_MAX_CHILD)
		return TRUE;
	return FALSE;
}

static int WaitingForMasterAddInputSlave(_state_data *shmp)
{				
	u8						input_msg[64] = {0},len,i;
	//float					fee;
	int						result;
	MASTER_SLAVE_ADD		*add;
	
	PutLogFunID("WaitingForMasterInputSlave");

	memset(input_msg,0,64);
	result = WaitingForInput(shmp,input_msg);
	if(result != INPUT_SUCCESS)
		return result;
	len = strlen((char *)input_msg) % (2*MAX_MSISDN_BLEN);
	
	if(len > MAX_MSISDN_ALEN || len < 3)
	{
		if(shmp->process_info.serviceInput++ >= SERVICE_INPUT_NUM)
		{
			return (result = INPUT_ERROR_EXIT);
		}
		else
			return (result = INPUT_ERROR_REINPUT);
	}
	
	for(i=0;i<len;i++)
	{
		if(input_msg[i] < '0' || input_msg[i] > '9')
		{
			if(shmp->process_info.serviceInput++ >= SERVICE_INPUT_NUM)
			{
				return (result = INPUT_ERROR_EXIT);
			}
			else
				return (result = INPUT_ERROR_REINPUT);
		}
	}
	CutUnknownPrefix((char *)input_msg);
	if(!strcmp((char *)shmp->caller_info.number, (char *)input_msg))
	{
		if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
		{
			return (result = INPUT_ERROR_EXIT);
		}
		return (result = INPUT_ERROR_REINPUT);
	}	
	
	add = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.add;
	strcpy((char *)add->slaveInfo.number, (char *)input_msg);
	return result;		
}

static int SendMasterAddConfirmToSrf(u_short portid)
{
	u8						slaveNumber[MAX_MSISDN_BLEN];
	int						len;
	_state_data 			*shmp;

	int						dlgid,invokeid=0;
	CAP_Message				cap_message;
	CapArg					capArg;
	CapPlayAnnouncement		*pPlayAnnouncement;
	CapMessageID			*pMID;
	CapVariablePart			*pV;
	u8						index=0;
	MASTER_SLAVE_ADD		*add;
	
	PutLogFunID("SendMasterAddConfirmToSrf");		

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	AddPPSStatistics(MIBPPS_PLAY_ANNOUNCEMENT,shmp->process_info.dir);	
	
	add = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.add;	

	dlgid  = shmp->context_info.dialogue_id;
   
	capArg.ocode = CAP_OC_PlayAnnouncement;
	capArg.message_flag = REQUEST;
	capArg.port_id = portid;
	capArg.dialogue_id = dlgid;
	capArg.invoke_id = invokeid;
    capArg.version = shmp->context_info.acn_ver;

	pPlayAnnouncement = &capArg.msg_list.playAnnouncementArg;

	pPlayAnnouncement->optional_flag = 0x03;
	pPlayAnnouncement->disconnectFromIPForbidden = 0x01;
	pPlayAnnouncement->requestAnnouncementComplete = 0x01;

	pPlayAnnouncement->informationToSend.choice_id = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.messageID.choice_id = 0x03;
	
	pMID = &pPlayAnnouncement->informationToSend.inbandInfo.messageID;

	pMID->variableMessage.elementaryMessageID = 
		GetAccountVoiceID(shmp->caller_info.head,shmp->caller_info.tail)*65536 + MASTER_CONFIRM_ADD;
	pMID->variableMessage.variableParts.num = 2;

	
	/*********************************	slave number ************************************/		
	index = 0;	
	len = strlen((char *)add->slaveInfo.number);
	ppsAsciiToBcdR(slaveNumber, (char *)add->slaveInfo.number,len);
	if(len>(MAX_MSISDN_BLEN-1)*2) 
		len = (MAX_MSISDN_BLEN - 1 )*2;
	pV = &pMID->variableMessage.variableParts.variablePart[index];
	pV->choice_id = 1;
	
	pV->number[0] = (len+1)/2+1;
	if(len%2==0)
	{
		pV->number[1] = 0x04;
		memcpy(&pV->number[2],slaveNumber,(len+1)/2);
	}
	else
	{
		pV->number[1] = 0x24;
		memcpy(&pV->number[2],slaveNumber,(len+1)/2);
		pV->number[2+(len+1)/2] &=0x0F;
	}	
	/*********************************	slave number ************************************/
	

	index = 1;
	pV = &pMID->variableMessage.variableParts.variablePart[index];
	pV->choice_id = 0;
	pV->integer = add->cosID;	
	
	pPlayAnnouncement->informationToSend.inbandInfo.optional_flag = 0x07;
	pPlayAnnouncement->informationToSend.inbandInfo.numberOfRepetitions = 0x01;
	pPlayAnnouncement->informationToSend.inbandInfo.duration = 0x00;
	pPlayAnnouncement->informationToSend.inbandInfo.interval = 0x01;

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);


#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif
	return 1;

}

static int checkAddSlaveNumber(_state_data 	*shmp)
{
	//MASTER_SLAVE_ADD		*add;
	u_char					slaveBCD[MAX_MSISDN_BLEN];
	_account_info			*slave_info;
	_prepaid_info 			*prepaidInfo;
	int						i,len;
	
	PutLogFunID("checkAddSlaveNumber");

	slave_info = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.add.slaveInfo;	
	if(GetAccountPos(slave_info) == FALSE)
	{		
		return  2;
	}

	if((prepaidInfo = getPrepaidInfo(slave_info)) == NULL)
		return 2;

	if(prepaidInfo->poolAccount.role != MASTER_SLAVE_NONE)
		return 1;
	memset(slaveBCD,0,MAX_MSISDN_BLEN);
	len = strlen((char *)slave_info->number);
	AsciiToBcd(slaveBCD, (char *)slave_info->number,(len+1)/2*2);
	slaveBCD[MAX_MSISDN_BLEN-1] = len;
	if(len %2 ==0)
		slaveBCD[len/2] = 0xFF; 
	else
		slaveBCD[len/2] |= 0x0F; 

	for(i=0;i<POOL_MAX_CHILD;i++)
	{
		if(prepaidInfo->poolAccount.roleParty.parent.childMsisdn[i][MAX_MSISDN_BLEN-1] < 3)
			continue;
		if(!memcmp(slaveBCD,prepaidInfo->poolAccount.roleParty.parent.childMsisdn[i],(len+1)/2*2))	
			return 1;
	}
			
	return 0;		
}

static int WaitingForMasterAddInputCos(_state_data *shmp)
{				
	u_char				input_msg[64] = {0};
	int					result;
	MASTER_SLAVE_ADD	*add;
	
	memset(input_msg,0,64);
	result = WaitingForInput(shmp,input_msg);
	if(result != INPUT_SUCCESS)
		return result;

	if(strlen((char *)input_msg) != 1
		|| (input_msg[0] < '0' || input_msg[0] > '1'))
	{
		if(shmp->process_info.serviceInput++ >= SERVICE_INPUT_NUM)
		{
			return (result = INPUT_ERROR_EXIT);
		}
		else
			return (result = INPUT_ERROR_REINPUT);
	}
	add = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.add;
	add->cosID = input_msg[0] - '0';	
	return result;		
}

static int masterAddWaitForChoice(_state_data 	*shmp)
{
	u_char				input_msg[64] = {0};
	int					result;
	MASTER_SLAVE_ADD	*add;
	
	memset(input_msg,0,64);
	result = WaitingForInput(shmp,input_msg);
	if(result != INPUT_SUCCESS)
		return result;

	if(strlen((char *)input_msg) != 1
		|| (input_msg[0] < '0' || input_msg[0] > '3'))
	{
		if(shmp->process_info.serviceInput++ >= SERVICE_INPUT_NUM)
		{
			return (result = INPUT_ERROR_EXIT);
		}
		else
			return (result = INPUT_ERROR_REINPUT);
	}
	add = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.add;
	add->choice= input_msg[0] - '0';	

	return result;		
}

static int getMasterAddChoice(_state_data *shmp)
{					
	MASTER_SLAVE_ADD		*add;

	add = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.add;
	return add->choice;	
}

static void addProcessSetMaster(_state_data 	*shmp)
{
	_account_info			*slave_info;
	_prepaid_info 			*prepaidInfo;
	UserData_Pool_Account	*poolAccount;
	u8						len,index,*childMsisdnBCD;
	u_char					*childMsisdnASCCI;
	int						charge;
	
	slave_info = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.add.slaveInfo;	
	if((prepaidInfo = getPrepaidInfo(&shmp->caller_info)) == NULL)
		return;
	
	poolAccount = &prepaidInfo->poolAccount;
	poolAccount->role = MASTER_SLAVE_PARENT;

	for(index=0;index<POOL_MAX_CHILD;index++)
	{
		if(poolAccount->roleParty.parent.childMsisdn[index][MAX_MSISDN_BLEN-1] < 3)
			break;
	}
	if(index >= POOL_MAX_CHILD)
		return;
	childMsisdnBCD = poolAccount->roleParty.parent.childMsisdn[index];	
	memset(childMsisdnBCD,0,MAX_MSISDN_BLEN);	
	childMsisdnASCCI = slave_info->number;	
	len = strlen((char *)childMsisdnASCCI);
	AsciiToBcd(childMsisdnBCD, (char *)childMsisdnASCCI,(len+1)/2*2);
	childMsisdnBCD[MAX_MSISDN_BLEN-1] = len;
	if(len %2 ==0)
		childMsisdnBCD[len/2] = 0xFF; 
	else
		childMsisdnBCD[len/2] |= 0x0F; 
					
	increMasterChildren(prepaidInfo);	
	charge = masterChangeSlaveCharge(shmp,slave_info);	
	smppNotifyMasterADD(shmp->caller_info.number,slave_info->number);
	SendAccountRealSync_2(&shmp->caller_info,-charge,0.0,OMC_OCODE_EDIT);
}

static void addProcessSetSlave(_state_data 	*shmp)
{
	_account_info			*slave_info;
	_prepaid_info 			*prepaidInfo,*master;
	UserData_Pool_Account	*poolAccount;
	COSTable				*cosTableItem;
	u8						len,tmp;

	slave_info = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.add.slaveInfo;	
	if((master = getPrepaidInfo(&shmp->caller_info)) == NULL)
		return;
	if((prepaidInfo = getPrepaidInfo(slave_info)) == NULL)
		return ;	
	poolAccount = &prepaidInfo->poolAccount;
	poolAccount->role = MASTER_SLAVE_CHILD;
	
	memset(poolAccount->roleParty.child.parentMsisdn,0xff,MAX_MSISDN_BLEN);	
	len = strlen((char *)shmp->caller_info.number);

	AsciiToBcd(poolAccount->roleParty.child.parentMsisdn, (char *)shmp->caller_info.number,(len+1)/2*2);
	poolAccount->roleParty.child.parentMsisdn[MAX_MSISDN_BLEN-1] = len;
	if(len %2 ==0)
		poolAccount->roleParty.child.parentMsisdn[len/2] = 0xFF; 
	else
		poolAccount->roleParty.child.parentMsisdn[len/2] |= 0x0F; 
						
	poolAccount->roleParty.child.callsToday = 0;
	poolAccount->roleParty.child.chargedToday = 0;
	
	cosTableItem = &ppsParam.ppsTables.cosTable[master->cos_id];
	
	tmp = shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.add.cosID%MAX_CHILD_COS_PER_PARENT;
	prepaidInfo->cos_id = cosTableItem->poolAccount[0].roleParty.parent.cosIDForChild[tmp];
	smppNotifySlaveADD(shmp->caller_info.number,slave_info->number);
	SendAccountRealSync_2(slave_info,0.0,0.0,OMC_OCODE_EDIT);	
}

static int masterAddProc(u_short portid)
{
	_state_data 	*shmp;
	int 			result = SERVICE_KEEP_STATE,rst;
	MASTER_SLAVE_ADD		*add;
	
	PutLogFunID("addProc");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	
	switch(getMasterAddState(portid))
	{
		case S_MASTER_ADD_IDLE:					
			clearMasterAddInfo(portid);
			if(isMasterFullSlave(portid) == TRUE)
			{
				playPromptVoice(portid,ADD_FAIL_FULL);
				changeMasterAddState(portid,S_MASTER_ADD_WAIT_PLAY_DONE);
			}
			else
			{
				playPromptAndCollectVoice(portid,MASTER_INPUT_CHILD_ADD,MAX_IVR_INPUT_LEN);
				changeMasterAddState(portid,S_MASTER_ADD_WAIT_SLAVE);
			}
		break;
		case S_MASTER_ADD_WAIT_SLAVE:
			rst = WaitingForMasterAddInputSlave(shmp);
			switch(rst)
			{
				case NO_INPUT:
				break;				
				case INPUT_SUCCESS:	
					rst = checkAddSlaveNumber(shmp);
					switch(rst)
					{
						case 0:							
							playPromptAndCollectVoice(portid,MASTER_SELECT_COS,1);					
							changeMasterAddState(portid,S_MASTER_ADD_WAIT_COS);
						break;
						case 1:/*	is already a master or slave number	*/
							playPromptAndCollectVoice(portid,ADD_FAIL_ALREADY_EXIST,MAX_IVR_INPUT_LEN);
							changeMasterAddState(portid,S_MASTER_ADD_IDLE);
						break;
						case 2:/*	not exist in pps	*/
							playPromptAndCollectVoice(portid,InvalidAccountIputAgain,MAX_IVR_INPUT_LEN);	
						break;
					}
				break;
				case INPUT_ERROR_REINPUT:					
					playPromptAndCollectVoice(portid,InvalidAccountIputAgain,MAX_IVR_INPUT_LEN);		
				break;
				case INPUT_ERROR_EXIT:
					result = SERVICE_EXIT_PPS;
				break;
			}		
		break;			
		case S_MASTER_ADD_WAIT_COS:
			rst = WaitingForMasterAddInputCos(shmp);
			switch(rst)
			{
				case NO_INPUT:
				break;				
				case INPUT_SUCCESS:										
					rst = checkMasterFee(portid);
					switch(rst)
					{
						case CHECK_TRANSFERED_FEE_OK:
							changeMasterAddState(portid,S_MASTER_ADD_PLAY_CONFIRM);
						break;
						case CHECK_TRANSFERED_FEE_INSUFFIENT:
							playPromptVoice(portid,TRANSFERED_FEE_INSUFFIENT);
							changeMasterAddState(portid,S_MASTER_ADD_WAIT_PLAY_DONE);
						break;
						case CHECK_TRANSFERED_FEE_EXPIERED:	
						default:
							playPromptVoice(portid,TRANSFERED_FEE_EXPIERED);
							changeMasterAddState(portid,S_MASTER_ADD_WAIT_PLAY_DONE);
						break;
					}
				break;
				case INPUT_ERROR_REINPUT:					
					playPromptAndCollectVoice(portid,MASTER_SELECT_COS,1);
				break;
				case INPUT_ERROR_EXIT:
					result = SERVICE_EXIT_PPS;
				break;
			}		
		break;
		case S_MASTER_ADD_PLAY_CONFIRM:
			SendMasterAddConfirmToSrf(portid);
			changeMasterAddState(portid,S_MASTER_ADD_WAIT_PLAY_CONFIRM);
		break;
		case S_MASTER_ADD_WAIT_PLAY_CONFIRM:
			rst = CallingCardWaitingForSpecialResourceReport(shmp);
			if(rst == SERVICE_KEEP_STATE)
				break;					
			else if(rst == 1)	
			{															
				playPromptAndCollectVoice(portid,CONFIRM_LISTEN_AGAIN,1);
				changeMasterAddState(portid,S_MASTER_ADD_WAIT_CONFIRM);
			}
			else
				result = SERVICE_EXIT_PPS;
		break;
		case S_MASTER_ADD_WAIT_CONFIRM:
			rst = masterAddWaitForChoice(shmp);
			switch(rst)
			{
				case NO_INPUT:
				break;				
				case INPUT_SUCCESS:
					rst = getMasterAddChoice(shmp);					
					switch(rst)
					{
						case CONFIRM_OK:
							changeMasterAddState(portid,S_MASTER_ADD_PROCESSING);
						break;
						case CONFIRM_ENTER_AGAIN:
							changeMasterAddState(portid,S_MASTER_ADD_IDLE);
						break;
						case CONFIRM_LISTEN_RE:
							changeMasterAddState(portid,S_MASTER_ADD_PLAY_CONFIRM);
						break;
						case CONFIRM_CANCEL:
							changeMasterAddState(portid,S_MASTER_ADD_EXIT);
						break;						
					}					
				break;
				case INPUT_ERROR_REINPUT:
					playPromptAndCollectVoice(portid,YES_OR_NO,1);					
				break;
				case INPUT_ERROR_EXIT:
					result = SERVICE_EXIT_PPS;
				break;
			}		
		break;
		case S_MASTER_ADD_PROCESSING:					
			addProcessSetMaster(shmp);
			addProcessSetSlave(shmp);
			RealTransferToSlave(shmp);
			playPromptVoice(portid,MASTER_ADD_SUCCESS);
			changeMasterAddState(portid,S_MASTER_ADD_WAIT_PLAY_DONE);
		break;
		case S_MASTER_ADD_WAIT_PLAY_DONE:
			rst = CallingCardWaitingForSpecialResourceReport(shmp);
			if(rst == SERVICE_KEEP_STATE)
				break;					
			else if(rst == 1)	
			{																		
				changeMasterAddState(portid,S_MASTER_ADD_EXIT);
			}
			else
				result = SERVICE_EXIT_PPS;
		break;		
		case S_MASTER_ADD_EXIT:
			result = SERVICE_RETURN_TO_PARENT;			
		break;
		default:
			result = SERVICE_EXIT_PPS;
		break;
	}	
	return result;
}
/******************************	add	***********************************************/



/******************************	delete	***********************************************/
#define changeMasterDelState(portid,val) do { \
	del = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.del;\
	del->state = val;\
	shmp->process_info.serviceInput = 0;\
	shmp->process_info.funnel = 0;\
	pps_print_event(shmp->process_info.logMsisdn,"[%05d]\33[32m%s\33[0m transfer to state \33[36m%s\33[0m", portid, __FUNCTION__, #val); \
} while(0)

static  u8 getMasterDelState(u_short portid)
{
	_state_data 			*shmp;
	MASTER_SLAVE_DEL		*del;
	
	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	del = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.del;
	return del->state;
}

static void clearMasterDelInfo(u_short portid)
{
	_state_data 			*shmp;
	MASTER_SLAVE_DEL		*del;

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

	del = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.del;
	memset(del,0,sizeof(MASTER_SLAVE_DEL));
}

static int isMasterEmptySlave(u_short portid)
{
	_prepaid_info 	*prepaidInfo;
	u8				result;
	_state_data 	*shmp;

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	if((prepaidInfo = getPrepaidInfo(&shmp->caller_info)) == NULL)
		return TRUE;			
	result = getHowManyChildren(prepaidInfo);	
	if(result <= 0)
		return TRUE;
	return FALSE;
}

static int WaitingForMasterDelInputSlave(_state_data *shmp)
{				
	u8						input_msg[64] = {0},len,i;
	int						result;
	MASTER_SLAVE_DEL		*del;
	

	memset(input_msg,0,64);
	result = WaitingForInput(shmp,input_msg);
	if(result != INPUT_SUCCESS)
		return result;
	len = strlen((char *)input_msg) % (2*MAX_MSISDN_BLEN);

	for(i=0;i<len;i++)
	{
		if(input_msg[i] < '0' || input_msg[i] > '9')
		{
			if(shmp->process_info.serviceInput++ >= SERVICE_INPUT_NUM)
			{
				return (result = INPUT_ERROR_EXIT);
			}
			else
				return (result = INPUT_ERROR_REINPUT);
		}
	}
	CutUnknownPrefix((char *)input_msg);	
	del = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.del;	
	strcpy((char *)del->slaveInfo.number, (char *)input_msg);
	return result;		
}


static void SendMasterDelConfirmToSrf(u_short portid)
{			
   	int										dlgid,invokeid=0,len;
   	u_char									u_msisdn[12];
   	//char									buf[32];
   	CAP_Message								cap_message;
   	CapArg									capArg;
   	CapPromptAndCollectUserInformation		*pPCUI;
   	CapMessageID							*pMID;
	MASTER_SLAVE_DEL						*del;
	_state_data    							*shmp=(_state_data *) &smshm_ptr->state_data;


	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	PutLogFunID("SendFavPromptAndCollectUserInfo");

	AddPPSStatistics(MIBPPS_PCUI,shmp->process_info.dir);
	
	del = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.del;		
   
	dlgid  = shmp->context_info.dialogue_id;
   
	capArg.ocode = CAP_OC_PromptAndCollectUserInformation;
	capArg.message_flag = REQUEST;
	capArg.port_id = portid;
	capArg.dialogue_id = dlgid;
	capArg.invoke_id = invokeid;
   	capArg.version = shmp->context_info.acn_ver;

	pPCUI = &capArg.msg_list.promptAndCollectUserInformationArg;	

    pPCUI->collectedInfo.choice_id = 0x00;
	pPCUI->collectedInfo.collectedDigits.minimumNbOfDigits = 1;
	pPCUI->collectedInfo.collectedDigits.maximumNbOfDigits = 1;		
	pPCUI->collectedInfo.collectedDigits.optional_flag = 0x78;
	pPCUI->collectedInfo.collectedDigits.firstDigitTimeOut = 10;
	pPCUI->collectedInfo.collectedDigits.interDigitTimeOut = 10;
	pPCUI->collectedInfo.collectedDigits.errorTreatment = repeatPrompt;
	pPCUI->collectedInfo.collectedDigits.interruptableAnnInd = 0;

	pPCUI->optional_flag = 0x03;
	pPCUI->disconnectFromIPForbidden = 0x01;	
	
	pPCUI->informationToSend.choice_id = 0x00;
	pPCUI->informationToSend.inbandInfo.messageID.choice_id = 0x03;

	pMID = &pPCUI->informationToSend.inbandInfo.messageID;
	pMID->variableMessage.elementaryMessageID =
		GetAccountVoiceID(shmp->caller_info.head,shmp->caller_info.tail)*65536 + MASTER_CONFIRM_DEL;
	pMID->variableMessage.variableParts.num = 1;

	pMID->variableMessage.variableParts.variablePart[0].choice_id = 1;	
	len = strlen((char *)del->slaveInfo.number);
	ppsAsciiToBcdR(u_msisdn, (char *)del->slaveInfo.number,len);
	if(len>(MAX_MSISDN_BLEN-1)*2) 
		len = (MAX_MSISDN_BLEN - 1 )*2;
		
	pMID->variableMessage.variableParts.variablePart[0].number[0] = (len+1)/2+1;
	if(len%2==0)
	{
		pMID->variableMessage.variableParts.variablePart[0].number[1] = 0x04;
		memcpy(&pMID->variableMessage.variableParts.variablePart[0].number[2],
			u_msisdn,
			(len+1)/2);	
	}
	else
	{
		pMID->variableMessage.variableParts.variablePart[0].number[1] = 0x24;
		memcpy(&pMID->variableMessage.variableParts.variablePart[0].number[2],
			u_msisdn,
			(len+1)/2);	
		pMID->variableMessage.variableParts.variablePart[0].number[2+(len+1)/2] &=0x0F;
	}	
	
	pPCUI->informationToSend.inbandInfo.optional_flag = 0x07;
	pPCUI->informationToSend.inbandInfo.numberOfRepetitions = 0x01;
	pPCUI->informationToSend.inbandInfo.duration = 0x00;
	pPCUI->informationToSend.inbandInfo.interval = 0x01;

	StuffCapMessage(capArg,&cap_message);
	WriteScfMsg(cap_message);


#if DEBUG
	if(debug_messages<=MAX_DEBUG_MESSAGES)	
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn)
	{
		ppsDebugCapMsg(&cap_message,1);
		debug_messages ++;
	}
#endif
}

static int checkDelSlaveNumber(_state_data 	*shmp)
{
	u_char					*slaveNumber,slaveStoredNumber[2*MAX_MSISDN_BLEN];
	_account_info			*slave_info;
	_prepaid_info 			*prepaidInfo;
	u8						len,i,totalChild,*pChild;
	
	PutLogFunID("checkDelSlaveNumber");

	slave_info = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.del.slaveInfo;
	slaveNumber = slave_info->number;
	
	if((prepaidInfo = getPrepaidInfo(&shmp->caller_info)) == NULL)
		return 1;
	
	if(GetAccountPos(slave_info) == FALSE)
	{		
		return	2;
	}
	
	totalChild = prepaidInfo->poolAccount.roleParty.parent.childNumber%(POOL_MAX_CHILD+1);
	for(i=0;i<totalChild;i++)
	{	
		pChild = prepaidInfo->poolAccount.roleParty.parent.childMsisdn[i];
		len = pChild[MAX_MSISDN_BLEN-1];
		BcdToAscii((char *)slaveStoredNumber,pChild,18);
		StringCut((char *)slaveStoredNumber,'F');
		slaveStoredNumber[len] = 0;	
		if(!strcmp((char *)slaveNumber, (char *)slaveStoredNumber))	
			return 0;
	}						
	return 1;		
}

static int masterDelWaitForChoice(_state_data 	*shmp)
{
	u_char				input_msg[64] = {0};
	int					result;
	MASTER_SLAVE_DEL	*del;
	
	memset(input_msg,0,64);
	result = WaitingForInput(shmp,input_msg);
	if(result != INPUT_SUCCESS)
		return result;

	if(strlen((char *)input_msg) != 1
		|| (input_msg[0] < '0' || input_msg[0] > '2'))
	{
		if(shmp->process_info.serviceInput++ >= SERVICE_INPUT_NUM)
		{
			return (result = INPUT_ERROR_EXIT);
		}
		else
			return (result = INPUT_ERROR_REINPUT);
	}
	del = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.del;
	del->choice = input_msg[0] - '0';	

	return result;		
}

static int getMasterDelChoice(_state_data *shmp)
{					
	MASTER_SLAVE_DEL	*del;

	del = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.del;
	return del->choice;	
}

static void delProcessSetMaster(_state_data 	*shmp)
{
	_account_info			*slave_info;
	_prepaid_info 			*prepaidInfo;
	UserData_Pool_Account	*poolAccount;
	u8						len,i,totalChild,*pChild;	
	u_char					*slaveNumber,slaveStoredNumber[2*MAX_MSISDN_BLEN];

	slave_info = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.del.slaveInfo;	
	slaveNumber = slave_info->number;
	if((prepaidInfo = getPrepaidInfo(&shmp->caller_info)) == NULL)
		return;
	poolAccount = &prepaidInfo->poolAccount;
	totalChild = poolAccount->roleParty.parent.childNumber%(POOL_MAX_CHILD+1);
	if(totalChild == 0)
	{
		poolAccount->role = MASTER_SLAVE_NONE;
		return;
	}
	for(i=0;i<totalChild;i++)
	{	
		pChild = poolAccount->roleParty.parent.childMsisdn[i];
		len = pChild[MAX_MSISDN_BLEN-1];
		BcdToAscii((char *)slaveStoredNumber,pChild,18);
		StringCut((char *)slaveStoredNumber,'F');
		slaveStoredNumber[len] = 0;
		if(!strcmp((char *)slaveNumber, (char *)slaveStoredNumber))	
			break;
	}
	if(i >= totalChild)
		return;
	if(i >= totalChild-1)
		memset(&poolAccount->roleParty.parent.childMsisdn[i],0,MAX_MSISDN_BLEN);
	else
	{
		memmove(&poolAccount->roleParty.parent.childMsisdn[i],
				&poolAccount->roleParty.parent.childMsisdn[i+1],
				(totalChild-i-1)*MAX_MSISDN_BLEN);
		memset(&poolAccount->roleParty.parent.childMsisdn[totalChild-1],0,MAX_MSISDN_BLEN);
	}
	
	totalChild = decMasterChildren(prepaidInfo);
	if(totalChild <= 0)		
		poolAccount->role = MASTER_SLAVE_NONE;
	smppNotifyMasterDEL(shmp->caller_info.number,slave_info->number);	
	SendAccountRealSync_2(&shmp->caller_info,0.0,0.0,OMC_OCODE_EDIT);
}

static void delProcessSetSlave(_state_data 	*shmp)
{
	_account_info			*slave_info;
	_prepaid_info 			*prepaidInfo;
	UserData_Pool_Account	*poolAccount;	

	slave_info = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.del.slaveInfo;	
	if((prepaidInfo = getPrepaidInfo(slave_info)) == NULL)
		return ;		
	
	poolAccount = &prepaidInfo->poolAccount;
	memset(poolAccount,0,sizeof(UserData_Pool_Account));
	poolAccount->role = MASTER_SLAVE_NONE;	
	smppNotifySlaveDEL(shmp->caller_info.number,slave_info->number);
	SendAccountRealSync_2(slave_info,0.0,0.0,OMC_OCODE_EDIT);
}	


enum{
	S_MASTER_DEL_IDLE,
	S_MASTER_DEL_WAIT_SLAVE,
	S_MASTER_DEL_WAIT_CONFIRM,
	S_MASTER_DEL_PROCESSING,
	S_MASTER_DEL_WAIT_PLAY_DONE,
	S_MASTER_DEL_EXIT,
};

static int masterDelProc(u_short portid)
{
	_state_data 	*shmp;
	int 			result = SERVICE_KEEP_STATE,rst;
	MASTER_SLAVE_DEL		*del;

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	
	switch(getMasterDelState(portid))
	{
		case S_MASTER_DEL_IDLE:					
			clearMasterDelInfo(portid);
			if(isMasterEmptySlave(portid) == TRUE)
			{
				playPromptVoice(portid,DEL_FAIL_EMPTY);
				changeMasterDelState(portid,S_MASTER_DEL_WAIT_PLAY_DONE);
			}
			else
			{
				playPromptAndCollectVoice(portid,MASTER_INPUT_CHILD_DEL,MAX_IVR_INPUT_LEN);
				changeMasterDelState(portid,S_MASTER_DEL_WAIT_SLAVE);
			}
		break;
		case S_MASTER_DEL_WAIT_SLAVE:
			rst = WaitingForMasterDelInputSlave(shmp);
			switch(rst)
			{
				case NO_INPUT:
				break;				
				case INPUT_SUCCESS:	
					rst = checkDelSlaveNumber(shmp);
					switch(rst)
					{
						case 0:
							SendMasterDelConfirmToSrf(portid);				
							changeMasterDelState(portid,S_MASTER_DEL_WAIT_CONFIRM);
						break;
						case 1:/*	not your child	*/
							playPromptAndCollectVoice(portid,DEL_FAIL_NOT_YOUR_CHILD,MAX_IVR_INPUT_LEN);
						break;				
						case 2:/*	not exist in pps	*/
							playPromptAndCollectVoice(portid,InvalidAccountIputAgain,MAX_IVR_INPUT_LEN);	
						break;
					}
				break;
				case INPUT_ERROR_REINPUT:					
					playPromptAndCollectVoice(portid,MASTER_INPUT_CHILD_DEL,MAX_IVR_INPUT_LEN);
				break;
				case INPUT_ERROR_EXIT:
					result = SERVICE_EXIT_PPS;
				break;
			}		
		break;			
		case S_MASTER_DEL_WAIT_CONFIRM:
			rst = masterDelWaitForChoice(shmp);
			switch(rst)
			{
				case NO_INPUT:
				break;				
				case INPUT_SUCCESS:
					rst = getMasterDelChoice(shmp);					
					switch(rst)
					{
						case CONFIRM_OK:
							changeMasterDelState(portid,S_MASTER_DEL_PROCESSING);
						break;
						case CONFIRM_ENTER_AGAIN:
							changeMasterDelState(portid,S_MASTER_DEL_IDLE);
						break;
						case CONFIRM_CANCEL:
							changeMasterDelState(portid,S_MASTER_DEL_EXIT);
						break;						
					}					
				break;
				case INPUT_ERROR_REINPUT:
					playPromptAndCollectVoice(portid,YES_OR_NO,1);					
				break;
				case INPUT_ERROR_EXIT:
					result = SERVICE_EXIT_PPS;
				break;
			}		
		break;
		case S_MASTER_DEL_PROCESSING:
			delProcessSetMaster(shmp);
			delProcessSetSlave(shmp);
			playPromptVoice(portid,MASTER_DEL_SUCCESS);
			changeMasterDelState(portid,S_MASTER_DEL_WAIT_PLAY_DONE);
		break;
		case S_MASTER_DEL_WAIT_PLAY_DONE:
			rst = CallingCardWaitingForSpecialResourceReport(shmp);
			if(rst == SERVICE_KEEP_STATE)
				break;					
			else if(rst == 1)	
			{																		
				changeMasterDelState(portid,S_MASTER_DEL_EXIT);
			}
			else
				result = SERVICE_EXIT_PPS;
		break;		
		case S_MASTER_DEL_EXIT:
			result = SERVICE_RETURN_TO_PARENT;			
		break;
		default:
			result = SERVICE_EXIT_PPS;
		break;
	}	
	return result;
}

/******************************	delete	***********************************************/
#define changeMasterSlaveState(portid,val) do { \
	masterSlaveCard = &shmp->process_info.ppsService.masterSlaveCard;\
	masterSlaveCard->state = val;\
	shmp->process_info.serviceInput = 0;\
	shmp->process_info.funnel = 0;\
	pps_print_event(shmp->process_info.logMsisdn,"[%05d]\33[32m%s\33[0m transfer to state \33[36m%s\33[0m", portid, __FUNCTION__, #val); \
} while(0)


static u8 getMasterSlaveState(u_short portid)
{
	_state_data 			*shmp;

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

	return shmp->process_info.ppsService.masterSlaveCard.state;
}

static int WaitForMasterChoice(_state_data *shmp)
{				
	u_char				input_msg[64] = {0};
	int					result;
	
	PutLogFunID("WaitForChoice");

	memset(input_msg,0,64);
	result = WaitingForInput(shmp,input_msg);
	if(result != INPUT_SUCCESS)
		return result;

	if(strlen((char *)input_msg) != 1
		|| (input_msg[0] < '0' || input_msg[0] > '3'))
	{
		if(shmp->process_info.serviceInput++ >= SERVICE_INPUT_NUM)
		{
			return (result = INPUT_ERROR_EXIT);
		}
		else
			return (result = INPUT_ERROR_REINPUT);
	}
	
	shmp->process_info.ppsService.masterSlaveCard.choice = input_msg[0] - '0';	
	return result;		
}

static int WaitForSalveChoice(_state_data *shmp)
{				
	u_char				input_msg[64] = {0};
	int					result;
	
	PutLogFunID("WaitForChoice");

	memset(input_msg,0,64);
	result = WaitingForInput(shmp,input_msg);
	if(result != INPUT_SUCCESS)
		return result;

	if(strlen((char *)input_msg) != 1
		|| (input_msg[0] < '0' || input_msg[0] > '1'))
	{
		if(shmp->process_info.serviceInput++ >= SERVICE_INPUT_NUM)
		{
			return (result = INPUT_ERROR_EXIT);
		}
		else
			return (result = INPUT_ERROR_REINPUT);
	}
	
	shmp->process_info.ppsService.masterSlaveCard.choice = input_msg[0] - '0';	
	return result;		
}

static int getMasterSalveFunc(_state_data *shmp)
{					
	return shmp->process_info.ppsService.masterSlaveCard.choice;
}


enum MASTER_SLAVE_CARD_STATE{
	S_MASTER_SLAVE_IDLE,
	S_MASTER_CHOICE,
	S_SLAVE_CHOICE,
	S_MASTER_INQUIRY,
	S_SLAVE_INQUIRY,
	S_MASTER_ADD_SLAVE,
	S_MASTER_DEL_SLAVE,
	S_MASTER_PLAY,
};

void clearMasterSlaveInfo(u_short portid)
{
	_state_data 	*shmp;
	
	PutLogFunID("clearTransferInfo");

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

	memset(&shmp->process_info.ppsService.masterSlaveCard,0,sizeof(MASTER_SLAVE_CARD));
}


int getPoolAccountRole(u_short portid)
{
	_prepaid_info 	*prepaidInfo = NULL;
	_state_data 	*shmp;

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

	if (shmp->caller_info.head < MSISDN_HEAD_NUM && shmp->caller_info.tail < UNIT_STORE_ACCOUNT) 
	{
		prepaidInfo = &ramshm_ptr->prepaid_data.prepaid_info[shmp->caller_info.head][shmp->caller_info.tail];		
	}
	if(prepaidInfo == NULL)
		return MASTER_SLAVE_NONE;
	return prepaidInfo->poolAccount.role;
}

static int getCosPoolRole(u_short portid)
{
	//_prepaid_info 	*prepaidInfo = NULL;
	_state_data 	*shmp;
	u8				cosID=0;
	COSTable		*cosTableItem;
	
	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	cosID = GetLocalCosID(&shmp->caller_info);
	cosTableItem = &ppsParam.ppsTables.cosTable[cosID];
	return cosTableItem->poolAccount[0].role;
}		

int masterSlaveIVRProc(u_short portid)
{
	_state_data 	*shmp;
	int 			result_sub = SERVICE_KEEP_STATE,result_main = SERVICE_KEEP_STATE;
	MASTER_SLAVE_CARD		*masterSlaveCard;
	
	PutLogFunID("masterSlaveIVRProc");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	if(shmp->process_info.funnel++>PROMPT_AND_COLLECT_TIMER)
	{		
		return SERVICE_EXIT_PPS;
	}
	switch(getMasterSlaveState(portid))
	{
		case S_MASTER_SLAVE_IDLE:
			clearMasterSlaveInfo(portid);	
			switch(getCosPoolRole(portid))
			{
				case MASTER_SLAVE_NONE:
					playPromptVoice(portid,SERIVCE_NOT_APPLIED);
					changeMasterSlaveState(portid,S_MASTER_PLAY);
				break;
				default:
					if(getPoolAccountRole(portid) == MASTER_SLAVE_CHILD)
					{
						playPromptAndCollectVoice(portid,SLAVE_CARD_PROMPT,1);
						changeMasterSlaveState(portid,S_SLAVE_CHOICE);
					}
					else				
					{
						playPromptAndCollectVoice(portid,MASTER_CARD_PROMPT,1);
						changeMasterSlaveState(portid,S_MASTER_CHOICE);
					}
				break;
			}			
		break;
		case S_MASTER_CHOICE:
			result_sub = WaitForMasterChoice(shmp);
			switch(result_sub)
			{
				case NO_INPUT:
				break;
				case INPUT_SUCCESS:
					switch(getMasterSalveFunc(shmp))
					{
						case 0:
							result_main = SERVICE_RETURN_TO_PARENT;
						break;
						case 1:
							changeMasterSlaveState(portid,S_MASTER_INQUIRY);
						break;
						case 2:
							if(getCosPoolRole(portid) != MASTER_SLAVE_PARENT)
							{
								playPromptVoice(portid,SERIVCE_NOT_APPLIED);
								changeMasterSlaveState(portid,S_MASTER_PLAY);
							}
							else
								changeMasterSlaveState(portid,S_MASTER_ADD_SLAVE);
						break;
						case 3:	
							changeMasterSlaveState(portid,S_MASTER_DEL_SLAVE);
						break;						
						default:
							result_main = SERVICE_EXIT_PPS;
						break;
					}
				break;
				case INPUT_ERROR_REINPUT:
					playPromptAndCollectVoice(portid,MASTER_CARD_PROMPT,1);
				break;
				case INPUT_ERROR_EXIT:
					result_main = SERVICE_EXIT_PPS;
				break;
			}
		break;
		case S_SLAVE_CHOICE:
			result_sub = WaitForSalveChoice(shmp);
			switch(result_sub)
			{
				case NO_INPUT:
				break;
				case INPUT_SUCCESS:
					switch(getMasterSalveFunc((shmp)))
					{
						case 0:
							result_main = SERVICE_RETURN_TO_PARENT;
						break;
						case 1:
							changeMasterSlaveState(portid,S_SLAVE_INQUIRY);
						break;										
						default:
							result_main = SERVICE_EXIT_PPS;
						break;
					}
				break;
				case INPUT_ERROR_REINPUT:
					playPromptAndCollectVoice(portid,SLAVE_CARD_PROMPT,1);
				break;
				case INPUT_ERROR_EXIT:
					result_main = SERVICE_EXIT_PPS;
				break;
			}
		break;	
		case S_MASTER_INQUIRY:
			result_sub = masterEnquiryProc(portid);	
			switch(result_sub)
			{
				case SERVICE_KEEP_STATE:
				break;
				case SERVICE_RETURN_TO_PARENT:
					changeMasterSlaveState(portid,S_MASTER_SLAVE_IDLE);
				break;
				case SERVICE_EXIT_PPS:
				default:
					result_main = SERVICE_EXIT_PPS;
				break;
			}
		break;
		case S_SLAVE_INQUIRY:
			result_sub = slaveEnquiryProc(portid);	
			switch(result_sub)
			{
				case SERVICE_KEEP_STATE:
				break;
				case SERVICE_RETURN_TO_PARENT:
					changeMasterSlaveState(portid,S_MASTER_SLAVE_IDLE);
				break;
				case SERVICE_EXIT_PPS:
				default:
					result_main = SERVICE_EXIT_PPS;
				break;
			}
		break;
		case S_MASTER_ADD_SLAVE:
			result_sub = masterAddProc(portid);	
			switch(result_sub)
			{
				case SERVICE_KEEP_STATE:
				break;
				case SERVICE_RETURN_TO_PARENT:
					changeMasterSlaveState(portid,S_MASTER_SLAVE_IDLE);
				break;
				case SERVICE_EXIT_PPS:
				default:
					result_main = SERVICE_EXIT_PPS;
				break;
			}
		break;
		case S_MASTER_DEL_SLAVE:
			result_sub = masterDelProc(portid);	
			switch(result_sub)
			{
				case SERVICE_KEEP_STATE:
				break;
				case SERVICE_RETURN_TO_PARENT:
					changeMasterSlaveState(portid,S_MASTER_SLAVE_IDLE);
				break;
				case SERVICE_EXIT_PPS:
				default:
					result_main =  SERVICE_EXIT_PPS;
				break;
			}
		break;
		case S_MASTER_PLAY:
			result_sub = CallingCardWaitingForSpecialResourceReport(shmp);
			if(result_sub == SERVICE_KEEP_STATE)
				break;					
			else if(result_sub == 1)	
			{																		
				result_main = SERVICE_RETURN_TO_PARENT;
			}
			else
				result_main = SERVICE_EXIT_PPS;
		break;
	}	
	return result_main;
}

static int fillTransferStateData(_state_data 	*shmp,_account_info *masterAccount,_account_info *childAccount,float fee)
{
	shmp->process_info.ppsService.feeTransfer.fee = fee;
	memcpy(&shmp->caller_info,masterAccount,sizeof(_account_info));
	if(GetAccountPos(&shmp->caller_info) == FALSE)
		return -1;	
	memcpy(&shmp->process_info.ppsService.feeTransfer.account,childAccount,sizeof(_account_info));
	if(GetAccountPos(&shmp->process_info.ppsService.feeTransfer.account) == FALSE)
		return -1;	
	return 1;
}

static int childAutoTransferInFromMaster(_prepaid_info  *slave)
{		
	int 				cos_id=0,rst;
	COSTable			*cosTableItem;
	_prepaid_info  		*master;
	_account_info 		masterAccount,childAccount;
	u8					*msisdnBCD,len;
	float				transferFee,diff;
	COS_Pool_Account	*pA;
		
	if(slave->poolAccount.role != MASTER_SLAVE_CHILD)
		return 0;
	memset(&masterAccount,0,sizeof(_account_info));
	msisdnBCD = slave->poolAccount.roleParty.child.parentMsisdn;
	len = msisdnBCD[MAX_MSISDN_BLEN-1];
	BcdToAscii((char *)masterAccount.number,msisdnBCD,18);
	StringCut((char *)masterAccount.number,'F');
	masterAccount.number[len] = 0;

	if(GetAccountPos(&masterAccount) == FALSE)
		return -1;
	
	memset(&childAccount,0,sizeof(_account_info));			
	msisdnBCD = slave->msisdn;

	len = msisdnBCD[MAX_MSISDN_BLEN-1];
	BcdToAscii((char *)childAccount.number,msisdnBCD,18);
	StringCut((char *)childAccount.number,'F');
	childAccount.number[len] = 0;
					
	if((master = getPrepaidInfo(&masterAccount)) == NULL)
		return -1;
		
	cos_id = slave->cos_id%MaxCosTableItem;
	cosTableItem = &ppsParam.ppsTables.cosTable[cos_id];
	pA = &cosTableItem->poolAccount[0];

	transferFee = pA->roleParty.child.maxFeePerDay;
	
	if(isPromotionCanBeTransfered(&masterAccount) == TRUE)
		diff = transferFee - (slave->balance+slave->promo_balance);					
	else
		diff = transferFee - slave->balance;
	
	rst = checkTransferedPartialFee(&masterAccount,diff);
	switch(rst)
	{
		case CHECK_TRANSFERED_FEE_OK:
			
		break;
		case CHECK_TRANSFERED_FEE_INSUFFIENT:
			pps_print_error(0,"%s insufficient fee",masterAccount.number);
			return -1;
		break;
		case CHECK_TRANSFERED_FEE_EXPIERED:	
			pps_print_error(0,"%s expired",masterAccount.number);
			return -1;
		break;
	}
	if(GetAccountPos(&childAccount) == FALSE)
		return -1;
	poolTransferAccount(&masterAccount,&childAccount,diff);
	SendTransferCDR(&masterAccount,&childAccount,-diff);
	SendTransferCDR(&childAccount,&masterAccount,diff);

	return 2;
}

static int checkMasterFee(u_short portid)
{	
	//_prepaid_info 				*prepaidInfo;
	_state_data 				*shmp;
	MASTER_SLAVE_ADD			*add;
	u8							cosID;
	COSTable					*cosTableItem;
	COS_Pool_Account			*pA;		
	float						transferFee,slaveAddFee;
	int							rst;
	
	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;

	add = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.add;	
	cosID = getAddingSlaveCosId(shmp,add);
	cosTableItem = &ppsParam.ppsTables.cosTable[cosID];	

	pA = &cosTableItem->poolAccount[0];
	transferFee = pA->roleParty.child.maxFeePerDay;

	slaveAddFee = getAddSlaveCharge(&shmp->caller_info);
	rst = checkTransferedPartialFee(&shmp->caller_info,transferFee+slaveAddFee);	
	return rst;
}
	 
static int getAddingSlaveCosId(_state_data *shmp,MASTER_SLAVE_ADD	*add)
{
	int 				cos_id;
	COSTable			*cosTableItem;

	cos_id = GetLocalCosID(&shmp->caller_info);
	cosTableItem = &ppsParam.ppsTables.cosTable[cos_id];	
	cos_id = cosTableItem->poolAccount[0].roleParty.parent.cosIDForChild[add->cosID%MaxCosTableItem];
	return cos_id;
}

static int RealTransferToSlave(_state_data *shmp)
{		
	int 				cos_id=0,rst;
	COSTable			*cosTableItem;
	double				transferFee;
	COS_Pool_Account	*pA;	
	_prepaid_info		*master,*slave;
	MASTER_SLAVE_ADD	*add;
	_state_data			newShmp;
	
	add = &shmp->process_info.ppsService.masterSlaveCard.masterSlaveFunc.add;	
	if((master = getPrepaidInfo(&shmp->caller_info)) == NULL)
		return -1;
	if((slave = getPrepaidInfo(&add->slaveInfo)) == NULL)
		return -1;	
	cos_id = getAddingSlaveCosId(shmp,add);
	cosTableItem = &ppsParam.ppsTables.cosTable[cos_id];
	
	pA = &cosTableItem->poolAccount[0];
	transferFee = pA->roleParty.child.maxFeePerDay;
	
	rst = fillTransferStateData(&newShmp,&shmp->caller_info,&add->slaveInfo,transferFee);
	if(rst < 0)
		return -1;
	
	FeeTransferTransaction(&newShmp);	
	return 2;
}

static int smppNotifyParentTransfer(_prepaid_info  	*slave)
{
	u8				*msisdnBCD,len;
	u8				masterNumber[2*MAX_MSISDN_BLEN],slaveNumber[2*MAX_MSISDN_BLEN];
	u_char			msg[MAX_SMS_LEN*4]={0};

	
	memset(masterNumber,0,2*MAX_MSISDN_BLEN);
	msisdnBCD = slave->poolAccount.roleParty.child.parentMsisdn;	
	len = msisdnBCD[MAX_MSISDN_BLEN-1];
	BcdToAscii((char *)masterNumber,msisdnBCD,18);
	StringCut((char *)masterNumber,'F');
	masterNumber[len] = 0;

	memset(slaveNumber,0,2*MAX_MSISDN_BLEN);
	msisdnBCD = slave->msisdn;	
	len = msisdnBCD[MAX_MSISDN_BLEN-1];
	BcdToAscii((char *)slaveNumber,msisdnBCD,18);
	StringCut((char *)slaveNumber,'F');
	slaveNumber[len] = 0;
			
	strcpy((char *)msg, (char *)slaveNumber);
	strcat((char *)msg," ");
	strcat((char *)msg, (char *)getSmsSentenceNative(0,SMS_POOL_CHILD_LOW_FEE));
	return smppSendMOSM((char *)masterNumber, (char *)ppsParam.ppsTables.serviceNumber[FeeTransferPosition].number
						,msg,strlen((char *)msg),0);	
}

static int getSlaveRechargeType(int 		cos_id)
{
	COSTable			*cosTableItem;
	COS_Pool_Account	*pA;
	
	cos_id = cos_id%MaxCosTableItem;
	cosTableItem = &ppsParam.ppsTables.cosTable[cos_id];
	pA = & cosTableItem->poolAccount[0];

	return pA->roleParty.child.periodicTransferOrAutoByParent;
}


static BOOL isSlaveNeedTransferFee(_prepaid_info  	*slave)
{
	int 				cos_id=0;
	COSTable			*cosTableItem;
	COS_Pool_Account	*pA;
	double				transferFee;
	
	cos_id = slave->cos_id%MaxCosTableItem;
	cosTableItem = &ppsParam.ppsTables.cosTable[cos_id];
	pA = &cosTableItem->poolAccount[0];

	transferFee = pA->roleParty.child.maxFeePerDay;
	
	if(slave->balance + slave->promo_balance >= transferFee)
		return FALSE;
	return TRUE;
}

void resetPoolSlaveDaily(u_short head,u_short tail)
{			
	_prepaid_data   *shmp=&ramshm_ptr->prepaid_data;
	_prepaid_info 	*slave;

	slave = &shmp->prepaid_info[head][tail];
	
	if(slave->poolAccount.role != MASTER_SLAVE_CHILD)
		return;
		
	slave->poolAccount.roleParty.child.callsToday = 0;
	slave->poolAccount.roleParty.child.smsToday = 0;
	slave->poolAccount.roleParty.child.chargedToday = 0;	
	if(isSlaveNeedTransferFee(slave) == FALSE)
		return;
	switch(getSlaveRechargeType(slave->cos_id))
	{
		case 0:			
			childAutoTransferInFromMaster(slave);
		break;
		case 1:
		default:
			smppNotifyParentTransfer(slave);
		break;
	}
}

int isPoolChildReachCallLimit(_state_data *shmp)
{
	int 				cos_id=0;
	COSTable			*cosTableItem;
	COS_Pool_Account	*pA;
	_prepaid_info  		*slave=NULL;	

	if(shmp->caller_info.fee == 0)
		return 0;
	if (shmp->caller_info.head < MSISDN_HEAD_NUM 
		&& shmp->caller_info.tail < UNIT_STORE_ACCOUNT) 
	{
		slave = &ramshm_ptr->prepaid_data.prepaid_info[shmp->caller_info.head][shmp->caller_info.tail];		
	}
	if(slave == NULL)
		return 0;	
	if(slave->poolAccount.role != MASTER_SLAVE_CHILD)
		return 0;
	cos_id = slave->cos_id%MaxCosTableItem;
	cosTableItem = &ppsParam.ppsTables.cosTable[cos_id];
	
	pA = & cosTableItem->poolAccount[0];
	if(slave->poolAccount.roleParty.child.callsToday >= pA->roleParty.child.maxCallsPerDay)
		return 1;
	if(getConsumeFee(slave) >= pA->roleParty.child.maxFeePerDay)
		return 2;
	return 0;		
}

int isPoolChildReachSMSLimit(_state_data *shmp)
{
	int 				cos_id=0;
	COSTable			*cosTableItem;
	COS_Pool_Account	*pA;
	_prepaid_info  		*slave=NULL;	

	if(shmp->caller_info.fee == 0)
		return 0;
	if (shmp->caller_info.head < MSISDN_HEAD_NUM 
		&& shmp->caller_info.tail < UNIT_STORE_ACCOUNT) 
	{
		slave = &ramshm_ptr->prepaid_data.prepaid_info[shmp->caller_info.head][shmp->caller_info.tail];		
	}
	if(slave == NULL)
		return 0;
	if(slave->poolAccount.role != MASTER_SLAVE_CHILD)
		return 0;
	cos_id = slave->cos_id%MaxCosTableItem;
	cosTableItem = &ppsParam.ppsTables.cosTable[cos_id];
	
	pA = & cosTableItem->poolAccount[0];
	if(slave->poolAccount.roleParty.child.smsToday >= pA->roleParty.child.maxSMSPerDay)
		return 1;
	if(getConsumeFee(slave) >= pA->roleParty.child.maxFeePerDay)
		return 2;
	return 0;		
}

int isPoolChildReachFeeLimit(_account_info *ptr)
{
	int 				cos_id=0;
	COSTable			*cosTableItem;
	COS_Pool_Account	*pA;
	_prepaid_info  		*slave=NULL;	

	if(ptr->fee == 0)
		return 0;
	if (ptr->head < MSISDN_HEAD_NUM 
		&& ptr->tail < UNIT_STORE_ACCOUNT) 
	{
		slave = &ramshm_ptr->prepaid_data.prepaid_info[ptr->head][ptr->tail];		
	}
	if(slave == NULL)
		return 0;
	if(slave->poolAccount.role != MASTER_SLAVE_CHILD)
		return 0;
	cos_id = slave->cos_id%MaxCosTableItem;
	cosTableItem = &ppsParam.ppsTables.cosTable[cos_id];
	
	pA = & cosTableItem->poolAccount[0];
	
	if(getConsumeFee(slave) >= pA->roleParty.child.maxFeePerDay)
		return 2;
	return 0;		
}

	

void increPoolChildCalls(_account_info *ptr)
{
	_prepaid_info  	*slave=NULL;	
	DWORD			instance;
	
	if (ptr->head < MSISDN_HEAD_NUM 
		&& ptr->tail < UNIT_STORE_ACCOUNT) 
	{
		slave = &ramshm_ptr->prepaid_data.prepaid_info[ptr->head][ptr->tail];		
	}
	if(slave == NULL)
		return;
	if(slave->poolAccount.role != MASTER_SLAVE_CHILD)
		return;	
	slave->poolAccount.roleParty.child.callsToday++;
	instance = ptr->head * UNIT_STORE_ACCOUNT + ptr->tail;
    SendAccountRealSync(instance,0.0,0.0,OMC_OCODE_EDIT);
}

void increPoolChildSMS(_account_info *ptr)
{
	_prepaid_info  	*slave=NULL;	
	DWORD			instance;
	
	if (ptr->head < MSISDN_HEAD_NUM 
		&& ptr->tail < UNIT_STORE_ACCOUNT) 
	{
		slave = &ramshm_ptr->prepaid_data.prepaid_info[ptr->head][ptr->tail];		
	}
	if(slave == NULL)
		return;
	if(slave->poolAccount.role != MASTER_SLAVE_CHILD)
		return;	
	slave->poolAccount.roleParty.child.smsToday++;
	instance = ptr->head * UNIT_STORE_ACCOUNT + ptr->tail;
    SendAccountRealSync(instance,0.0,0.0,OMC_OCODE_EDIT);
}

void increPoolChildCharged(_account_info *ptr,double charged)
{
	_prepaid_info  	*slave=NULL;	
	
	if (ptr->head < MSISDN_HEAD_NUM 
		&& ptr->tail < UNIT_STORE_ACCOUNT) 
	{
		slave = &ramshm_ptr->prepaid_data.prepaid_info[ptr->head][ptr->tail];		
	}
	if(slave == NULL)
		return;
	if(slave->poolAccount.role != MASTER_SLAVE_CHILD)
		return;	
	slave->poolAccount.roleParty.child.chargedToday += charged;
}

static int isChildRechargeAllowed(_prepaid_info 	*prepaidInfo)
{
	COSTable			*cosTableItem;
	COS_Pool_Account	*pA;
	int					cos_id;
	
	cos_id = prepaidInfo->cos_id%MaxCosTableItem;
	cosTableItem = &ppsParam.ppsTables.cosTable[cos_id];	
	pA = &cosTableItem->poolAccount[0];
	if(pA->roleParty.child.isRechargeAllowed)
		return TRUE;
	
	return FALSE;		
}

int isChildTransferAllowed(_prepaid_info 	*prepaidInfo)
{
	COSTable			*cosTableItem;
	COS_Pool_Account	*pA;
	int					cos_id;
	
	cos_id = prepaidInfo->cos_id%MaxCosTableItem;
	cosTableItem = &ppsParam.ppsTables.cosTable[cos_id];	
	pA = &cosTableItem->poolAccount[0];
	if(pA->roleParty.child.isTransferAllowed)
		return TRUE;
	return FALSE;		
}

int isTransferAllowed(u_short portid)
{
	_prepaid_info 		*prepaidInfo;
	_state_data 		*shmp;
	
	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;

	if((prepaidInfo = getPrepaidInfo(&shmp->caller_info)) == NULL)
		return FALSE;
	
	if(prepaidInfo->poolAccount.role == MASTER_SLAVE_CHILD)
		return isChildTransferAllowed(prepaidInfo);

        GetAccountPos(&shmp->caller_info);
        if(GetAccountStatus(&shmp->caller_info) != T_NORMAL)
            return FALSE;
	
	return TRUE;	
}

int isRechargeAllowed(u_short portid)
{
	_prepaid_info 		*prepaidInfo;
	_state_data 		*shmp;
	int					rst;

	return TRUE;
	
	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	if((prepaidInfo = getPrepaidInfo(&shmp->caller_info)) == NULL)
		return FALSE;
	if(prepaidInfo->poolAccount.role == MASTER_SLAVE_CHILD)
	{
		rst = isChildRechargeAllowed(prepaidInfo);
		if(rst == FALSE)
		{
			pps_print_error(shmp->process_info.logMsisdn,"[%05d]slave card ,recharge not allowed",portid);	
		}
		return  rst;
	}
			
	return TRUE;	
}


static int smppNotifyMasterADD(u_char *masterNumber,u_char *slaveNumber)
{
	char					msg[MAX_SMS_LEN*4]={0};
	char					dayTimeReadable[32]={0};

	ppsgetdaytime_readFormat(dayTimeReadable);
	strcpy(msg, (char *)getSmsSentenceNative(0,SMS_POOL_ADDED_CHILD));

	cliManipulationFunction((char *)slaveNumber, (char *)masterNumber );
	strcat(msg, (char *)slaveNumber);
	strcat(msg," ");
	strcat(msg, (char *)getSmsSentenceNative(0,SMS_ON));
	strcat(msg," ");
	strcat(msg, dayTimeReadable);
	return smppSendMOSM((char *)masterNumber, (char *)ppsParam.ppsTables.serviceNumber[PoolAccountPosition].number, (u_char *)msg,strlen(msg),0);
}

static int smppNotifyMasterDEL(u_char *masterNumber,u_char *slaveNumber)
{
	char					msg[MAX_SMS_LEN*4]={0};
	char					dayTimeReadable[32]={0};

	ppsgetdaytime_readFormat(dayTimeReadable);
	strcpy(msg, (char *)getSmsSentenceNative(0,SMS_POOL_DELED_CHILD));	

	cliManipulationFunction((char *)slaveNumber, (char *)masterNumber );

	strcat(msg, (char *)slaveNumber);
	strcat(msg," ");
	strcat(msg, (char *)getSmsSentenceNative(0,SMS_ON));
	strcat(msg," ");
	strcat(msg, dayTimeReadable);
	return smppSendMOSM((char *)masterNumber, (char *)ppsParam.ppsTables.serviceNumber[PoolAccountPosition].number, (u_char *)msg,strlen(msg),0);	
}

static int smppNotifySlaveADD(u_char *masterNumber,u_char *slaveNumber)
{
	char					msg[MAX_SMS_LEN*4]={0};
	char					dayTimeReadable[32]={0};

	ppsgetdaytime_readFormat(dayTimeReadable);
	strcpy(msg, (char *)getSmsSentenceNative(0,SMS_POOL_BEEN_ADDED_CHILD));	

	cliManipulationFunction((char *)masterNumber, (char *)slaveNumber );

	strcat(msg, (char *)masterNumber);
	strcat(msg," ");
	strcat(msg, (char *)getSmsSentenceNative(0,SMS_ON));
	strcat(msg," ");
	strcat(msg, dayTimeReadable);
	return smppSendMOSM((char *)slaveNumber, (char *)ppsParam.ppsTables.serviceNumber[PoolAccountPosition].number, (u_char *)msg,strlen(msg),0);	
}

static int smppNotifySlaveDEL(u_char *masterNumber,u_char *slaveNumber)
{
	char					msg[MAX_SMS_LEN*4]={0};
	char					dayTimeReadable[32]={0};

	ppsgetdaytime_readFormat(dayTimeReadable);
	strcpy(msg, (char *)getSmsSentenceNative(0,SMS_POOL_BEEN_DELED_CHILD));	

	cliManipulationFunction((char *)masterNumber, (char *)slaveNumber );
		
	strcat(msg, (char *)masterNumber);
	strcat(msg," ");
	strcat(msg, (char *)getSmsSentenceNative(0,SMS_ON));
	strcat(msg," ");
	strcat(msg, dayTimeReadable);
	return smppSendMOSM((char *)slaveNumber, (char *)ppsParam.ppsTables.serviceNumber[PoolAccountPosition].number, (u_char *)msg,strlen(msg),0);	
}


void ppsgetdaytime_readFormat(char *daytime_buf)
{
    struct tm 	*t,tt;
    long 		curr_time;

    t=&tt;
    curr_time=time((long *)0);
    t=localtime(&curr_time);
    sprintf(daytime_buf,"%04d-%02d-%02d %02d:%02d:%02d",
            t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour,
            t->tm_min, t->tm_sec);
    daytime_buf[19] = 0;
}


static int getAddSlaveCharge(_account_info *accountInfo)
{
	int 			head,tail;
	int 			tariff_id=0;

	head = accountInfo->head;
	tail = accountInfo->tail;
	
	if(head>=MSISDN_HEAD_NUM) 
		return 0;
	tariff_id = GetAccountZoneID(head,tail);
	if(tariff_id>=MAX_ZONE_NUM || tariff_id<0) tariff_id = 0;

	return ramshm_ptr->tariff_data.comm_tariff[tariff_id].childChangeChargeAmount;
}

int increMasterChangeCounter(_prepaid_info *prepaidInfo)
{
	u_char *times;
	
	if(prepaidInfo == NULL)
		return 0;	

	PutLogFunID("increMasterChangeCounter");


	times = &prepaidInfo->poolAccount.roleParty.parent.changeTimes;
	if(*times<0x7F) 
		return (++(*times));
	return *times; 
}


int IncreasePoolAccountChangeCounter(int head, int tail)
{
	PutLogFunID("IncreasePoolAccountChangeCounter");

	if(head<MSISDN_HEAD_NUM)
	{
		return increMasterChangeCounter(&ramshm_ptr->prepaid_data.prepaid_info[head][tail]);
	}
	return 0;
}

extern void SendManualOperationCDR(_account_info *caller_info, _account_info *called_info, int charge);
int masterChangeSlaveCharge(_state_data *shmp,_account_info *slaveInfo)
{
	int					head,tail;
	int					amount,times;
	_prepaid_info		*ptr;
	COSTable			*cosTableItem;
	int					cos_id;
	
	PutLogFunID("masterChangeSlaveCharge");
	head = shmp->caller_info.head;
	tail = shmp->caller_info.tail;	
	if(head>=MSISDN_HEAD_NUM) 
		return 0;
	ptr = &ramshm_ptr->prepaid_data.prepaid_info[head][tail];
	cos_id = ptr->cos_id%MaxCosTableItem;
	cosTableItem = &ppsParam.ppsTables.cosTable[cos_id];	
	if(!cosTableItem->serviceControl[0].poolAccountChangeChargeFlag)
		return 0;		
	IncreasePoolAccountChangeCounter(head,tail);
	times = cosTableItem->serviceControl[0].poolAccountFreeChangeTimes;
	if(ptr->poolAccount.roleParty.parent.changeTimes <= times)
		return 0;
	
	amount = getAddSlaveCharge(&shmp->caller_info);
	
	ptr->balance -= amount;
	
	SendManualOperationCDR(&shmp->caller_info,&shmp->called_info,-amount);
	return amount;
}

int BillingChildNumberChange(_state_data *shmp)
{
	int				head,tail;
	int				amount,tariff_id=0;
	_prepaid_info	*ptr;

	PutLogFunID("BillingChildNumberChange");

	head = shmp->caller_info.head;
	tail = shmp->caller_info.tail;
	
	if(head>=MSISDN_HEAD_NUM) 
		return 0;
	tariff_id = GetAccountZoneID(head,tail);
	if(tariff_id>=MAX_ZONE_NUM || tariff_id<0) tariff_id = 0;

	ptr = &ramshm_ptr->prepaid_data.prepaid_info[head][tail];
	amount = ramshm_ptr->tariff_data.comm_tariff[tariff_id].childChangeChargeAmount;
	ptr->balance = ptr->balance - amount;
	shmp->caller_info.charge = amount;
	return 1;
}

int CheckWetherPoolNumber(_account_info *caller, _account_info *called)
{
	int  					i,len;
	char 					msisdn[32];
	UserData_Pool_Account	*poolAccount;	
    _prepaid_data    		*shmp=&ramshm_ptr->prepaid_data;

	PutLogFunID("CheckWetherPoolNumber");
	poolAccount = &shmp->prepaid_info[caller->head][caller->tail].poolAccount;
	if(caller->head < MSISDN_HEAD_NUM && caller->tail <UNIT_STORE_ACCOUNT)
	{			
		if(poolAccount->role == MASTER_SLAVE_CHILD)
		{
			len = poolAccount->roleParty.child.parentMsisdn[MAX_MSISDN_BLEN-1];
			if(len>MAX_MSISDN_ALEN || len<2) 
				return FALSE;
			BcdToAscii(msisdn,poolAccount->roleParty.child.parentMsisdn,MAX_MSISDN_ALEN);
			msisdn[len] = 0;
			CutUnknownPrefix(msisdn);
			if(strcmp(msisdn, (char *)called->number)==0) 
				return TRUE;
		}
		else if(poolAccount->role == MASTER_SLAVE_PARENT)
		{
			if(!poolAccount->roleParty.parent.childNumber)
				return NOT_FAVORITE_NUMBER;
			for(i=0;i<POOL_MAX_CHILD;i++)
			{
				len = poolAccount->roleParty.parent.childMsisdn[i][MAX_MSISDN_BLEN-1];
				if(len>MAX_MSISDN_ALEN || len<2) 
					continue;
				BcdToAscii(msisdn,poolAccount->roleParty.parent.childMsisdn[i],MAX_MSISDN_ALEN);
				msisdn[len] = 0;
				CutUnknownPrefix(msisdn);
				if(strcmp(msisdn, (char *)called->number)==0) 
					return TRUE;
			}
		}
		else
			return FALSE;				
	}
	return FALSE;
}


void ChangeTariffToPoolCallTariff(_state_data *shmp,_bill_tariff 	*ptar)
{
	u_short 		rUnit=60;
	float			rAmount=0;
	u_short 		Unit=0;
	u_char 			tier;
	int 			tariff_id;
	
	PutLogFunID("ChangeTariffToPoolCallTariff");

	tariff_id = shmp->caller_info.location;
    Unit = ptar->unit_time;
    if(Unit == 0) Unit = 60;
	if(tariff_id>=MAX_ZONE_NUM || tariff_id<0) tariff_id = 0;

    rUnit = ramshm_ptr->tariff_data.comm_tariff[tariff_id].poolAccountChargeUnit;
	rAmount = ramshm_ptr->tariff_data.comm_tariff[tariff_id].poolAccountChargeAmount;

	if(rUnit ==0) rUnit = 60;
    
	tier = getCurrentTier(shmp,ptar);
	ptar->tierRating.rating[tier].base_fee =  Unit * rAmount /rUnit;
}





