/*
*********************************************************************************
*                                                                               *
* NOTICE:                                                                 *
*                                                                               *
*********************************************************************************
*  
*                                      
*/
 
    
/*********************************************************************************
 *                              <mgc_port_info.c>                                                              
 *     This file contain APIs which is provided to MGC to send and receive MGCP msg
 *
 *
 *    Author                         Date
 *    ------                        ------
 *    Sam Yao                     Aug 2008                                                                                              
 *********************************************************************************/





/*-----------------------------------------------------------------------*/
/*                        INCLUDE HEADER FILES                           */
/*-----------------------------------------------------------------------*/


#include "./include/mgc_port_info.h"
#include "./include/mgc_debug.h"
#include "./include/mgc_conn_info.h"
#include "./include/mgc_chnl_info.h"
#include "./include/mgc_mgcp.h"
#include "./include/mgc_tandem_info.h"
#include "./include/mgc_internal.h"
#ifdef MGC_PORT_LIST_EN
#include "./include/mgc_port_list.h"
#endif

extern 	MGC_SAP *mgc_sap_get_index_sap(int index);


static PORT_INFO mgcPort[MGC_MAX_NUM_OF_PORT];


/*-----------------------------------------------------------------------
            MGC_PORT_INFO    M A N A G E R
 ------------------------------------------------------------------------*/	 

char *mgc_port_info_print_opera_id(MGC_MG_OPER_ID_TYPE operaId)
{
    switch(operaId)
    {
        case MGC_OPER_ID_CONNECT_CHNL:
			return "MGC_OPER_ID_CONNECT_CHNL";
		case MGC_OPER_ID_CONNECT_DTMF:
			return "MGC_OPER_ID_CONNECT_DTMF";
		case MGC_OPER_ID_CONNECT_TONE:
			return "MGC_OPER_ID_CONNECT_TONE";
		case MGC_OPER_ID_CRCX:
			return "MGC_OPER_ID_CRCX";
		case MGC_OPER_ID_MDCX:
			return "MGC_OPER_ID_MDCX";
		case MGC_OPER_ID_DLCX:
			return "MGC_OPER_ID_DLCX";
		case MGC_OPER_ID_RQNT:
			return "MGC_OPER_ID_RQNT";
		case MGC_OPER_ID_AUEP:
			return "MGC_OPER_ID_AUEP";
		case MGC_OPER_ID_CONNECT_AAS :
			return "MGC_OPER_ID_CONNECT_AAS ";
		case MGC_OPER_ID_TANDEM_CREATE:
			return "MGC_OPER_ID_TANDEM_CREATE";
		case MGC_OPER_ID_TANDEM_SET_TAR:
			return "MGC_OPER_ID_TANDEM_SET_TAR";
		case MGC_OPER_ID_TANDEM_UNSET_TAR:
			return "MGC_OPER_ID_TANDEM_UNSET_TAR";
		case MGC_OPER_ID_TANDEM_CLEAR:
			return "MGC_OPER_ID_TANDEM_CLEAR";
		case MGC_OPER_ID_TANDEM_FORK_CHNL:
			return "MGC_OPER_ID_TANDEM_FORK_CHNL";			
		case MGC_OPER_ID_IND:
			return "MGC_OPER_ID_IND";
		case MGC_OPER_ID_CREATE_VIRTUAL_CHNL:
			return "MGC_OPER_ID_CREATE_VIRTUAL_CHNL";
		case MGC_OPER_ID_RELEASE_VIRTUAL_CHNL:
			return "MGC_OPER_ID_RELEASE_VIRTUAL_CHNL";
		case MGC_OPER_ID_UPDATE_CHNL_MEDIA:
			return"MGC_OPER_ID_UPDATE_CHNL_MEDIA";
		default:
		    break;
    }

    return  "MGC_OPER_ID_UNDEF";	
}


char *mgc_port_info_print_cmd(MGC_CMD_TYPE cmd)
{
    switch(cmd)
    {
        case MGC_CMD_CRCX:
			return "MGC_CMD_CRCX";
		case MGC_CMD_MDCX:
			return "MGC_CMD_MDCX";
		case MGC_CMD_DLCX:
			return "MGC_CMD_DLCX";
		case MGC_CMD_RQNT:
			return "MGC_CMD_RQNT";
		case MGC_CMD_NTFY:
			return "MGC_CMD_NTFY";
		case MGC_CMD_AUEP:
			return "MGC_CMD_AUEP";
		case MGC_CMD_RSIP:
			return "MGC_CMD_RSIP";
		case MGC_CMD_NOP:
			return "MGC_CMD_NOP";
		default:
			return "MGC_CMD_UNDEF";
    }
}



/***************************************************************************
 * mgc_port_info_step_info_init
 * ------------------------------------------------------------------------
 * General: init step operate info
 * Return Value: void
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: 	pStep - the pointer of the object
 ***************************************************************************/
void mgc_port_info_step_info_init(MGCF_STEP_INFO *pStepInfo)
{
    if(pStepInfo == NULL)
        return;

    pStepInfo->cmd = MGC_CMD_UNDEF;
	pStepInfo->delay = MGC_OPERA_NO_DELAY;
	pStepInfo->pPeerConn = NULL;
	pStepInfo->mode = MGC_CON_MODE_UNDEF;
	pStepInfo->remoteIp = 0;
    memset(&pStepInfo->pkgEvent , 0, sizeof(PKG_EVENT));
	memset(&pStepInfo->pkgSig , 0, sizeof(PKG_SIGNAL));	
	memset(&pStepInfo->pkgReq , 0 , sizeof(PKG_REQ));
	pStepInfo->eventEn = FALSE;
	pStepInfo->reqEn = FALSE;
	pStepInfo->sigEn= FALSE;
	return;
}


/***************************************************************************
 * mgc_port_info_set_step_info
 * ------------------------------------------------------------------------
 * General: set up step infomation
 * Return Value: void
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: 	pStep - the pointer of the step info object
 *           cmd -  MGCP cmd which should be used in the step
 *           pPeerConn - the pointer of the connection which is at peer position of the operate connection
 *           delay - the time of this step should be delayed
 *           mode - the connect mode of the operate connection
 *           pPkgEvent - the event thing needed in the step
 *           pPkgSig - the signal thing needed in the step
 *           pPkgReq -  the request msg needed in the step
 *           pCodeList - the codelist which should be negotiate in the step
 ***************************************************************************/
void mgc_port_info_set_step_info(MGCF_STEP_INFO *pStepInfo , MGC_CMD_TYPE cmd , CONNECT_INFO *pPeerConn , 
	                                  WORD delay, MGC_CON_MODE mode, PKG_EVENT *pPkgEvent, PKG_SIGNAL *pPkgSig , PKG_REQ *pPkgReq)
{
    if(pStepInfo == NULL)
	    return;

	pStepInfo->delay = delay;
	pStepInfo->pPeerConn = pPeerConn;
	pStepInfo->mode = mode;
	pStepInfo->cmd = cmd;
	
	if(pPkgEvent != NULL)
    {
        memcpy(&pStepInfo->pkgEvent , pPkgEvent, sizeof(PKG_EVENT));	
	    pStepInfo->eventEn = TRUE;
	}
	else
	{
        memset(&pStepInfo->pkgEvent , 0, sizeof(PKG_EVENT));	
		pStepInfo->eventEn = FALSE;
	}
	
	if(pPkgSig != NULL)
	{
	    memcpy(&pStepInfo->pkgSig , pPkgSig, sizeof(PKG_SIGNAL));
		pStepInfo->sigEn= TRUE;
	}
	else
	{
		memset(&pStepInfo->pkgSig , 0, sizeof(PKG_SIGNAL));
		pStepInfo->sigEn= FALSE;
	}

    if(pPkgReq != NULL)
    {
        memcpy(&pStepInfo->pkgReq , pPkgReq , sizeof(PKG_REQ));
		pStepInfo->reqEn = TRUE;
    }
    else
    {
        memset(&pStepInfo->pkgReq , 0 , sizeof(PKG_REQ));
		pStepInfo->reqEn = FALSE;
    }

	return;
}


