/*
*********************************************************************************
*                                                                               *
* NOTICE:                                                                 *
*                                                                               *
*********************************************************************************
*  
*                                      
*    
*       mgcSap <---------mgcPhyPorts --------> mgcMgInfo
*
*
*/
 

 
    
/*********************************************************************************
 *                              <mgc_phy_port.c>                                                              
 *     This file should provide MG_INFO object APIs
 *
 *    Author                         Date
 *    ------                        ------
 *    Sam Yao                     Aug 2008                                                                                              
 *********************************************************************************/


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

#include "./include/mgc_phy_port.h"
#include "./include/mgc_debug.h"
#include "./include/mgc_chnl_info.h"
#include "./include/mgc_ctl.h"
#include "./include/mgc_mg_info.h"
#include "./include/mgc_internal.h"

static PHY_PORT_INFO	mgcPhyPort[MGC_MAX_NUM_OF_PHY_PORT];

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

/***************************************************************************
 * mgc_phy_port_init
 * ------------------------------------------------------------------------
 * General: init PHY_PORT_INFO structure objcet
 * Return Value:  void.
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: 	pPhyPort- the pointer of the PHY_PORT_INFO object which should be init
 *	       id - the id of the MG_INFO object
 ***************************************************************************/
void mgc_phy_port_init(PHY_PORT_INFO *pPhyPort , int id)
{
    int i;
    if((pPhyPort == NULL)||(id < 0))
        return;		
	
	pPhyPort->id = id;
    pPhyPort->portNo = -1;
	pPhyPort->monFlag = 0;
	pPhyPort->status = MGC_PHY_PORT_STATUS_UNDEF;
	pPhyPort->portType = MGC_PHY_PORT_TYPE_UNDEF;
	pPhyPort->pMgInfo = NULL;	
	pPhyPort->pMgcSap= NULL;
	pPhyPort->chnlNum = 0;

    for(i=0 ; i<MGC_MAX_CHNL_NUM_PER_PHY ; i++)
    {
        pPhyPort->pChnlInfo[i] = NULL;
    }
    return;	
}

void mgc_phy_port_setup(void)
{
    int i;
	PHY_PORT_INFO *pPhyPort;
	
    for(i=0 ; i<MGC_MAX_NUM_OF_PHY_PORT ; i++)
    {
        pPhyPort = &mgcPhyPort[i];
		mgc_phy_port_init(pPhyPort, i);
    }	
    return;
}

/***************************************************************************
 * mgc_phy_port_clear
 * ------------------------------------------------------------------------
 * General: clear PHY_PORT_INFO structure objcet
 * Return Value:  void.
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: 	pPhyPort- the pointer of the PHY_PORT_INFO object which should be init
 ***************************************************************************/
void mgc_phy_port_clear(PHY_PORT_INFO *pPhyPort)
{
    int i;
    CHNL_INFO *pChnlInfo = NULL;
	
    if(pPhyPort == NULL)
        return;

    for(i=0 ; i<MGC_MAX_CHNL_NUM_PER_PHY ; i++)
    {
        pChnlInfo = pPhyPort->pChnlInfo[i];
		
		if(pChnlInfo == NULL)
			continue;
		
	    mgc_chnl_info_clear(pChnlInfo);	
		if(pPhyPort->pMgInfo->mgAttr.mgType != MGC_MG_TYPE_TANDEM)
		    mgc_ctl_chnl_remove_one();
    }

    mgc_phy_port_init(pPhyPort , pPhyPort->id);	
}



/***************************************************************************
 * mgc_phy_port_get_unused_phy
 * ------------------------------------------------------------------------
 * General: get unused PHY_PORT_INFO structure objcet
 * Return Value:  if failure return NULL , else return the pointer of the PHY_PORT_INFO object.
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: void
 ***************************************************************************/
