
#include    "../include/includes.h"
#include    "../include/message.h"
#include    "../include/ppsm.h"
#include    "../include/cdrme.h"
#include    "../include/ramdata.h"
#include    "../include/mfunc.h"
#include    "../include/config.h"
#include    "../include/param.h"
#include    "../include/precard.h"
#include    "../include/callingCard.h"
#include    "../include/plat_inc.h"
#include    "../../../../plat/scf/src/include/scfpub.h"
#include    "../../../../plat/scf/src/include/scfmsg.h"

extern _state_machine		*smshm_ptr;

/*------------------------------------------------*/
extern int ppsDebugCapMsg();
extern int decode_initialDP();
extern int decode_initialDPSMS();
extern int IsMNPCalledNumber(char *number);
extern char* GetCapError(); 
extern void PpsHanldeOprProc();
extern int ImportBillSMS();
extern int SendScfTcEND();
extern int UpdateBalanceForRecharge();





extern int SendAccountInfoBySMPP();
extern int log_warning();
extern int SendScfUError();
extern int CheckPromotionLatchFlag();
extern int sendConnectForCRDService();
extern int CheckWetherRoamingUser();
extern int GetAccountZoneIDByLocationInfo();
extern int CheckWetherFavoriteNumber();
extern int GetAccountMTZoneID();
extern int CheckWetherRoamingMTUser();
extern int GetAccountMTZoneIDByLocationInfo();
extern int pps_send_map_open();
extern int pps_send_mnp_ati();
extern int pps_send_map_close();
extern int pps_debug_map_msg();
extern int SendConnectForVMSService();
extern int SendPreWarningRequestBCSMEvent();
extern int CheckSeriveIdentification();
extern int CheckSRFResource();
extern int SendEstablishTemporaryConnection();


extern int SendAccountBalanceBySrf();
extern int CheckPINValidity();
extern int GetAccountFavoriteNumberCounter();
extern int StoreAccountFavoriteNumber();
extern int IncreaseFavoriteNumberChangeCounter();
extern int BillingFavoriteNumberChange();
extern int GetAccountFavoriteNumber();
extern int SendFavPromptAndCollectUserInfo();
extern int UpdateAccountDefaultLanguageType();
extern int UpdateAccountPIN();
extern int ppsMapState();
extern int CreatePPSSubsIndexTable();
extern int CreateQuenceList();
extern int ReadSyncMessageForInit();
extern int ppsDebugRt();
extern int srfActivityMonitor();
extern int CheckCRDRingBackServiceKey(int serviceKey);
/********************************************************/
extern u_short			debug_messages;
extern int		  		logMsgFlag;
extern struct	timeval tvnow;
extern unsigned short send_activitytest_timer;
extern PPSParamStruct	ppsParam;
/******** from ppsm.c ******************/
extern int InquiryManageProc(u_short portid);
extern int RechargeManageProc(u_short portid);
extern int PINManagementProc(u_short portid,u_char callingCardFlag);
extern	int WaitingForRechargePIN(u_short portid);
/******** from ppsm.c ******************/
                                                            
/******** from callingCardMsg.c ******************/         
int WaitForMainMenu(_state_data *shmp,u_short portid);      
extern int WaitingForInputCallingCardAccountResponse(_state_data *shmp);
extern int WaitingForInputCalledNumber(_state_data *shmp);  
extern int WaitingForInputTransferOutAccount(_state_data *shmp);
extern int WaitingForPin(_state_data *shmp,u8 type);        
extern int CallingCardWaitingForSpecialResourceReport(_state_data *shmp);
extern int CallingCardInquiryManageProc(u_short portid);    
extern int CallingCardSendReleaseCall(u_short portid);      
extern int CallingCardRechargeManageProc(u_short portid);   
/******** from callingCardMsg.c ******************/         