/***************************************************************************
 * mgc_port_info_oper_step_init
 * ------------------------------------------------------------------------
 * General: init step  info
 * Return Value: void
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: 	pStep - the pointer of the object
 *            id - the id of the step
 ***************************************************************************/
void mgc_port_info_oper_step_init(MGCF_OPER_STEP *pMgcfOperStep , PORT_INFO *pPortInfo , int id)
{
    if((pMgcfOperStep == NULL)||(pPortInfo == NULL))
        return;

    pMgcfOperStep->id = id;
	pMgcfOperStep->status = MGCP_OPER_STEP_UNDEF;
	pMgcfOperStep->pConnect = NULL;
	pMgcfOperStep->hdlPort = 0;
	pMgcfOperStep->llCmd = 0;
	pMgcfOperStep->pPortInfo = pPortInfo;
	mgc_port_info_step_info_init(&pMgcfOperStep->stepInfo);
	return;
}

/***************************************************************************
 * mgc_port_info_get_step_port
 * ------------------------------------------------------------------------
 * General: find the owner of the step
 * Return Value: void
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: 	pStep - the pointer of the object
 ***************************************************************************/
PORT_INFO *mgc_port_info_get_step_port(MGCF_OPER_STEP *pOperStep)
{
    if(pOperStep == NULL)
	    return NULL;	

    return pOperStep->pPortInfo;	
}


/***************************************************************************
 * mgc_port_info_find_port_by_id
 * ------------------------------------------------------------------------
 * General: find the PORT_INFO object by id
 * Return Value: if failure return NULL , else return pointer of the port
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: 	id - the id of the PORT_INFO object
 ***************************************************************************/
PORT_INFO *mgc_port_info_find_port_by_id(int id)
{
    if((id <0) ||(id >= MGC_MAX_NUM_OF_PORT))
        return NULL;

    return &mgcPort[id]	;
}

/***************************************************************************
 * mgc_port_info_get_unused_oper_step
 * ------------------------------------------------------------------------
 * General: find unused step in the specific PORT_INFO object
 * Return Value: if failure return NULL , else return pointer of the step
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pPortInfo - the pointer of the PORT_INFO object
 ***************************************************************************/
MGCF_OPER_STEP *mgc_port_info_get_unused_oper_step(PORT_INFO *pPortInfo)
{
    int i;
	MGCF_OPER_STEP *pMgcfOperStep = NULL;
	
    if(pPortInfo == NULL)
        return NULL;
  
    for(i=0 ; i<MGC_MAX_OPER_STEPS_NUM ; i++)
    {
        pMgcfOperStep = &pPortInfo->mgcfOperSteps[i];
		
        if(pMgcfOperStep->pConnect != NULL)
		    continue;		

		return pMgcfOperStep;
    }

    return NULL;
}


/***************************************************************************
 * mgc_port_info_set_oper_step
 * ------------------------------------------------------------------------
 * General: set up step related operation parameter
 * Return Value: if failure return FALSE , else return TRUE
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pMgcfOperStep - the pointer of the step
 *           pConnect - the pointer of the operate connect
 *           pStepInfo - the pointer of the related step infomation
 ***************************************************************************/
BOOL mgc_port_info_set_oper_step(MGCF_OPER_STEP *pMgcfOperStep , CONNECT_INFO *pConnect , MGCF_STEP_INFO *pStepInfo)
{
    if((pMgcfOperStep == NULL)||(pConnect == NULL)||(pStepInfo == NULL))
        return FALSE;		

    if(pMgcfOperStep->status != MGCP_OPER_STEP_UNDEF)	
        return FALSE;
	
	pMgcfOperStep->pConnect = pConnect;
	pMgcfOperStep->status = MGCP_OPER_STEP_REQUEST;
	memcpy(&pMgcfOperStep->stepInfo , pStepInfo , sizeof(MGCF_STEP_INFO));
	return TRUE;
}

/***************************************************************************
 * mgc_port_info_add_opera_to_port
 * ------------------------------------------------------------------------
 * General: add a operation into the specific PORT_INFO object
 * Return Value: if failure return FALSE , else return TRUE
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pPortInfo - the pointer of the PORT_INFO object
 *           pConnect - the pointer of the operate connect
 *           pStepInfo - the pointer of the related step infomation
 ***************************************************************************/
BOOL mgc_port_info_add_opera_to_port(PORT_INFO *pPortInfo , CONNECT_INFO *pConnect , MGCF_STEP_INFO *pStepInfo)
{
    MGCF_OPER_STEP *pOperStep = NULL;    
	
    if((pPortInfo == NULL)||(pConnect == NULL)||(pStepInfo == NULL))
        return FALSE;	
    
    pOperStep = mgc_port_info_get_unused_oper_step(pPortInfo);
	if(pOperStep == NULL)
	{
	    MGC_ERROR("port[%d] is full of operations" , pPortInfo->id);
	    return FALSE;	
	}

    if(mgc_port_info_set_oper_step(pOperStep , pConnect , pStepInfo) == FALSE)
	    return FALSE;

    if(pStepInfo->cmd != MGC_CMD_AUEP)
    {
	MGC_DEBUG("mgcPort[%d]step[%d] set conn[%d] to do %s" , pPortInfo->id ,pOperStep->id , pConnect->id , mgc_port_info_print_cmd(pStepInfo->cmd));
    }
    return TRUE;	
}


/***************************************************************************
 * mgc_port_info_add_ind_to_port
 * ------------------------------------------------------------------------
 * General: add a ind info into the specific PORT_INFO object
 * Return Value: if failure return FALSE , else return TRUE
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pPortInfo - the pointer of the PORT_INFO object
 *           pConnect - the pointer of the operate connect
 *           cmd - the MGCP cmd 
 *           hdlport - low-layer operate id
 *           remoteIp -peerIp parse from low-layer
 ***************************************************************************/
BOOL mgc_port_info_add_ind_to_port(PORT_INFO *pPortInfo , CONNECT_INFO *pConnect , MGC_CMD_TYPE cmd , int hdlPort , DWORD remoteIp)
{
    MGCF_OPER_STEP *pOperStep = NULL;    
	
    if((pPortInfo == NULL)||(pConnect == NULL))
        return FALSE;	
    
    pOperStep = mgc_port_info_get_unused_oper_step(pPortInfo);
	if(pOperStep == NULL)
	    return FALSE;

    if(pOperStep->status != MGCP_OPER_STEP_UNDEF)	
	    return FALSE;

    pOperStep->pConnect = pConnect;
	pOperStep->status = MGCP_OPER_STEP_IND;
	pOperStep->hdlPort = hdlPort;	
	pOperStep->llCmd = 404;
	pOperStep->stepInfo.remoteIp = remoteIp;
	pOperStep->stepInfo.cmd = cmd;

    if(cmd != MGC_CMD_AUEP)
    {
    MGC_DEBUG("mgcPort[%d]step[%d] add conn[%d] ind %s" , pPortInfo->id,pOperStep->id , pConnect->id , mgc_port_info_print_cmd(cmd));	
    }
	return TRUE;
}


/***************************************************************************
 * mgc_port_info_oper_success_report
 * ------------------------------------------------------------------------
 * General: report success to the up-layer 
 * Return Value: void
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pPortInfo - the pointer of the PORT_INFO object
 *           pMgcSap - the pointer of the mgcSap which should be reported 
 ***************************************************************************/
