/*
*********************************************************************************
*                                                                               *
* NOTICE:                                                                 *
*                                                                               *
*********************************************************************************
*/
 
    
/*********************************************************************************
 *                              <mgc_interanl.c>                                                              
 *     This file should is internal interface to do misc operation. So far, only AUEP is used 
 *    Author                         Date
 *    ------                        ------
 *    Sam Yao                     Aug 2008                                                                                              
 *********************************************************************************/



/*-----------------------------------------------------------------------*/
/*                        INCLUDE HEADER FILES                           */
/*-----------------------------------------------------------------------*/
#include "./include/mgc_internal.h"
#include "./include/mgc_debug.h"
#include "./include/mgc_mg_info.h"

static MGC_INTERNAL_SAP mgcItlSap;
static ITL_OPERA_STRUCT opera[ITL_OPERA_NUM];

extern int mgc_update_phy_port_status(CHNL chnl, BOOL status);
extern int mgc_auep_chnl(WORD usrPort, CHNL chnl);
void mgc_internal_opera_init(ITL_OPERA_STRUCT *pOpera , int usrPort);

BOOL mgc_internal_get_local_ip(char *ipAddr)
{
    struct hostent  *host;
	char localName[50];

    if(ipAddr == NULL)
        return FALSE;

    if (gethostname(localName , 50) == -1)
    {
        return FALSE;
    }	

    if ((host = gethostbyname(localName)) == NULL)
    {
        return FALSE;
    }	

    sprintf(ipAddr, "%d.%d.%d.%d", 
            (BYTE)host->h_addr_list[0][0],
			(BYTE)host->h_addr_list[0][1],
			(BYTE)host->h_addr_list[0][2],
			(BYTE)host->h_addr_list[0][3]);	  

    return TRUE;	
}



char *mgc_internal_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_UNDEF:
			return "MGC_OPER_ID_UNDEF";	
		case MGC_OPER_ID_IND:
			return "MGC_OPER_ID_IND";
		case MGC_OPER_ID_TANDEM_CREATE:
			return "MGC_OPER_ID_TANDEM_CREATE";
		case MGC_OPER_ID_TANDEM_CLEAR:
			return "MGC_OPER_ID_TANDEM_CLEAR";
		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";			
        default:
			break;
    }

	return "MGC_OPERA_ID_UNSUPPORTED";
}



int mgc_internal_get_sap_index(void)
{
    return mgcItlSap.mgcSapIndex;
}

ITL_OPERA_STRUCT *mgc_internal_find_owne_opera(int usrPort)
{
    ITL_OPERA_STRUCT *pOpera = NULL;
    int i;

    for(i=0; i<ITL_OPERA_NUM ; i++)
    {
        pOpera = &opera[i];

		if(pOpera->userPort != usrPort)
		    continue;

		return pOpera;
    }
    return NULL;
}



int mgc_internal_ind_callback(CHNL chnl, MGC_CMD_TYPE cmd, WORD *usrPort, WORD mgcPort, MEDIA_ATTR *mediaAttr)
{

    return 0;
}


int mgc_internal_cnf_callback(WORD usrPort, WORD mgcPort, MGC_MG_OPER_ID_TYPE operId, MGC_OPER_RESULT success, WORD cause)
{
    ITL_OPERA_STRUCT *pOpera = NULL;
	MG_INFO *pMgInfo = NULL;
    BOOL status = FALSE;
    pOpera = mgc_internal_find_owne_opera(usrPort);
    if(pOpera == NULL)	
    {
        MGC_WARN("internal usrport[%d] lost owner" , usrPort);
        return -1;
    }
    if(pOpera->status != ITL_OPERA_STATE_REQUEST)
    {
	   mgc_internal_opera_init(pOpera, pOpera->userPort);
	   return -1;
    }
   // MGC_DEBUG("opera[%d] operate %s" , pOpera->userPort , success?"success" : "failure");
    switch(operId)
    {
       case MGC_OPER_ID_AUEP:	   	  
	   	    pMgInfo = mgc_mg_info_get_index_mg(pOpera->chnl.mgNo);
	   	    if(success == MGC_OPER_SUCCESS)
	   	    {
	   	        status = TRUE;
	   	    }
			mgc_mg_info_update_mg_status(pMgInfo, status);	
			mgc_delete_port(mgc_internal_get_sap_index(), pOpera->chnl.mgNo, pOpera->chnl.portNo);
	   	    break;
	   default:
	   	    MGC_WARN("internal opera do not support %s" , mgc_internal_print_opera_id(operId));
	   	    break;
    }

	mgc_internal_opera_init(pOpera, pOpera->userPort);
    return 0;
}

ITL_OPERA_STRUCT *mgc_internal_get_idle_opera(void)
{
    ITL_OPERA_STRUCT *pOpera = NULL;
    int i;

    for(i=0 ; i<ITL_OPERA_NUM ; i++)
    {
        pOpera = &opera[i];
		
        if(pOpera->status != ITL_OPERA_STATE_IDLE)
		   continue;

		return pOpera;
    }
	
	return NULL;
}

void mgc_internal_opera_init(ITL_OPERA_STRUCT *pOpera , int usrPort)
{
    if(pOpera == NULL)
        return;

    pOpera->userPort = usrPort;
    pOpera->status = ITL_OPERA_STATE_IDLE;
    memset(&pOpera->chnl , 0 ,sizeof(CHNL));
    return;
}

void mgc_internal_opera_clear(void)
{
    int i;	
    ITL_OPERA_STRUCT *pOpera = NULL;
	
    for(i=0 ; i<ITL_OPERA_NUM ; i++)
    {
        pOpera = &opera[i];

		if(pOpera->status == ITL_OPERA_STATE_IDLE)
		    continue;

	    mgc_delete_port(mgc_internal_get_sap_index(), pOpera->chnl.mgNo, pOpera->chnl.portNo);
		mgc_internal_opera_init(pOpera, pOpera->userPort);     		
    }

    return;	
}