PHY_PORT_INFO *mgc_phy_port_get_unused_phy(void)
{
    int i;
    PHY_PORT_INFO *pPhyPort = NULL;

    for(i=0 ; i<MGC_MAX_NUM_OF_PHY_PORT ; i++)
    {
        pPhyPort = &mgcPhyPort[i];
		if((pPhyPort->chnlNum == 0)&&(pPhyPort->pMgInfo == NULL))
		    return pPhyPort;
    }	
    return NULL;
}

/***************************************************************************
 * mgc_phy_port_set_chnl_num
 * ------------------------------------------------------------------------
 * General: set the chnl number of the phyport according to the portType
 * Return Value:  void
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pPhyPort - the pointer of the PHY_PORT_INFO object
 *           portType - the type of the port 
 ***************************************************************************/
void mgc_phy_port_set_chnl_num(PHY_PORT_INFO *pPhyPort , MGC_PHY_PORT_TYPE portType)
{
    if(pPhyPort == NULL)
        return;

    switch(portType)	
    {
        case MGC_PHY_PORT_TYPE_UNDEF:
			pPhyPort->chnlNum = 0;
			break;
        case MGC_PHY_PORT_TYPE_ANALOG:
			pPhyPort->chnlNum = MGC_CHNL_NUM_AALN_PER_PORT;
			break;
        case MGC_PHY_VIRTUAL_TYPE_ANN:
			pPhyPort->chnlNum = MGC_CHNL_NUM_ANN_PER_TYPE;
			break;
        case MGC_PHY_VIRTUAL_TYPE_TANDEM:
			pPhyPort->chnlNum = MGC_CHNL_NUM_TANDEM_PER_TYPE;
			break;
        case MGC_PHY_VIRTUAL_TYPE_INTERNAL:
			pPhyPort->chnlNum = MGC_CHNL_NUM_INTERNAL_PER_PORT;
			break;
		case MGC_PHY_VIRTUAL_TYPE_SURVEILLANCE:
			pPhyPort->chnlNum = MGC_CHNL_NUM_SERVEILLANCE_PER_TYPE;
		default :
			pPhyPort->chnlNum = MGC_CHNL_NUM_DS_PER_PORT;
			break;
    }

    return;	
}


/***************************************************************************
 * mgc_phy_port_attach_chnl
 * ------------------------------------------------------------------------
 * General: attach chnls to the phyPort 
 * Return Value:  if failure return FALSE , else return TRUE
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pPhyPort - the pointer of the PHY_PORT_INFO object
 ***************************************************************************/
BOOL mgc_phy_port_attach_chnl(PHY_PORT_INFO *pPhyPort)
{
    int i;
    CHNL_INFO *pChnlInfo = NULL;

    if(pPhyPort == NULL)
        return FALSE;

    for(i=0 ; i<pPhyPort->chnlNum ; i++)	
    {
        pChnlInfo = mgc_chnl_info_get_unused_chnl();
		if(pChnlInfo == NULL)
		    return FALSE;

        if((mgc_ctl_is_chnl_full() == TRUE)&&(pPhyPort->pMgInfo->mgAttr.mgType != MGC_MG_TYPE_TANDEM))
		    return FALSE;
		
		pPhyPort->pChnlInfo[i] = pChnlInfo;
		
		if(mgc_chnl_info_attach_to_phy_port(pChnlInfo , pPhyPort) == FALSE)
		    return FALSE;	

		mgc_chnl_info_status_set(pChnlInfo , MGC_CHNL_INFO_STATUS_IDLE);
		
		if(pPhyPort->pMgInfo->mgAttr.mgType != MGC_MG_TYPE_TANDEM)		
		    mgc_ctl_chnl_add_one();
    }

    if(pPhyPort->chnlNum == 0)
    {
        MGC_ERROR("mg[%d]port[%d] not support type!" , pPhyPort->pMgInfo->id , pPhyPort->portNo);
        return FALSE;
    }

    if(pPhyPort->portNo != ITL_OPERA_PORT_NO)
    {
        MGC_DEBUG("mg[%d]port[%d] ==> phyPort[%d] {chnlInfo[%d] ~ chnlInfo[%d]}" ,
 		        pPhyPort->pMgInfo->id ,pPhyPort->portNo,pPhyPort->id , pPhyPort->pChnlInfo[0]->id, pPhyPort->pChnlInfo[pPhyPort->chnlNum-1]->id);    
    }
	
    return TRUE;	
}

