#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"
#include <stdlib.h>

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

extern	int SendUSSDRequest(u_short portid, char *ussd_info);
extern 	int smppSendMsg(u_char *peerNumber,u_char *msg,u_char serviceNumPosition);


extern	int	StuffCapMessage(CapArg capArg, PCAP_Message pcap_message);
extern 	int ppsDebugCapMsg(CAP_Message *cap_message,int flag);
extern 	BOOL isPromotionCanBeTransfered(_account_info	   *accountInfo);
extern	BOOL isPromotionFirstTransfered(_account_info      *accountInfo);

extern void SendManualOperationCDR(_account_info *caller_info,_account_info *called_info,int charge);
extern int get_transfer_resolution();

extern u_short		debug_messages;
extern int		  	logMsgFlag;


static double feeAsciiToFloat(u_char *fee);

ulong getSystemCurrencyResolution();

#define	MAX_FEE_LENGTH			7

enum transfeeAccountState
{
        S_TRANSFER_IDLE,
        S_INPUT_DESTNUMBER,
        S_WART_INPUT_DESTNUMBER,
        S_INPUT_DESTNUMBER_AGAIN,
        S_WART_INPUT_DESTNUMBER_AGAIN,
        S_MATCH_DESTNUMBER,
        S_DESTNUMBER_NOT_MATCHED,
        S_TRANSFER_CHECK_DSTNUMBER,
        S_TRANSFER_CHECK_TRANSFERED_FEE,
        S_FULL_PARTIAL_TRANSFER_CHOICE,
        S_WAIT_FULL_PARTIAL_TRANSFER_CHOICE,
        S_INPUT_FEE_TRANSFERED,
        S_WAIT_INPUT_FEE_TRANSFERED,
        S_PLAY_TRANSFERED_FEE_ERROR,
        S_WRONG_INPUT_FEE,
        S_TRANSFER_CONFIRM,
        S_PLAY_TRANSFER_CONFIRM_SUCCESS,
        S_WAIT_TRANSFER_CONFIRM,
        S_TRANSFER_PROCESSING,
        S_PLAY_TRANSFERED_FEE_SUCCESS,
        S_CHECK_USSD_INPUT,
        S_USSD_FT_ALL_IN_ONE_INPUT,
        S_USSD_FT_REST_START,
        S_TRANSFER_EXIT,
};


enum transfer_mode{
	FULL_TRANSFER_MODE,
	PARTIAL_TRANSFER_MODE,
};


#define changeTransferState(portid,val) do { \
	feeTransfer = &shmp->process_info.ppsService.feeTransfer;\
	feeTransfer->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)

u8 getTransferState(u_short portid)
{
	_state_data 	*shmp;

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	return shmp->process_info.ppsService.feeTransfer.state;
}

void playPromptAndCollectVoice(u_short portid,u_short voiceID,u8 inputLen)
{
	_state_data 	*shmp;

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	shmp->process_info.funnel = 0;
	shmp->process_info.srfRelease = 0;
	shmp->process_info.voiceID = voiceID;
	shmp->process_info.maxPCUInfoLen = inputLen;
	shmp->process_info.endOfReplyDigit[0] = 1;
	shmp->process_info.endOfReplyDigit[1] = 12;
	SendPromptAndCollectUserInfo(portid);
}

 void playPromptVoice(u_short portid,u_short voiceID)
{
	_state_data 			*shmp;

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	shmp->process_info.funnel = 0;
	shmp->process_info.srfRelease = 0;
	shmp->process_info.voiceID = voiceID;
	SendSrfPlayAnnouncement(portid);
}

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

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

	memset(&shmp->process_info.ppsService.feeTransfer,0,sizeof(TRANSFER_FEE));
}


int WaitingForInput(_state_data *shmp,u8 *inputMsg)
{
	int				retval = NO_INPUT,dlgid,msglen,len;
	CAP_Message		capmsg;
	CapArg			capArg;
    CapPromptAndCollectUserInformation	*pPCUI;
	
	PutLogFunID("WaitingForInputTransferOutAccount");

	dlgid = shmp->context_info.dialogue_id;

	if(!ReadScfMsg(&capmsg,dlgid))
	{
		return retval;
	}

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

	switch(capmsg.msgOperaCode)
	{
		case CAP_OC_PromptAndCollectUserInformation:
			AddPPSStatistics(MIBPPS_PCUI_RES,shmp->process_info.dir);
			shmp->process_info.funnel = 0;
			msglen = capmsg.msgContent[3]*256 + capmsg.msgContent[4];
			capArg.version = shmp->context_info.acn_ver;
			if(decode_capmsg((char *)&capmsg.msgContent[5],
							msglen,
							capmsg.msgOperaCode,
							CAP_CONFIRM,
							&capArg)<0)
			{
				return (retval = INPUT_ERROR_EXIT);
			}
			pPCUI=&capArg.msg_list.promptAndCollectUserInformationArg;
			len = pPCUI->digitsResponse[0];
			if(len > MAX_IVR_INPUT_LEN) 
				len = MAX_IVR_INPUT_LEN;			

			if(pPCUI->digitsResponse[1] & 0x20)
			{
				pPCUI->digitsResponse[len] |=0xF0;
			}			
			ppsBcdToAsciiR((char *)inputMsg,&pPCUI->digitsResponse[2],2*(len-1));
			StringCut((char *)inputMsg,'F');				
			retval = INPUT_SUCCESS;
		break;
		case CAP_O_UABORT:
		case CAP_O_PABORT:
		default:
			retval = INPUT_ERROR_EXIT;
		break;
	}
	return retval;	
}

static double asciiFeeToFloat(u_char *feeChar)
{
	u_char		*pFloat;
	double		value;
	u8			i,len,Btimes = 0;

	len = strlen((char *)feeChar);
	if(strlen((char *)feeChar) > MAX_FEE_LENGTH)
		return -1;
	for(i = 0;i < len;i++)
	{/*	only  '0' - '9' and 'B' are allowed		*/
		if(feeChar[i] == 'B')
			Btimes++;
		if(feeChar[i] < '0' && feeChar[i] > '9' && feeChar[i] != 'B')
			return -1;
	}

	if(Btimes > 1)/*	'B' only one time	*/
		return -1;
	
	if(feeChar[0] == 'B')
		return -1;		
	
	pFloat = (u_char *)strchr((char *)feeChar,'B');
	if(pFloat != NULL)
		*pFloat = '.';
	
	value = feeAsciiToFloat(feeChar);
	if(value <= 0)
		return -1;
	return 	value;
}

ulong getSystemCurrencyResolution()
{
	long					resolution;
	
	switch(ppsParam.ppsTables.promptResolution[0].currencyResolution)
	{
	  case 0:
		resolution = 1;
	  break;
	  case 1:
		resolution = 10;
	  break;
	  case 2:
	  default:
		resolution = 100;
	  break;
	
	}	
	return resolution;
}

static int WaitingForInputTransferOutFee(_state_data *shmp)
{
	u_char					input_msg[64] = {0};
	double					fee;
	ulong					resolution = 1;
	int						result;
	
	PutLogFunID("WaitingForInputTransferOutFee");

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

	fee = asciiFeeToFloat(input_msg);
	if(fee <= 0 )
		return 2;/*	format error	*/
	if(get_transfer_resolution())
		resolution = getSystemCurrencyResolution();	
	
	shmp->process_info.ppsService.feeTransfer.fee = (int)(fee*resolution);
	
	return result;	
}

int WaitingForInputTransferOutAccount(_state_data *shmp)
{
	u_char					input_msg[64] = {0};
	int						result;
	
	PutLogFunID("WaitingForInputTransferOutFee");

	memset(input_msg,0,64);	
	if(shmp->process_info.ussd_transfer_one_input_flag ==1 )
	{
		result = INPUT_SUCCESS;
		strcpy((char *)input_msg, shmp->process_info.tmpDigits);
	}
	else
		result = WaitingForInput(shmp,input_msg);
	if(result != INPUT_SUCCESS)
		return result;

	CutUnknownPrefix((char *)input_msg);
	if((strlen((char *)input_msg) > MAX_ASCII_NUMBER_LEN)
		||!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);
	}
	
	memset(&shmp->called_info,0,sizeof(_account_info));	
	strcpy((char *)shmp->called_info.number, (char *)input_msg);				
	if(GetAccountPos(&shmp->called_info) == FALSE)
	{
		if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
		{
			return (result = INPUT_ERROR_EXIT);
		}
		return (result = INPUT_ERROR_REINPUT);
	}
       if(get_transfer_status_normal_flag())
        {
            int status = GetAccountStatus(&shmp->called_info);
            if(status != T_NORMAL &&
		 status != T_FRESH &&
		 status != T_SUSPEND)
            {
                if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
                {
                    return (result = INPUT_ERROR_EXIT);
                }
                return (result=INPUT_ERROR_REINPUT);
            }
        }
	
	return result;	
}



void saveFirstInputtedTransferOutAccount(_state_data *shmp)
{
	memcpy(&shmp->process_info.ppsService.feeTransfer.account,&shmp->called_info,sizeof(_account_info));
}

int matchTwoInpuutedTransferOutAccount(_state_data *shmp)
{
	if(!strcmp((char *)shmp->process_info.ppsService.feeTransfer.account.number, (char *)shmp->called_info.number))
		return 1;
	return 0;
}

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

	memset(input_msg,0,64);
	result = WaitingForInput(shmp,input_msg);
	if(result != INPUT_SUCCESS)
		return result;
	if(input_msg[0] < '0' || input_msg[0] > '1')
	{
		if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
		{
			return INPUT_ERROR_EXIT;
		}
		return INPUT_ERROR_REINPUT;
	}
	shmp->process_info.ppsService.feeTransfer.transferMode = input_msg[0];	
	return result;		
}

