/**
* Copyright(c) 2012 Sunmedia Technologies - All Rights Reserved.
*
* @file
*
* @brief this file defines closed caption and vchip interface for app layer.
*
* The file supports the closed caption and vchip functions by used for app layer.
* The datas related closed caption functions include analog and digitial datas and
* the datas related vchip functions include analog datas only.
*/
#include <ctype.h>
#include "gl_types.h"
#include "gl_mutex.h"
#include "al_basictypes.h"
#include "ai_debug_config.h"
#include "al_fw.h"
#include "al_cc.h"
#include "ai_cc.h"
#include "mid_cc.h"

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

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

#define CC_MUTEX_LOCK()	{ if(g_pstCCMutex) {GL_MutexLock(g_pstCCMutex);}}
#define CC_MUTEX_UNLOCK()	{ if(g_pstCCMutex) {GL_MutexUnlock(g_pstCCMutex);}}

static GL_Mutex_t g_pstCCMutex = NULL;
/**< CC init or uninit flag */
static al_bool g_bCCInitFlag = al_false;
/**< CC start or stop flag*/
static al_bool g_bCCStartFlag = al_false;
static al_bool g_bCCViewFlag = al_false;
#ifdef CONFIG_ATSC_SYSTEM
static CaptionServiceDesc_t g_stCCDescInfo;
#endif
static al_void  _AI_CC_XDS_CallBack(XDSEvent_t eventtype, void *param)
{
	switch(eventtype)
	{
		case XDS_CURRENT_PROG_TITLE:
			{
				printf("\n========[%s, %d]\n",__FUNCTION__,__LINE__);
				al_uint8 *progname = (al_uint8 *)param;
				al_uint32 tvhdl = AL_DB_INVALIDHDL;
				frmwrk_pfOpConext_t pfGetCurrentHdl = al_null;
				AL_FW_GetContextCb(&pfGetCurrentHdl);
				if (pfGetCurrentHdl != al_null)
				{
					pfGetCurrentHdl(FW_CONTEXT_TYPE_GET_CURRENT_TVHDL, FW_CONTEXT_OP_TYPE_READ,
						(al_void *)&tvhdl, 0);
				}
				if((tvhdl != AL_DB_INVALIDHDL) && (progname != NULL))
				{
					AL_ServiceDetail_t stServInfo;
					AL_DB_QueryDetail(tvhdl, (al_void *)&stServInfo);
					memset(stServInfo.stAnalogServ.szChannelName, 0, DB_ATV_MAX_CHNAME_LEN);
                    snprintf((al_int8 *)stServInfo.stAnalogServ.szChannelName, DB_ATV_MAX_CHNAME_LEN, (al_int8 *)progname);
					//strcpy((al_int8 *)stServInfo.stADBServ.szChannelName, (al_int8 *)progname);
					AL_DB_QueryDetail(tvhdl, (al_void *)&stServInfo);
				}
			}
			break;
		case XDS_FUTURE_PROG_TITLE:
			{
				printf("\n========[%s, %d]\n",__FUNCTION__,__LINE__);
				al_uint8 *progname = (al_uint8 *)param;
				al_uint32 tvhdl = AL_DB_INVALIDHDL;
				frmwrk_pfOpConext_t pfGetCurrentHdl = al_null;
				AL_FW_GetContextCb(&pfGetCurrentHdl);
				if (pfGetCurrentHdl != al_null)
				{
					pfGetCurrentHdl(FW_CONTEXT_TYPE_GET_CURRENT_TVHDL, FW_CONTEXT_OP_TYPE_READ,
						(al_void *)&tvhdl, 0);
				}
				if((tvhdl != AL_DB_INVALIDHDL) && (progname != NULL))
				{
					AL_ServiceDetail_t stServInfo;
					AL_DB_QueryDetail(tvhdl, (al_void *)&stServInfo);
					memset(stServInfo.stAnalogServ.szChannelName, 0, DB_ATV_MAX_CHNAME_LEN);
                    snprintf((al_int8 *)stServInfo.stAnalogServ.szChannelName, DB_ATV_MAX_CHNAME_LEN, (al_int8 *)progname);
					//strcpy((al_int8 *)stServInfo.stADBServ.szChannelName, (al_int8 *)progname);
					AL_DB_QueryDetail(tvhdl, (al_void *)&stServInfo);
				}
			}
			break;
		case XDS_EVENT_MAX:
		default:
			break;
	}
}

