#include "./include/mgcp_pub.h"
#include "./include/mgcp.h"
#include "./include/mgcp_const.h"
#include "./include/mgcp_ext.h"
#include "./include/mgcp_struct.h"
#include "./include/mgcp_msg.h"

int mgcp_create_trans_id(WORD port)
{
	if (port >= MGCP_MAX_NUM_OF_PORT)
		return -1;
	
	mgcpTransStart[port]++;
	
	mgcpPort[port].transId = (port << 16) | mgcpTransStart[port];
	
	return 0;
}

int mgcp_match_client_trans(DWORD transId)
{
	WORD		port;
	DWORD		srcIp;
	MGCP_PORT	*trans;
	
	port = transId >> 16;
	
	if (port >= MGCP_MAX_NUM_OF_PORT)
		return -1;
	
	trans = &mgcpPort[port];
	if (trans->flag == 0)
		return -1;
	
	srcIp = mgcpRvMsg.msgSrcIP;
	
	if ((trans->reqInd == MGCP_REQUEST) 
		 && (trans->transId == transId) 
		 && (trans->para.ip == srcIp))
		return port;
	
	return -1;
}

int mgcp_match_server_trans(DWORD transId)
{
	WORD 		port;
	DWORD		srcIp;
	MGCP_PORT	*trans;
	
	srcIp = mgcpRvMsg.msgSrcIP;
	
	for (port = 1; port < MGCP_MAX_NUM_OF_PORT; port++)
	{
		trans = &mgcpPort[port];
		if (trans->flag == 0)
			continue;
		
		if ((trans->reqInd == MGCP_INDICATION) 
			  && (trans->transId == transId) 
			  && (trans->para.ip == srcIp))
		{
			if (1 == trans->state2)
			{
				mgcp_send_msg(port, MGCP_RESPONSE);
				
				trans->timer = MGCP_TIME_WAIT_TIMER;
			}	  
			return port;
		}
	}
	
	return -1;
}

BYTE mgcp_trans_init_proc(WORD port)
{
	if (port >= MGCP_MAX_NUM_OF_PORT)
		return 0;
	
	memset((BYTE *) &mgcpPort[port], 0, sizeof(MGCP_PORT));
	
	return 1;
}

BYTE mgcp_trans_idle_proc(WORD port)
{
	BYTE		cmd;
	MGCP_PARA	*para;
	MGCP_PORT	*trans;
	
	if (port >= MGCP_MAX_NUM_OF_PORT)
		return 0;
	
	trans = &mgcpPort[port];
	cmd = trans->cmd;
	
	if ((cmd < MGCP_CMD_CRCX) || (cmd > MGCP_CMD_RSIP))
		return 3;
	
	para = &trans->para;
	
	if (para->sl.cmdRes == MGCP_COMMAND)
	{
		para->sl.cmdRes = 0;
		
		if (trans->reqInd == MGCP_REQUEST)
		{
			mgcp_create_trans_id(port);
			if (mgcp_send_msg(port, MGCP_COMMAND) < 0)
			{
				if (mgcpSap[0].MGCP_cnf == NULL)
					return 3;
				mgcpSap[0].MGCP_cnf(trans->cmd, trans->usrPort, port, MGCP_RET_CODE_TRANS_TIME_OUT, &trans->para);
				  return 3;
			}
			trans->timer = MGCP_MAX_RETRANS_TIMER;
			return 1;
		}
		else if (trans->reqInd == MGCP_INDICATION)
		{
			if (mgcpSap[0].MGCP_ind == NULL)
				return 3;
			
			if (mgcpSap[0].MGCP_ind(cmd, &trans->usrPort, port, para) < 0)
				return 3;
			
			trans->timer = MGCP_MAX_RETRANS_TIMER;
			return 2;
		}
		else
			return 3;
	}
	
	return 3;
}