void mgc_port_info_oper_success_report(PORT_INFO *pPortInfo , MGC_SAP *pMgcSap)
{
    if((pPortInfo == NULL)||(pMgcSap == NULL))
        return;		

    if(pPortInfo->mgcfOperId != MGC_OPER_ID_AUEP)
    {
	MGC_DEBUG("mgcPort[%d] %s success" , pPortInfo->id , mgc_port_info_print_opera_id(pPortInfo->mgcfOperId));
    }
    pMgcSap->cnf_func(pPortInfo->usrPort , pPortInfo->id , pPortInfo->mgcfOperId , MGC_OPER_SUCCESS , pPortInfo->cause);
    return; 
}

/***************************************************************************
 * mgc_port_info_oper_failure_report
 * ------------------------------------------------------------------------
 * General: report failure to the up-layer 
 * Return Value: void
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pPortInfo - the pointer of the PORT_INFO object
 *           pMgcSap - the pointer of the mgcSap which should be reported 
 ***************************************************************************/
void mgc_port_info_oper_failure_report(PORT_INFO *pPortInfo , MGC_SAP *pMgcSap)
{
    if((pPortInfo == NULL)||(pMgcSap == NULL))
        return;		
	
    if(pPortInfo->mgcfOperId != MGC_OPER_ID_AUEP)
    {
	MGC_ERROR("mgcPort[%d] %s failure" , pPortInfo->id , mgc_port_info_print_opera_id(pPortInfo->mgcfOperId));
    }
	pMgcSap->cnf_func(pPortInfo->usrPort , pPortInfo->id , pPortInfo->mgcfOperId , MGC_OPER_FAILURE , MGCP_RET_CODE_TRANS_TIME_OUT);
    return;	
}



/***************************************************************************
 * mgc_port_info_oper_step_request
 * ------------------------------------------------------------------------
 * General: send mgcp req according to the step info
 * Return Value: if failure return FALSE , else return TRUE
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pMgcfOperStep - the pointer of the operate step
 ***************************************************************************/
BOOL mgc_port_info_oper_step_request(MGCF_OPER_STEP *pMgcfOperStep)
{
	int ret;
	CONNECT_INFO *pConnect = NULL;
	PHY_PORT_INFO *pPhyPort = NULL;
    BOOL result = FALSE;
	MGCP_PARA mgcpPara;
	PORT_INFO *pPortInfo = NULL;
	PORT_INFO *pPortInfoTmp = NULL;
    MG_INFO *pMgInfo = NULL;
	BYTE mgcpCmd;
	
	if(pMgcfOperStep == NULL)
	    return FALSE;
	
    pPortInfo = mgc_port_info_get_step_port(pMgcfOperStep);
	if(pPortInfo == NULL)
	    return FALSE;	

	if(pMgcfOperStep->status != MGCP_OPER_STEP_REQUEST)
        return FALSE;		

    if(pMgcfOperStep->pConnect == NULL)
		return FALSE;
	
	pConnect = pMgcfOperStep->pConnect;
	
	if(pMgcfOperStep->stepInfo.cmd != MGC_CMD_AUEP)
	{
    //    MGC_DEBUG("mgcPort[%d]step[%d] conn[%d] request" , pPortInfo->id , pMgcfOperStep->id , pConnect->id);	
	}	
	
    if(pConnect->pOperStep != NULL)    //wait for pre-step work over
    {
        pPortInfoTmp = mgc_port_info_get_step_port(pConnect->pOperStep);
		if(pPortInfoTmp != NULL)
		{
			MGC_WARN("conn[%d] suspend by mgcPort[%d]step[%d] %s!" , 
				      pConnect->id , pPortInfoTmp->id , pConnect->pOperStep->id , mgc_port_info_print_opera_id(pPortInfoTmp->mgcfOperId));		
		}
        if((pConnect->pOperStep->stepInfo.cmd == MGC_CMD_NOP)&&(pConnect->pOperStep->stepInfo.delay != MGC_OPERA_NO_DELAY))
		    pConnect->pOperStep->stepInfo.delay = MGC_OPERA_NO_DELAY;
	    return TRUE;	
    }

    if(mgc_connect_attach_step_info(pConnect, pMgcfOperStep) == FALSE)    
	    return FALSE;

    pMgInfo = mgc_connect_get_own_mg_info(pConnect);
    if(pMgInfo == NULL)
        return FALSE;   
		
    pPhyPort = mgc_connect_get_own_phy_port_info(pConnect);
    if(pPhyPort == NULL)
        return FALSE;	

    memset(&mgcpPara , 0 , sizeof(MGCP_PARA));	
    switch(pMgcfOperStep->stepInfo.cmd)
    {
        case MGC_CMD_CRCX:
			 if(pMgInfo->mgAttr.mgType == MGC_MG_TYPE_INTERNAL)
			 {
                 mgc_connect_set_status(pConnect , MGC_CONNECT_STATUS_CREATED);				 
                 pMgcfOperStep->status = MGCP_OPER_STEP_RESPONSE_GET;
	             return TRUE;			 
			 }

             if((mgc_connect_get_status(pConnect) == MGC_CONNECT_STATUS_CREATED)||(mgc_connect_get_status(pConnect) == MGC_CONNECT_STATUS_CREATE))
             {
                 pMgcfOperStep->status = MGCP_OPER_STEP_RESPONSE_GET;
	             return TRUE;		             
             }
			 
			 if(mgc_connect_get_status(pConnect) != MGC_CONNECT_STATUS_IDLE)
			 {   
			     result = FALSE;
				 break;
			 }
			 mgc_connect_attr_init(pConnect);	
			 result = mgc_connect_crcx_para_create(pConnect , &mgcpPara);
			 mgc_connect_set_status(pConnect , MGC_CONNECT_STATUS_CREATING);			
			 break;
		case MGC_CMD_MDCX:
             if(pMgInfo->mgAttr.mgType == MGC_MG_TYPE_INTERNAL)
             {
                 pMgcfOperStep->status = MGCP_OPER_STEP_RESPONSE_GET;
                 return TRUE;
             }			
              			 
			 if((mgc_connect_get_status(pConnect) != MGC_CONNECT_STATUS_CREATED)&&(mgc_connect_get_status(pConnect) != MGC_CONNECT_STATUS_CREATE))
			 {
			     result = FALSE;
				 break;
			 }			

			 if(mgc_connect_get_status(pConnect) == MGC_CONNECT_STATUS_CREATE)
			 {   
				mgc_connect_set_status(pConnect,MGC_CONNECT_STATUS_CREATED);			        
			 }
	 
			 result = mgc_connect_mdcx_para_create(pConnect , &mgcpPara);
			 if(result == TRUE)
			 {
			     if(mgc_connect_is_conn_need_update(pConnect , &mgcpPara) == FALSE)
			     {
			        MGC_DEBUG("conn[%d] do not need send mdcx" , pConnect->id);
	                pMgcfOperStep->status = MGCP_OPER_STEP_RESPONSE_GET;
	                return TRUE;			    
			     }
			 }
			 break;
		case MGC_CMD_DLCX:
             if(pMgInfo->mgAttr.mgType == MGC_MG_TYPE_INTERNAL)	
             {    
				 mgc_connect_codec_list_init(&pConnect->codecList);
	             memset(&pConnect->mediaAttr , 0 , sizeof(MEDIA_ATTR));
	             memset(&pConnect->operRec , 0 , sizeof(OPER_REC));
	             memset(&pConnect->mgcpRec , 0 , sizeof(MGCP_REC_TAG));               
                 mgc_connect_set_status(pConnect, MGC_CONNECT_STATUS_IDLE);
                 pMgcfOperStep->status = MGCP_OPER_STEP_RESPONSE_GET;
	             return TRUE;	             
             }
			 
			 if((mgc_connect_get_status(pConnect) != MGC_CONNECT_STATUS_CREATED)&&
			 	(mgc_connect_get_status(pConnect) != MGC_CONNECT_STATUS_CREATE)&&
			 	(mgc_connect_get_status(pConnect) != MGC_CONNECT_STATUS_CREATING)
			 	)
			 {			
			     MGC_WARN("conn[%d] is not created,do not need dlcx" , pConnect->id);
				 pMgcfOperStep->status = MGCP_OPER_STEP_RESPONSE_GET;
			     return TRUE;
			 }				
			 result = mgc_connect_dlcx_para_create(pConnect , &mgcpPara);
			 break;
		case MGC_CMD_AUEP:
             if(pMgInfo->mgAttr.mgType == MGC_MG_TYPE_INTERNAL)
             {
                 pMgcfOperStep->status = MGCP_OPER_STEP_RESPONSE_GET;
                 return TRUE;
             }	
			 
			 if(mgc_connect_get_status(pConnect) != MGC_CONNECT_STATUS_IDLE)
			 {
			     result = FALSE;
				 break;
			 }			
			 result = mgc_connect_auep_para_create(pConnect , &mgcpPara);			
			 break;
		case MGC_CMD_NTFY:
             if(pMgInfo->mgAttr.mgType == MGC_MG_TYPE_INTERNAL)
             {
                 pMgcfOperStep->status = MGCP_OPER_STEP_RESPONSE_GET;
                 return TRUE;
             }				
			 break;
		case MGC_CMD_RQNT:
             if(pMgInfo->mgAttr.mgType == MGC_MG_TYPE_INTERNAL)
             {
                 pMgcfOperStep->status = MGCP_OPER_STEP_RESPONSE_GET;
                 return TRUE;
             }				
			 if((mgc_connect_get_status(pConnect) != MGC_CONNECT_STATUS_CREATED)&&(mgc_connect_get_status(pConnect) != MGC_CONNECT_STATUS_CREATE))
			 {			
			     MGC_WARN("conn[%d] is not created, can't send reqnt" , pConnect->id);
			     result = FALSE;
				 break;
			 }					
			 result = mgc_connect_rqnt_para_create(pConnect , &mgcpPara);
		     break;
		case MGC_CMD_RSIP:			
			 break;
	    case MGC_CMD_NOP:		//do nothing for this cmd
		     pMgcfOperStep->status = MGCP_OPER_STEP_RESPONSE_GET;
		     return TRUE;			
		default:
			break;
    }

    if(result == FALSE)
	    return FALSE;

    mgcpCmd = mgc_mgcp_convert_cmd_to_mgcp(pMgcfOperStep->stepInfo.cmd);
	ret = MGCP_req(mgc_mgcp_get_sap_index(), mgcpCmd , pPortInfo->id , &mgcpPara);
	if(ret < 0)
	    return FALSE;
    pMgcfOperStep->hdlPort = ret;
    pMgcfOperStep->status= MGCP_OPER_STEP_REQUEST_SENT;	

    if(pMgcfOperStep->stepInfo.cmd != MGC_CMD_AUEP)	
    {
	MGC_DEBUG("mgcPort[%d]Step[%d] conn[%d] send request %s" ,
		       pPortInfo->id, pMgcfOperStep->id ,pConnect->id , mgc_port_info_print_cmd(pMgcfOperStep->stepInfo.cmd));
    }

	return TRUE;
}