static int entryCallingCardProc(u_short portid,_state_data 	*shmp)
{
	int 	result = pin_mng_keep_state,rst;
	
	PutLogFunID("entryCallingCardProc");
	if(shmp->process_info.funnel++>PROMPT_AND_COLLECT_TIMER)
	{		
		shmp->process_info.tcos = CALLER_EXPIRIED; 
		CallingCardSendReleaseCall(portid);
		return pin_mng_exit;
	}
	switch(shmp->process_info.sub_state_2)
	{
		case callingCardIdle:
			shmp->process_info.sub_state_2 = inputCallingCardAccount;		
		//break;
		case inputCallingCardAccount:
			shmp->process_info.funnel = 0;
			shmp->process_info.serviceInput = 0;								
			shmp->process_info.voiceID = PleaseInputCallingCardAccount;
			shmp->process_info.endOfReplyDigit[0] = 1;/* length */
			shmp->process_info.endOfReplyDigit[1] = 12;/* # */
			shmp->process_info.maxPCUInfoLen = 20;	  /* max length	*/
			SendPromptAndCollectUserInfo(portid);
			shmp->process_info.sub_state_2 = waitForCallingCardAccount;
		break;
		case waitForCallingCardAccount:
			rst = WaitingForInputCallingCardAccountResponse(shmp);
			switch(rst)
			{
				case 0:
				break;
				case 2:
					shmp->process_info.funnel = 0;
					shmp->process_info.srfRelease = 0;
					shmp->process_info.voiceID = InvalidAccountIputAgain;
					shmp->process_info.maxPCUInfoLen = 20;
					shmp->process_info.endOfReplyDigit[0] = 1;
					shmp->process_info.endOfReplyDigit[1] = 12;
					SendPromptAndCollectUserInfo(portid);
				break;
				case 1:
					shmp->process_info.serviceInput = 0;
					shmp->process_info.funnel = 0;
					shmp->process_info.sub_state_2 = inputCallingCardAccountPassword;						
				break;
				case 3:
					result = pin_mng_exit;
				break;
			}
		break;		
		case inputCallingCardAccountPassword:
			shmp->process_info.serviceInput = 0;
			shmp->process_info.funnel = 0;
			shmp->process_info.srfRelease = 0;
			shmp->process_info.voiceID = INPUT_OLD_PIN;
			shmp->process_info.maxPCUInfoLen = 6;
			shmp->process_info.endOfReplyDigit[0] = 1;
			shmp->process_info.endOfReplyDigit[1] = 12;
			SendPromptAndCollectUserInfo(portid);
			shmp->process_info.sub_state_2 = checkCallingCardAccountPassword;
		break;
		case checkCallingCardAccountPassword:
			rst = WaitingForPin(shmp,0);
			switch(rst)
			{
				case 0:
				break;
				case 2:
					shmp->process_info.maxPCUInfoLen = 6;				
					shmp->process_info.funnel = 0;
					shmp->process_info.srfRelease = 0;
					shmp->process_info.voiceID = ERROR_PIN;
					shmp->process_info.endOfReplyDigit[0] = 1;
					shmp->process_info.endOfReplyDigit[1] = 12;
					SendPromptAndCollectUserInfo(portid);
				break;
				case 1:
					shmp->process_info.serviceInput = 0;
					shmp->process_info.funnel = 0;
					shmp->process_info.sub_state_2 = entrySuccess;
				break;
				case 3:
					result = pin_mng_exit;
				break;
			}
		break;
		case entrySuccess:
			result = entrySuccess;		
			shmp->process_info.sub_state_2 = callingCardIdle;		
		break;						
		default:
			result = pin_mng_exit;
			shmp->process_info.sub_state_2 = callingCardIdle;
		break;
	}
	return result;
}


static int entryCallingCardProc_ccc(u_short portid,_state_data 	*shmp)
{
	int 	result = pin_mng_keep_state,rst;
	
	PutLogFunID("entryCallingCardProccc");
	if(shmp->process_info.funnel++>PROMPT_AND_COLLECT_TIMER)
	{		
		shmp->process_info.tcos = CALLER_EXPIRIED; 
		CallingCardSendReleaseCall(portid);
		return pin_mng_exit;
	}
	switch(shmp->process_info.sub_state_2)
	{
		case callingCardIdle:
			shmp->process_info.sub_state_2 = inputCallingCardAccount;		
			shmp->process_info.ccc_flag = 1;
		//break;
		case inputCallingCardAccount:
			shmp->process_info.funnel = 0;
			shmp->process_info.serviceInput = 0;								
			shmp->process_info.voiceID = PleaseInputCallingCardAccount;
			shmp->process_info.endOfReplyDigit[0] = 1;/* length */
			shmp->process_info.endOfReplyDigit[1] = 12;/* # */
			shmp->process_info.maxPCUInfoLen = 20;	  /* max length	*/
			SendPromptAndCollectUserInfo(portid);
			shmp->process_info.sub_state_2 = waitForCallingCardAccount;
		break;
		case waitForCallingCardAccount:
			rst = WaitingForInputCallingCardAccountResponse_ccc(shmp);
			switch(rst)
			{
				case 0:
				break;
				case 2:
					shmp->process_info.funnel = 0;
					shmp->process_info.srfRelease = 0;
					shmp->process_info.voiceID = InvalidAccountIputAgain;
					shmp->process_info.maxPCUInfoLen = 20;
					shmp->process_info.endOfReplyDigit[0] = 1;
					shmp->process_info.endOfReplyDigit[1] = 12;
					SendPromptAndCollectUserInfo(portid);
				break;
				case 1:
					shmp->process_info.serviceInput = 0;
					shmp->process_info.funnel = 0;
					shmp->process_info.sub_state_2 = entrySuccess;
				break;
				case 3:
					result = pin_mng_exit;
				break;
			}
		break;		
		break;
		case entrySuccess:
			result = entrySuccess;		
			shmp->process_info.sub_state_2 = callingCardIdle;		
		break;						
		default:
			result = pin_mng_exit;
			shmp->process_info.sub_state_2 = callingCardIdle;
		break;
	}
	return result;
}