static int WaitForChoice(_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(input_msg[0] < '0' || input_msg[0] > '3')
	{
		if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
		{
			return INPUT_ERROR_EXIT;
		}
		return INPUT_ERROR_REINPUT;
	}
	shmp->process_info.ppsService.feeTransfer.transferMode = input_msg[0];	
	return result;		
}

static int WaitForChoice_chargeOrTransfer(_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(input_msg[0] < '1' || input_msg[0] > '2')
	{
		if(shmp->process_info.serviceInput++>=SERVICE_INPUT_NUM)
		{
			return INPUT_ERROR_EXIT;
		}
		return INPUT_ERROR_REINPUT;
	}
	shmp->process_info.ppsService.feeTransfer.transferMode = input_msg[0];	
	return result;		
}

int getInputtedChoice(_state_data *shmp)
{
	return shmp->process_info.ppsService.feeTransfer.transferMode - '0';
}


long GetPromotionExpiration(_account_info *ptr)
{
    _prepaid_data    *shmp=&ramshm_ptr->prepaid_data;

	PutLogFunID("GetIncomingExpiration");

    return (ptr->head < MSISDN_HEAD_NUM && ptr->tail < UNIT_STORE_ACCOUNT) ?
            shmp->prepaid_info[ptr->head][ptr->tail].promo_date
            : (tvnow.tv_sec+1);
}
float GetPromotion(_account_info *ptr)
{
    _prepaid_data    *shmp=&ramshm_ptr->prepaid_data;

	PutLogFunID("GetIncomingExpiration");

    return (ptr->head < MSISDN_HEAD_NUM && ptr->tail < UNIT_STORE_ACCOUNT) ?
            shmp->prepaid_info[ptr->head][ptr->tail].promo_balance : 0;
}

int checkTransferedPartialFee(_account_info   *callerInfo,float feeTransfered)
{
	float 		balance=0;	
	BOOL		balanceExpired=FALSE,promotionExpired=FALSE;
	
	if(isPromotionCanBeTransfered(callerInfo))
	{
		if(GetExpiration(callerInfo) <= tvnow.tv_sec)
			balanceExpired = TRUE;
		if(GetPromotionExpiration(callerInfo) <= tvnow.tv_sec)	
			promotionExpired = TRUE;
		if(balanceExpired && promotionExpired)
			return CHECK_TRANSFERED_FEE_EXPIERED;
		if(!balanceExpired)
			balance += GetBalanceWithOutPromotion(callerInfo->head,callerInfo->tail);			
		if(!promotionExpired)
			balance += GetPromotion(callerInfo);			
	}
	else
	{
		if(GetExpiration(callerInfo) <= tvnow.tv_sec)
			return CHECK_TRANSFERED_FEE_EXPIERED;	
		balance = GetBalanceWithOutPromotion(callerInfo->head,callerInfo->tail);
	}

	if(balance < feeTransfered || feeTransfered<= 0)
		return CHECK_TRANSFERED_FEE_INSUFFIENT;
		
	return CHECK_TRANSFERED_FEE_OK;	
}

int GetBalanceWithOutPromotion(int head, int tail)
{
	 _prepaid_data    *shmp=&ramshm_ptr->prepaid_data;

	PutLogFunID("getBalanceWithOutPromotion");

    if (head < MSISDN_HEAD_NUM && tail < UNIT_STORE_ACCOUNT)
        return shmp->prepaid_info[head][tail].balance;
    return FALSE;
	
}

int checkTransferedFullFee(_state_data 	*shmp)
{
	float balance;

	if(GetBalance(&shmp->caller_info) <= 0)
		return CHECK_TRANSFERED_FEE_INSUFFIENT;
	if(GetExpiration(&shmp->caller_info) < (tvnow.tv_sec+1)
		&& GetPromotionExpiration(&shmp->caller_info) < (tvnow.tv_sec+1))
		return CHECK_TRANSFERED_FEE_EXPIERED;
	if(isPromotionCanBeTransfered(&shmp->caller_info))
	{
		balance = GetAccountBalance(shmp->caller_info.head,shmp->caller_info.tail);
	}
	else
	{
		balance = GetBalanceWithOutPromotion(shmp->caller_info.head,shmp->caller_info.tail);			
	}
	if(balance<=0)
		return CHECK_TRANSFERED_FEE_INSUFFIENT;
	shmp->process_info.ppsService.feeTransfer.fee = balance;				
	return CHECK_TRANSFERED_FEE_OK;	
}

static int expieredDaysTransfer_not_used(_account_info *callerInfo,_account_info *destInfo,float transferedFee,float promotion)
{
	_prepaid_data   		*prepaidPoint=&ramshm_ptr->prepaid_data;
	_prepaid_info			*pcalled,*pcaller;
	float					balance,daysPerBalance,valid_time;
	long 					diff;
	COSTable				*cosTableItem;
	
		
	pcalled = &prepaidPoint->prepaid_info[destInfo->head][destInfo->tail];	
	pcaller = &prepaidPoint->prepaid_info[callerInfo->head][callerInfo->tail];
	cosTableItem = &ppsParam.ppsTables.cosTable[pcalled->cos_id%MaxCosTableItem];
	
	if(transferedFee > 0)
	{
		balance = pcaller->balance; 
		diff = GetExpiration(callerInfo) - tvnow.tv_sec;
		if(balance == 0)
			daysPerBalance = 0;
		else
			daysPerBalance = diff/balance;
		valid_time = transferedFee*daysPerBalance;
		pcalled->mo_expiration_date = valid_time + pcalled->mo_expiration_date; 

		if(cosTableItem->accountValidity[0].maxAccountValidityDays<=0) 
			cosTableItem->accountValidity[0].maxAccountValidityDays = 730;
    	if(pcalled->mo_expiration_date > tvnow.tv_sec+ cosTableItem->accountValidity[0].maxAccountValidityDays*24*3600)
		pcalled->mo_expiration_date = tvnow.tv_sec + cosTableItem->accountValidity[0].maxAccountValidityDays*24*3600;
	}

	if(promotion > 0)
	{
		balance = pcaller->promo_balance; 
		diff = GetPromotionExpiration(callerInfo) - tvnow.tv_sec;
		if(balance == 0)
			daysPerBalance = 0;
		else
			daysPerBalance = diff/balance;
		valid_time = promotion*daysPerBalance;		
		pcalled->promo_date = valid_time + pcalled->promo_date; 
		if(cosTableItem->accountValidity[0].maxAccountValidityDays<=0) 
			cosTableItem->accountValidity[0].maxAccountValidityDays = 730;
    	if(pcalled->promo_date > tvnow.tv_sec+ cosTableItem->accountValidity[0].maxAccountValidityDays*24*3600)
		pcalled->promo_date = tvnow.tv_sec + cosTableItem->accountValidity[0].maxAccountValidityDays*24*3600;
	}
	return 1;
}

static int expieredDaysTransfer(_account_info *callerInfo,_account_info *destInfo,float transferedFee,float promotion)
{
	_prepaid_data   		*prepaidPoint=&ramshm_ptr->prepaid_data;
	_prepaid_info			*pcalled,*pcaller;
	
       if(get_not_change_transfer_expiry_date())		
       {return 1;}
       
	pcalled = &prepaidPoint->prepaid_info[destInfo->head][destInfo->tail];	
	pcaller = &prepaidPoint->prepaid_info[callerInfo->head][callerInfo->tail];
	
	if(transferedFee > 0)
	{
		if(pcalled->mo_expiration_date < pcaller->mo_expiration_date)
			pcalled->mo_expiration_date = pcaller->mo_expiration_date; 	
		if(pcalled->mt_expiration_date < pcaller->mt_expiration_date)
			pcalled->mt_expiration_date = pcaller->mt_expiration_date; 	
	}

	if(promotion > 0)
	{
		if(pcalled->promo_date < pcaller->promo_date)
			pcalled->promo_date = pcaller->promo_date; 		
	}
	
	return 1;

}