/***************************************************************************
 * mgc_port_info_oper_step_cnf
 * ------------------------------------------------------------------------
 * General: step cnf process
 * Return Value: if failure return FALSE , else return TRUE
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pMgcfOperStep - the pointer of the operate step
 *           pPara - the pointer of the resp Msg
 ***************************************************************************/
BOOL mgc_port_info_oper_step_cnf(MGCF_OPER_STEP *pMgcOperStep , MGCP_PARA *pPara)
{
	BOOL result = FALSE;
	CONNECT_INFO *pConnect = NULL;
    PORT_INFO *pPortInfo = NULL;
    MG_INFO *pMgInfo = NULL;
	PHY_PORT_INFO *pPhyPort = NULL;
	CHNL_INFO *pChnlInfo = NULL;	
	MGC_CMD_TYPE  cmd;
	int connNo = -1;
	int chnlNo = -1;
	WORD retCode;
	
    if((pMgcOperStep == NULL)||(pPara == NULL))
        return FALSE;		
	
    if(pMgcOperStep->status != MGCP_OPER_STEP_REQUEST_SENT)
		return FALSE;

    if(pMgcOperStep->pConnect == NULL)
	    return FALSE;
	
    retCode = pMgcOperStep->llCmd;
    pConnect = pMgcOperStep->pConnect;
	cmd = pMgcOperStep->stepInfo.cmd;

	pChnlInfo = mgc_connect_get_own_chnl_info(pConnect);
	pPhyPort = mgc_connect_get_own_phy_port_info(pConnect);
	pMgInfo = mgc_connect_get_own_mg_info(pConnect);
	pPortInfo = mgc_port_info_get_step_port(pMgcOperStep);	  

    if(pPortInfo == NULL)
    {
        MGC_ERROR("step lost mgcPort!!");
        return FALSE;
    }
	
	if((pChnlInfo == NULL)||(pPhyPort == NULL)||(pMgInfo == NULL))
	{
	    MGC_ERROR("mgcPort[%d]step[%d] lost conn rec" , pPortInfo->id , pMgcOperStep->id);
	    return FALSE;
	}


    pMgcOperStep->status = MGCP_OPER_STEP_RESPONSE_GET;	
    switch( cmd )
    {
        case MGC_CMD_CRCX:
			if(retCode == 200)
			{		    
			    result = mgc_connect_crcx_resp_parse_para(pConnect , pPara);	
				if(result == TRUE)
					mgc_connect_set_status(pConnect , MGC_CONNECT_STATUS_CREATE);					
			}
			else if(retCode == 502)
			{
			    MGC_DEBUG("need to insert dlcx");
				pPortInfo = mgc_port_info_get_step_port(pMgcOperStep);
				result = mgc_port_info_insert_dlcx_req(pPortInfo, pConnect);
                mgc_connect_dettach_step_info(pConnect);
			}
			else
			{
			    MGC_DEBUG("connect[%d] crcx failed!" , pConnect->id);				
			    result = FALSE;
			}			
			break;
		case MGC_CMD_MDCX:
			if(retCode == 200)
			{
			    result = mgc_connect_mdcx_resp_parse_para(pConnect , pPara);
			}
			else
			{
			    result = FALSE;
			}
			break;
		case MGC_CMD_DLCX:
            if(pConnect->pTandem == NULL)
            {
                 mgc_chnl_info_detach_connect(pConnect->pChnlInfo, pConnect) ;				 
				 mgc_connect_init(pConnect, pConnect->id);				 
            }
            else
            {    
                 mgc_connect_set_status(pConnect,MGC_CONNECT_STATUS_IDLE);
				 mgc_connect_codec_list_init(&pConnect->codecList);
	             memset(&pConnect->mediaAttr , 0 , sizeof(MEDIA_ATTR));
	             memset(&pConnect->operRec , 0 , sizeof(OPER_REC));
	             memset(&pConnect->mgcpRec , 0 , sizeof(MGCP_REC_TAG));             
            }

			    result = TRUE;	
			break;
		case MGC_CMD_AUEP:
			if(retCode == 200)
			    result = TRUE;		
			
			if(mgc_chnl_info_detach_connect(pConnect->pChnlInfo, pConnect) == FALSE)
			    mgc_connect_init(pConnect, pConnect->id);			
			break;
		case MGC_CMD_NTFY:
			if(retCode== 200)
			    result = TRUE;	
			break;
		case MGC_CMD_RQNT:
			if(retCode == 200)
			    result = TRUE;			
		    break;
		case MGC_CMD_RSIP:
			if(retCode == 200)
			    result = TRUE;				
			break;
		default:
			break;    
    }

    if(cmd != MGC_CMD_AUEP)
    {
    MGC_DEBUG("conn[%d] get %s response code %d %s" , 
		       pConnect->id , mgc_port_info_print_cmd(cmd) , retCode , result?"success":"failure");	

        if(result == FALSE)
        {
            connNo = mgc_connect_get_connNo_of_chnl_info(pConnect, pChnlInfo);
			chnlNo = mgc_chnl_info_get_chnl_no_of_phy(pChnlInfo,pPhyPort);
            MGC_ERROR("mg[%d]port[%d]chnl[%d]conn[%d] %s get %d mgcPort[%d]step[%d] %s",
				       pMgInfo->id , pPhyPort->portNo , chnlNo, connNo , mgc_port_info_print_cmd(cmd) ,
				       retCode , pPortInfo->id , pMgcOperStep->id , mgc_port_info_print_opera_id(pPortInfo->mgcfOperId));
        }		
    }	
	return result;
}


