/**
* Copyright(c) 2011 Sunmedia Technologies - All Rights Reserved.
*
* @file
*
* @brief this file describes subtitle descriptor parsing and supports
* the interface of subtitle module.
*/
#include <sys/ioctl.h>
#include <ctype.h>
#include "gl_types.h"
#include "gl_mutex.h"
#include "al_basictypes.h"
#include "al_sbtvd_subtitle.h"
#include "ai_debug_config.h"
#include "mid_sub_dtv_interface.h"
#include "drv_dtv_external.h"
#include "drv_dtv_common.h"
#include "mid_siutil_dvb.h"
#include "kmf_ioctl.h"
#include "drv_tuner_external.h"
#include "ap_extern.h"
#include "pvrparser.h"
#include "mid_tspl_util.h"
#include "mid_tspl_parser.h"

#if ISDBSUB_DBG_FLAG
	#define SUBTITLE_DEBUG_MESSAGE(fmt, arg...) \
	do { \
		UMFDBG(0,"[Debug]%s: %d Line ", __FUNCTION__, __LINE__); \
		UMFDBG(0,fmt, ##arg); \
	} while(0)
#else
	#define SUBTITLE_DEBUG_MESSAGE(fmt,arg...);
#endif

#if ISDBSUB_ERROR_FLAG
	#define SUBTITLE_ERROR_MESSAGE(fmt, arg...) \
	do { \
		UMFDBG(0,"[Error]%s: %d Line ", __FUNCTION__, __LINE__); \
		UMFDBG(0,fmt, ##arg); \
	} while(0)
#else
	#define SUBTITLE_ERROR_MESSAGE(fmt, arg...);
#endif

#define SUBTITLE_MUTEX_LOCK()	{if(g_pstSBSubMutex) {GL_MutexLock(g_pstSBSubMutex);}}
#define SUBTITLE_MUTEX_UNLOCK()	{if(g_pstSBSubMutex) {GL_MutexUnlock(g_pstSBSubMutex);}}

#define MAX_SUBTITLE_NUM				(32) /**< maximal descriptor number for a stream */

static GL_Mutex_t g_pstSBSubMutex = NULL;
static al_bool g_bSBSubInitFlag = al_false;
static al_bool g_bSBSubStartFlag = al_false;
static al_uint32 SBSubNum = 0;
static al_int32 SubChanHdl = INVALID_HANDLE;
static AL_SBSUBPidInfo_t stSBSubDescInfo[MAX_SUBTITLE_NUM];

static void _AI_SBSUB_StartRing(al_uint16 Pid)
{
	DMIOC_RINGCFG_PARAM stRingParam;
	memset(&stRingParam, 0, sizeof(DMIOC_RINGCFG_PARAM));
	stRingParam.retval = INVALID_HANDLE;
	stRingParam.DemuxUnit = 0;
	stRingParam.StreamType = DTV_Subtitle;
	stRingParam.RingType = TS_DEMUX_TYPE_PES_SP;
	stRingParam.PID = Pid;
	stRingParam.Queue_ID = NULL;
	ioctl(dtvdev, DTV_IOCTL_RingConfig, &stRingParam);
	DMIOC_SETRING_PARAM stSetParam;
	memset(&stSetParam, 0, sizeof(DMIOC_SETRING_PARAM));
	stSetParam.bEnable = TRUE;
	SubChanHdl = stRingParam.retval;
	stSetParam.Config_idx = stRingParam.retval;
	ioctl(dtvdev, DTV_IOCTL_SetRing, &stSetParam);
}

static al_void _AI_SBSUB_StopRing(al_int32 ChanHdl)
{
	DMIOC_SETRING_PARAM stSetParam;
	memset(&stSetParam, 0, sizeof(DMIOC_SETRING_PARAM));
	stSetParam.bEnable = FALSE;
	stSetParam.Config_idx = ChanHdl;
	ioctl(dtvdev, DTV_IOCTL_SetRing, &stSetParam);
}

/**
* @brief subtitle init function.
*
* This api is used to create mutex for protecting the shared resource and so on.
*
* @param al_void.
*
* @return AL_SUCCESS if initialization is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_SBSUB_Init(al_void)
{
	GL_Status_t ret = GL_FAILURE;

	if(g_bSBSubInitFlag)
	{
		SUBTITLE_DEBUG_MESSAGE("Subtitle has been inited!\n");
		return AL_SUCCESS;
	}

	ret = GL_MutexCreate("SubtitleMutex",&g_pstSBSubMutex);

	if (ret != GL_SUCCESS)
	{
		SUBTITLE_ERROR_MESSAGE("Error %d: %s call GL_SemaphoreCreate for mutex failed!\n", ret, __FUNCTION__);
		goto SUBTITLE_INIT_FAILED;
	}

	g_bSBSubInitFlag = al_true;

	return AL_SUCCESS;

SUBTITLE_INIT_FAILED:

	if(g_pstSBSubMutex)
	{
		GL_MutexDelete(g_pstSBSubMutex);
	}

	g_bSBSubInitFlag = al_false;

	return AL_FAILURE;
}

/**
* @brief subtitle uninit function.
*
* This api is used to delete mutex for protecting the shared resource and so on.
*
* @param al_void.
*
* @return AL_SUCCESS if uninitialization is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_SBSUB_Uninit(al_void)
{
	if (g_bSBSubInitFlag)
	{
		if(g_pstSBSubMutex)
		{
			GL_MutexDelete(g_pstSBSubMutex);
			g_pstSBSubMutex = NULL;
		}
		g_bSBSubInitFlag = al_false;
	}
	return AL_SUCCESS;
}

/**
* @brief subtitle start function.
*
* @param Index user selects subtitle number on the subtitle menu, and using index, the special
* subtitle descriptor information will be gotten from subtitle descriptor buffer.
*
* @return AL_SUCCESS if starting is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_SBSUB_Start(al_int Index)
{
	SUBTITLE_DEBUG_MESSAGE("\n=======AL_SBSUB_Start start!!!!!!!!\n");
	int ret = 0;
	SUBTITLE_MUTEX_LOCK();
	if(g_bSBSubStartFlag == al_true)
	{
		SUBTITLE_DEBUG_MESSAGE("Subtitle has started!\n");
		SUBTITLE_MUTEX_UNLOCK();
		return AL_SUCCESS;
	}
	if ((al_uint32)Index < SBSubNum)
	{
#ifdef CONFIG_SUPPORT_PVR
		if(MID_TSPLParser_GetThreadState())
		{
			al_uint32 u32PEState = MID_TSPL_MODE_MAX;
			MID_TSPLParser_GetPlayState(&u32PEState, NULL);
			if((u32PEState==MID_TSPL_MODE_PLAY)||(u32PEState==MID_TSPL_MODE_PAUSE)
			   ||(u32PEState==MID_TSPL_MODE_FB)||(u32PEState==MID_TSPL_MODE_FF)
			   ||(u32PEState==MID_TSPL_MODE_SF)||(u32PEState==MID_TSPL_MODE_SB))
			{
			    MID_TSPLParser_SetSubtitleStream(TRUE,stSBSubDescInfo[Index].wPid);
			}
			else
			{
				SUBTITLE_MUTEX_UNLOCK();
				SUBTITLE_ERROR_MESSAGE("set subtitle id error!\n");
				return AL_FAILURE;
			}
		}
		else
#endif
		{
	        _AI_SBSUB_StartRing(stSBSubDescInfo[Index].wPid);
			ret = mid_sbtvd_sub_dtv_open();
			if(ret == 0)
			{
				SUBTITLE_ERROR_MESSAGE("Dvb Subtitle don't start!\n");
				SUBTITLE_MUTEX_UNLOCK();
				return AL_FAILURE;
			}
		}
	}
	g_bSBSubStartFlag = al_true;
	SUBTITLE_MUTEX_UNLOCK();
	SUBTITLE_DEBUG_MESSAGE("\n=======AL_SBSUB_Start start success!!!!!!!!\n");

	return AL_SUCCESS;

}

/**
* @brief subtitle stop function.
*
* @param al_void.
*
* @return AL_SUCCESS if stoping is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_SBSUB_Stop(al_void)
{
	SUBTITLE_MUTEX_LOCK();
	if(g_bSBSubStartFlag == al_false)
	{
		SUBTITLE_DEBUG_MESSAGE("Subtitle has stopped!\n");
		SUBTITLE_MUTEX_UNLOCK();
		return AL_SUCCESS;
	}
    mid_sbtvd_sub_dtv_close();
	if(SubChanHdl != INVALID_HANDLE)
	{
    	_AI_SBSUB_StopRing(SubChanHdl);
		SubChanHdl = INVALID_HANDLE;
	}
	g_bSBSubStartFlag = al_false;

	SUBTITLE_MUTEX_UNLOCK();

	return AL_SUCCESS;
}

/**
* @brief subtitle reset function.
*
* The buffer that stores subtitle descriptor information is static buffer, so
* it needs be reset with following initialization or a programe change.
*
* @param al_void.
*
* @return AL_SUCCESS if reseting is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_SBSUB_Reset(al_void)
{
	SUBTITLE_MUTEX_LOCK();

	SBSubNum = 0;

	memset(&stSBSubDescInfo, 0xff, sizeof(AL_SBSUBPidInfo_t) * MAX_SUBTITLE_NUM);

	SUBTITLE_MUTEX_UNLOCK();

	return AL_SUCCESS;
}

/**
* @brief the function can get the valid subtitle descriptor total number.
*
* Before the subtitle module starts to work, it needs get the subtitle descpritor
* total number. if the total number is more than 0, the subtitle module will start
* to work. otherwise stop to work.
*
* @param *GetTotalNum get the dvb subtitle total number.
*
* @return AL_SUCCESS if getting total number is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_SBSUB_GetTotalNum(al_uint32 *GetTotalNum)
{
	if(GetTotalNum == al_null)
	{
		return AL_FAILURE;
	}
	SUBTITLE_MUTEX_LOCK();

	*GetTotalNum = SBSubNum;

	if (*GetTotalNum <= 0)
	{
		SUBTITLE_DEBUG_MESSAGE("Get invalid subtitle number!\n");
		SUBTITLE_MUTEX_UNLOCK();
		return AL_FAILURE;
	}

	SUBTITLE_MUTEX_UNLOCK();

	return AL_SUCCESS;

}

/**
* @brief the function can get the parsed subtitle descriptor information.
*
* After creating the subtitle menu with pressing subtitle key, the subtitle menu
* with all subtitle types will be shown on the screen. So when displayed information
* is inited, the parsed subtitle descriptor information will be gotten.
*
* @note Index value is less than the total subtitle descriptor number.
*
* @param Index using the index can get special subtitle descriptor information from
* the buffer.
*
* @param *SubtitleDescInfo it will store the gotten subtitle descriptor information.
*
* @return AL_SUCCESS if getting subtitle descriptor information is successful,
* AL_FAILURE otherwise.
*/
AL_Return_t AL_SBSUB_GetDescInfo(al_int Index, AL_SBSUBPidInfo_t *SubtitleDescInfo)
{
	if((SubtitleDescInfo == al_null) || (Index < 0))
	{
		return AL_FAILURE;
	}
	SUBTITLE_MUTEX_LOCK();

	if ((al_uint32)Index <= SBSubNum)
	{
		memcpy(SubtitleDescInfo, &stSBSubDescInfo[Index], sizeof(AL_SBSUBPidInfo_t));
		SUBTITLE_MUTEX_UNLOCK();
		return AL_SUCCESS;
	}

	SUBTITLE_MUTEX_UNLOCK();

	return AL_FAILURE;
}

/**
* @brief the function can get the subtitle start status.
*
* @param* None.
*
* @return AL_SUCCESS if getting subtitle start flag is true,
* AL_FAILURE otherwise.
*/
AL_Return_t AL_SBSUB_GetStartFlag(void)
{
	if (g_bSBSubStartFlag)
	{
		return AL_SUCCESS;
	}
	return AL_FAILURE;
}

/**
* @brief the function can set subtitle display window freezed or not.
*
* After the video is freezed with pressing freeze key, if the subtitle is
* displaying on the screen, the subtitle needs be freezed. Else the
* video isn't freezed with pressing freeze key again,  if the subtitle is
* displaying on the screen, the subtitle needn't be freezed.
*
* @param FreezeStatus if freeze is true, the subtitle needs be freezed.
* Else if freeze is false, the subtitle needn't be freezed.
*
* @return AL_SUCCESS if setting freeze is successful,
* AL_FAILURE otherwise.
*/
AL_Return_t AL_SBSUB_SetFreeze(al_bool FreezeStatus)
{
	mid_sbtvd_sub_dtv_pause(FreezeStatus);
	return AL_SUCCESS;
}

/**
* @brief the function can parse subtitle descriptor in PMT.
*
* After parsing PMT, PSI listener will start to work. When the stream
* type is private data of PES packet, and the descriptor type is stream identifier
* descriptor, the  stream identifier descriptor will be parsing. When parsing the
* stream identifier descriptor, the information will be stored to subtitle buffer.
*
* @param *Data  stream identifier descpriptor data.
*
* @param DataLen the number of bytes of descriptors.
*
* @param Pid  stream identifier pid.
*
* @return AL_SUCCESS if parsing  stream identifier descriptor is successful,
* AL_FAILURE otherwise .
*/
AL_Return_t AI_SBSUB_ParseDesc(al_uint8 *Data, al_uint16 DataLen, al_uint16 Pid)
{
	al_uint8 u8DescTag = 0;
	al_uint8 u8DescLen = 0;
	al_uint8 u8DescPos = 0;
	al_uint16 u16Pos = 0;

	if(Data == al_null)
	{
		return AL_FAILURE;
	}
	SUBTITLE_MUTEX_LOCK();
	while (u16Pos < DataLen && SBSubNum < MAX_SBSUB_NUM)
	{
		u8DescTag = Data[u16Pos++];
		u8DescLen = Data[u16Pos++];

		if (u8DescTag == DESCR_STREAM_ID)
		{
			while (u8DescPos + 1 <= u8DescLen && SBSubNum < MAX_SBSUB_NUM)
			{
				if((Data[u16Pos]>=0x30 && Data[u16Pos]<=0x37)||
					(Data[u16Pos]==0x87 || Data[u16Pos]==0x88))
				{
					stSBSubDescInfo[SBSubNum].wPid = Pid;
					SBSubNum++;
					SUBTITLE_DEBUG_MESSAGE("[SUB] Got a SBSUB content  pid=%x\n",Pid);
				}
				u8DescPos++;
			}
		}
		u16Pos += u8DescLen;
	}
	SUBTITLE_MUTEX_UNLOCK();
	return AL_SUCCESS;
}

#ifdef CONFIG_SUPPORT_PVR
AL_Return_t AI_SBSUB_GetFileTsSubInfo(al_void)
{
	al_uint32 Subtitle_Num = 0;
    al_int subtitle_id;
	al_uint8 i;

	SUBTITLE_MUTEX_LOCK();

    MID_TSPLParser_GetTotalSubtitleStreamCount(&Subtitle_Num);
    for (i = 0; i < Subtitle_Num; i++)
    {
        subtitle_id = MID_TSPL_PVR_GetSubtitleID(i);
		if(SBSubNum < MAX_SUBTITLE_NUM)
		{
            stSBSubDescInfo[SBSubNum].wPid = subtitle_id;
			SBSubNum++;
		}
    }
	SUBTITLE_MUTEX_UNLOCK();
    return AL_SUCCESS;
}
#endif