int poolTransferAccount(_account_info *callerInfo,_account_info *destInfo,float transferedFee)
{	/*Notice: Be sure to call checkTransferedPartialFee() first to check */
        u_long                  instance;
        int                     retval=0;
        _prepaid_data   		*prepaidPoint=&ramshm_ptr->prepaid_data;
        _prepaid_info   		*pcaller,*pcalled;
		float					diff=0;
		double				oldCallerBalance,oldCallerPromo,oldCalledBalance,oldCalledPromo;
		BOOL 					balanceExpired=FALSE,promotionExpired=FALSE;		

		if(transferedFee == 0)
		{
			//pps_print_error(0,"%s no need to transfer fee:%0.4f to %s",callerInfo->number,transferedFee,destInfo->number);
			return -1;
		}
		
        pcalled = &prepaidPoint->prepaid_info[destInfo->head][destInfo->tail];
		oldCalledBalance = pcalled->balance;
		oldCalledPromo = pcalled->promo_balance;
        pcaller = &prepaidPoint->prepaid_info[callerInfo->head][callerInfo->tail];
		oldCallerBalance = pcaller->balance;
		oldCallerPromo = pcaller->promo_balance;
		
		if(isPromotionCanBeTransfered(callerInfo) == FALSE)
		{
			expieredDaysTransfer(callerInfo,destInfo,transferedFee,0);
			pcalled->balance += transferedFee;
		    pcaller->balance -= transferedFee;
		}
		else
		{
			if(GetExpiration(callerInfo) <= tvnow.tv_sec)
				balanceExpired = TRUE;
			if(GetPromotionExpiration(callerInfo) <= tvnow.tv_sec)	
				promotionExpired = TRUE;
			
			if(balanceExpired == TRUE)
			{
				expieredDaysTransfer(callerInfo,destInfo,0,transferedFee);
				pcalled->promo_balance += transferedFee;
			    pcaller->promo_balance -= transferedFee;
			}
			else if(promotionExpired == TRUE)
			{
				expieredDaysTransfer(callerInfo,destInfo,transferedFee,0);
				pcalled->balance += transferedFee;
			    pcaller->balance -= transferedFee;
			}
			else 
			{			
				if(isPromotionFirstTransfered(callerInfo) == FALSE)
				{						
					if(transferedFee > pcaller->balance)
					{
						diff = transferedFee - pcaller->balance;				
						expieredDaysTransfer(callerInfo,destInfo,transferedFee - diff,diff);
						pcalled->balance += transferedFee - diff;
				        pcaller->balance = 0;
						pcalled->promo_balance += diff;
				        pcaller->promo_balance -= diff;				
						
					}
					else
					{
						expieredDaysTransfer(callerInfo,destInfo,transferedFee,0);
						pcalled->balance += transferedFee;
				        pcaller->balance -= transferedFee;
						
					}
				}
				else if(isPromotionFirstTransfered(callerInfo) == TRUE)
				{
					if(transferedFee > pcaller->promo_balance)
					{
						diff = transferedFee - pcaller->promo_balance;
						expieredDaysTransfer(callerInfo,destInfo,diff,transferedFee - diff);
						pcalled->promo_balance += transferedFee - diff;
				        pcaller->promo_balance = 0;		
						pcalled->balance += diff;
				        pcaller->balance -= diff;
						
					}
					else 
					{
						expieredDaysTransfer(callerInfo,destInfo,0,transferedFee);
						pcalled->promo_balance += transferedFee;
				        pcaller->promo_balance -= transferedFee;				
					}
				}
			}
		}
		UpdateAccountStatus(destInfo->head, destInfo->tail, T_NORMAL);
        instance = destInfo->head * UNIT_STORE_ACCOUNT + destInfo->tail;
		if(pcalled->balance >= 0)
		{
        	UpdateAccountOverdraft(destInfo->head, destInfo->tail, 0);
		}
		resetCMBTimes(destInfo);
        SendAccountRealSync(instance,
							(pcalled->balance-oldCalledBalance),
							(pcalled->promo_balance-oldCalledPromo),
							OMC_OCODE_EDIT);
        instance = callerInfo->head * UNIT_STORE_ACCOUNT + callerInfo->tail;
        SendAccountRealSync(instance,
							(pcaller->balance-oldCallerBalance),
							(pcaller->promo_balance-oldCallerPromo),
							OMC_OCODE_EDIT);
        return (retval = 1);
}


void notifyUserTransferResult(_state_data 	*shmp,u8 callerOrCalled)
{
	u_char 			msgSend[MAX_SMS_LEN*4] = {0}, /*tmpbuf[64]={0},*/ buf[MAX_SMS_LEN*2]={0};
	float				balance;
	//u_char			expire_date[128]={0},promotion_expire_date[128]={0};
	//int				i,j;
	u_char			dayTimeReadable[32]={0};
	char				tmpCaller[32],tmpCalled[32];

	balance = shmp->process_info.ppsService.feeTransfer.fee;
	if(balance == 0)
	{
		pps_print_error(shmp->process_info.logMsisdn,"[%05d]No need to notify transfer result,fee:%0.4f",shmp->process_info.portid,balance);
		return;
	}
	
	ppsgetdaytime_readFormat((char *)dayTimeReadable);
	
	switch(callerOrCalled)
	{
		case NOTIFY_CALLER:
			strcpy((char *)msgSend, (char *)getSmsSentenceNative(0, SMS_TRANSFERED_OUT));				
		break;
		case NOTIFY_CALLED:		
		default:
			strcpy((char *)msgSend, (char *)getSmsSentenceNative(0,SMS_TRANSFERED_IN));
		break;
	}	
	
	fillMoneyToContent(balance, (char *)buf);
	strcat((char *)msgSend, (char *)buf);
	switch(callerOrCalled)
	{
		case NOTIFY_CALLER:		
			strcpy(tmpCaller, (char *)shmp->process_info.ppsService.feeTransfer.account.number);
			strcpy(tmpCalled, (char *)shmp->caller_info.number);
			cliManipulationFunction(tmpCaller,tmpCalled);

			sprintf((char *)msgSend+strlen((char *)msgSend), " %s %s", getSmsSentenceNative(0,SMS_TO), tmpCaller);
			sprintf((char *)msgSend+strlen((char *)msgSend), " %s %s", getSmsSentenceNative(0,SMS_ON), dayTimeReadable);
			{
				char tmp_info[256];

				GetAccountPromptInfo(&shmp->caller_info, tmp_info);
				strcat((char *)msgSend, tmp_info);

				smppSendMsg(shmp->caller_info.number,msgSend,FeeTransferPosition);
				
			}
			/*
			smppSendMsg(shmp->caller_info.number,msgSend,FeeTransferPosition);

			i = shmp->caller_info.head%MSISDN_HEAD_NUM;
			j = shmp->caller_info.tail%UNIT_STORE_ACCOUNT;
			AsciiTime(expire_date,ramshm_ptr->prepaid_data.prepaid_info[i][j].mo_expiration_date);

			AsciiTime(promotion_expire_date,ramshm_ptr->prepaid_data.prepaid_info[i][j].promo_date);
			
			smppSendAccountInfo(shmp->caller_info.number,
					ppsParam.ppsTables.serviceNumber[FeeTransferPosition].number,
					(long)ramshm_ptr->prepaid_data.prepaid_info[i][j].balance,expire_date,
					(long)ramshm_ptr->prepaid_data.prepaid_info[i][j].promo_balance,promotion_expire_date,
					0,"","", 
					ramshm_ptr->prepaid_data.prepaid_info[i][j].language_type );
					*/
		break;
		case NOTIFY_CALLED:		
		default:			
			strcpy(tmpCaller, (char *)shmp->caller_info.number);
			strcpy(tmpCalled, (char *)shmp->process_info.ppsService.feeTransfer.account.number);
			cliManipulationFunction(tmpCaller,tmpCalled);

			sprintf((char *)msgSend+strlen((char *)msgSend), " %s %s", getSmsSentenceNative(0, SMS_FROM), tmpCaller);
			sprintf((char *)msgSend+strlen((char *)msgSend), " %s %s", getSmsSentenceNative(0, SMS_ON), dayTimeReadable);
			{
				char tmp_info[256];
				
				GetAccountPromptInfo(&shmp->process_info.ppsService.feeTransfer.account, tmp_info);
				strcat((char *)msgSend, tmp_info);
				
				smppSendMsg(shmp->process_info.ppsService.feeTransfer.account.number,msgSend,FeeTransferPosition);
			}
			/*
			smppSendMsg(shmp->process_info.ppsService.feeTransfer.account.number,msgSend,FeeTransferPosition);
			
			i = shmp->process_info.ppsService.feeTransfer.account.head;
			j = shmp->process_info.ppsService.feeTransfer.account.tail;			
			AsciiTime(expire_date,ramshm_ptr->prepaid_data.prepaid_info[i][j].mo_expiration_date);
			AsciiTime(promotion_expire_date,ramshm_ptr->prepaid_data.prepaid_info[i][j].promo_date);
			smppSendAccountInfo(shmp->process_info.ppsService.feeTransfer.account.number,
					ppsParam.ppsTables.serviceNumber[FeeTransferPosition].number,
					(long)ramshm_ptr->prepaid_data.prepaid_info[i][j].balance,expire_date,
					(long)ramshm_ptr->prepaid_data.prepaid_info[i][j].promo_balance,promotion_expire_date,
					0,"","", 
					ramshm_ptr->prepaid_data.prepaid_info[i][j].language_type);
					*/
		break;
	}		
}

void notifyUserTransferResult_1(_account_info *srcUsr, _account_info *dstUsr, int amount, u8 callerOrCalled)
{
	u_char 			msgSend[MAX_SMS_LEN*4] = {0}, /*tmpbuf[64]={0}, */buf[MAX_SMS_LEN*2]={0};
	float			balance;
	//u_char			expire_date[128]={0},promotion_expire_date[128]={0};
	//int				i,j;
	u_char			dayTimeReadable[32]={0};
	char				tmpCaller[32],tmpCalled[32];

	balance = amount;
	if(balance == 0.0)
	{
		return;
	}
	
	ppsgetdaytime_readFormat((char *)dayTimeReadable);
	
	switch(callerOrCalled)
	{
		case NOTIFY_CALLER:
			strcpy((char *)msgSend, (char *)getSmsSentenceNative(0,SMS_TRANSFERED_OUT));				
		break;
		case NOTIFY_CALLED:		
		default:
			strcpy((char *)msgSend, (char *)getSmsSentenceNative(0,SMS_TRANSFERED_IN));
		break;
	}	
	
	fillMoneyToContent(balance, (char *)buf);
	strcat((char *)msgSend, (char *)buf);
	switch(callerOrCalled)
	{
		case NOTIFY_CALLER:		
			strcpy(tmpCaller, (char *)dstUsr->number);
			strcpy(tmpCalled, (char *)srcUsr->number);
			cliManipulationFunction(tmpCaller, tmpCalled);

			sprintf((char *)msgSend+strlen((char *)msgSend), " %s %s", getSmsSentenceNative(0,SMS_TO), tmpCaller);
			sprintf((char *)msgSend+strlen((char *)msgSend), " %s %s", getSmsSentenceNative(0,SMS_ON), dayTimeReadable);
			{
				char tmp_info[256];

				GetAccountPromptInfo(srcUsr, tmp_info);
				strcat((char *)msgSend, tmp_info);

				smppSendMsg(srcUsr->number, msgSend, FeeTransferPosition);
				
			}
		break;
		case NOTIFY_CALLED:		
		default:			
			strcpy(tmpCaller, (char *)srcUsr->number);
			strcpy(tmpCalled, (char *)dstUsr->number);
			cliManipulationFunction(tmpCaller, tmpCalled);

			sprintf((char *)msgSend+strlen((char *)msgSend), " %s %s", getSmsSentenceNative(0, SMS_FROM), tmpCaller);
			sprintf((char *)msgSend+strlen((char *)msgSend), " %s %s", getSmsSentenceNative(0, SMS_ON), dayTimeReadable);
			{
				char tmp_info[256];
				
				GetAccountPromptInfo(dstUsr, tmp_info);
				strcat((char *)msgSend, tmp_info);
				
				smppSendMsg(dstUsr->number, msgSend, FeeTransferPosition);
			}
		break;
	}		
}