/***************************************************************************
 * mgc_port_info_oper_step_ind
 * ------------------------------------------------------------------------
 * General: step ind process
 * Return Value: if failure return FALSE , else return TRUE
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pMgcfOperStep - the pointer of the operate step
 ***************************************************************************/
BOOL mgc_port_info_oper_step_ind(MGCF_OPER_STEP *pMgcfOperStep)
{
	int ret;
	CHNL chnl;
	CONNECT_INFO *pConnect = NULL;
	PHY_PORT_INFO *pPhyPort = NULL;
	PORT_INFO *pPortInfo = NULL;
    MG_INFO *pMgInfo = NULL;
	CHNL_INFO *pChnlInfo = NULL;
	WORD usrPort;
	
	if(pMgcfOperStep == NULL)
	    return FALSE;
	
    pPortInfo = mgc_port_info_get_step_port(pMgcfOperStep);
	if(pPortInfo == NULL)
	    return FALSE;	
 
	if(pMgcfOperStep->status != MGCP_OPER_STEP_IND)
        return FALSE;		

    if(pMgcfOperStep->pConnect == NULL)
		return FALSE;

	pConnect = pMgcfOperStep->pConnect;
    if(mgc_connect_attach_step_info(pConnect, pMgcfOperStep) == FALSE)    
	    return FALSE;

    pMgInfo = mgc_connect_get_own_mg_info(pConnect);
	if(pMgInfo == NULL)
	    return FALSE;

	if(pMgInfo->mgAttr.mgType == MGC_MG_TYPE_INTERNAL)
	{
	    pMgcfOperStep->status = MGCP_OPER_STEP_RESPONSE;
	    return TRUE;
	}
	
    pPhyPort = mgc_connect_get_own_phy_port_info(pConnect);
	pChnlInfo = mgc_connect_get_own_chnl_info(pConnect);
	if((pPhyPort == NULL)||(pChnlInfo == NULL))
	    return FALSE;	

	pMgcfOperStep->status = MGCP_OPER_STEP_IND_SENT;
	if(pPhyPort->pMgcSap->ind_func == NULL)
	    return TRUE;

    chnl.mgNo = pMgInfo->id;
	chnl.portNo = pPhyPort->portNo;
	chnl.chlNo = mgc_chnl_info_get_chnl_no_of_phy(pChnlInfo, pPhyPort);
	chnl.connectNo = mgc_connect_get_connNo_of_chnl_info(pConnect, pChnlInfo);
	if(mgc_connect_get_step_info(pConnect) == NULL)
	    return FALSE;

	if(strlen(pConnect->mediaAttr.conId) != 0)
	{
		usrPort = atoi(pConnect->mediaAttr.conId); 
		MGC_DEBUG("sent %s to usrPort[%d]" , mgc_port_info_print_cmd(pMgcfOperStep->stepInfo.cmd) , usrPort);
	}

    switch(pMgcfOperStep->stepInfo.cmd)
    {
        case MGC_CMD_CRCX:
			 mgc_connect_set_status(pConnect,MGC_CONNECT_STATUS_CREATING);
        case MGC_CMD_MDCX:
        case MGC_CMD_DLCX:
		case MGC_CMD_NTFY:	
			 ret = pPhyPort->pMgcSap->ind_func(chnl, pMgcfOperStep->stepInfo.cmd , &usrPort, pPortInfo->id , &pConnect->mediaAttr);			 
	         break;	
        case MGC_CMD_RQNT:
        case MGC_CMD_AUEP:
        case MGC_CMD_RSIP:
			 ret = pPhyPort->pMgcSap->ind_func(chnl, pMgcfOperStep->stepInfo.cmd , &usrPort, pPortInfo->id , NULL);			
	         break;		
		default:
			  break;
    }	
    if(ret < 0)
	    return FALSE;

    if(strlen(pConnect->mediaAttr.conId) == 0)
    {
	    sprintf(pConnect->mediaAttr.conId , "%d" , usrPort);	
        MGC_DEBUG("conn[%d] get usrPort[%s]" , pConnect->id , pConnect->mediaAttr.conId);
    }
	
	return TRUE;
}



/***************************************************************************
 * mgc_port_info_oper_step_resp
 * ------------------------------------------------------------------------
 * General: step send resp Msg
 * Return Value: if failure return FALSE , else return TRUE
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pMgcfOperStep - the pointer of the operate step
 ***************************************************************************/
BOOL mgc_port_info_oper_step_resp(MGCF_OPER_STEP *pMgcfOperStep)
{
	CONNECT_INFO *pConnect = NULL;
	PORT_INFO *pPortInfo = NULL;
    MGCP_PARA mgcpPara;
	BOOL result = FALSE;
	if(pMgcfOperStep == NULL)
	    return FALSE;
	
    pPortInfo = mgc_port_info_get_step_port(pMgcfOperStep);
	if(pPortInfo == NULL)
	    return FALSE;	

	if(pMgcfOperStep->status != MGCP_OPER_STEP_RESPONSE)
        return FALSE;		

    pConnect = pMgcfOperStep->pConnect;
	if(pConnect == NULL)
	    return FALSE;


    switch(pMgcfOperStep->stepInfo.cmd)
    {
        case MGC_CMD_CRCX:
			 if(pMgcfOperStep->llCmd == 200)
			 {			     
				 mgc_connect_set_status(pConnect,MGC_CONNECT_STATUS_CREATED);
				 result = TRUE;
			 }
			 mgc_mgcp_create_connect_con_id(pConnect, &mgcpPara);
			 mgc_mgcp_create_connect_sdp(pConnect,&mgcpPara);
			 break;
		case MGC_CMD_MDCX:
			 result = TRUE;
			 break;
		case MGC_CMD_DLCX:
		case MGC_CMD_AUEP:
		case MGC_CMD_RQNT:
		case MGC_CMD_NTFY:
			 break;
		default:
			 break;
    }

    mgc_mgcp_response_msg(pConnect, &mgcpPara, pMgcfOperStep->llCmd);
    if(result == FALSE)
    {
        mgc_chnl_info_detach_connect(pConnect->pChnlInfo, pConnect);
		mgc_connect_init(pConnect, pConnect->id);
    }

    mgc_connect_dettach_step_info(pConnect);
	return TRUE;
}


void mgc_port_info_set_fsm_time(PORT_INFO *pPortInfo , WORD timer)
{
    if(pPortInfo == NULL)
	    return;

	pPortInfo->mgcfTimer = timer;
	return;
}