/**
* @brief closed caption init function.
*
* This api is used to create mutex for protecting the shared resource.
* the closed caption decoder task
*
* @param VChip_CallBack callback function pointer.
*
* @return AL_SUCCESS if initialization is successful, AL_FAILURE
* otherwise.
*/
AL_Return_t AI_CC_Init(Vchip_Callback_f VChip_CallBack)
{
	GL_Status_t ret = GL_FAILURE;
	if(VChip_CallBack == al_null)
	{
		CC_ERROR_MESSAGE("\ninvalid parameter!\n");
		return AL_FAILURE;
	}
	
	if(g_bCCInitFlag)
	{
		CC_DEBUG_MESSAGE("ClosedCaption has been inited!\n");
		return AL_SUCCESS;
	}

	ret = GL_MutexCreate("CloseCaptionMutex", &g_pstCCMutex);

	if (ret != GL_SUCCESS)
	{
		CC_ERROR_MESSAGE("Error %d:call GL_SemaphoreCreate for mutex failed!\n", ret);
		goto CC_INIT_FAILED;
	}
	MID_CC_CallBack_t callback;
	callback.vchip_callback = VChip_CallBack;
	callback.xds_callback = &_AI_CC_XDS_CallBack;
	if(MID_CC_Initialize(callback) != MID_CC_SUCCESS)
	{
		CC_ERROR_MESSAGE("Error %d:MID_CC_Initialize()failed!\n", ret);
		return AL_FAILURE;
	}

	g_bCCInitFlag = al_true;

	return AL_SUCCESS;

CC_INIT_FAILED:

	if(g_pstCCMutex)
	{
		GL_MutexDelete(g_pstCCMutex);
	}

	g_bCCInitFlag = al_false;

	return AL_FAILURE;
}

/**
* @brief closed caption 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_CC_Uninit(al_void)
{
	if(g_bCCInitFlag == al_false)
	{
		CC_DEBUG_MESSAGE("ClosedCaption has been uninited!\n");
		return AL_SUCCESS;
	}
	CC_MUTEX_LOCK();
	if((MID_Get_CC_Status() == CC_VIEW))
	{
		if(MID_CC_Unview() != MID_CC_SUCCESS)
		{
			CC_ERROR_MESSAGE("ClosedCaption stop false!\n");
			CC_MUTEX_UNLOCK();
			return AL_FAILURE;
		}
	}
	if (MID_Get_CC_Status() == CC_START)
	{
		if(MID_CC_Stop() != MID_CC_SUCCESS)
		{
			CC_ERROR_MESSAGE("ClosedCaption stop false!\n");
			CC_MUTEX_UNLOCK();
			return AL_FAILURE;
		}
	}
	if(MID_CC_Terminate() != MID_CC_SUCCESS)
	{
		CC_ERROR_MESSAGE("ClosedCaption terminate false!\n");
		CC_MUTEX_UNLOCK();
		return AL_FAILURE;
	}

	CC_MUTEX_UNLOCK();

	if (g_bCCInitFlag)
	{
		if(g_pstCCMutex)
		{
			GL_MutexDelete(g_pstCCMutex);
			g_pstCCMutex = NULL;
		}
		g_bCCInitFlag = al_false;
	}
	return AL_SUCCESS;
}

#ifdef CONFIG_ATSC_SYSTEM
/**
* @brief the function will get digital caption service descriptor information.
*
* @param *CCDescInfo gotten the caption service descriptor information.
*
* @return AL_SUCCESS if gotten descriptor information is successful, AL_FAILURE 
* otherwise.
*/
AL_Return_t AI_CC_GetDescInfo(CaptionServiceDesc_t *CCDescInfo)
{
	if(CCDescInfo == al_null)
	{
		return AL_FAILURE;
	}
	memcpy(&g_stCCDescInfo, CCDescInfo, sizeof(CaptionServiceDesc_t));
	return AL_SUCCESS;
}
#endif
/**
* @brief closed caption start function.
*
* The function will start to get cc and xds data from tt slicer and 
* creat decode thread to decode cc and xds data.
*
* @param srctype mid layer need source type to decode cc608 or cc708.
*
* @return AL_SUCCESS if starting is successful, AL_FAILURE
* otherwise.
*/
AL_Return_t AL_CC_Start(AL_CC_Source_Type_t srctype)
{
	MID_CC_Source_Type_t type = MID_CC_SRC_MAX;
	if(g_bCCStartFlag == al_true)
	{
		CC_DEBUG_MESSAGE("\nClosedCaption has started!\n");
		return AL_SUCCESS;
	}
	CC_MUTEX_LOCK();
	switch(srctype)
	{
		case AL_CC_SRC_ATV:
			type = MID_CC_SRC_ATV;
			break;
		case AL_CC_SRC_DTV:
			type = MID_CC_SRC_DTV;
			break;
		case AL_CC_SRC_MAX:
		default:
			break;
	}
	if(MID_CC_Start(type) != MID_CC_SUCCESS)
	{
		CC_ERROR_MESSAGE("\nstart cc fail!!!!!\n");
		CC_MUTEX_UNLOCK();
		return AL_FAILURE;
	}
	g_bCCStartFlag = al_true;
	CC_MUTEX_UNLOCK();
	return AL_SUCCESS;
}