void SendTransferCDR(_account_info *caller_info,_account_info *called_info,float charge)
{
    _tocdr_report  	pcdr;
    char           	buf[BUFSIZE]={""}; 
	int			   	fee,balance,len;
	int			 	head, tail;
		
	PutLogFunID("SendManualOperationCDR");

	head = caller_info->head;
	tail = caller_info->tail;
	
    memset(&pcdr, 0, sizeof(_tocdr_report));
    if (charge > 0)
	{
        pcdr.type[0] = CT_TRANFER_IN;
		pcdr.type[1] = CT_TRANFER_IN>>8;
	}
    else if (charge < 0)
	{
        pcdr.type[0] = CT_TRANFER_OUT;
		pcdr.type[1] = CT_TRANFER_OUT>>8;
	}
	else
	{
		//pps_print_error(0,"transfee fee is %d,%s no need to send cdr at %s",
			//			charge,caller_info->number,__FUNCTION__);
		return ;
	}
    AsciiToBcd(pcdr.seizuretime, ppsgetdaytime(buf), 14);
    AsciiToBcd(pcdr.answertime, ppsgetdaytime(buf), 14);
    AsciiToBcd(pcdr.releasetime, ppsgetdaytime(buf), 14); 
    pcdr.duration[0] = 0;
	fee =  (int)charge;
	fee = abs(fee);
    memcpy(pcdr.charge,&fee,4);
    balance = (int) GetAccountBalance(head, tail);
    memcpy(pcdr.balance,&balance,4);

    GetAccountMsisdn(head,tail,&pcdr.msisdn[1]);
	ByteRev(pcdr.msisdn,9,0);

	pcdr.msisdn[0]=0x91;
	memcpy(pcdr.caller,pcdr.msisdn,9);
    buf[0] = 0;

	pcdr.called[0] = 0x91;	
	len = strlen((char *)called_info->number)%20;
	ppsAsciiToBcdR(&pcdr.called[1], (char *)called_info->number,(len+1)/2*2);
	if(len %2)
	{
		pcdr.called[(len+1)/2] |= 0xF0;
	}
	if(len<21)
	{
		pcdr.called[(len+1)/2+1] = 0xFF;
	}
			
	sprintf(buf,"FFFFFFFFFFFFFFFFFF");
    AsciiToBcd(pcdr.imsi,buf,16);
	
    pcdr.tcos[0] = NORMAL_CLEARING%256;

	CDRStatistics(&pcdr,charge, 0);
	StoreCDR(&pcdr);
    pps_real_update_user_file(head, tail);

#if DEBUG
   if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
    DebugMsg(debugmib.display.asciiOut, "SendTransferCDR");
#endif
}


static void sendTransferInCDR(_state_data *shmp)
{
	float			charge;

	
	charge = shmp->process_info.ppsService.feeTransfer.fee;
	SendTransferCDR(&shmp->process_info.ppsService.feeTransfer.account,&shmp->caller_info,charge);			
}

static void sendTransferOutCDR(_state_data *shmp)
{	
	float			charge;
	
	charge = shmp->process_info.ppsService.feeTransfer.fee;
	SendTransferCDR(&shmp->caller_info,&shmp->process_info.ppsService.feeTransfer.account,-charge);		
}

void FeeTransferTransaction(_state_data *shmp)
{
	poolTransferAccount(&shmp->caller_info,
						&shmp->process_info.ppsService.feeTransfer.account,
						shmp->process_info.ppsService.feeTransfer.fee);
	
	notifyUserTransferResult(shmp,NOTIFY_CALLER);
	notifyUserTransferResult(shmp,NOTIFY_CALLED);

	sendTransferInCDR(shmp);
	sendTransferOutCDR(shmp);							
}

int SendTransferInfoPromptToSrf(u_short portid)
{
	int						balance,centbalance,hth_b,th_b,h_b,b_b;
	char					expire_date[20]="",buf[BUFSIZE]="";
	int						resolution=100;
	int						len;
	_state_data 			*shmp;

	int						dlgid,invokeid=0;
	CAP_Message				cap_message;
	CapArg					capArg;
	CapPlayAnnouncement		*pPlayAnnouncement;
	CapMessageID			*pMID;
	u8						transferNumber[MAX_MSISDN_BLEN];
	u8						varIndex = 0;
	
	PutLogFunID("SendTransferInfoPromptToSrf");

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

	AddPPSStatistics(MIBPPS_PLAY_ANNOUNCEMENT,shmp->process_info.dir);

	balance = shmp->process_info.ppsService.feeTransfer.fee;
									
	if(balance < 0)
		balance = 0;

	AsciiTime(expire_date,GetExpiration(&shmp->caller_info));
   
	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;
	
	resolution = getSystemCurrencyResolution();
	
	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); 

	
	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 +
							INPUT_TRANSFER_CONFIRM;
   

	pMID->variableMessage.variableParts.num = 2;
	

	pMID->variableMessage.variableParts.variablePart[varIndex].choice_id = 4;
	sprintf(buf,"%02d",hth_b);

	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[varIndex].price[0],
			buf,2);
	sprintf(buf,"%d%d",th_b,h_b);

	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[varIndex].price[1],
			buf,2);
	sprintf(buf,"%02d",b_b);

	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[varIndex].price[2],
			buf,2);
	sprintf(buf,"%02d",centbalance);

	ppsAsciiToBcdR(&pMID->variableMessage.variableParts.variablePart[varIndex].price[3],
			buf,2);	

	varIndex++;
			
	len = strlen((char *)shmp->process_info.ppsService.feeTransfer.account.number);
	ppsAsciiToBcdR(transferNumber, (char *)shmp->process_info.ppsService.feeTransfer.account.number, len);	
	if(len>(MAX_MSISDN_BLEN-1)*2) 
		len = (MAX_MSISDN_BLEN - 1 )*2;
	
	pMID->variableMessage.variableParts.variablePart[varIndex].choice_id = 1;	
	pMID->variableMessage.variableParts.variablePart[varIndex].number[0] = (len+1)/2+1;
	if(len%2==0)
	{
		pMID->variableMessage.variableParts.variablePart[varIndex].number[1] = 0x04;
		memcpy(&pMID->variableMessage.variableParts.variablePart[varIndex].number[2],
				transferNumber,
				(len+1)/2);

	}
	else
	{
		pMID->variableMessage.variableParts.variablePart[varIndex].number[1] = 0x24;
		memcpy(&pMID->variableMessage.variableParts.variablePart[varIndex].number[2],
				transferNumber,
				(len+1)/2);
		pMID->variableMessage.variableParts.variablePart[varIndex].number[2+(len+1)/2] &=0x0F;
	}


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

	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;
}

int getUssdACK_old(u_short portid,u_char *ussd_data)
{
    MapOprSrv_struct    opr_srv;
	u8					data_flow[256];
	
    struct MapPUSSR_Arg	*pussr_arg;
        	
	_state_data         *shmp = (_state_data *) smshm_ptr->state_data;    

	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);			
	if(!map_get_oprdata(data_flow,shmp->context_info.map_did))
    {
    	return 0;
    }
	if((data_flow[9] != UnstrctSSReq) || data_flow[1]<14)
	{	
		if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
					"\n\33[31m portid: %d ,did: %d, wait USSDR_ACK but %d received\33[0m",
					portid,shmp->context_info.map_did,data_flow[9]);
		}		
		pps_send_map_close(portid);
		return -1;
	}
			
	if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
			"\nportid: %d ,did: %d, Get Map opr,type:<%d>, PUSSR  ",
			portid,shmp->context_info.map_did,
			data_flow[9]);			
		pps_debug_map_msg(data_flow,0);
	}
					
	opr_srv.version = shmp->context_info.acn_ver;	
	opr_srv.message_type = data_flow[9];
	opr_srv.message_flag = data_flow[10];
	opr_srv.port_id = portid;
	opr_srv.dialogue_id = shmp->context_info.map_did;		
			
	if(extract_mapparam(&opr_srv,
		data_flow[9],
		data_flow[10],
		data_flow[14]*256+data_flow[15],
		&data_flow[16])<=0)
	{
		if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"\n\33[31mportid: %d ,did: %d, decode PUSSR failed \33[0m",
				portid,shmp->context_info.map_did);
		}		
		return -1;
	}
	//shmp->context_info.invoke_id = data_flow[11];
			
	pussr_arg = &opr_srv.msg_list.pussr_arg;
	if(pussr_arg->param_flag != 0x01)
	{
		if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"\n\33[31mportid: %d ,did: %d, decode ussd failed,no content,param flag:%d \33[0m",
				portid,shmp->context_info.map_did,pussr_arg->param_flag);
		}		
		return -1;
	}				
			
	switch(pussr_arg->ussd_arg.ussd_scheme & 0x0f)
	{
		case 0x00:
		case 0x0f: /* 7bit */
			smppDecodeSM((char *)pussr_arg->ussd_arg.ussd_string.ussd_data,
						 (char *)ussd_data,
						 pussr_arg->ussd_arg.ussd_string.string_len); 
		break;
		case 0x04: /* 8bit */
		default:
			memcpy(ussd_data,
					pussr_arg->ussd_arg.ussd_string.ussd_data,
					pussr_arg->ussd_arg.ussd_string.string_len);	
		break;
	}
	if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
			"\nportid: %d ,did: %d, USSD data: \r\n\%s  ",
			portid,shmp->context_info.map_did,
			ussd_data);								
	}
			
	return strlen((char *)ussd_data);
}