void mgc_port_info_set_oper_id(PORT_INFO *pPortInfo , MGC_MG_OPER_ID_TYPE operId)
{
    if(pPortInfo == NULL)
	    return;

    pPortInfo->mgcfOperId = operId;
    if(operId != MGC_OPER_ID_AUEP)
    {
	MGC_DEBUG("mgcPort[%d] set %s" , pPortInfo->id , mgc_port_info_print_opera_id(operId));
}
}




/***************************************************************************
 * mgc_port_info_init
 * ------------------------------------------------------------------------
 * General: PORT_INFO object init
 * Return Value: void
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pPortInfo -  the pointer of the PORT_INFO object
 *           id - the id of the PORT_INFO object
 ***************************************************************************/
void mgc_port_info_init(PORT_INFO *pPortInfo , int id)
{
    int i;
	MGCF_OPER_STEP *pMgcfOperStep = NULL;
	
    if(pPortInfo == NULL)
        return;

    pPortInfo->id = id;
	pPortInfo->assigned = FALSE;
	pPortInfo->mgcfOperId = MGC_OPER_ID_UNDEF;
	pPortInfo->usrPort = 0xFFFF;
	pPortInfo->mgcfTimer = MGC_MGCF_TIMER_20S;
	pPortInfo->pMgcOperCurrent = NULL;
    pPortInfo->cause = 0;
    for(i=0 ; i<MGC_MAX_OPER_STEPS_NUM ; i++)
    {    
        pMgcfOperStep = &pPortInfo->mgcfOperSteps[i];
		mgc_port_info_oper_step_init(pMgcfOperStep, pPortInfo,i);
    }
	
    return;	
}

void mgc_port_info_setup(void)
{
    int i;
	PORT_INFO *pPortInfo = NULL;
	
    for(i=0 ; i<MGC_MAX_NUM_OF_PORT ; i++)
    {
        pPortInfo = &mgcPort[i];
        mgc_port_info_init(pPortInfo , i);
    }	
    return;
}

/***************************************************************************
 * mgc_port_info_clear
 * ------------------------------------------------------------------------
 * General: clear  PORT_INFO object 
 * Return Value: void
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pPortInfo -  the pointer of the PORT_INFO object
 ***************************************************************************/
void mgc_port_info_clear(PORT_INFO *pPortInfo)
{
    int i;
	MGCF_OPER_STEP *pMgcfOperStep = NULL;	
	CONNECT_INFO *pConnect = NULL;
	MGCP_PARA mgcpPara;
    MG_INFO *pMgInfo;
	
    if(pPortInfo == NULL)
        return;

    for(i=0 ; i<MGC_MAX_OPER_STEPS_NUM ; i++)
    {
        pMgcfOperStep = &pPortInfo->mgcfOperSteps[i];

		pConnect = pMgcfOperStep->pConnect;
        pMgInfo = mgc_connect_get_own_mg_info(pConnect);
		if((pConnect == NULL)||(pMgInfo == NULL))
		    continue;			

        mgc_connect_dettach_step_info(pConnect);
        if(	(pMgcfOperStep != pPortInfo->pMgcOperCurrent)&&
			(pMgInfo->mgAttr.mgType != MGC_MG_TYPE_ANN))
		    continue;	

		if((mgc_connect_get_status(pConnect) == MGC_CONNECT_STATUS_CREATED)||
			(mgc_connect_get_status(pConnect) == MGC_CONNECT_STATUS_CREATE))	
		{
			if(mgc_connect_dlcx_para_create(pConnect , &mgcpPara) == TRUE)
				MGCP_req(mgc_mgcp_get_sap_index(), MGCP_CMD_DLCX , 0xFFFF , &mgcpPara);
		}		

		mgc_connect_set_status(pConnect,MGC_CONNECT_STATUS_IDLE);
		mgc_connect_codec_list_init(&pConnect->codecList);
		memset(&pConnect->mediaAttr , 0 , sizeof(MEDIA_ATTR));
		memset(&pConnect->operRec , 0 , sizeof(OPER_REC));
		memset(&pConnect->mgcpRec , 0 , sizeof(MGCP_REC_TAG));	

        if(pMgInfo->mgAttr.mgType == MGC_MG_TYPE_INTERNAL)	
        {
            mgc_chnl_info_detach_connect(pConnect->pChnlInfo, pConnect);
			mgc_connect_init(pConnect, pConnect->id);
        }
		MGC_DEBUG("mgcPort[%d]step[%d] clear conn[%d]" , pPortInfo->id , pMgcfOperStep->id , pConnect->id); 			
    }

    mgc_port_info_init(pPortInfo , pPortInfo->id);
    return;	
}




/***************************************************************************
 * mgc_port_info_get_unused_port
 * ------------------------------------------------------------------------
 * General: find a unused PORT_INFO object
 * Return Value: if failure return NULL , else return pointer of the object
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: void
 ***************************************************************************/
PORT_INFO *mgc_port_info_get_unused_port(void)
{
    int i;
	static int index = 0;
    PORT_INFO *pPortInfo = NULL;
    PORT_INFO *pPortInfoTmp = NULL;

    i = index ;
    do
    {
       i++;
	   if(i == MGC_MAX_NUM_OF_PORT)
	       i=0;	

        pPortInfo = &(mgcPort[i]);
		if(pPortInfo->assigned == TRUE)
            continue;			

		pPortInfoTmp = pPortInfo;
		index = i;
		break;
	   
    }while(i != index);

    return pPortInfoTmp;
}

void mgc_port_info_rm_conn_from_pre_port_info(CONNECT_INFO *pConnect)
{
    int i;
    PORT_INFO *pPrePortInfo =  NULL;    
    MGCF_OPER_STEP *pStep = NULL;
	
    if((pConnect == NULL)||(pConnect->pPrePortInfo == NULL))
	    return;	

    pPrePortInfo = pConnect->pPrePortInfo;

    for(i=0 ; i<MGC_MAX_OPER_STEPS_NUM ; i++)
    {
        pStep = &pPrePortInfo->mgcfOperSteps[i];
        
		if(pStep == pPrePortInfo->pMgcOperCurrent)
		    continue;

		if(pStep->pConnect != pConnect)
		    continue;

		mgc_port_info_oper_step_init(pStep, pStep->pPortInfo, pStep->id);
		pConnect->pPrePortInfo = NULL;
		MGC_DEBUG("conn[%d] remove from mgcPort[%d]step[%d]" , pConnect->id , pPrePortInfo->id , pStep->id);
    }

    return;
}

void mgc_port_info_conn_rec_port_info(PORT_INFO *pPortInfo)
{
    MGCF_OPER_STEP *pStep = NULL;
	CONNECT_INFO *pConn = NULL;
	int i;
    if(pPortInfo == NULL)
	    return;	

    for(i=0 ; i<MGC_MAX_OPER_STEPS_NUM ; i++)
    {
        pStep = &pPortInfo->mgcfOperSteps[i];

		if(pStep->status != MGCP_OPER_STEP_REQUEST)
		    continue;

		pConn = pStep->pConnect;
		if(pConn == NULL)
		{
		    MGC_ERROR("mgcPort[%d]step[%d] lost conn" , pPortInfo->id , pStep->id);
			continue;
		}

		mgc_port_info_rm_conn_from_pre_port_info(pConn);
		pConn->pPrePortInfo = pPortInfo;		
    }
	
    return;	
}

/***************************************************************************
 * mgc_port_info_set_step_to_start
 * ------------------------------------------------------------------------
 * General: make the PORT_INFO object to process it's steps
 * Return Value: void
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pPortInfo - the pointer of the PORT_INFO object
 ***************************************************************************/
void mgc_port_info_set_step_to_start(PORT_INFO *pPortInfo)
{
    if(pPortInfo == NULL)
       return;		

    if(pPortInfo->mgcfOperSteps[0].pConnect == NULL)
       return;		

#ifdef MGC_REC_PORT
    mgc_port_info_conn_rec_port_info(pPortInfo);
#endif

#ifdef MGC_PORT_LIST_EN
    mgc_port_list_add_to_active_list(pPortInfo);
#endif

	pPortInfo->pMgcOperCurrent = &(pPortInfo->mgcfOperSteps[0]);
	pPortInfo->assigned = TRUE;
    return;	
}