/**
* @brief closed caption stop function.
*
* 1.The function will stop to get cc and xds data from tt slicer and 
* stop to decode cc and xds data;
* 2.The function will stop to display cc on the screen.
*
* @param al_void.
*
* @return AL_SUCCESS if starting is successful, AL_FAILURE
* otherwise.
*/
AL_Return_t AL_CC_Stop(al_void)
{
	if(g_bCCStartFlag == al_false)
	{
		CC_DEBUG_MESSAGE("\nClosedCaption has stopped!\n");
		return AL_SUCCESS;
	}
	if(g_bCCViewFlag == al_true)
	{
		AL_CC_Unview();
	}
	CC_MUTEX_LOCK();
	if(MID_CC_Stop() != MID_CC_SUCCESS)
	{
		CC_ERROR_MESSAGE("\nstop cc fail!!!!!\n");
		CC_MUTEX_UNLOCK();
		return AL_FAILURE;
	}
	g_bCCStartFlag = al_false;
	CC_MUTEX_UNLOCK();
	return AL_SUCCESS;
}

/**
* @brief closed caption start to display function.
*
* The function will display closed caption on the screen
*
* @param *CCInfo the display information gotten from eeprom/flash if user setting
* the display information on the main menu.
*
* @return AL_SUCCESS if starting is successful, AL_FAILURE
* otherwise.
*/
AL_Return_t AL_CC_View(AL_CC_Info_t *CCInfo)
{
	CCInitAttrib_t CCInitAttribute ;
	CCType_t cc_type = CC_TYPE_MAX;
	
	memset(&CCInitAttribute, 0, sizeof(CCInitAttrib_t));
	CC_MUTEX_LOCK();
	if(CCInfo == al_null)
	{
		CC_ERROR_MESSAGE("\ninvalid ClosedCaption parameter!\n");
		CC_MUTEX_UNLOCK();
		return AL_FAILURE;
	}
	if(g_bCCViewFlag == al_true)
	{
		CC_DEBUG_MESSAGE("\nClosedCaption has started!\n");
		CC_MUTEX_UNLOCK();
		return AL_SUCCESS;
	}
	if(CCInfo->CcServNum >= AL_CC_SERV_CS1 && CCInfo->CcServNum <= AL_CC_SERV_CS6)
	{
		cc_type = CC_TYPE_CC708;
	}
	else if(CCInfo->CcServNum >= AL_CC_SERV_CC1 && CCInfo->CcServNum <= AL_CC_SERV_TXT4)
	{
		cc_type = CC_TYPE_CC608;
	}
	else
	{
		cc_type = CC_TYPE_MAX;
	}
	if(cc_type == CC_TYPE_CC708)
	{
		CCInitAttribute.CCFontAttrib.FontSize = CCInfo->CcFontSize;
		CCInitAttribute.CCFontAttrib.FontStyle = CCInfo->CcFontStyle;
		CCInitAttribute.CCFontAttrib.fgColor = CCInfo->CcFgColor;
		CCInitAttribute.CCFontAttrib.FgOpacityType = CCInfo->CcFgOpacity;
		CCInitAttribute.CCFontAttrib.bgColor = CCInfo->CcBgColor;
		CCInitAttribute.CCFontAttrib.BgOpacityType = CCInfo->CcBgOpacity;
		CCInitAttribute.CCFontAttrib.FontEdgeType = CCInfo->CcFontEdgeType;
		CCInitAttribute.CCFontAttrib.EdgeColor = CCInfo->CcFontEdgeColor;
	}
	if(MID_CC_View(CCInfo->CcServNum, cc_type, &CCInitAttribute) != MID_CC_SUCCESS)
	{
		CC_ERROR_MESSAGE("\nStart ClosedCaption fail!\n");
		CC_MUTEX_UNLOCK();
		return AL_FAILURE;
	}

	g_bCCViewFlag = al_true;

	CC_MUTEX_UNLOCK();
	return AL_SUCCESS;
}