BYTE mgcp_trans_await_peer_response_proc(WORD port)
{
	MGCP_PORT	*trans;
	MGCP_SL		*sl;
	
	if (port >= MGCP_MAX_NUM_OF_PORT)
		return 0;
	
	trans = &mgcpPort[port];
	sl = &trans->para.sl;
	
	if ((trans->cmd < MGCP_CMD_CRCX) || (trans->cmd > MGCP_CMD_RSIP))
		return 1;
	
	if (sl->cmdRes == MGCP_RESPONSE)
	{
		if (mgcpSap[0].MGCP_cnf == NULL)
			return 1;
		
		if (mgcpSap[0].MGCP_cnf(trans->cmd, trans->usrPort, port, sl->retCode, &trans->para) < 0)
			return 1;
		else
		{
			if ((sl->retCode < 100) ||
				(sl->retCode >= 200))
				return 1;
			sl->cmdRes = 0;
			trans->gotProvRes = 1;
		}
	}
	
	if (trans->timer > 0)
	{
		if (--trans->timer == 0)
		{
			if (mgcpSap[0].MGCP_cnf == NULL)
				return 1;
			mgcpSap[0].MGCP_cnf(trans->cmd, trans->usrPort, port, MGCP_RET_CODE_TRANS_TIME_OUT, &trans->para);
			return 1;
		}
		else if ((trans->gotProvRes == 0) &&
			((trans->timer % MGCP_RETRANS_TIMER) == 0))
			mgcp_send_msg(port, MGCP_COMMAND);
	}
	
	return 0;
}

BYTE mgcp_trans_await_user_response_proc(WORD port)
{
	MGCP_PORT	*trans;
	MGCP_SL		*sl;

	if (port >= MGCP_MAX_NUM_OF_PORT)
		return 0;
	
	trans = &mgcpPort[port];
	sl = &trans->para.sl;
	
	switch (trans->state2 & 1)
	{
	case 0:
		if (sl->cmdRes == MGCP_RESPONSE)
		{
			if (mgcp_send_msg(port, MGCP_RESPONSE) < 0)
				return 1;
			
			if ((sl->retCode < 100) ||
				(sl->retCode >= 200))
			{
				trans->state2 = 1;	
				trans->timer = MGCP_TIME_WAIT_TIMER;
				return 0;
			}
			sl->cmdRes = 0;
			trans->gotProvRes = 1;
		}
		
		if (trans->timer > 0)
		{
			if (--trans->timer == 0)
			{
				if (mgcp_send_rsp(port, MGCP_RET_CODE_TRANS_TIME_OUT_INDEX) < 0)
					return 1;
				
				trans->state2 = 1;	
				trans->timer = MGCP_TIME_WAIT_TIMER;
				return 0;
			}
		}
		break;
	case 1:
		if (trans->timer > 0)
		{
			if (--trans->timer == 0)
				return 1;
		}
		break;
	}
	
	return 0;
}

void mgcp_trans_proc()
{
	WORD port;
	
	for (port = 1; port < MGCP_MAX_NUM_OF_PORT; port++)
	{
		if (mgcpPort[port].flag != 1)
			continue;
		
		switch (mgcpPort[port].state)
		{
		case MGCP_TRANS_IDLE_STATE:
			switch (mgcp_trans_idle_proc(port))
			{
			case 0:
				break;
			case 1:
				mgcpPort[port].state = MGCP_TRANS_AWAIT_PEER_RESPONSE_STATE;
				break;
			case 2:
				mgcpPort[port].state = MGCP_TRANS_AWAIT_USER_RESPONSE_STATE;
				break;
			case 3:
				mgcpPort[port].state = MGCP_TRANS_INIT_STATE;	
				break;
			}
			break;
		case MGCP_TRANS_AWAIT_PEER_RESPONSE_STATE:
			switch (mgcp_trans_await_peer_response_proc(port))
			{
			case 0:
				break;
			case 1:
				mgcpPort[port].state = MGCP_TRANS_INIT_STATE;
				break;
			}
			break;
		case MGCP_TRANS_AWAIT_USER_RESPONSE_STATE:
			switch (mgcp_trans_await_user_response_proc(port))
			{
			case 0:
				break;
			case 1:
				mgcpPort[port].state = MGCP_TRANS_INIT_STATE;
				break;
			}
			break;
		case MGCP_TRANS_INIT_STATE:
			switch (mgcp_trans_init_proc(port))
			{
			case 0:
				break;
			case 1:
				mgcpPort[port].state = MGCP_TRANS_IDLE_STATE;
				break;
			}
			break;
		}
	}
}