/***************************************************************************
 * mgc_port_info_set_step_to_next
 * ------------------------------------------------------------------------
 * General: make PORT_INFO object move to the next step
 * Return Value: if no more step return TRUE, else return FALSE
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pPortInfo - the pointer of the PORT_INFO object
 ***************************************************************************/
BOOL mgc_port_info_set_step_to_next(PORT_INFO *pPortInfo)
{
    int i;
    MGCF_OPER_STEP *pMgcOperCurrent = NULL;
	MGCF_OPER_STEP *pMgcOperNext = NULL;
    if(pPortInfo == NULL)
	    return FALSE;	

    pMgcOperCurrent = pPortInfo->pMgcOperCurrent;
	if(pMgcOperCurrent == NULL)
	    return FALSE;

    /*the duration between two steps*/
    if(pMgcOperCurrent->stepInfo.delay> MGC_OPERA_NO_DELAY)
    {
        return FALSE;
    }

    for(i=0 ; i<MGC_MAX_OPER_STEPS_NUM ; i++)
    {
        if(pPortInfo->mgcfOperSteps[i].status == MGCP_OPER_STEP_REQUEST)
        {
		    pMgcOperNext = &pPortInfo->mgcfOperSteps[i];
			break;
        }
    }

    if(pMgcOperNext == NULL)
	    return TRUE;

    MGC_DEBUG("mgcPort[%d] current step[%d] =>> step[%d]" , pPortInfo->id , pMgcOperCurrent->id , pMgcOperNext->id);
	pPortInfo->pMgcOperCurrent = pMgcOperNext;
	return FALSE;
}




/***************************************************************************
 * mgc_port_info_cnf
 * ------------------------------------------------------------------------
 * General: cnf function to handle response to the PORT_INFO object
 * Return Value: if failure return -1, else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pPortInfo - the pointer of the PORT_INFO object
 *           cmd - MGCP cmd
 *           hdlPort - low-layer operate id
 *           retCode - response code
 *           pPara - response msg
 ***************************************************************************/
int mgc_port_info_cnf(PORT_INFO *pPortInfo , BYTE cmd, WORD hdlPort, WORD retCode, MGCP_PARA *pPara)
{
    MGCF_OPER_STEP *pCurrentStep = NULL;
	MGC_SAP  *pMgcSap = NULL;

    if((pPortInfo == NULL)||(pPara == NULL))
	    return -1;	

    pCurrentStep = pPortInfo->pMgcOperCurrent;
	if(pCurrentStep == NULL)
	{
	    MGC_ERROR("lost opera record");
        mgc_port_info_clear(pPortInfo);
	    return -1;		  
	}

	if(pCurrentStep->hdlPort != hdlPort)
	{
	    MGC_ERROR("lost mismatch hdlport");
		mgc_port_info_clear(pPortInfo);
		return -1;		  
	}
	
    if(pCurrentStep->stepInfo.cmd!= cmd)
    {
        MGC_ERROR("mismatch cmd");	
	    mgc_port_info_clear(pPortInfo);
		return -1;        
    }

    if(pCurrentStep->pConnect == NULL)
    {
        MGC_ERROR("lost connection record");
        mgc_port_info_clear(pPortInfo);
		return -1;        
    }
    
	pMgcSap = mgc_connect_get_conn_report_sap(pCurrentStep->pConnect);
    pCurrentStep->llCmd = retCode;
    if(mgc_port_info_oper_step_cnf(pCurrentStep , pPara) ==	FALSE)
    {
        if(pPortInfo->mgcfOperId != MGC_OPER_ID_AUEP)
        {
			MGC_ERROR("req cnf failure!");		        
        }
        mgc_port_info_oper_failure_report(pPortInfo , pMgcSap);			
        mgc_connect_dettach_step_info(pCurrentStep->pConnect);
	    mgc_port_info_clear(pPortInfo);
	    return -1;		
    }

	if(--pCurrentStep->stepInfo.delay <= 0 )
	{
        mgc_connect_dettach_step_info(pCurrentStep->pConnect);
		if(mgc_port_info_set_step_to_next(pPortInfo) == TRUE)
		{
			mgc_port_info_oper_success_report(pPortInfo , pMgcSap); 		
	    mgc_port_info_init(pPortInfo, pPortInfo->id);
			if(pPortInfo->mgcfOperId != MGC_OPER_ID_AUEP)
			{
				MGC_DEBUG("mgcPort[%d] work over" , pPortInfo->id); 	
			}	
		}
	}	
	
    return 0;
}


char *mgc_port_info_print_step_status(MGCF_OPER_STEP *pOperaStep)
{
    if(pOperaStep == NULL)
	    return "MGCP_OPER_STEP_UNDEF";

	switch(pOperaStep->status)
	{
	    case MGCP_OPER_STEP_REQUEST:
			return "MGCP_OPER_STEP_REQUEST";
        case MGCP_OPER_STEP_REQUEST_SENT:
			return "MGCP_OPER_STEP_REQUEST_SENT";
		case MGCP_OPER_STEP_RESPONSE_GET:
			return "MGCP_OPER_STEP_RESPONSE_GET";
		default:
			return "MGCP_OPER_STEP_UNDEF";	
	}
	return "MGCP_OPER_STEP_UNDEF";	
}

/***************************************************************************
 * mgc_port_info_fsm
 * ------------------------------------------------------------------------
 * General: PORT_INFO object fsm function
 * Return Value: void
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pPortInfo - the pointer of the PORT_INFO object
 ***************************************************************************/
