#include "./include/mgc_port_list.h"
#include "./include/mgc_port_info.h"
#include "./include/mgc_debug.h"

#define MGC_MAX_NUM_OF_PORT_NODE (MGC_MAX_NUM_OF_PORT)

MGC_PORT_NODE mgcPortNode[MGC_MAX_NUM_OF_PORT_NODE];
MGC_PORT_LIST mgcPortActiveList;

static void mgc_port_list_node_init(MGC_PORT_NODE *pNode , int id)
{
    if(pNode == NULL)
	    return;

	pNode->id = id;
	pNode->pPortInfo = NULL;
	pNode->pPrior = NULL;
	pNode->pNext = NULL;
	pNode->pList = NULL;
	return;
}

static void mgc_port_list_init(MGC_PORT_LIST *pList)
{
    if(pList == NULL)
	    return;

	pList->pHead = NULL;
	pList->len = 0;
	return;
}

static MGC_PORT_NODE *mgc_port_list_get_unused_node(void)
{
    int i;
	static int index = 0 ;
	MGC_PORT_NODE *pNode = NULL;
	MGC_PORT_NODE *pNodeTmp = NULL;

    i = index;
	do
	{
	    i++;

		if(i == MGC_MAX_NUM_OF_PORT_NODE)
		    i = 0;

		pNode = &mgcPortNode[i];

		if((pNode->pNext != NULL)||(pNode->pPrior != NULL))
		    continue;

		if((pNode->pPortInfo != NULL)||(pNode->pList != NULL))
		{
		    MGC_ERROR("mgcNode[%d] error rec" , pNode->id);
			mgc_port_list_node_init(pNode, pNode->id);
			continue;
		}

		pNodeTmp = pNode;
		index = i;
		break;
		
	}while( i!=index);

    return pNodeTmp;	
}

void mgc_port_list_setup(void)
{
    int i;
    MGC_PORT_NODE *pNode = NULL;

    for(i=0 ; i<MGC_MAX_NUM_OF_PORT_NODE ; i++)
    {
        pNode = &mgcPortNode[i];
		mgc_port_list_node_init(pNode, i);
    }

	mgc_port_list_init(&mgcPortActiveList);
}


WORD mgc_port_list_get_len(MGC_PORT_LIST *pList)
{
    if(pList == NULL)
	    return 0;
	
    return pList->len;
}

MGC_PORT_NODE *mgc_port_list_get_tail(MGC_PORT_LIST *pList)
{    
    if((pList == NULL)||(pList->pHead == NULL))
	    return NULL;

    return (pList->pHead->pPrior);
}


static BOOL mgc_port_list_add_node_to_list(MGC_PORT_LIST *pList , MGC_PORT_NODE *pNode)
{
    MGC_PORT_NODE *pNodeTail;
    if((pList == NULL)||(pNode == NULL))
	    return FALSE;

    if(pList->pHead == NULL)
    {
        pList->pHead = pNode;
		pList->pHead->pPrior = pNode;
		pList->pHead->pNext = pNode;
		pNode->pList = pList;
    }

    pNodeTail = mgc_port_list_get_tail(pList);
	if(pNodeTail == NULL)
	{
	    MGC_ERROR("lost portlist tail");
		return FALSE;
	}

	pNode->pPrior = pNodeTail;
	pNode->pNext = pNodeTail->pNext;
	pNode->pList = pList;
	pNodeTail->pNext = pNode;
	pList->pHead->pPrior = pNode;
	pList->len++;

	return TRUE;	
}

static MGC_PORT_NODE *mgc_port_list_find_port_in_active_list(PORT_INFO *pPortInfo)
{
    MGC_PORT_NODE *pNode = NULL;
    MGC_PORT_NODE *pNodeTmp = NULL;	
    MGC_PORT_NODE *pHead = NULL;
	
    if(pPortInfo == NULL)
	    return NULL;	

    pHead = mgcPortActiveList.pHead;

	if(pHead == NULL)
	    return NULL;

    pNode = pHead;
	do{
	    if(pNode->pPortInfo == pPortInfo)
	    {
	        pNodeTmp = pNode;
			break;
	    }

		pNode = pNode->pNext;
	}while(pNode != pHead);
	
	return pNodeTmp;
}