/***************************************************************************
 * mgc_phy_port_find_port_of_mg
 * ------------------------------------------------------------------------
 * General: find the phyPort in the MG accroding to the PortNo
 * Return Value:  if failure return NULL , else return the pointer of the PHY_PORT_INFO object
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pMgInfo -  the pointer of the MG
 *           portNo - the portNo of the phyPort
 ***************************************************************************/
PHY_PORT_INFO *mgc_phy_port_find_port_of_mg(MG_INFO *pMgInfo , int portNo)
{
    int i;
    PHY_PORT_INFO *pPhyPort = NULL;
	
    if(pMgInfo == NULL)
        return NULL;

    for(i=0 ; i<MGC_MAX_PHY_PORT_PER_MG ; i++)
    {
        pPhyPort = pMgInfo->pPhyPort[i];

		if(pPhyPort == NULL)
		    continue;

		if(pPhyPort->portNo != portNo)
		    continue;

		return pPhyPort;
    }

	return NULL;
}


/***************************************************************************
 * mgc_phy_port_find_port_of_mg_by_index
 * ------------------------------------------------------------------------
 * General: find the phyPort in the MG accroding to the index
 * Return Value:  if failure return NULL , else return the pointer of the PHY_PORT_INFO object
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pMgInfo -  the pointer of the MG
 *           index - index
 ***************************************************************************/
PHY_PORT_INFO *mgc_phy_port_find_port_of_mg_by_index(MG_INFO *pMgInfo , int index)
{
    PHY_PORT_INFO *pPhyPort = NULL;
	
    if(pMgInfo == NULL)
        return NULL;

    pPhyPort = pMgInfo->pPhyPort[index];
	if(pPhyPort == NULL)
	    return NULL;	

    return pPhyPort;
}

/***************************************************************************
 * mgc_phy_port_update_status
 * ------------------------------------------------------------------------
 * General: update phyPort status
 * Return Value:  void
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pPhyPort - the pointer of the PHY_PORT_INFO object
 *           status - the status of the phyPort
 ***************************************************************************/
void mgc_phy_port_update_status(PHY_PORT_INFO *pPhyPort , BOOL status)
{
    if(pPhyPort == NULL)
	    return;

    if(status)
    {
        pPhyPort->status = MGC_PHY_PORT_STATUS_ON_LINE;
    }
    else
    {
        pPhyPort->status = MGC_PHY_PORT_STATUS_OFF_LINE;    
    }
	return;
}

/***************************************************************************
 * mgc_phy_port_find_idle_chnl
 * ------------------------------------------------------------------------
 * General: find a idle chnl in the phyPort
 * Return Value:  if failure return NULL , else return the pointer of the chnl
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pPhyPort - the pointer of the PHY_PORT_INFO object
 ***************************************************************************/
CHNL_INFO *mgc_phy_port_find_idle_chnl(PHY_PORT_INFO *pPhyPort)
{
    int i;
	CHNL_INFO *pChnlInfo = NULL;

    if(pPhyPort == NULL)
	    return NULL;

    for(i=0 ; i<MGC_MAX_CHNL_NUM_PER_PHY ; i++)
    {
        pChnlInfo = pPhyPort->pChnlInfo[i];

		if(pChnlInfo == NULL)
		    continue;

		if(pChnlInfo->connectNum != 0)
		    continue;

		return pChnlInfo;
    }

	return NULL;
}


/***************************************************************************
 * mgc_phy_port_assign_idle_connection
 * ------------------------------------------------------------------------
 * General: find a idle connection in the phyPort
 * Return Value:  if failure return NULL , else return the pointer of the connction
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pPhyPort - the pointer of the PHY_PORT_INFO object
 ***************************************************************************/