void mgc_port_info_fsm(PORT_INFO *pPortInfo)
{
    int i;
    MGCF_OPER_STEP *pCurrentStep = NULL;
	MGCF_OPER_STEP *pStep = NULL;		
	MGCP_OPER_STEP_STATUS stepStatus;
	MGC_SAP *pSap = NULL;
	BOOL result = TRUE;
    if(pPortInfo == NULL)
        return;		

    if(pPortInfo->pMgcOperCurrent == NULL)
        return;

    pCurrentStep = pPortInfo->pMgcOperCurrent;
	pSap = mgc_connect_get_conn_report_sap(pCurrentStep->pConnect);
    //MGC_DEBUG("mgcPort[%d]step[%d] state %s" , pPortInfo->id , pCurrentStep->id , mgc_port_info_print_step_status(pCurrentStep));
    stepStatus = pCurrentStep->status;
    switch(stepStatus)
    {
        case MGCP_OPER_STEP_REQUEST:
			 if(mgc_port_info_oper_step_request(pCurrentStep) == TRUE)
			 {
			     result = TRUE;
			 }
			 else
			 {
			     result = FALSE;
			 }
			break;
		case MGCP_OPER_STEP_REQUEST_SENT:			
			pPortInfo->mgcfTimer--;			
			if(pPortInfo->mgcfTimer == 0)
			{
			    result = FALSE;
				MGC_WARN("mgcPort[%d] operate timeout" , pPortInfo->id );
			}
			break;
		case MGCP_OPER_STEP_RESPONSE_GET:		
			//MGC_DEBUG("mgcPort[%d]step[%d] delay %d" , pPortInfo->id, pCurrentStep->id , pCurrentStep->stepInfo.delay);
			if(--pCurrentStep->stepInfo.delay <= 0 )
			{		
				mgc_connect_dettach_step_info(pCurrentStep->pConnect);			
			    if(mgc_port_info_set_step_to_next(pPortInfo) == TRUE)
			    {
			        mgc_port_info_oper_success_report(pPortInfo , pSap); 	
					if(pPortInfo->mgcfOperId != MGC_OPER_ID_AUEP)
					{
                         MGC_DEBUG("mgcPort[%d] work over" , pPortInfo->id);						
					} 					
					mgc_port_info_init(pPortInfo, pPortInfo->id);
			    }
			}			
			break;
/*************************************************************************
*    following status is used for MG control,  up status is used for MGC control
****************************************************************************/			
		case MGCP_OPER_STEP_IND:
			// MGC_DEBUG("mgcPort[%d]step[%d] enter IND" , pPortInfo->id , pCurrentStep->id);
			 result = mgc_port_info_oper_step_ind(pCurrentStep);
			 break;
		case MGCP_OPER_STEP_IND_SENT:
            // MGC_DEBUG("mgcPort[%d]step[%d] delay %d" , pPortInfo->id, pCurrentStep->id , pCurrentStep->stepInfo.delay);			
			 pPortInfo->mgcfTimer--;						 
			 if(pPortInfo->mgcfTimer == 0)
			 {
			     pCurrentStep->status = MGCP_OPER_STEP_RESPONSE;
				 MGC_WARN("mgcPort[%d]Step[%d] operate timeout" , pPortInfo->id , pCurrentStep->id);
			 }			
			break;
		case MGCP_OPER_STEP_RESPONSE:
			 result = mgc_port_info_oper_step_resp(pCurrentStep);
			 if(result == TRUE)
			     mgc_port_info_init(pPortInfo, pPortInfo->id);		     	
			 break;
		default:
			 MGC_WARN("mgcPort[%d]step[%d] unhandle state %d" , pPortInfo->id , pCurrentStep->id , pCurrentStep->status);
			 break;
    }

    switch(stepStatus)
    {
        case MGCP_OPER_STEP_REQUEST:
	    case MGCP_OPER_STEP_REQUEST_SENT:	
	    case MGCP_OPER_STEP_RESPONSE_GET:
             if(result == FALSE)
             {
                MGC_DEBUG("mgcPort[%d] step[%d] state %s failure",  pPortInfo->id , pCurrentStep->id , mgc_port_info_print_step_status(pCurrentStep));
                mgc_port_info_oper_failure_report(pPortInfo , mgc_connect_get_conn_report_sap(pCurrentStep->pConnect));
                mgc_connect_dettach_step_info(pCurrentStep->pConnect);				
		        mgc_port_info_clear(pPortInfo);
             }			
			 break;
		case MGCP_OPER_STEP_IND:	 
		case MGCP_OPER_STEP_IND_SENT:	 
	    case MGCP_OPER_STEP_RESPONSE:	
			 if(result == FALSE)
			 {
			     for(i=0 ; i<MGC_MAX_OPER_STEPS_NUM ; i++)
			     {
			         pStep = & pPortInfo->mgcfOperSteps[i];

					 if(pStep->pConnect == NULL)
					     continue;

                 //    mgc_port_info_oper_step_resp(pStep);
					 mgc_chnl_info_detach_connect(pStep->pConnect->pChnlInfo, pStep->pConnect);
					 mgc_connect_init(pStep->pConnect, pStep->pConnect->id);
			     }
			     mgc_port_info_init(pPortInfo, pPortInfo->id);
			 }
			 break;
		default :
			 break;
	}
    return;	
}

BOOL mgc_port_info_insert_dlcx_req(PORT_INFO *pPortInfo , CONNECT_INFO *pConnect)
{
    int i;
	PORT_INFO portInfoTmp;
    MGCF_OPER_STEP *pStep = NULL;
    CONNECT_INFO *pConnTmp = NULL;

    if((pPortInfo == NULL)||(pConnect == NULL))
	    return FALSE;

    mgc_port_info_init(&portInfoTmp, 0xFFFF);

    if(pPortInfo->pMgcOperCurrent == NULL)
	    return FALSE;	

    if(pPortInfo->pMgcOperCurrent->pConnect != pConnect)
	    return FALSE;	

    pConnTmp = mgc_connect_dup_attr(pConnect);
    if(pConnTmp == NULL)
	    return FALSE;	
	
    mgc_connect_add_dlcx(pConnTmp, &portInfoTmp);
    pPortInfo->pMgcOperCurrent->status = MGCP_OPER_STEP_REQUEST;
	mgc_connect_set_status(pConnect,MGC_CONNECT_STATUS_IDLE);
    for(i= 0; i<MGC_MAX_OPER_STEPS_NUM ; i++)
    {
        pStep= &pPortInfo->mgcfOperSteps[i];

        if(pStep->status != MGCP_OPER_STEP_REQUEST)
		    continue;	
		
        if(mgc_port_info_add_opera_to_port(&portInfoTmp, pStep->pConnect, &pStep->stepInfo) == TRUE)
		    continue;

        return FALSE;
    }

    portInfoTmp.usrPort = pPortInfo->usrPort;
	portInfoTmp.mgcfTimer = pPortInfo->mgcfTimer;
    mgc_port_info_set_oper_id(&portInfoTmp , pPortInfo->mgcfOperId);

    mgc_port_info_init(pPortInfo, pPortInfo->id);

	mgc_connect_add_nop(pConnect, pPortInfo);
    for(i= 0; i<MGC_MAX_OPER_STEPS_NUM ; i++)
    {
        pStep= &(portInfoTmp.mgcfOperSteps[i]);

        if(pStep->status != MGCP_OPER_STEP_REQUEST)
		    continue;	
		
        if(mgc_port_info_add_opera_to_port(pPortInfo, pStep->pConnect, &pStep->stepInfo) == TRUE)
		    continue;

        mgc_port_info_init(pPortInfo,  pPortInfo->id);
        return FALSE;    
    }

    mgc_port_info_set_step_to_start(pPortInfo);
    mgc_port_info_set_oper_id(pPortInfo , portInfoTmp.mgcfOperId);
    pPortInfo->usrPort = portInfoTmp.usrPort;
    return TRUE;
}


BOOL mgc_port_info_mv_step_into_new_port(PORT_INFO *pPortInfo , MGCF_OPER_STEP *pOperStep)
{
    int i;
    PORT_INFO *pOldPortInfo = NULL;
	MGCF_OPER_STEP *pStep = NULL;
    if((pPortInfo == NULL)||(pOperStep == NULL))
        return FALSE;

    pOldPortInfo = mgc_port_info_get_step_port(pOperStep);
	if(pOldPortInfo == NULL)
	    return FALSE;	
	
    MGC_DEBUG("enter %s" , __FUNCTION__);

	if(pOldPortInfo->pMgcOperCurrent != pOperStep)
	{
	   MGC_WARN("mgcPort[%d] illegal step status" , pOldPortInfo->id);
	   return FALSE;
	}
	
    if(pOperStep->stepInfo.delay != MGC_OPERA_NO_DELAY)
        pOperStep->stepInfo.delay = MGC_OPERA_NO_DELAY;
	
    for(i= pOperStep->id+1 ; i<MGC_MAX_OPER_STEPS_NUM ; i++)
    {
        pStep = &pOldPortInfo->mgcfOperSteps[i];

        if(pStep->status != MGCP_OPER_STEP_REQUEST)
		    continue;	

        if(pStep->stepInfo.delay != MGC_OPERA_NO_DELAY)
		    pStep->stepInfo.delay = MGC_OPERA_NO_DELAY;

        if(mgc_port_info_add_opera_to_port(pPortInfo, pStep->pConnect, &pStep->stepInfo) != TRUE)
		    break;

		mgc_port_info_oper_step_init(pStep, pStep->pPortInfo,pStep->id);		
    }

	return TRUE;
}


BYTE *mgc_port_info_get_res_addr(void)
{
    return (BYTE *)mgcPort;
}