static int makeCallProc(u_short portid,_state_data 	*shmp)
{
	int result = pin_mng_keep_state,rst,len;	
	_state_data 	*callOutShmp;
	
	PutLogFunID("makeCallProc");
	if(shmp->process_info.funnel++>PROMPT_AND_COLLECT_TIMER)
	{		
		shmp->process_info.tcos = CALLER_EXPIRIED; 
		CallingCardSendReleaseCall(portid);
		return pin_mng_exit;
	}
	switch(shmp->process_info.sub_state_2)
	{
		case callingCardIdle:/*	here need to check :is balance enough to iniate a call?	*/
			shmp->process_info.sub_state_2 = requireInputCalledNumber;			
			shmp->process_info.serviceInput = 0;
			shmp->process_info.funnel = 0;
		break;
		case requireInputCalledNumber:
			shmp->process_info.funnel = 0;
			shmp->process_info.serviceInput = 0;								
			shmp->process_info.voiceID = PleaseInputCalledNumber;
			shmp->process_info.endOfReplyDigit[0] = 1;/* length */
			shmp->process_info.endOfReplyDigit[1] = 12;/* # */
			shmp->process_info.maxPCUInfoLen = 20;	  /* max length	*/
			SendPromptAndCollectUserInfo(portid);
			shmp->process_info.sub_state_2 = waitForCalledNumber;
		break;
		case waitForCalledNumber:		
			rst = WaitingForInputCalledNumber(shmp);
			switch(rst)
			{
				case 0:
				break;
				case 2:
					shmp->process_info.funnel = 0;
					shmp->process_info.srfRelease = 0;
					shmp->process_info.voiceID = InvalidCalledNumberInputAgain;
					shmp->process_info.maxPCUInfoLen = 20;
					shmp->process_info.endOfReplyDigit[0] = 1;
					shmp->process_info.endOfReplyDigit[1] = 12;
					SendPromptAndCollectUserInfo(portid);
				break;
				case 1:
					shmp->process_info.serviceInput = 0;
					shmp->process_info.funnel = 0;
					shmp->process_info.sub_state_2 = requireRouteCalled;
				break;
				case 3:
					result = pin_mng_exit;
				break;
			}
		break;
		case requireRouteCalled:						
			shmp->process_info.funnel = 0;
			shmp->process_info.srfRelease = 0;
			shmp->process_info.voiceID = MakingCall;			
			SendSrfPlayAnnouncement(portid);
			shmp->process_info.sub_state_2 = waitSpecialResourceReport;
		break;		
		case waitSpecialResourceReport:
			rst = CallingCardWaitingForSpecialResourceReport(shmp);
			if(rst == pin_mng_keep_state)
				break;					
			else if(rst == 1)	
			{																		
				callOutShmp = (_state_data *)&smshm_ptr->state_data;
				callOutShmp += shmp->process_info.correlationID;			
				callOutShmp->process_info.disconnectForwardConnection = 1;
				callOutShmp->process_info.callingCardState = sendMainMenu;
				callOutShmp->process_info.callingCardFunction = MakeCall;
				len = strlen((char *)callOutShmp->charge_info.number);			
				memcpy(callOutShmp->process_info.tmpDigits,callOutShmp->charge_info.number,len);																																
				len = sizeof(_account_info);
				memcpy(&callOutShmp->called_info,&callOutShmp->charge_info,len);
				memcpy(&callOutShmp->caller_info,&shmp->caller_info,len);
				result = pin_mng_exit;				
			}
			else
				shmp->process_info.sub_state_2 = returnMainMenu;
		break;
		case returnMainMenu:
			shmp->process_info.callingCardState = sendMainMenu;			
		break;
		default:
			result = pin_mng_exit;
		break;
	}			
	return result;
}

static int inquiryBlanceProc(u_short portid,_state_data 	*shmp)
{
	int result= pin_mng_keep_state,rst;
	
	PutLogFunID("inquiryBlanceProc");
	switch(shmp->process_info.sub_state_2)
	{
		case callingCardIdle:
			shmp->process_info.sub_state_2 = inquiryAccount;	
			shmp->process_info.serviceInput = 0;
			shmp->process_info.funnel = 0;		
			shmp->process_info.sub_state = S_INQ_SEND_PROMPT;
		break;
		case inquiryAccount:
			rst = CallingCardInquiryManageProc(portid);
			if(rst == pin_mng_exit_to_main_menu)
				shmp->process_info.sub_state_2 = returnMainMenu;
		break;
		case returnMainMenu:
			shmp->process_info.callingCardState = sendMainMenu;
		break;
		default:
			result = pin_mng_exit;
		break;
	}
	return result;
}

static int rechargeAccoutProc(u_short portid,_state_data 	*shmp)
{
	int result = pin_mng_keep_state,rst;
	
	PutLogFunID("rechargeAccoutProc");
	switch(shmp->process_info.sub_state_2)
	{
		case callingCardIdle:
			shmp->process_info.sub_state_2 = rechargeAccount;		
			shmp->process_info.serviceInput = 0;
			shmp->process_info.funnel = 0;	
			shmp->process_info.sub_state = S_REC_CHECK_ACCOUNT_STATUS;
		break;
		case rechargeAccount:/*	use pps's function to recharge	*/
			rst = CallingCardRechargeManageProc(portid);
			if(rst == pin_mng_exit_to_main_menu)
				shmp->process_info.sub_state_2 = returnMainMenu;			
		break;		
		case returnMainMenu:
			shmp->process_info.callingCardState = sendMainMenu;
		break;
		default:
			result = pin_mng_exit;
		break;
	}	
	return result;
}