MGC_PORT_NODE *mgc_port_list_add_to_active_list(PORT_INFO *pPortInfo)
{
    MGC_PORT_NODE *pNode = NULL;
	
    if(pPortInfo == NULL)
	    return NULL;

    pNode = mgc_port_list_find_port_in_active_list(pPortInfo);
	if(pNode != NULL)
	    return pNode;	

    pNode = mgc_port_list_get_unused_node();

	if(pNode == NULL)
    {
	    MGC_ERROR("mgcPortNode is full!");
		return NULL;
    }

    pNode->pPortInfo = pPortInfo;

	if(mgc_port_list_add_node_to_list(&mgcPortActiveList, pNode) == FALSE)
	{
	    mgc_port_list_node_init(pNode, pNode->id);
	    return NULL;
	}
    //MGC_DEBUG("mgcPort[%d] add to mgcPortNode[%d]" , pPortInfo->id , pNode->id);
    return pNode;	
}




static BOOL mgc_port_list_remove_node_from_list(MGC_PORT_LIST *pList , MGC_PORT_NODE *pNode)
{
    MGC_PORT_NODE *pPrior = NULL;
    MGC_PORT_NODE *pNext = NULL;
	
    if((pList == NULL) || (pNode == NULL))
	    return FALSE;

    if(pNode->pList != pList)
    {
        MGC_ERROR("mgcPortNode[%d] not belong to the list" , pNode->id);
		return FALSE;
    }

    pPrior = pNode->pPrior;
	pNext = pNode->pNext;

    if((pPrior == NULL)||(pNext == NULL))
    {
        MGC_ERROR("mgcPortNode[%d] lost rec" , pNode->id);
        return FALSE;
    }

    pPrior->pNext = pNext;
	pNext->pPrior = pPrior;
	pList->len--;

	if(pList->pHead == pNode)
	{
	    pList->pHead = pNext;
	}

    if((pPrior == pNode)&&(pNext == pNode))
    {
        pList->pHead = NULL;
    }

    mgc_port_list_node_init(pNode, pNode->id);
    return TRUE;
}

BOOL mgc_port_list_remove_from_active_list(PORT_INFO *pPortInfo)
{
    MGC_PORT_NODE *pNode = NULL;
    
    if(pPortInfo == NULL)
	    return FALSE;	

    pNode = mgc_port_list_find_port_in_active_list(pPortInfo);
    if(pNode == NULL)
    {
        MGC_ERROR("mgcPort[%d] is not in the active list" , pPortInfo->id);
	    return FALSE;	    
    }

    if(mgc_port_list_remove_node_from_list(&mgcPortActiveList, pNode) == FALSE)
	    return FALSE;

    //MGC_DEBUG("mgcPort[%d] remove from mgcPortNode[%d]" , pPortInfo->id , pNode->id);
    return TRUE;	
}


void mgc_port_active_list_proc(void)
{
    MGC_PORT_NODE *pNode = NULL;
	MGC_PORT_NODE *pNodeTmp = NULL;
    PORT_INFO *pPortInfo = NULL;	
	MGC_PORT_LIST *pList = &mgcPortActiveList;
	
    if(pList->pHead == NULL)
	    return;

	pNode = pList->pHead;
    do{
		pPortInfo = pNode->pPortInfo;
        pNodeTmp = pNode;
	    pNode = pNode->pNext;
		
		if(pPortInfo == NULL)
		{
		    MGC_ERROR("mgcPortNode[%d] lost rec" , pNodeTmp->id);
			mgc_port_list_remove_node_from_list(pNodeTmp->pList, pNodeTmp);			
		}
		else
		{
			mgc_port_info_fsm(pNode->pPortInfo);		
			if(pPortInfo->assigned == FALSE)
			    mgc_port_list_remove_from_active_list(pPortInfo);
		}
		
	}while((pNode != pList->pHead)&&(pList->pHead != NULL));

    return;	
}