/***************************************************************************
 * mgc_internal_opera_auep_request
 * ------------------------------------------------------------------------
 * General: inferace to be used for auep detection
 * Return Value:  if failure return FALSE,  else return TRUE
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  pMgInfo -  the pointer of the MG_INFO object which need to send auep
 ***************************************************************************/
BOOL mgc_internal_opera_auep_request(MG_INFO *pMgInfo)
{
    ITL_OPERA_STRUCT *pOpera = NULL;
	int i,ret;
    PHY_PORT_INFO *pPhyPort = NULL;
	
    if(pMgInfo == NULL)
        return FALSE;		

    if((pMgInfo->created == FALSE)||(pMgInfo->mgAttr.ctrlType != MGC_MG_CTRL_TYPE_MGCP))
	    return FALSE;	

    if(pMgInfo->mgAttr.mgType ==MGC_MG_TYPE_INTERNAL)
    {
        pMgInfo->enable = TRUE;
		return TRUE;
    }
	
    for(i=0 ; i< MGC_MAX_PHY_PORT_PER_MG ; i++)
    {
        pPhyPort = pMgInfo->pPhyPort[i];
        pOpera = mgc_internal_get_idle_opera();
		
        if(pOpera == NULL)
        {        
            MGC_ERROR("internal opera is no more resource!");
            mgc_internal_opera_clear();			
		    continue;
        }
		
		if(pPhyPort == NULL)
		    continue;

        if(pPhyPort->pMgcSap == NULL)
		    continue;
		
        if(pPhyPort->pMgcSap->usrType != MGC_USER_TYPE_MGC)
		    continue;	

        ret = mgc_add_port(mgc_internal_get_sap_index(), pMgInfo->id, ITL_OPERA_PORT_NO , MGC_PHY_PORT_TYPE_E1);
	if(ret < 0)
	{
             mgc_delete_port(mgc_internal_get_sap_index(),pMgInfo->id,ITL_OPERA_PORT_NO);
	     mgc_internal_opera_init(pOpera, pOpera->userPort);
	     return FALSE;
	}
		
	pOpera->chnl.mgNo = pMgInfo->id;
	pOpera->chnl.portNo = ITL_OPERA_PORT_NO;
	pOpera->chnl.chlNo = 0;
	pOpera->chnl.connectNo = 0;
	pOpera->status = ITL_OPERA_STATE_REQUEST;
		
    if(MGC_RESULT_OK !=  mgc_auep_chnl(pOpera->userPort , pOpera->chnl))
        mgc_internal_opera_init(pOpera,  pOpera->userPort);
	
	break;
    }
	
	return TRUE;
}


/***************************************************************************
 * mgc_internal_sap_bind
 * ------------------------------------------------------------------------
 * General: inferace to be called in mgc_init
 * Return Value:  if failure return FALSE,  else return TRUE
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  void
 ***************************************************************************/
BOOL mgc_internal_sap_bind(void)
{
    MGC_INTERNAL_SAP *pSap = NULL;
	ITL_OPERA_STRUCT *pOpera = NULL;
    MGC_SAP *pMgcSap = NULL;
    int ret , i;

	pSap = &mgcItlSap;
	
    if(pSap == NULL)
        return FALSE;

    pSap->mgcSapIndex = -1;
    pMgcSap = &(pSap->mgcSap);
	sprintf(pMgcSap->usrName , "%s" , "MGC_ITL_SAP");
    pMgcSap->cnf_func = mgc_internal_cnf_callback;
	pMgcSap->ind_func = mgc_internal_ind_callback;
	pMgcSap->usrType = MGC_USER_TYPE_MGC;

	ret = mgc_bind(pMgcSap);
    if(ret < 0)
	    return FALSE;

    pSap->mgcSapIndex = ret;

    for(i=0 ; i<ITL_OPERA_NUM ; i++)
    {
        pOpera = &opera[i];
		mgc_internal_opera_init(pOpera, i);
    }
	return TRUE;
}

/***************************************************************************
 * mgc_internal_mg_create
 * ------------------------------------------------------------------------
 * General: inferace to be called in mgc_init to create internal mg
 * Return Value:  if failure return FALSE,  else return TRUE
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  void
 ***************************************************************************/
BOOL mgc_internal_mg_create(void)
{
	MGC_INTERNAL_SAP *pSap = NULL;
	MG_ATTR mgAttr;
	char localIp[33];
	int ret;

    pSap = &mgcItlSap;
    if(pSap->mgcSapIndex < 0)
	    return FALSE;	

    memset(&mgAttr , 0 , sizeof(MG_ATTR));
	mgAttr.mgType = MGC_MG_TYPE_INTERNAL;
	mgAttr.ctrlType = MGC_MG_CTRL_TYPE_MGCP;
	mgAttr.epDes = MGCP_EP_NAME_UNSTRUCTURED;
	mgAttr.ptime = 20;
    sprintf(mgAttr.domain , "InternalMG");
	mgc_internal_get_local_ip(localIp);
	mgAttr.ip = inet_addr(localIp);

    ret = mgc_create_MG(pSap->mgcSapIndex , &mgAttr);
    if(ret < 0)
        return FALSE;		

    pSap->mgNoITL = ret;
    ret = mgc_add_port(pSap->mgcSapIndex, pSap->mgNoITL , ITL_MG_INFO_PORT_NO , MGC_PHY_VIRTUAL_TYPE_INTERNAL);
	if(ret < 0)
	    return FALSE;

    return TRUE;	
}