enum changePasswordState
{
	passwordChange = 2	
};
static int changePasswordProc(u_short portid,_state_data 	*shmp)
{
	int result = pin_mng_keep_state,rst;
	
	PutLogFunID("changePasswordProc");
	switch(shmp->process_info.sub_state_2)
	{
		case callingCardIdle:
			shmp->process_info.sub_state_2 = passwordChange;
			shmp->process_info.serviceInput = 0;
			shmp->process_info.funnel = 0;
			shmp->process_info.sub_state = S_PIN_INPUT_OLD_PIN;	
		break;		
		case passwordChange:
			rst = PINManagementProc(portid,1);/*	use pps's password changing function	*/
			if(rst == pin_mng_exit_to_main_menu)
				shmp->process_info.sub_state_2 = returnMainMenu;
		break;
		case returnMainMenu:
			shmp->process_info.callingCardState = sendMainMenu;
		break;
		default:
			result = pin_mng_exit;
		break;
	}	
	return result;
}


enum exitCallingCardState
{	
	sendThankYou = 2,
	waitPlayBye,
	releaseResource
};

static int exitCallingCardProc(u_short portid,_state_data 	*shmp)
{
	int result = pin_mng_keep_state,dlgid;
	CAP_Message		capmsg;
	
	PutLogFunID("exitCallingCardProc");
	if(shmp->process_info.funnel++>PROMPT_AND_COLLECT_TIMER)
	{
		shmp->process_info.tcos = CALLER_EXPIRIED; 
		CallingCardSendReleaseCall(portid);		
		return pin_mng_exit;
	}
	switch(shmp->process_info.sub_state_2)
	{
		case callingCardIdle:
			shmp->process_info.sub_state_2 = sendThankYou;		
		break;
		case sendThankYou:
			shmp->process_info.funnel = 0;
			shmp->process_info.serviceInput = 0;
			shmp->process_info.voiceID = ThankYouUseByeBye;
			SendSrfPlayAnnouncement(portid);
			shmp->process_info.sub_state_2 = waitPlayBye;
		break;
		case waitPlayBye:
			dlgid = shmp->context_info.dialogue_id;
			if(!ReadScfMsg(&capmsg,dlgid))
				return result;
		
			#if DEBUG
				if(debug_messages<=MAX_DEBUG_MESSAGES)
				if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{  
					debug_messages ++;
					ppsDebugCapMsg(&capmsg,0);
				}
			#endif

			if(capmsg.msgOperaCode !=CAP_OC_SpecializedResourceReport)
			{
				if(debug_messages<=MAX_DEBUG_MESSAGES)
				if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{  
					debug_messages ++;
					DebugMsg(debugmib.display.asciiOut,"< Error message received >");
				}
				result = pin_mng_exit;
			}
			shmp->process_info.sub_state_2 = releaseResource;
		break;
		case releaseResource:
			shmp->process_info.tcos = NORMAL_CLEARING; 
			CallingCardSendReleaseCall(portid);			
			result = pin_mng_exit;
		break;
	}
	return result;
}