/**
* @brief closed caption stop to display function.
*
* The function will stop to display closed caption.
*
* @param al_void.
*
* @return AL_SUCCESS if stopping is successful, AL_FAILURE
* otherwise.
*/
AL_Return_t AL_CC_Unview(al_void)
{
	CC_MUTEX_LOCK();

	if(g_bCCViewFlag == al_false)
	{
		CC_DEBUG_MESSAGE("\nClosedCaption has stopped!\n");
		CC_MUTEX_UNLOCK();
		return AL_SUCCESS;
	}
	if(MID_CC_Unview() != MID_CC_SUCCESS)
	{
		CC_DEBUG_MESSAGE("\nStop ClosedCaption fail!\n");
		CC_MUTEX_UNLOCK();
		return AL_FAILURE;
	}
	g_bCCViewFlag = al_false;
	CC_MUTEX_UNLOCK();
	return AL_SUCCESS;
}

/**
* @brief the function will reset closed caption module, following initialization
* or a programe change.
*
* @param al_void.
*
* @return AL_SUCCESS if reseting is successful, AL_FAILURE
* therwise.
*/
AL_Return_t AL_CC_Reset(al_void)
{
	CC_MUTEX_LOCK();
	MID_CC_Reset();
	CC_MUTEX_UNLOCK();
	return AL_SUCCESS;
}

/**
* @brief the function will get closed caption data being valid or not.
*
* @param *Status gotten the signal status value. if gotten closed caption is
* successful, the gotten signal status is al_true, else the gotten signal status
* is al_false.
*
* @return AL_SUCCESS if gotten signal is successful, AL_FAILURE
* therwise.
*/
AL_Return_t AL_CC_GetSignalStatus(al_bool *Status)
{
	CC_MUTEX_LOCK();
	if(Status == al_null)
	{
		CC_ERROR_MESSAGE("invalid parameter!\n");
		CC_MUTEX_UNLOCK();
		return AL_FAILURE;
	}
	if(MID_CC_GetSignalStatus() != 0)
	{
		*Status = al_true;
	}
	else
	{
		*Status = al_false;
	}
	//printf("\n=======[%s, %d], status:%d\n",__FUNCTION__,__LINE__,*Status);
	CC_MUTEX_UNLOCK();
	return AL_SUCCESS;
}

