/*****************************************************************************
** File: ai_tp_list.c
**
** Description: FIFO
**
** Copyright(c) 2011 Sunmedia Technologies - All Rights Reserved
**
** Author : kun.li
**
** $Id $
*****************************************************************************/
#include "al_basictypes.h"
#include "ai_tp_list.h"
#include "gl_mempool.h"


typedef struct list_node
{
    struct list_node* next;
    void*           data;
} list_node_st;

typedef struct
{
	list_node_st stHead;
	void* pTail;
} list_mgm_st;

static inline void ai_list_add(list_node_st* pnew, list_node_st* head)
{
	pnew->next = head->next;
	head->next = pnew;
}

static inline void ai_list_delete(list_node_st* node, list_node_st* prev)
{
	prev->next = node->next;
}

static inline void ai_list_get_next(list_node_st* entry, list_node_st** node)
{
	*node = entry->next;
}

AL_Return_t AI_TpListInit(TpListHdl_st* pstHdl)
{
	list_mgm_st* pNode = al_null;

	if (al_null == pstHdl)
	{
		return AL_FAILURE;
	}

	if (al_null == (pNode = (list_mgm_st*)GL_MemAlloc(sizeof(list_mgm_st))))
	{
		return AL_FAILURE;
	}

	pNode->stHead.next = pNode->stHead.data = al_null;
	pNode->pTail = &pNode->stHead;

	*pstHdl = (TpListHdl_st)pNode;

	return AL_SUCCESS;
}

AL_Return_t AI_TpListAddNode(TpListHdl_st pstHdl, void* pstTpInfo, al_uint32 uiTpInfoSize)
{
	list_mgm_st* pstMgm = (list_mgm_st*)pstHdl;
	list_node_st* pstNode = al_null;
	al_uint32 uiSize = 0;

	if (al_null == pstTpInfo || al_null == pstMgm)
	{
		return AL_FAILURE;
	}

	uiSize = uiTpInfoSize + sizeof(list_node_st);

	pstNode = (list_node_st*)GL_MemAlloc(uiSize);

	if (al_null == pstNode)
	{
		return AL_FAILURE;
	}

	memset(pstNode, 0, uiSize);

	ai_list_add(pstNode, pstMgm->pTail);
	pstMgm->pTail = pstNode;
	pstNode->data = &pstNode[1];
	memcpy(pstNode->data, pstTpInfo, uiTpInfoSize);

	return AL_SUCCESS;
}

AL_Return_t AI_TpListGetNode(TpListHdl_st pstHdl, void** pstCurTpInfo)
{
	list_mgm_st* pstMgm = (list_mgm_st*)pstHdl;
	list_node_st* pstListNode = al_null;

	if (al_null == pstCurTpInfo || al_null == pstMgm)
	{
		return AL_FAILURE;
	}

	if (al_null == *pstCurTpInfo)
	{
		ai_list_get_next(&(pstMgm->stHead), &pstListNode);
	}
	else
	{
		ai_list_get_next(&(((list_node_st*)(*pstCurTpInfo))[-1]), &pstListNode);
	}

	if (al_null == pstListNode)
	{
		*pstCurTpInfo = al_null;
		return AL_FAILURE;
	}

	*pstCurTpInfo = pstListNode->data;

	return AL_SUCCESS;
}

AL_Return_t AI_TpListFree(TpListHdl_st pstHdl)
{
	list_mgm_st* pstMgm = (list_mgm_st*)pstHdl;
	list_node_st *pstNode, *pstPrev;

	if (al_null == pstMgm)
	{
		return AL_FAILURE;
	}

	pstNode = pstPrev = al_null;

	for (pstPrev = &(pstMgm->stHead), pstNode = pstPrev->next;
		pstNode != al_null; pstNode = pstPrev->next)
	{
		ai_list_delete(pstNode, pstPrev);
		GL_MemFree(pstNode);
		pstNode = al_null;
	}

	GL_MemFree(pstMgm);

	return AL_SUCCESS;
}

#ifdef CONFIG_DVB_SYSTEM_DVBS_SUPPORT
//add by hou.xin for dvb-s/s2 @20140318+++++++++++++
AL_Return_t AI_TpListDeleteOneNode(TpListHdl_st pstHdl, void** pstDelTpInfo)
{

    list_mgm_st* pstMgm = (list_mgm_st*)pstHdl;
    list_node_st* pstListNode = al_null;
    list_node_st *pstNode = al_null, *pstPrev = al_null;

    if (al_null == pstDelTpInfo || (al_null == *pstDelTpInfo) || al_null == pstMgm)
    {
        return AL_FAILURE;
    }
    pstListNode = &(((list_node_st*)(*pstDelTpInfo))[-1]);

    pstPrev = &(pstMgm->stHead);
    
    if (!pstPrev)
    {
        return AL_FAILURE;
    }
    while(1)
    {
    	if (pstPrev != NULL)
    	{
        	pstNode = pstPrev->next;
    	}
		else
		{
			break;
		}
        if (pstNode != al_null && pstPrev != al_null && pstNode == pstListNode)
        {
            ai_list_delete(pstNode, pstPrev);
            GL_MemFree(pstNode);
            pstNode = al_null;
            break;
        }
        pstPrev = pstNode;
    }

    if (al_null == pstPrev)
	{
		*pstDelTpInfo = al_null;
	}
    else
    {
        *pstDelTpInfo = pstPrev->data;
    }

    return AL_SUCCESS;
}
//add by hou.xin for dvb-s/s2----------------
#endif