CONNECT_INFO *mgc_phy_port_assign_idle_connection(PHY_PORT_INFO *pPhyPort)
{
    int i;
	CHNL_INFO *pChnlInfo = NULL;
	CONNECT_INFO *pConnect = NULL;
	
    if(pPhyPort == NULL)
        return NULL;	

    for(i=0 ; i<MGC_MAX_CHNL_NUM_PER_PHY ; i++)
    {
        pChnlInfo = pPhyPort->pChnlInfo[i];

		if(pChnlInfo == NULL)
		    continue;

		pConnect = mgc_chnl_info_assign_idle_connect(pChnlInfo);

		if(pConnect == NULL)
		    continue;

		return pConnect;
    }
	
    return NULL;
}



BYTE *mgc_phy_port_get_res_addr(void)
{
    return (BYTE *)mgcPhyPort;
}


static char *mgc_phy_port_print_user_type(MGC_USER_TYPE type)
{
    switch(type)
    {
        case MGC_USER_TYPE_MGC:
			return "MGC_USER_TYPE_MGC";
		case MGC_USER_TYPE_MG:
			return "MGC_USER_TYPE_MG";
		default :
			break;
    }

    return "MGC_USER_TYPE_UNDEF";	
}

void mgc_phy_port_print_chnl_info(PHY_PORT_INFO *pPhyPort)
{
    int i;
    CHNL_INFO *pChnlInfo;
    if(pPhyPort == NULL)
	    return;

    if((pPhyPort->portType != MGC_PHY_PORT_TYPE_E1)&&(pPhyPort->portType != MGC_PHY_PORT_TYPE_T1))
    {
        MGC_INFO("port type do not support!");
		return;
    }

	MGC_INFO("%8s  %10s  %10s  %10s  %20s" , "ChnlNo", "Status", "Mode" , "Codec" , "LocalIP");
    for(i=0 ; i<pPhyPort->chnlNum ; i++)
    {
        pChnlInfo = pPhyPort->pChnlInfo[i];

		if(pChnlInfo == NULL)
		    continue;

        MGC_INFO("chnl[%02d]  %10s  %10s  %10s  %20s", 
			       i , mgc_chnl_info_print_status(pChnlInfo), mgc_chnl_info_print_mode(pChnlInfo), 
			           mgc_chnl_info_print_codec(pChnlInfo), mgc_chnl_info_print_remote(pChnlInfo));
    }
	
	return;	
}

void mgc_phy_port_print(PHY_PORT_INFO *pPhyPort)
{
    if(pPhyPort == NULL)
	    return;

    if((pPhyPort->pMgInfo == NULL)||(pPhyPort->pMgcSap == NULL) )
    {
        MGC_INFO("mgcPhyPort[%d] is not used!" , pPhyPort->id);
        return;
    }

    MGC_INFO("mgInfo[%d]Port[%d] ==>> mgcPhyPort[%d] " , pPhyPort->pMgInfo->id , pPhyPort->portNo , pPhyPort->id);	
    MGC_INFO("mgInfo[%d]Port[%d] ==>> %s %s" ,
		       pPhyPort->pMgInfo->id , pPhyPort->portNo , pPhyPort->pMgcSap->usrName,mgc_phy_port_print_user_type(pPhyPort->pMgcSap->usrType));
    MGC_INFO("mgInfo[%d]Port[%d] %s" , pPhyPort->pMgInfo->id , pPhyPort->portNo, (pPhyPort->status == MGC_PHY_PORT_STATUS_ON_LINE)?"on":"off");	
	mgc_phy_port_print_chnl_info(pPhyPort);
	return;
}

int mgc_modify_port(BYTE sapIndex, WORD mgNo, BYTE portNo, BYTE portType)
{
    MGC_ERROR("port modify is not support now!");	
	MGC_ERROR("Please delete first , and then re-add");
    return -1;
}

void mgc_phy_port_set_mon(int id, BOOL enalbe)
{
    if((id<0)||(id >= MGC_MAX_NUM_OF_PHY_PORT))
	    return;

    mgcPhyPort[id].monFlag = enalbe;
}