int getUssdACK(u_short portid,u_char *ussd_data)
{
	MapOprSrv_struct    opr_srv;
	u8					data_flow[256];
	
    struct MapUSSR_Res  	*ussr_ack;
	_state_data         *shmp = (_state_data *) smshm_ptr->state_data;    

	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);			
	
	if(!map_get_oprdata(data_flow,shmp->context_info.map_did))
    {
    	return 0;
    }
	if((data_flow[9] != UnstrctSSReq) || data_flow[1]<14)
	{	
		if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"\n\33[31m portid: %d ,did: %d, wait USSDR_ACK but %d received\33[0m",
				portid,shmp->context_info.map_did,data_flow[9]);
		}		
		pps_send_map_close(portid);
		return -1;
	}
			
	if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
			"\nportid: %d ,did: %d, Get Map opr,type:<%d>, USSR  ",
			portid,shmp->context_info.map_did,
			data_flow[9]);			
		pps_debug_map_msg(data_flow,0);
	}
					
	opr_srv.version = shmp->context_info.acn_ver;	
	opr_srv.message_type = data_flow[9];
	opr_srv.message_flag = data_flow[10];
	opr_srv.port_id = portid;
	opr_srv.dialogue_id = shmp->context_info.map_did;		
			
	if(extract_mapparam(&opr_srv,
		data_flow[9],
		data_flow[10],
		data_flow[14]*256+data_flow[15],
		&data_flow[16])<=0)
	{
		if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"\n\33[31mportid: %d ,did: %d, decode USSR_ACK failed \33[0m",
				portid,shmp->context_info.map_did);
		}		
		return -1;
	}
			
	ussr_ack = &opr_srv.msg_list.ussr_res;
			
	if(ussr_ack->param_flag != 0x01)
	{
		if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
					"\n\33[31mportid: %d ,did: %d, USSR error received,no content,param flag is:%d \33[0m",
					portid,shmp->context_info.map_did,ussr_ack->param_flag);
		}		
		return -1;
	}				
		
	switch(ussr_ack->ussd_res.ussd_scheme & 0x0f)
	{
		case 0x00:
		case 0x0f: /* 7bit  */
			smppDecodeSM((char *)ussr_ack->ussd_res.ussd_string.ussd_data,
						 (char *)ussd_data,
						 ussr_ack->ussd_res.ussd_string.string_len); 
			if(ussr_ack->ussd_res.ussd_string.string_len %7 == 0)
			{
				int tmplen;
				tmplen =  ussr_ack->ussd_res.ussd_string.string_len*8/7;
				if(ussd_data[tmplen-1] == 0x0d) /* ussd padding byte: 0x0d */
				{
					ussd_data[tmplen-1] = '\0';
				}
			}
		break;
		case 0x04: /* 8bit */
		default:
			memcpy(ussd_data,
					ussr_ack->ussd_res.ussd_string.ussd_data,
					ussr_ack->ussd_res.ussd_string.string_len);	
		break;
	}
	if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
			"\nportid: %d ,did: %d, USSD data: \r\n\%s  ",
			portid,shmp->context_info.map_did,
			ussd_data);								
	}
	return strlen((char *)ussd_data);
}

int SendServiceNotApplied(u_short portid,u8 ussdSmsFlag,u8 serviceNumberPosition)
{
	u_char tmp[MAX_SMS_LEN*4] = {0};
	_state_data 	*shmp;


	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
		
	strcpy((char *)tmp, (char *)getSmsSentenceNative(0,SMS_SERVICE_NOT_APPLIED));
	switch(ussdSmsFlag)
	{
		case USSD_TRANSFER:
			//SendUSSDRequest(portid,tmp);
			SendUSSDNotify(portid, (char *)tmp);
		break;
		case SMS_TRANSFER:
		default:
			smppSendMsg(shmp->caller_info.number,tmp,serviceNumberPosition);
		break;
	}
	return 1;
}

static int SendTransferRequest(u_short portid,u8 ussdSmsFlag)
{
	u_char tmp[MAX_SMS_LEN*4] = {0};
	_state_data 	*shmp;

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	strcpy((char *)tmp, (char *)getSmsSentenceNative(0,SMS_TRANSFER_PROMPT));
	switch(ussdSmsFlag)
	{
		case USSD_TRANSFER:
			SendUSSDRequest(portid, (char *)tmp);
		break;
		case SMS_TRANSFER:
		default:
			smppSendMsg(shmp->caller_info.number,tmp,FeeTransferPosition);
		break;
	}
	return 1;
}


static int SendReinputTransferRequest(u_short portid,u8 ussdSmsFlag)
{
	u_char 			tmp[MAX_SMS_LEN*4] = {0};
	_state_data 	*shmp;

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	strcpy((char *)tmp, (char *)getSmsSentenceNative(0,SMS_FORMAT_ERROR));
	strcat((char *)tmp, (char *)getSmsSentenceNative(0,SMS_TRANSFER_PROMPT));

	switch(ussdSmsFlag)
	{
		case USSD_TRANSFER:
			SendUSSDRequest(portid, (char *)tmp);
		break;
		case SMS_TRANSFER:
		default:
			smppSendMsg(shmp->caller_info.number,tmp,FeeTransferPosition);
		break;
	}
	return 1;
}

static int SendTransferDstNumberErrorRequest(u_short portid,u8 ussdSmsFlag)
{
	u_char tmp[MAX_SMS_LEN*4] = {0};
	_state_data 	*shmp;

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	strcpy((char *)tmp, (char *)getSmsSentenceNative(0,SMS_INVALID_NUMBER));
	if(shmp->process_info.ussd_transfer_one_input_flag != 1)
	{
		strcat((char *)tmp, (char *)getSmsSentenceNative(0,SMS_TRANSFER_PROMPT));
	}
	switch(ussdSmsFlag)
	{
		case USSD_TRANSFER:
			if(shmp->process_info.ussd_transfer_one_input_flag == 1)
				SendUSSDNotify(portid, (char *)tmp);
			else	
				SendUSSDRequest(portid, (char *)tmp);
		break;
		case SMS_TRANSFER:
		default:
			smppSendMsg(shmp->caller_info.number,tmp,FeeTransferPosition);
		break;
	}
	return 1;
}

static int SendTransferInsufficientFeeRequest(u_short portid,u8 ussdSmsFlag)
{
	u_char tmp[MAX_SMS_LEN*4] = {0};
	_state_data 	*shmp;

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	strcpy((char *)tmp, (char *)getSmsSentenceNative(0,SMS_INSUFFICIENT_FEE));
	if(shmp->process_info.ussd_transfer_one_input_flag != 1)
	{
		strcat((char *)tmp, (char *)getSmsSentenceNative(0,SMS_TRANSFER_PROMPT));
	}
	switch(ussdSmsFlag)
	{
		case USSD_TRANSFER:
			if(shmp->process_info.ussd_transfer_one_input_flag == 1)
				SendUSSDNotify(portid, (char *)tmp);
			else	
				SendUSSDRequest(portid, (char *)tmp);
		break;
		case SMS_TRANSFER:
		default:
			smppSendMsg(shmp->caller_info.number,tmp,FeeTransferPosition);
		break;
	}
	return 1;
}

static int SendTransferExpiredAccountRequest(u_short portid,u8 ussdSmsFlag)
{
	u_char tmp[MAX_SMS_LEN*4] = {0};
	_state_data 	*shmp;

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	strcpy((char *)tmp, (char *)getSmsSentenceNative(0,SMS_EXPIRED_ACCOUNT));
	switch(ussdSmsFlag)
	{
		case USSD_TRANSFER:
			SendUSSDRequest(portid, (char *)tmp);
		break;
		case SMS_TRANSFER:
		default:
			smppSendMsg(shmp->caller_info.number,tmp,FeeTransferPosition);
		break;
	}
	return 1;
}

static int SendTransferInfoConfirmRequest(u_short portid,u8 ussdSmsFlag)
{
	_state_data 	*shmp;
	//TRANSFER_FEE	*transferInfo;
	float			balance;
	u_char 			tmp[MAX_SMS_LEN*4] = {0}, /*tmpbuf[64]={0}, */buf[MAX_SMS_LEN*2]={0};
	char				tmpCaller[32],tmpCalled[32];
	
	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	//transferInfo = &shmp->process_info.ppsService.feeTransfer;
	
	strcpy((char *)tmp, (char *)getSmsSentenceNative(0,SMS_WILL_TRANSFER_OUT));

	balance = shmp->process_info.ppsService.feeTransfer.fee;	
	fillMoneyToContent(balance, (char *)buf);
	strcat((char *)tmp, (char *)buf);

	strcpy(tmpCaller, (char *)shmp->process_info.ppsService.feeTransfer.account.number);
	strcpy(tmpCalled, (char *)shmp->caller_info.number);
	cliManipulationFunction(tmpCaller,tmpCalled);
	
	sprintf((char *)tmp+strlen((char *)tmp), " %s %s.", getSmsSentenceNative(0,SMS_TO), tmpCaller);
			
	strcat((char *)tmp, (char *)getSmsSentenceNative(0,SMS_YES_OR_NO));

	
	switch(ussdSmsFlag)
	{
		case USSD_TRANSFER:
			SendUSSDRequest(portid, (char *)tmp);
		break;
		case SMS_TRANSFER:
		default:
			smppSendMsg(shmp->caller_info.number,tmp,FeeTransferPosition);
		break;
	}
	return 1;
}