int callingCardProc(u_short portid)
{
	int result,retval1 = pin_mng_keep_state,retval;
	_state_data 	*shmp;
	
	
	PutLogFunID("callingCardProc");

	shmp = (_state_data *)&smshm_ptr->state_data;
	shmp += portid;
	
	
	if(shmp->process_info.disconnectForwardConnection == 1)
	{		
		SendScfTcEND(portid);
		return pin_mng_exit;
	}	
	
	switch(shmp->process_info.callingCardState)	
	{
		case entryCallingCard:
			if(ocs_get_calling_card_method() == 0)
				result = entryCallingCardProc(portid,shmp);
			else
				result = entryCallingCardProc_ccc(portid, shmp);
			if(result > pin_mng_exit)
				shmp->process_info.callingCardState = sendMainMenu;
			else
				retval1 = result;
		break;
		case sendMainMenu:/*	send main menu	*/
			shmp->process_info.funnel = 0;
			shmp->process_info.serviceInput = 0;
			shmp->process_info.voiceID = CallingCardMainMenu;
			shmp->process_info.maxPCUInfoLen = 1;
			shmp->process_info.callingCardState = chooseFunction;
			SendPromptAndCollectUserInfo(portid);
		break;
		case chooseFunction:/*	choose function		*/
			result = WaitForMainMenu(shmp,portid);							
			if(result < 0)
				break;			
			shmp->process_info.callingCardFunction = result;
			shmp->process_info.callingCardState = runFunction;
			shmp->process_info.sub_state_2 = callingCardIdle;
			break;
		case runFunction:/*	run funcion	*/
			switch(shmp->process_info.callingCardFunction)
			{
				case ExitCallingCard:
					shmp->process_info.callingCardState = exitCallingCardSys;
				break;
				case MakeCall:
					retval1 = makeCallProc(portid,shmp);
				break;
				case InquiryBlance:
					retval1 = inquiryBlanceProc(portid,shmp);
				break;
				case RechargeAccout:
					retval1 = rechargeAccoutProc(portid,shmp);
				break;
				case ChangePassword:
					retval1 = changePasswordProc(portid,shmp);
				break;
				case TransferAccount:
					retval = transferAccountIVRProc(portid);
					switch(retval)
					{
						case SERVICE_KEEP_STATE:
							retval1 = pin_mng_keep_state;
						break;					
						case SERVICE_RETURN_TO_PARENT:
							retval1 = pin_mng_exit_to_main_menu;
						break;
						case SERVICE_EXIT_PPS:
						default:
							retval1 = pin_mng_exit;
						break;
					}		
				break;				
				default:					
					shmp->process_info.callingCardState = sendMainMenu;
				break;
			}
		break;
		case exitCallingCardSys:
			retval1 = exitCallingCardProc(portid,shmp);		
		break;
		default:
		break;
	}
	return retval1;
}

 int CheckCallValidity_ccc(u_short portid)
{
	int retval;//,rst;
	 _state_data    *shmp=(_state_data *)&smshm_ptr->state_data;

	PutLogFunID("CheckCallValidity_ccc");

	shmp += portid;
	retval = shmp->process_info.state;

	shmp->caller_info.cos_id = ocs_get_calling_card_cos_id();
	shmp->context_info.callType = CT_MO_CC_CALL;
	SetCallType(shmp, CT_MO_CC_CALL);
	
	BillingProc_ccc(shmp, TRUE);
#if DEBUG
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
   {  
        debug_messages ++;
		DebugMsg(debugmib.display.asciiOut," \n============== number info ==============");
					
		DebugMsg(debugmib.display.asciiOut," Call type:Calling Card call ");
	
		DebugMsg(debugmib.display.asciiOut,"Caller valid_time: %d calltype: %d fee: %.04f", 
                 shmp->caller_info.valid_time,
                 shmp->process_info.call_type,
                 shmp->caller_info.fee);
		DebugMsg(debugmib.display.asciiOut,"Caller info : %s (%d %d) status:%d,cosid:%d,balance: %.04f", 
                 shmp->caller_info.number,
    		    shmp->caller_info.cos_id,
                 ocs_get_calling_card_left_balance(shmp->card_info.cardhead, shmp->card_info.cardtail));
		DebugMsg(debugmib.display.asciiOut,"Called valid_time: %d calltype: %d fee: %.04f ", 
                 shmp->called_info.valid_time,
                 shmp->process_info.call_type,
                 shmp->called_info.fee);
		DebugMsg(debugmib.display.asciiOut,"Called info: %s (%d %d) status: %d,cosid:%d, balance: %.04f", 
                 shmp->called_info.number,
                 shmp->called_info.head,
                 shmp->called_info.tail,
		    shmp->called_info.status,
		    shmp->called_info.cos_id,
                 GetBalance(&shmp->called_info));
	
		DebugMsg(debugmib.display.asciiOut,
                "Tariff :(%s) %s CT:%d DI:%d FreeTime:%d unit_time:%d Miniunit:%d Adj:%.04f ,CapFlag%d, Discount: %d",
				 shmp->charge_info.number,
				 shmp->process_info.tariff.bill_id,
				 shmp->process_info.tariff.call_type,
			     shmp->process_info.tariff.discountID,
                 shmp->process_info.tariff.free_time,
                 shmp->process_info.tariff.unit_time,
                 shmp->process_info.tariff.mini_unit,                
                 shmp->process_info.tariff.adjustment,
                 shmp->process_info.tariff.cap_flag,
                 GetDiscount(tvnow.tv_sec,shmp->process_info.tariff.discountID));
		DebugMsg(debugmib.display.asciiOut,
				 "tierInfo:L-%d,A-(units:%d,bf:%.04f,lf:%.04f),B-(units:%d,bf:%.04f,lf:%.04f),C-(units:%d,bf:%.04f,lf:%.04f)",				
				shmp->process_info.tariff.tierRating.tierNumber,
				shmp->process_info.tariff.tierRating.rating[0].units,
				shmp->process_info.tariff.tierRating.rating[0].base_fee,
				shmp->process_info.tariff.tierRating.rating[0].long_distance_fee,
				shmp->process_info.tariff.tierRating.rating[1].units,
				shmp->process_info.tariff.tierRating.rating[1].base_fee,
				shmp->process_info.tariff.tierRating.rating[1].long_distance_fee,
				shmp->process_info.tariff.tierRating.rating[2].units,
				shmp->process_info.tariff.tierRating.rating[2].base_fee,
				shmp->process_info.tariff.tierRating.rating[2].long_distance_fee);
	}
#endif

	shmp->process_info.playAnnouncement = 0;
	shmp->process_info.promptAndCollectUserInfo = 0;
	
	if (!IsEnableToCall_ccc(portid) ) 
	{
		/* no voice for CAP V1 */
		if(shmp->context_info.acn_ver<1)
		{
			shmp->process_info.tcos = SERVICE_NOT_AVAILABLE;
			SendReleaseCall(portid);
			return (retval= S_RELEASE_ALL);
		
		}

		{
			shmp->process_info.pre_warning = 0;
			shmp->process_info.playAnnouncement = 0;
			shmp->process_info.promptAndCollectUserInfo = 0;
	
			return (retval = S_REQUEST_EVENTS);
		}

		shmp->process_info.pre_warning = 0;
		shmp->process_info.playAnnouncement = 1;
    }

	retval = S_REQUEST_EVENTS;
	return retval;
}