static int SendReinputTransferConfrimRequest(u_short portid,u8 ussdSmsFlag)
{
	u_char 			tmp[MAX_SMS_LEN*4] = {0};
	_state_data 	*shmp;

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	strcpy((char *)tmp, (char *)getSmsSentenceNative(0,SMS_FORMAT_ERROR));
	strcat((char *)tmp, (char *)getSmsSentenceNative(0,SMS_YES_OR_NO));

	switch(ussdSmsFlag)
	{
		case USSD_TRANSFER:
			SendUSSDRequest(portid, (char *)tmp);
		break;
		case SMS_TRANSFER:
		default:
			smppSendMsg(shmp->caller_info.number,tmp,FeeTransferPosition);
		break;
	}
	return 1;
}

int SendTransferSuccessRequest(u_short portid,u8 ussdSmsFlag)
{	
	u_char 			tmp[MAX_SMS_LEN*4] = {0};
	_state_data 	*shmp;

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	strcpy((char *)tmp, (char *)getSmsSentenceNative(0,SMS_TRANSFER_SUCCESS));

	switch(ussdSmsFlag)
	{
		case USSD_TRANSFER:
			SendPSSREnd(portid, (char *)tmp);
			//SendUSSDRequest(portid, (char *)tmp);
		break;
		case SMS_TRANSFER:
		default:
			smppSendMsg(shmp->caller_info.number,tmp,FeeTransferPosition);
		break;
	}
	return 1;
}

static double feeAsciiToFloat(u_char *fee)
{
	u_char 	*p;
	float 	factor=0.1001;
	double 	value=0;
	
	if(fee == NULL)
		return 0;
	p = fee;
	while(isdigit(*p))
	{
		value = value*10+(*p-'0');
		p++;
	}
	if(*p == '.')
	{			
		p++;
		while(isdigit(*p))
		{
			value += factor*(*p-'0');
			p++;
			factor *= 0.1001;
		}
	}
	return value;
}

int getTransferInfo(u_short portid,u_char *ussd_data)
{/*	format:number#amount	*/
	_state_data 	*shmp;
	TRANSFER_FEE	*transferInfo;
	u8				i,len,Btimes = 0,Atimes = 0,Bposition,Aposition,resolution = 1;
	u8				*p,feeAscii[64]={0};
	double			fee;
	
	PutLogFunID("getTransferInfo");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	len = strlen((char *)ussd_data);
	for(i = 0;i < len;i++)
	{		
		if(!isdigit(ussd_data[i]) 
			&& ussd_data[i] != '#' 
			&& ussd_data[i] != '*' 
			&& ussd_data[i] != '.')
			return -1;
		if(ussd_data[i] == '#')
		{
			Btimes++;
			Bposition = i;
		}
		if(ussd_data[i] == '*' ||  ussd_data[i] == '.')
		{
			Atimes++;
			Aposition = i;
		}
	}

	if(Btimes != 1 || Atimes > 1)
		return -1;

	if(!isdigit(ussd_data[0]) || !isdigit(ussd_data[len - 1]))
		return -1;	
	
	if(Atimes >= 1)
	{		
		if(Bposition >= Aposition)
			return -1;
	}
	
	p = (u8 *)strchr((char *)ussd_data+1, '#');
	if(p == NULL)
		return -1;
	if(!isdigit(*(p+1)))
		return -1;
	
	transferInfo = &shmp->process_info.ppsService.feeTransfer;
	
	*p = 0;	

	memset(feeAscii,0,64);
	strcpy((char *)feeAscii, (char *)p+1);
	
	p = (u8 *)strchr((char *)feeAscii, '*');
	if(p != NULL)
	{
		*p = '.';
	}
	if(strlen((char *)feeAscii) > MAX_FEE_LENGTH)
		return -1;
	if(get_transfer_resolution())
		resolution = getSystemCurrencyResolution();
	fee = feeAsciiToFloat(feeAscii);
	transferInfo->fee = (int)(fee*resolution);
	if(transferInfo->fee <= 0)
		return -1;

	CutUnknownPrefix((char *)ussd_data);
	if(strlen((char *)ussd_data) > MAX_ASCII_NUMBER_LEN)
		return -1;
	memset(transferInfo->account.number,0,MAX_ASCII_NUMBER_LEN);
	strcpy((char *)transferInfo->account.number, (char *)ussd_data);	
	
	return 1;
}

int smppSendMsg(u_char *peerNumber,u_char *msg,u_char serviceNumPosition)
{
	//u_char			buf[256]={0};
	//int 			result = 0;

	PutLogFunID("smppSendMsg");


	return smppSendMOSM((char *)peerNumber, (char *)ppsParam.ppsTables.serviceNumber[serviceNumPosition].number
						, msg, strlen((char *)msg), 0);	
}


int saveTransferSMSACK(u_short portid,u_char *sms)
{
	_state_data 	*shmp;
	u8				len;
	
	PutLogFunID("saveSMSACK");

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

	len = strlen((char *)sms) % MAX_INPUT_SMS;
	
	memcpy(shmp->process_info.ppsService.feeTransfer.inputSMS,sms,len);
	shmp->process_info.ppsService.feeTransfer.inputSMS[len] = 0;
	shmp->process_info.ppsService.feeTransfer.smsTrigger = TRUE;
	return len;
}


static int getTransferSMSACK(u_short portid,u_char *sms)
{
	_state_data 	*shmp;

	PutLogFunID("getSMSACK");

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

	if(shmp->process_info.ppsService.feeTransfer.smsTrigger == FALSE)
		return 0;
	
	shmp->process_info.ppsService.feeTransfer.smsTrigger = FALSE;
	strcpy((char *)sms, (char *)shmp->process_info.ppsService.feeTransfer.inputSMS);
	return strlen((char *)sms);
}

static BOOL checkTransferDestNumber(u_short portid)
{
	_state_data 	*shmp;
	
	PutLogFunID("checkTransferDestNumber");

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

	CutUnknownPrefix((char *)shmp->process_info.ppsService.feeTransfer.account.number);
	if(!strcmp((char *)shmp->caller_info.number, (char *)shmp->process_info.ppsService.feeTransfer.account.number))
	{
		return FALSE;
	}
        if(GetAccountPos(&shmp->process_info.ppsService.feeTransfer.account)==FALSE)
            return FALSE;
        if(get_transfer_status_normal_flag())
        {
            int status = GetAccountStatus(&shmp->process_info.ppsService.feeTransfer.account);
            if(status == T_NORMAL ||
			status == T_FRESH ||
			status  == T_SUSPEND)
			return TRUE;
	     else
                return FALSE;
        }
        return TRUE;
}


int transferAccountSMSProc(u_short portid)
{
	_state_data 	*shmp;
	u_char			short_message[256];
	int 			result = 0;
	TRANSFER_FEE  *feeTransfer;
	
	PutLogFunID("transferAccountSMSProc");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	switch(getTransferState(portid))
	{
		case S_TRANSFER_IDLE:	
			if(isTransferAllowed(portid) == FALSE)
			{
				SendServiceNotApplied(portid,SMS_TRANSFER,FeeTransferPosition);
				changeTransferState(portid,S_TRANSFER_EXIT);
				return SERVICE_RETURN_TO_PARENT;
			}		
			result = checkTransferedPartialFee(&shmp->caller_info,1.0);
			if(result == CHECK_TRANSFERED_FEE_INSUFFIENT )
			{
				SendTransferInsufficientFeeRequest(portid,SMS_TRANSFER);
				return SERVICE_EXIT_PPS;
			}

			changeTransferState(portid,S_WART_INPUT_DESTNUMBER);
		case S_WART_INPUT_DESTNUMBER:
			result = getTransferSMSACK(portid,short_message);
			switch(result)
			{
				case 0:
				break;
				case -1:					
					return SERVICE_EXIT_PPS;
				break;
				default:					
					short_message[result] = 0;
					result = getTransferInfo(portid,short_message);
					if(result < 0)
					{							
					 	SendReinputTransferRequest(portid,SMS_TRANSFER);
						return SERVICE_EXIT_PPS;
					}
					else
						changeTransferState(portid,S_TRANSFER_CHECK_TRANSFERED_FEE);
				break;
			}		
		case S_TRANSFER_CHECK_TRANSFERED_FEE:			
			result = checkTransferedPartialFee(&shmp->caller_info,shmp->process_info.ppsService.feeTransfer.fee);
			switch(result)
			{
				case CHECK_TRANSFERED_FEE_INSUFFIENT:						
					SendTransferInsufficientFeeRequest(portid,SMS_TRANSFER);
					return SERVICE_EXIT_PPS;
				break;
				case CHECK_TRANSFERED_FEE_EXPIERED:
					SendTransferExpiredAccountRequest(portid,SMS_TRANSFER);
					return SERVICE_EXIT_PPS;
				break;
				case CHECK_TRANSFERED_FEE_OK:
				default:
					changeTransferState(portid,S_TRANSFER_CHECK_DSTNUMBER);
				break;				
			}
		case S_TRANSFER_CHECK_DSTNUMBER:
			if(checkTransferDestNumber(portid) == FALSE)
			{				
				SendTransferDstNumberErrorRequest(portid,SMS_TRANSFER);
				return SERVICE_EXIT_PPS;
			}
			else
				changeTransferState(portid,S_TRANSFER_PROCESSING);/*	skip confirm	*/				
		case S_TRANSFER_PROCESSING:
			FeeTransferTransaction(shmp);
						
			changeTransferState(portid,S_TRANSFER_EXIT);			
		case S_TRANSFER_EXIT:
			clearTransferInfo(portid);
			return SERVICE_RETURN_TO_PARENT;
		break;
	}
	return SERVICE_KEEP_STATE;
}


int transferAccountUSSDProc(u_short portid)
{
	_state_data 	*shmp;
	u_char			ussd_data[256]={0};
	int 			result = 0;
	TRANSFER_FEE  *feeTransfer;
	
	PutLogFunID("transferAccountUSSDProc");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	switch(getTransferState(portid))
	{
		case S_TRANSFER_IDLE:	
			if(pps_get_adaptor_flag())
			{
				changeTransferState(portid,S_USSD_FT_REST_START);
				break;
			}
			if(isTransferAllowed(portid) == FALSE)
			{
				SendServiceNotApplied(portid,USSD_TRANSFER,FeeTransferPosition);
				changeTransferState(portid,S_TRANSFER_EXIT);
				break;
			}
			result = checkTransferedPartialFee(&shmp->caller_info,1.0);
			if(result == CHECK_TRANSFERED_FEE_INSUFFIENT)
			{
				SendTransferInsufficientFeeRequest(portid,USSD_TRANSFER);
				return SERVICE_EXIT_PPS;
			}
			
			if(shmp->process_info.ussd_transfer_one_input_flag == 1)
			{
				changeTransferState(portid,S_USSD_FT_ALL_IN_ONE_INPUT);
				break;
			}
			clearTransferInfo(portid);			

			SendTransferRequest(portid,USSD_TRANSFER);
			changeTransferState(portid,S_WART_INPUT_DESTNUMBER);
		break;		
		case S_WART_INPUT_DESTNUMBER:
			result = getUssdACK(portid,ussd_data);
			switch(result)
			{
				case 0:
				break;
				case -1:					
					return SERVICE_EXIT_PPS;
				break;
				default:					
					result = getTransferInfo(portid,ussd_data);
					if(result < 0)
					{
						if(shmp->process_info.serviceInput++ >= SERVICE_INPUT_NUM)	
							return SERVICE_EXIT_PPS;
					 	SendReinputTransferRequest(portid,USSD_TRANSFER);
					}
					else
						changeTransferState(portid,S_TRANSFER_CHECK_TRANSFERED_FEE);
				break;
			}		
		break;
		case S_TRANSFER_CHECK_TRANSFERED_FEE:			
			result = checkTransferedPartialFee(&shmp->caller_info,shmp->process_info.ppsService.feeTransfer.fee);
			switch(result)
			{
				case CHECK_TRANSFERED_FEE_INSUFFIENT:
					if(shmp->process_info.serviceInput++ >= SERVICE_INPUT_NUM)
					{
						return SERVICE_EXIT_PPS;
					}
					SendTransferInsufficientFeeRequest(portid,USSD_TRANSFER);
					changeTransferState(portid,S_WART_INPUT_DESTNUMBER);
				break;
				case CHECK_TRANSFERED_FEE_EXPIERED:
					SendTransferExpiredAccountRequest(portid,USSD_TRANSFER);
					return SERVICE_EXIT_PPS;
				break;
				case CHECK_TRANSFERED_FEE_OK:
				default:
					changeTransferState(portid,S_TRANSFER_CHECK_DSTNUMBER);
				break;				
			}
		break;
		case S_TRANSFER_CHECK_DSTNUMBER:
			if(checkTransferDestNumber(portid) == FALSE)
			{
				if(shmp->process_info.serviceInput++ >= SERVICE_INPUT_NUM)
				{
					return SERVICE_EXIT_PPS;
				}
				SendTransferDstNumberErrorRequest(portid,USSD_TRANSFER);
				changeTransferState(portid,S_WART_INPUT_DESTNUMBER);
			}
			else
				changeTransferState(portid,S_TRANSFER_CONFIRM);
		break;
		case S_TRANSFER_CONFIRM:
			SendTransferInfoConfirmRequest(portid,USSD_TRANSFER);
			changeTransferState(portid,S_WAIT_TRANSFER_CONFIRM);
		break;
		case S_WAIT_TRANSFER_CONFIRM:
			result = getUssdACK(portid,ussd_data);
			switch(result)
			{
				case 0:
				break;
				case -1:					
					return SERVICE_EXIT_PPS;
				break;
				default:
					if(result != 1)
					{
						if(shmp->process_info.serviceInput++ >= SERVICE_INPUT_NUM)
							return SERVICE_EXIT_PPS;							
						else
							SendReinputTransferConfrimRequest(portid,USSD_TRANSFER);
					}
					result = ussd_data[0] - '0';
					switch(result)
					{
						case CONFIRM_OK:
							changeTransferState(portid,S_TRANSFER_PROCESSING);
						break;
						case CONFIRM_ENTER_AGAIN:
							changeTransferState(portid,S_TRANSFER_IDLE);
						break;
						case CONFIRM_CANCEL:
							changeTransferState(portid,S_TRANSFER_EXIT);
						break;
						default:
							return SERVICE_EXIT_PPS;
						break;
					}					
				break;
			}		
		break;
		case S_TRANSFER_PROCESSING:
			FeeTransferTransaction(shmp);
									
			changeTransferState(portid,S_TRANSFER_EXIT);			
		break;		
		case S_USSD_FT_ALL_IN_ONE_INPUT:
			strcpy((char *)shmp->process_info.ppsService.feeTransfer.account.number, shmp->process_info.tmpDigits);
			result = WaitingForInputTransferOutAccount(shmp);
			if(result != INPUT_SUCCESS)
			{
				SendTransferDstNumberErrorRequest(portid,USSD_TRANSFER);		
				changeTransferState(portid,S_TRANSFER_EXIT);			
				break;	
			}
			if(checkTransferDestNumber(portid) == FALSE)
			{
				SendTransferDstNumberErrorRequest(portid,USSD_TRANSFER);
				return SERVICE_EXIT_PPS;
			}
			
			result = checkTransferedPartialFee(&shmp->caller_info,shmp->process_info.ppsService.feeTransfer.fee);
			switch(result)
			{
				case CHECK_TRANSFERED_FEE_INSUFFIENT:
					SendTransferInsufficientFeeRequest(portid,USSD_TRANSFER);
				break;
				case CHECK_TRANSFERED_FEE_EXPIERED:
					SendTransferExpiredAccountRequest(portid,USSD_TRANSFER);
				break;
				case CHECK_TRANSFERED_FEE_OK:
					FeeTransferTransaction(shmp);
				default:
				break;				
			}

									
			changeTransferState(portid,S_TRANSFER_EXIT);			
			
		break;
		case S_USSD_FT_REST_START:
			result = pps_rest_transfer_process(portid);
			if(result != 0)
			{
				changeTransferState(portid,S_TRANSFER_EXIT);					
			}
		break;
		case S_TRANSFER_EXIT:
			clearTransferInfo(portid);
			return SERVICE_EXIT_PPS;
		break;
	}
	return SERVICE_KEEP_STATE;
}


int chargeOrTransfer(u_short portid)
{
	_state_data 	*shmp;
	int 			result = SERVICE_KEEP_STATE,rst;
	TRANSFER_FEE  *feeTransfer;
	
	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	if(shmp->process_info.funnel++>PROMPT_AND_COLLECT_TIMER)
	{		
		return SERVICE_EXIT_PPS;
	}
	switch(getTransferState(portid))
	{
		case S_TRANSFER_IDLE:				
			clearTransferInfo(portid);			
			changeTransferState(portid,S_WAIT_TRANSFER_CONFIRM);
			playPromptAndCollectVoice(portid,CHARGE_OR_TRANSFER,1);
		break;		
		case S_WAIT_TRANSFER_CONFIRM:
			rst = WaitForChoice_chargeOrTransfer(shmp);
			switch(rst)
			{
				case NO_INPUT:
				break;				
				case INPUT_SUCCESS:
					rst = getInputtedChoice(shmp);					
					switch(rst)
					{
						case CONFIRM_OK:
							changeTransferState(portid,S_TRANSFER_EXIT);
						break;
						case CONFIRM_ENTER_AGAIN:
							changeTransferState(portid,S_TRANSFER_EXIT);
						break;						
						default:
							result = SERVICE_EXIT_PPS;
						break;
					}					
				break;
				case INPUT_ERROR_REINPUT:
					playPromptAndCollectVoice(portid,CHARGE_OR_TRANSFER,1);					
				break;
				case INPUT_ERROR_EXIT:
					result = SERVICE_EXIT_PPS;
				break;
			}		
		break;
		case S_TRANSFER_EXIT:
			result = SERVICE_RETURN_TO_PARENT;
		break;
		default:
			result = SERVICE_EXIT_PPS;
		break;
	}
	return result;
}