int WaitingforAnsweredProc_ccc(u_short portid)
{
	_state_data  	*shmp=(_state_data *)&smshm_ptr->state_data;
	//DWORD        	instance = 0;
	int           	retval, release_flag = 0x00,tcend_flag=0;
	int           	dlgid,msglen,edpr;
	CAP_Message   	capmsg;
	struct        	CapArg capArg;
	//CHARGED_FEE		chargedFee;
	char			 error[32];

	PutLogFunID("WaitingforAnsweredProc_ccc");

	shmp += portid;

	dlgid  = shmp->context_info.dialogue_id;

	retval = shmp->process_info.state;
	if (shmp->process_info.funnel >= pps_get_answer_timer_out()) //WAITINGFOR_ANSWERED_DELAY )
	{
		shmp->process_info.tcos = NO_ANSWER;
		if(debug_messages<=MAX_DEBUG_MESSAGES)
		if(logMsgFlag & 0x01 || shmp->process_info.logMsisdn)
        	{
			debug_messages ++;
			DebugMsg(debugmib.display.asciiOut,"P/DID: Wait for answer timeout!"
					,portid,dlgid);
		}

		SendReleaseCall(portid);

		if(shmp->process_info.ro_if.adaptor_enabled == 1)
		{
		
			shmp->process_info.sub_state = 0;							
			retval = S_RO_CALL_TERMIATED;
		}
		else
		{
			retval = S_RELEASE_ALL;
		}

		return retval;
	}
	
	shmp->process_info.funnel ++;

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

	if(capmsg.msgOperaCode != CAP_OC_EventReportBCSM)
	{
	   if(capmsg.msgOperaCode != CAP_OC_ApplyChargingReport)
	   {
			shmp->process_info.tcos = NETWORK_OUT_OF_ORDER;
#if DEBUG
  		   if(logMsgFlag & 0x04 || logMsgFlag & 0x01 ||  shmp->process_info.logMsisdn)
		   {
			  debug_messages ++;
			  DebugMsgDelimiter();
			  DebugMsg(debugmib.display.asciiOut,
			  "Warning: pid=%d did=%d  '%s' received (Waiting for ANSWER)",
			  portid,dlgid,GetCapError(error,capmsg.msgOperaCode));
			  ppsDebugCapMsg(&capmsg,0);
		   }
#endif

			SendReleaseCall(portid);

			if(shmp->process_info.ro_if.adaptor_enabled == 1)
			{
				shmp->process_info.sub_state = 0;							
				retval = S_RO_CALL_TERMIATED;
			}
			else
			{
				retval = S_RELEASE_ALL;
			}
			return retval;
	  }
	  else
	  {
	     AddPPSStatistics(MIBPPS_CHARGINGREPORT,shmp->process_info.dir);
		#if DEBUG
			 if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			 {  
				debug_messages ++;
				DebugMsgDelimiter();
				DebugMsg(debugmib.display.asciiOut,"[%04d] EventReportBCSM Received! (%ld.%ld)",
						portid,tvnow.tv_sec,tvnow.tv_usec);
			 }
			 if((logMsgFlag & 0x02 )|| shmp->process_info.logMsisdn )
			 {
				debug_messages ++;
				ppsDebugCapMsg(&capmsg,0);
			 }
		 #endif
		 return retval;
	   }
    }
#if DEBUG
    if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
	{  
	   debug_messages ++;
	    DebugMsgDelimiter();
		DebugMsg(debugmib.display.asciiOut,"portid=%d, dlgid=%d EventReportBCSM Received! (%ld.%ld)",
		portid,shmp->context_info.dialogue_id,tvnow.tv_sec,tvnow.tv_usec);
	}
	if((logMsgFlag & 0x02)|| shmp->process_info.logMsisdn )
	{
	   debug_messages ++;
		ppsDebugCapMsg(&capmsg,0);
	}
#endif
	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;
	edpr = capArg.msg_list.eventReportBCSMArg.eventTypeBCSM;
	switch(edpr)
	{
		case capp_routeSelectFailure:
			release_flag = 0x01;
			//tcend_flag = 0x01;
			shmp->process_info.tcos = NO_ROUTE;
		break;
		case capp_oCalledPartyBusy:
		case capp_tBusy:
			release_flag = 0x01;
			shmp->process_info.tcos = USER_BUSY;
		break;
		case capp_oNoAnswer:
		case capp_tNoAnswer:
			release_flag = 0x01;
			shmp->process_info.tcos = NO_ANSWER;
		break;
		case capp_oAbandon:
		case capp_tAbandon:	 
			release_flag = 0x01;
			//tcend_flag = 0x01;
			shmp->process_info.tcos = CALL_REJECTED;
		break;
		case capp_oAnswer:
		case capp_tAnswer:
		#if DEBUG
			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
			{  
				debug_messages ++;
				DebugMsg(debugmib.display.asciiOut,"portid=%d EventReportBCSM (Answered)!",portid);
			}
		#endif

			shmp->cdr_info.answertime = tvnow.tv_sec;
			shmp->process_info.duration = 0;
			shmp->process_info.down = 0;
			shmp->process_info.funnel = 0;

			AddPPSStatistics(MIBPPS_ANSWERED,shmp->process_info.dir);
			retval = S_WAITINGFOR_EVENTS;  
			
			if(shmp->process_info.serviceKey != 1)
			{
				shmp->caller_info.charge += shmp->caller_info.fee;
				shmp->called_info.charge += shmp->called_info.fee;	
				shmp->card_info.cc_call_charge += shmp->caller_info.fee;
			}
		break;
		case capp_oDisconnect:
		case capp_tDisconnect:
			release_flag = 0x01;
			shmp->process_info.tcos = edpr;
		break;
		default:
			release_flag = 0x01;
			shmp->process_info.tcos = NETWORK_OUT_OF_ORDER;
			#if DEBUG
			if(debug_messages<=MAX_DEBUG_MESSAGES)
			if(logMsgFlag & 0x04 || logMsgFlag & 0x01 )
			{
				debug_messages ++;
				DebugMsgDelimiter();
				DebugMsg(debugmib.display.asciiOut,
						"Warning: pid=%d did=%d Error Message %d,edpr:%d (Waiting for ANSWER)",
						dlgid,shmp->context_info.dialogue_id,capmsg.msgOperaCode,edpr);
				ppsDebugCapMsg(&capmsg,0);
			}
			#endif
		break;
	}/* switch */
		
	if(release_flag)
	{
		if(tcend_flag)
		{
			SendScfTcEND(portid);
			retval = S_RELEASE_ALL;
		}			
		else
		{
			SendReleaseCall(portid);

			if(shmp->process_info.ro_if.adaptor_enabled == 1)
			{
				shmp->process_info.sub_state = 0;							
				retval = S_RO_CALL_TERMIATED;
			}
			else
			{
				retval = S_RELEASE_ALL;
			}
		}
		return retval;
	}
    
	return retval;
}