int transferAccountIVRProc(u_short portid)
{
	_state_data 	*shmp;
	int 			result = SERVICE_KEEP_STATE,rst;
	TRANSFER_FEE  *feeTransfer;
	
	PutLogFunID("transferPPSAccountProc");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	if(shmp->process_info.funnel++>PROMPT_AND_COLLECT_TIMER)
	{		
		clearTransferInfo(portid);
		return SERVICE_EXIT_PPS;
	}
	switch(getTransferState(portid))
	{
		case S_TRANSFER_IDLE:	
			if(isTransferAllowed(portid) == FALSE)
			{
				playPromptVoice(portid,SERIVCE_NOT_APPLIED);				
				changeTransferState(portid,S_PLAY_TRANSFERED_FEE_ERROR);
				break;
			}
			rst = checkTransferedPartialFee(&shmp->caller_info,1.0);
			if(rst == CHECK_TRANSFERED_FEE_INSUFFIENT)
			{
				playPromptVoice(portid,TRANSFERED_FEE_INSUFFIENT);
				changeTransferState(portid,S_PLAY_TRANSFERED_FEE_ERROR);
				return result;
			}
			
			clearTransferInfo(portid);
			changeTransferState(portid,S_INPUT_DESTNUMBER);
		break;		
		case S_INPUT_DESTNUMBER:
			playPromptAndCollectVoice(portid,PleaseInputTransferInAccount,MAX_IVR_INPUT_LEN);
			changeTransferState(portid,S_WART_INPUT_DESTNUMBER);
		break;
		case S_WART_INPUT_DESTNUMBER:
			rst = WaitingForInputTransferOutAccount(shmp);
			switch(rst)
			{
				case NO_INPUT:
				break;				
				case INPUT_SUCCESS:					
					saveFirstInputtedTransferOutAccount(shmp);
					changeTransferState(portid,S_INPUT_DESTNUMBER_AGAIN);
				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_INPUT_DESTNUMBER_AGAIN:
			playPromptAndCollectVoice(portid,PleaseInputTransferInAccountAgain,MAX_IVR_INPUT_LEN);
			changeTransferState(portid,S_WART_INPUT_DESTNUMBER_AGAIN);
		break;
		case S_WART_INPUT_DESTNUMBER_AGAIN:
			rst = WaitingForInputTransferOutAccount(shmp);
			switch(rst)
			{
				case NO_INPUT:
				break;				
				case INPUT_SUCCESS:
					changeTransferState(portid,S_MATCH_DESTNUMBER);
				break;
				case INPUT_ERROR_REINPUT:
					playPromptAndCollectVoice(portid,InvalidAccountIputAgain,MAX_IVR_INPUT_LEN);
					changeTransferState(portid,S_WART_INPUT_DESTNUMBER);			
				break;
				case INPUT_ERROR_EXIT:
					result = SERVICE_EXIT_PPS;
				break;
			}		
		break;			
		case S_MATCH_DESTNUMBER:
			if(matchTwoInpuutedTransferOutAccount(shmp))
				changeTransferState(portid,S_FULL_PARTIAL_TRANSFER_CHOICE);
			else
				changeTransferState(portid,S_DESTNUMBER_NOT_MATCHED);
		break;
		case S_DESTNUMBER_NOT_MATCHED:
			playPromptVoice(portid,NotMatchedTransferOutAccount);
			changeTransferState(portid,S_PLAY_TRANSFERED_FEE_ERROR);
		break;	
		case S_FULL_PARTIAL_TRANSFER_CHOICE:
			playPromptAndCollectVoice(portid,FULL_PARTIAL_TRANSFER_CHOICE,1);
			changeTransferState(portid,S_WAIT_FULL_PARTIAL_TRANSFER_CHOICE);
		break;
		case S_WAIT_FULL_PARTIAL_TRANSFER_CHOICE:
			rst = WaitForTransferMode(shmp);
			switch(rst)
			{
				case NO_INPUT:
				break;				
				case INPUT_SUCCESS:
					rst = getInputtedChoice(shmp);
					if( rst == FULL_TRANSFER_MODE)
					{
						rst = checkTransferedFullFee(shmp);
						switch(rst)
						{
							case CHECK_TRANSFERED_FEE_OK:
								changeTransferState(portid,S_TRANSFER_CONFIRM);
							break;
							case CHECK_TRANSFERED_FEE_INSUFFIENT:
								playPromptVoice(portid,TRANSFERED_FEE_INSUFFIENT);
								changeTransferState(portid,S_PLAY_TRANSFERED_FEE_ERROR);
							break;
							case CHECK_TRANSFERED_FEE_EXPIERED:								
							default:
								playPromptVoice(portid,TRANSFERED_FEE_EXPIERED);
								changeTransferState(portid,S_PLAY_TRANSFERED_FEE_ERROR);
							break;
						}
					}
					else if( rst == PARTIAL_TRANSFER_MODE)
						changeTransferState(portid,S_INPUT_FEE_TRANSFERED);
					else
						changeTransferState(portid,S_FULL_PARTIAL_TRANSFER_CHOICE);
				break;
				case INPUT_ERROR_REINPUT:
					playPromptAndCollectVoice(portid,FULL_PARTIAL_TRANSFER_CHOICE,1);					
				break;
				case INPUT_ERROR_EXIT:
					result = SERVICE_EXIT_PPS;
				break;
			}		
		break;
		case S_INPUT_FEE_TRANSFERED:			
			playPromptAndCollectVoice(portid,INPUT_FEE_TRANSFERED,MAX_FEE_LENGTH);
			changeTransferState(portid,S_WAIT_INPUT_FEE_TRANSFERED);
		break;
		case S_WAIT_INPUT_FEE_TRANSFERED:
			rst = WaitingForInputTransferOutFee(shmp);
			switch(rst)
			{
				case NO_INPUT:
				break;				
				case INPUT_SUCCESS:
					rst = checkTransferedPartialFee(&shmp->caller_info,shmp->process_info.ppsService.feeTransfer.fee);
					switch(rst)
					{
						case CHECK_TRANSFERED_FEE_OK:
							changeTransferState(portid,S_TRANSFER_CONFIRM);
						break;
						case CHECK_TRANSFERED_FEE_INSUFFIENT:
							playPromptVoice(portid,TRANSFERED_FEE_INSUFFIENT);
							changeTransferState(portid,S_PLAY_TRANSFERED_FEE_ERROR);
						break;
						case CHECK_TRANSFERED_FEE_EXPIERED:	
						default:
							playPromptVoice(portid,TRANSFERED_FEE_EXPIERED);
							changeTransferState(portid,S_PLAY_TRANSFERED_FEE_ERROR);
						break;
					}
				break;
				case INPUT_ERROR_REINPUT:
					playPromptAndCollectVoice(portid,INPUT_FEE_TRANSFERED_FORMAT_ERROR,MAX_IVR_INPUT_LEN);
				break;
				case INPUT_ERROR_EXIT:
					result = SERVICE_EXIT_PPS;
				break;
			}		
		break;
		case S_TRANSFER_CONFIRM:
			SendTransferInfoPromptToSrf(portid);
			changeTransferState(portid,S_PLAY_TRANSFER_CONFIRM_SUCCESS);
		break;
		case S_PLAY_TRANSFER_CONFIRM_SUCCESS:
			rst = CallingCardWaitingForSpecialResourceReport(shmp);
			if(rst == SERVICE_KEEP_STATE)
				break;					
			else if(rst == 1)	
			{	
				playPromptAndCollectVoice(portid,CONFIRM_LISTEN_AGAIN,1);
				changeTransferState(portid,S_WAIT_TRANSFER_CONFIRM);
			}
			else
				result = SERVICE_EXIT_PPS;				
		break;
		case S_WAIT_TRANSFER_CONFIRM:
			rst = WaitForChoice(shmp);
			switch(rst)
			{
				case NO_INPUT:
				break;				
				case INPUT_SUCCESS:
					rst = getInputtedChoice(shmp);					
					switch(rst)
					{
						case CONFIRM_OK:
							changeTransferState(portid,S_TRANSFER_PROCESSING);
						break;
						case CONFIRM_ENTER_AGAIN:
							changeTransferState(portid,S_FULL_PARTIAL_TRANSFER_CHOICE);
						break;
						case CONFIRM_LISTEN_RE:
							changeTransferState(portid,S_TRANSFER_CONFIRM);
						break;
						case CONFIRM_CANCEL:
						default:
							changeTransferState(portid,S_TRANSFER_EXIT);
						break;
					}					
				break;
				case INPUT_ERROR_REINPUT:
					playPromptAndCollectVoice(portid,CONFIRM_LISTEN_AGAIN,1);					
				break;
				case INPUT_ERROR_EXIT:
					result = SERVICE_EXIT_PPS;
				break;
			}		
		break;
		case S_TRANSFER_PROCESSING:
			FeeTransferTransaction(shmp);
						
			playPromptVoice(portid,TransferSuccess);
			changeTransferState(portid,S_PLAY_TRANSFERED_FEE_SUCCESS);
		break;
		case S_PLAY_TRANSFERED_FEE_SUCCESS:
			rst = CallingCardWaitingForSpecialResourceReport(shmp);
			if(rst == SERVICE_KEEP_STATE)
				break;					
			else if(rst == 1)	
			{																		
				changeTransferState(portid,S_TRANSFER_EXIT);
			}
			else
				result = SERVICE_EXIT_PPS;
		break;
		case S_PLAY_TRANSFERED_FEE_ERROR:
			rst = CallingCardWaitingForSpecialResourceReport(shmp);
			if(rst == SERVICE_KEEP_STATE)
				break;					
			else if(rst == 1)	
			{																		
				changeTransferState(portid,S_TRANSFER_EXIT);
			}
			else
				result = SERVICE_EXIT_PPS;
		break;
		case S_TRANSFER_EXIT:
			clearTransferInfo(portid);
			result = SERVICE_RETURN_TO_PARENT;			
		break;
		default:
			clearTransferInfo(portid);
			result = SERVICE_EXIT_PPS;
		break;
	}	
	return result;
}