int WaitingForEventsReport_ccc(u_short portid)
{
	int         		retval, release_flag = 0x00,tcend_flag=0x00;
	int         		dlgid,msglen, /*instance = 0,*/edpr;//,update_flag=0;
	CAP_Message 		capmsg;
	struct      		CapArg capArg;
	//CHARGED_FEE			chargedFee;
	
	_state_data *shmp=(_state_data *)&smshm_ptr->state_data;

	PutLogFunID("WaitingForEventsReport_ccc");

	shmp += portid;
	retval = shmp->process_info.state;


	dlgid  = shmp->context_info.dialogue_id;

	if (shmp->process_info.funnel >= ACTIVITY_TEST_DELAY )
	{
#if DEBUG
		if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn )
		{  
			debug_messages ++;
			DebugMsgDelimiter();
			DebugMsg(debugmib.display.asciiOut,"portid=%d ActivityTest missed! (%ld.%ld)",
					portid,tvnow.tv_sec,tvnow.tv_usec);
		}
#endif
		shmp->process_info.tcos = ACTIVITY_MISSED;
		shmp->cdr_info.releasetime = tvnow.tv_sec;

		if(shmp->process_info.serviceKey == 1)
		{
			ChargeAccountByRealCallDuration(portid);
		}
		else
		{		      
			UpdateRechargeCardBalance(&shmp->card_info, -shmp->card_info.cc_call_charge);
			SendCDR(portid);
		}

		SendReleaseCall(portid);

		retval = S_RELEASE_ALL;
		
		return (retval);
	}

	if(ReadScfMsg(&capmsg,dlgid))
	{
#if DEBUG
		if((logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
		{
		   ppsDebugCapMsg(&capmsg,0);
		}
#endif
		if(capmsg.msgOperaCode == CAP_OC_ActivityTest ) 
		{
			if(capmsg.msgContent[2] != 0x03)
			{
				shmp->process_info.funnel = 0;
				AddPPSStatistics(MIBPPS_ACTIVITYR,shmp->process_info.dir);
				#if DEBUG
					if((logMsgFlag & 0x04) ||
						(logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
					{  
						DebugMsgDelimiter();
						DebugMsg(debugmib.display.asciiOut,
							"portid=%d ActivityTest Received! (%ld.%ld)",
						portid,tvnow.tv_sec,tvnow.tv_usec);
					}
				#endif
			}
		}
		else if(capmsg.msgOperaCode == 251) //notice 
		{
			shmp->process_info.funnel = 0;
			#if DEBUG
				if((logMsgFlag & 0x04) || 
					(logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{  
					DebugMsgDelimiter();
					DebugMsg(debugmib.display.asciiOut,
						"portid=%d Notice Received while waiting for ACT! (%ld.%ld)",
							portid,tvnow.tv_sec,tvnow.tv_usec);
				}
			#endif
		}
		else if(capmsg.msgOperaCode == CAP_OC_ApplyChargingReport 
						/* charging report */
			|| capmsg.msgOperaCode == CAP_OC_EventReportBCSM) 
				/* bcsm event report */
		{
			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)
			{
				#if DEBUG
				if((logMsgFlag & 0x04) || 
					(logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{  
					DebugMsgDelimiter();
					DebugMsg(debugmib.display.asciiOut,
									"portid=%d Decode failed OC=%d",
					portid,capmsg.msgOperaCode);
				}
				#endif
				return retval;					
			}
			
			if(capmsg.msgOperaCode == CAP_OC_ApplyChargingReport)
			{
				#if DEBUG
				if((logMsgFlag & 0x04) || 
					(logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{  
					DebugMsgDelimiter();
					DebugMsg(debugmib.display.asciiOut,
						"portid=%d ApplyChargingReport Received! (%ld.%ld)",
						portid,tvnow.tv_sec,tvnow.tv_usec);
				}
				#endif
				 /* charging time control */
				if(capArg.msg_list.applyChargingReportArg.callActive)
				{
					if(	shmp->process_info.ro_if.adaptor_enabled == 1)
					{
						if(shmp->process_info.ro_if.granted_value>0)
							SendApplyCharging(portid);
					}
					else
							SendApplyCharging(portid);

				}
				if(shmp->process_info.serviceKey ==1)
				{
					shmp->process_info.realCallDuration += 
						capArg.msg_list.applyChargingReportArg.timeInformation.timeIfNoTariffSwitch;
				}

				AddPPSStatistics(MIBPPS_CHARGINGREPORT,shmp->process_info.dir);
			}

			if(capmsg.msgOperaCode == CAP_OC_EventReportBCSM)
			{
				#if DEBUG
				if((logMsgFlag & 0x04) || 
					(logMsgFlag & 0x02) || shmp->process_info.logMsisdn)
				{  
					DebugMsgDelimiter();
					DebugMsg(debugmib.display.asciiOut,
						"portid=%d EventReportBCSM Received (disconnect)! (%ld.%ld)",
							portid,tvnow.tv_sec,tvnow.tv_usec);
				}
				#endif

				edpr = capArg.msg_list.eventReportBCSMArg.eventTypeBCSM;
				switch(edpr)
				{
					case capp_oDisconnect:
					case capp_tDisconnect:
					default:
						release_flag = 0x01;
						shmp->process_info.tcos = edpr;
						AddPPSStatistics(MIBPPS_DISCONNECT,shmp->process_info.dir);
						shmp->cdr_info.releasetime = tvnow.tv_sec;
					break;
				}/* switch */

				if(release_flag)
				{
					if(tcend_flag)
						SendScfTcEND(portid);
					else
						SendReleaseCall(portid);
					shmp->cdr_info.releasetime = tvnow.tv_sec;
					{
						UpdateRechargeCardBalance(&shmp->card_info, -shmp->card_info.cc_call_charge);

						SendCDR(portid);
					}
					
					if(shmp->process_info.ro_if.adaptor_enabled == 1)
					{
						shmp->process_info.sub_state = 0;					
						retval = S_RO_CALL_TERMIATED;
					}
					else
						retval = S_RELEASE_ALL;
					return retval;
				}
			}
		}
		else
		{
			shmp->process_info.tcos = INVALID_MESSAGE;
			shmp->cdr_info.releasetime = tvnow.tv_sec;			
			{
				UpdateRechargeCardBalance(&shmp->card_info, -shmp->card_info.cc_call_charge);
				
				SendCDR(portid);
			}

			SendReleaseCall(portid);
			retval = S_RELEASE_ALL;
			
			return retval;
		}
	}/* ReadScfMsg */

	if(shmp->process_info.serviceKey != 1 && shmp->process_info.ro_if.adaptor_enabled == 0)
	{
	
		if (shmp->caller_info.valid_time <= 0      /*  Acquire next call period */
			|| shmp->called_info.valid_time <= 0) 
		{ 
			BillingProc_ccc(shmp, FALSE);
			shmp->caller_info.charge += shmp->caller_info.fee;
			shmp->called_info.charge += shmp->called_info.fee;
			shmp->card_info.cc_call_charge += shmp->caller_info.fee;
		}

		if (shmp->caller_info.valid_time <= 0
					|| shmp->called_info.valid_time <= 0) 
		{ 
			shmp->cdr_info.releasetime = tvnow.tv_sec;
			if(shmp->process_info.tcos != CALLER_REACH_CHARGE_LIMIT)
			{
				shmp->process_info.tcos = CALLER_CREDIT_OUT;
			}

			UpdateRechargeCardBalance(&shmp->card_info, -shmp->card_info.cc_call_charge);
			 
			SendCDR(portid);
			SendReleaseCall(portid); 

			return (retval = S_RELEASE_ALL);
		}

		shmp->caller_info.valid_time --;
		shmp->called_info.valid_time --;

	}

	
	shmp->process_info.down ++ ;
	if(shmp->process_info.down >=send_activitytest_timer) //SEND_ACTIVITYTEST_PERIODIC)
	{
		shmp->process_info.down = 0;
		SendActivityTest(portid);     
	}
	shmp->process_info.funnel ++;

	shmp->process_info.duration ++;
	if(shmp->process_info.duration>ppsParam.max_call_duration*50)
	{
	    if(shmp->process_info.send_warning_sms_flag == 0)
	    {
	        char warning_message[256];
	        
	        shmp->process_info.send_warning_sms_flag = 1;

	        sprintf(warning_message, "call duration exceed MAX call duration %d minutes, caller=%s, called=%s, port id=%d",
	        	ppsParam.max_call_duration, shmp->caller_info.number, shmp->called_info.number, portid);

	        sendPPSTestShortMessage(warning_message);
	    }
	}

	return retval;
}

