/**
* Copyright(c) 2011 Sunmedia Technologies - All Rights Reserved.
*
* @file al_parent_control.c
*
* @brief this file defines atsc parent control for RRT/DRRT and content advisory descriptor dispose.
*
* 
* 1.This file not dispose RRT, because for RRT rating only support TV-Rating/MPAA static rating information.
* 2.This file store DRRT information to cash for application get and set.
* 3.This file provide check content advisory descriptor for current program and user setting rating value.
*/
#include "gl_mutex.h"
#ifdef CONFIG_ATSC_SYSTEM
#include "psip.h"
#include "ai_multiple_string.h"
#endif
#include "ai_debug_config.h"
#include "al_basictypes.h"
#include "ai_parent_control.h"
#include "al_parent_control.h"
#include "al_fw.h"
#include "unicode.h"

#define AL_PARENT_CONTROL_DEBUG_FLAG (0)
#define AL_PARENT_CONTROL_ERROR_FLAG (1)

#if AL_PARENT_CONTROL_DEBUG_FLAG
	#define PARENT_CONTROL_DEBUG_MSG(fmt, arg...) \
	do { \
		printf("[Debug]%s: %d Line ", __FILE__, __LINE__); \
		printf(fmt, ##arg); \
	} while(0)
#else
	#define PARENT_CONTROL_DEBUG_MSG(fmt, arg...);
#endif

#if AL_PARENT_CONTROL_ERROR_FLAG
	#define PARENT_CONTROL_ERROR_MSG(fmt, arg...) \
	do { \
		printf("[Error]%s: %d Line ", __FILE__, __LINE__); \
		printf(fmt, ##arg); \
	} while(0)
#else
	#define PARENT_CONTROL_ERROR_MSG(fmt, arg...);
#endif

#define PARENTCONTROL_MUTEX_LOCK(Mutex)\
{\
	if(Mutex)\
	{\
		GL_MutexLock(Mutex);\
	}\
}

#define PARENTCONTROL_MUTEX_UNLOCK(Mutex)\
{\
	if(Mutex)\
	{\
		GL_MutexUnlock(Mutex);\
	}\
}

#define RRT_DUMP_FLAG

/* For rating checking */
#define RATINGVALUE_US_BLOCK(tv, dia, lan, sex, vio, child, fv, mpaa) \
	((((tv & 0xF) << 0) | ((dia & 0x7) << 4) | ((lan & 0x7) << 7) \
	| ((sex & 0x7) << 10) | ((vio & 0x7) << 13) | ((child & 0xf) << 16) \
	| ((fv & 0xF) << 20) | ((mpaa & 0xF) << 24)) & 0x0FFFFFFF)
#define RATINGVALUE_TVPG(value) ((value) & 0x00FFFFFF)
#define RATINGVALUE_MPAA(value) ((value) & 0x0F000000)
#define TVPG_MSG_MAX (45)

/* For XDS Content Advisory transform */
#define XDS_RATINGSYSTEM_FIELD(data) \
	(((data[1] & 0x08) | ((data[0] & 0x38) >> 3)) & 0x0F)
#define XDS_MPAA_FIELD(data) (data[0] & 0x07)
#define XDS_TVPG_FIELD(data) (data[1] & 0x07)
#define XDS_CAN_FIELD(data) (data[1] & 0x07)
#define XDS_DIA_FIELD(data) ((data[0] & 0x20) >> 5)
#define XDS_LAN_FIELD(data) ((data[1] & 0x08) >> 3)
#define XDS_SEX_FIELD(data) ((data[1] & 0x10) >> 4)
#define XDS_VIO_FIELD(data) ((data[1] & 0x20) >> 5)
#define XDS_FV_FIELD(data) ((data[1] & 0x20) >> 5)

/* Inner definition */
typedef enum
{
	AI_PARENTCONTROL_MEM_DIMEN = 0,
	AI_PARENTCONTROL_MEM_RATING,
	AI_PARENTCONTROL_MEM_NAME,
	AI_PARENTCONTROL_MEM_MAX,
} AI_PC_MemType_t;

typedef enum
{
    AI_PC_Rating_MPAA,
    AI_PC_Rating_TVPG,
    AI_PC_Rating_CANE,
    AI_PC_Rating_CANF,
    AI_PC_Rating_MAX,
}AI_PC_Rating_System_t;

enum
{
	PC_RATING = 0,
	PC_DETAIL = 4,
};

typedef struct
{
	AL_PC_region_list_t pc_reg_id;
	al_uint8	pc_enable;
} AI_PC_details_t;

typedef struct
{
	al_uint32 u32RatingValue;
	al_uint32 u32RatingMsg;
} AI_PC_Rating_t;

static AI_PC_RRT_t g_stRRTInfo;
static GL_Mutex_t g_ParentControlMutex = al_null;
static AI_pfPCCallback g_pfPCCallbks = al_null;
static al_uint32 g_CurrLockDimen = AL_PC_TV_NULL;
static al_uint32 g_OriginalLockDimen = AL_PC_TV_NULL;

AI_PC_Rating_t g_RatingList_US[] =
{
	//                                      TV D L  S V  C FV MPAA
	{RATINGVALUE_US_BLOCK(1, 0, 0, 0, 0, 0, 0, 0), AL_PC_TV_NULL},		//TV-NONE
	{RATINGVALUE_US_BLOCK(0, 0, 0, 0, 0, 1, 0, 0), AL_PC_US_CHILD|AL_PC_TV_Y},		//TV-Y
	{RATINGVALUE_US_BLOCK(0, 0, 0, 0, 0, 2, 0, 0), AL_PC_US_CHILD|AL_PC_TV_Y7},		//TV-Y7
	{RATINGVALUE_US_BLOCK(0, 0, 0, 0, 0, 2, 1, 0), AL_PC_US_CHILD|AL_PC_TV_Y7_FV},	//TV-Y7-FV
	{RATINGVALUE_US_BLOCK(2, 0, 0, 0, 0, 0, 0, 0), AL_PC_US_TV|AL_PC_TV_G},		//TV-G
	{RATINGVALUE_US_BLOCK(3, 0, 0, 0, 0, 0, 0, 0), AL_PC_US_TV|AL_PC_TV_PG},		//TV-PG
	{RATINGVALUE_US_BLOCK(3, 1, 0, 0, 0, 0, 0, 0), AL_PC_US_DIA|AL_PC_DIA_PG},		//TV-PG-D
	{RATINGVALUE_US_BLOCK(3, 0, 1, 0, 0, 0, 0, 0), AL_PC_US_LAN|AL_PC_LAN_PG},		//TV-PG-L
	{RATINGVALUE_US_BLOCK(3, 0, 0, 1, 0, 0, 0, 0), AL_PC_US_SEX|AL_PC_SEX_PG},		//TV-PG-S
	{RATINGVALUE_US_BLOCK(3, 0, 0, 0, 1, 0, 0, 0), AL_PC_US_VIO|AL_PC_VIO_PG},		//TV-PG-V
	{RATINGVALUE_US_BLOCK(3, 1, 1, 0, 0, 0, 0, 0), AL_PC_US_DIA|AL_PC_DIA_PG},		//TV-PG-D-L
	{RATINGVALUE_US_BLOCK(3, 1, 0, 1, 0, 0, 0, 0), AL_PC_US_DIA|AL_PC_DIA_PG},		//TV-PG-D-S
	{RATINGVALUE_US_BLOCK(3, 1, 0, 0, 1, 0, 0, 0), AL_PC_US_DIA|AL_PC_DIA_PG},		//TV-PG-D-V
	{RATINGVALUE_US_BLOCK(3, 0, 1, 1, 0, 0, 0, 0), AL_PC_US_LAN|AL_PC_LAN_PG},		//TV-PG-L-S
	{RATINGVALUE_US_BLOCK(3, 0, 1, 0, 1, 0, 0, 0), AL_PC_US_LAN|AL_PC_LAN_PG},		//TV-PG-L-V
	{RATINGVALUE_US_BLOCK(3, 0, 0, 1, 1, 0, 0, 0), AL_PC_US_SEX|AL_PC_SEX_PG},		//TV-PG-S-V
	{RATINGVALUE_US_BLOCK(3, 1, 1, 1, 0, 0, 0, 0), AL_PC_US_DIA|AL_PC_DIA_PG},		//TV-PG-D-L-S
	{RATINGVALUE_US_BLOCK(3, 1, 1, 0, 1, 0, 0, 0), AL_PC_US_DIA|AL_PC_DIA_PG},		//TV-PG-D-L-V
	{RATINGVALUE_US_BLOCK(3, 1, 0, 1, 1, 0, 0, 0), AL_PC_US_DIA|AL_PC_DIA_PG},		//TV-PG-D-S-V
	{RATINGVALUE_US_BLOCK(3, 0, 1, 1, 1, 0, 0, 0), AL_PC_US_LAN|AL_PC_LAN_PG},		//TV-PG-L-S-V
	{RATINGVALUE_US_BLOCK(3, 1, 1, 1, 1, 0, 0, 0), AL_PC_US_DIA|AL_PC_DIA_PG},		//TV-PG-D-L-S-V
	{RATINGVALUE_US_BLOCK(4, 0, 0, 0, 0, 0, 0, 0), AL_PC_US_TV|AL_PC_TV_14},		//TV-14
	{RATINGVALUE_US_BLOCK(4, 1, 0, 0, 0, 0, 0, 0), AL_PC_US_DIA|AL_PC_DIA_14},		//TV-14-D
	{RATINGVALUE_US_BLOCK(4, 0, 1, 0, 0, 0, 0, 0), AL_PC_US_LAN|AL_PC_LAN_14},		//TV-14-L
	{RATINGVALUE_US_BLOCK(4, 0, 0, 1, 0, 0, 0, 0), AL_PC_US_SEX|AL_PC_SEX_14},		//TV-14-S
	{RATINGVALUE_US_BLOCK(4, 0, 0, 0, 1, 0, 0, 0), AL_PC_US_VIO|AL_PC_VIO_14},		//TV-14-V
	{RATINGVALUE_US_BLOCK(4, 1, 1, 0, 0, 0, 0, 0), AL_PC_US_DIA|AL_PC_DIA_14},		//TV-14-D-L
	{RATINGVALUE_US_BLOCK(4, 1, 0, 1, 0, 0, 0, 0), AL_PC_US_DIA|AL_PC_DIA_14},		//TV-14-D-S
	{RATINGVALUE_US_BLOCK(4, 1, 0, 0, 1, 0, 0, 0), AL_PC_US_DIA|AL_PC_DIA_14},		//TV-14-D-V
	{RATINGVALUE_US_BLOCK(4, 0, 1, 1, 0, 0, 0, 0), AL_PC_US_LAN|AL_PC_LAN_14},		//TV-14-L-S
	{RATINGVALUE_US_BLOCK(4, 0, 1, 0, 1, 0, 0, 0), AL_PC_US_LAN|AL_PC_LAN_14},		//TV-14-L-V
	{RATINGVALUE_US_BLOCK(4, 0, 0, 1, 1, 0, 0, 0), AL_PC_US_SEX|AL_PC_SEX_14},		//TV-14-S-V
	{RATINGVALUE_US_BLOCK(4, 1, 1, 1, 0, 0, 0, 0), AL_PC_US_DIA|AL_PC_DIA_14},		//TV-14-D-L-S
	{RATINGVALUE_US_BLOCK(4, 1, 1, 0, 1, 0, 0, 0), AL_PC_US_DIA|AL_PC_DIA_14},		//TV-14-D-L-V
	{RATINGVALUE_US_BLOCK(4, 1, 0, 1, 1, 0, 0, 0), AL_PC_US_DIA|AL_PC_DIA_14},		//TV-14-D-S-V
	{RATINGVALUE_US_BLOCK(4, 0, 1, 1, 1, 0, 0, 0), AL_PC_US_LAN|AL_PC_LAN_14},		//TV-14-L-S-V
	{RATINGVALUE_US_BLOCK(4, 1, 1, 1, 1, 0, 0, 0), AL_PC_US_DIA|AL_PC_DIA_14},		//TV-14-D-L-S-V
	{RATINGVALUE_US_BLOCK(5, 0, 0, 0, 0, 0, 0, 0), AL_PC_US_TV|AL_PC_TV_MA},		//TV-MA
	{RATINGVALUE_US_BLOCK(5, 0, 1, 0, 0, 0, 0, 0), AL_PC_US_LAN|AL_PC_LAN_MA},		//TV-MA-L
	{RATINGVALUE_US_BLOCK(5, 0, 0, 1, 0, 0, 0, 0), AL_PC_US_SEX|AL_PC_SEX_MA},		//TV-MA-S
	{RATINGVALUE_US_BLOCK(5, 0, 0, 0, 1, 0, 0, 0), AL_PC_US_VIO|AL_PC_VIO_MA},		//TV-MA-V
	{RATINGVALUE_US_BLOCK(5, 0, 1, 1, 0, 0, 0, 0), AL_PC_US_LAN|AL_PC_LAN_MA},		//TV-MA-L-S
	{RATINGVALUE_US_BLOCK(5, 0, 1, 0, 1, 0, 0, 0), AL_PC_US_LAN|AL_PC_LAN_MA},		//TV-MA-L-V
	{RATINGVALUE_US_BLOCK(5, 0, 0, 1, 1, 0, 0, 0), AL_PC_US_SEX|AL_PC_SEX_MA},		//TV-MA-S-V
	{RATINGVALUE_US_BLOCK(5, 0, 1, 1, 1, 0, 0, 0), AL_PC_US_LAN|AL_PC_LAN_MA},		//TV-MA-L-S-V
	{RATINGVALUE_US_BLOCK(0, 0, 0, 0, 0, 0, 0, 1), AL_PC_US_MPAA|AL_PC_MPAA_NA},	//MPAA-N/A
	{RATINGVALUE_US_BLOCK(0, 0, 0, 0, 0, 0, 0, 2), AL_PC_US_MPAA|AL_PC_MPAA_G},		//MPAA-G
	{RATINGVALUE_US_BLOCK(0, 0, 0, 0, 0, 0, 0, 3), AL_PC_US_MPAA|AL_PC_MPAA_PG},	//MPAA-PG
	{RATINGVALUE_US_BLOCK(0, 0, 0, 0, 0, 0, 0, 4), AL_PC_US_MPAA|AL_PC_MPAA_PG_13},	//MPAA-PG13
	{RATINGVALUE_US_BLOCK(0, 0, 0, 0, 0, 0, 0, 5), AL_PC_US_MPAA|AL_PC_MPAA_R},		//MPAA-R
	{RATINGVALUE_US_BLOCK(0, 0, 0, 0, 0, 0, 0, 6), AL_PC_US_MPAA|AL_PC_MPAA_NC_17},	//MPAA-NC-17
	{RATINGVALUE_US_BLOCK(0, 0, 0, 0, 0, 0, 0, 7), AL_PC_US_MPAA|AL_PC_MPAA_X},		//MPAA-X
	{RATINGVALUE_US_BLOCK(0, 0, 0, 0, 0, 0, 0, 8), AL_PC_US_MPAA|AL_PC_MPAA_NR},	//MPAA-Not Rated
};

AL_Return_t _AI_PC_ManageMem(al_void ** pData, al_uint8 uLenth, AI_PC_MemType_t eMemType)
{
	al_uint8 uCount1 = 0;
	al_uint8 uCount2 = 0;

	if (pData == al_null)
	{
		return AL_INVALID_PARAM;
	}
	
	/**< Free memery */
	if (*pData != al_null)
	{
		switch (eMemType)
		{
			case AI_PARENTCONTROL_MEM_DIMEN:
				{
					AI_PC_RatingDimension_t *pDimension = (AI_PC_RatingDimension_t *)(*pData);

					for (uCount1 = 0; uCount1 < uLenth; uCount1++)
					{
						if (pDimension[uCount1].RatingValue != al_null)
						{
							for (uCount2 = 0; uCount2< pDimension[uCount1].NumOfValues; uCount2++)
							{
								if (pDimension[uCount1].RatingValue[uCount2].String != al_null)
								{
									printf("free rating value string !!!!\n");
									AL_SAFE_FREE(pDimension[uCount1].RatingValue[uCount2].String);
								}
							}
							printf("free rating value !!!!\n");
							AL_SAFE_FREE(pDimension[uCount1].RatingValue);
						}

						if (pDimension[uCount1].stDimensionName.String != al_null)
						{printf("free dimension name string !!!!\n");
							AL_SAFE_FREE(pDimension[uCount1].stDimensionName.String);
						}
					}
					printf("free dimension !!!!\n");
					AL_SAFE_FREE(pDimension);
					*pData = al_null;
				}
				break;

			case AI_PARENTCONTROL_MEM_RATING:
				{
					AI_PC_RatingValue_t *pRatingValue = (AI_PC_RatingValue_t *)(*pData);

					for (uCount2 = 0; uCount2< uLenth; uCount2++)
					{
						if (pRatingValue[uCount2].String != al_null)
						{
							AL_SAFE_FREE(pRatingValue[uCount2].String);
						}
					}

					AL_SAFE_FREE(pRatingValue);
					*pData = al_null;
				}
				break;

			case AI_PARENTCONTROL_MEM_NAME:
				{
					al_uint8 *pName = (al_uint8 *)(*pData);
					AL_SAFE_FREE(pName);
					*pData = al_null;
				}
				break;

			default:
				PARENT_CONTROL_ERROR_MSG("parental control invalid memery type.\n");
				break;
		}
	}
	/**< Alloc memery */
	else
	{
		switch (eMemType)
		{
			case AI_PARENTCONTROL_MEM_DIMEN:
				{
					(*pData) = (AI_PC_RatingDimension_t *)al_zero_malloc(sizeof(AI_PC_RatingDimension_t) * uLenth);
					printf("alloc dimension !!!!\n");
				}
				break;

			case AI_PARENTCONTROL_MEM_RATING:
				{
					(*pData) = (AI_PC_RatingValue_t *)al_zero_malloc(sizeof(AI_PC_RatingValue_t) * uLenth);
					printf("alloc rating value !!!!\n");
				}
				break;

			case AI_PARENTCONTROL_MEM_NAME:
				{
					(*pData) = (al_uint8 *)al_zero_malloc(sizeof(al_uint8) * uLenth);
					printf("alloc string !!!!\n");
				}
				break;

			default:
				PARENT_CONTROL_ERROR_MSG("parental control invalid memery type.\n");
				break;
		}

		if (*pData == al_null)
		{
			PARENT_CONTROL_ERROR_MSG("parental control alloc memery failed.\n");
			return AL_FAILURE;
		}
	}

	return AL_SUCCESS;
}

#ifdef CONFIG_ATSC_SYSTEM
static AL_Return_t _AI_PC_GetDrrtLockFlag(
	AL_PC_DimenUserSet_t stUserSeting, 
	al_uint8 u8Dim, al_uint8 u8Value, al_bool *pbEnable)
{
    al_uint8 *p; 

    if (al_null == pbEnable)
    {
        return AL_INVALID_PARAM;
    }

    p = &(stUserSeting.u8aDrrtUserPerference[u8Dim][0]);
    p += (u8Value>>3);

    *pbEnable = ( (*p) & (0x80>>(u8Value&0x07)) ) ? al_true : al_false;
	
    return AL_SUCCESS;
}

static AL_Return_t _AI_PC_SetDrrtLockFlag(
	AL_PC_DimenUserSet_t *pstUserSeting, 
	al_uint8 u8Dim, al_uint8 u8Value, al_bool bEnable)
{
	al_uint8 *p;

    p = &(pstUserSeting->u8aDrrtUserPerference[u8Dim][0]);
    p += (u8Value>>3);

    if(al_true == bEnable)    
    {
        (*p) |= (0x80>>(u8Value&0x07));
    }
    else
    {
        (*p) &= ~(0x80>>(u8Value&0x07));
    }
    
    return AL_SUCCESS;
}
#endif

/**
* @brief Gets the User Set Rating Value from Flash Memory
*
* @param rating_level[output] Pointer to store the data
*
* @return AL_SUCCESS if get demension success, AL_FAILURE otherwise.
*/
static AL_Return_t _AI_PC_GetUserRatingLevel(al_uint32 *rating_level)
{
	frmwrk_pfOpConext_t pfGetContext = al_null;
	
	if (rating_level == NULL)
	{
		PARENT_CONTROL_ERROR_MSG(" INVALID Input Parameters\n");
		return AL_FAILURE;
	}

	AL_FW_GetContextCb(&pfGetContext);
	
	if (pfGetContext != al_null)
	{
		pfGetContext(FW_CONTEXT_TYPE_RRT_USERSET, FW_CONTEXT_OP_TYPE_READ, (al_void *)rating_level ,0);
	}

	return AL_SUCCESS;
}

/**
* @brief Sets the User Set Rating Value into Flash Memory;
*
* @param rating_level[input] data to store
*
* @return AL_SUCCESS if get demension success, AL_FAILURE otherwise.
*/
static AL_Return_t _AI_PC_SetUserRatingLevel(al_uint32 rating_level)
{
	frmwrk_pfOpConext_t pfGetContext = al_null;
	
	AL_FW_GetContextCb(&pfGetContext);
	
	if (pfGetContext != al_null)
	{
		pfGetContext(FW_CONTEXT_TYPE_RRT_USERSET, FW_CONTEXT_OP_TYPE_WRITE, (al_void *)&rating_level ,0);
	}

	return AL_SUCCESS;
}

static al_uint32 _AI_PC_GetUSRatingDimen(UINT32 u32RatingValue)
{
	al_uint8 i = 0;
	al_uint8 len = sizeof(g_RatingList_US) / sizeof(g_RatingList_US[0]);
	for (i = 0; i < len; i++)
	{
		if (i < TVPG_MSG_MAX)
		{
			if (RATINGVALUE_TVPG(u32RatingValue)
				== RATINGVALUE_TVPG(g_RatingList_US[i].u32RatingValue))
			{
				return g_RatingList_US[i].u32RatingMsg;
			}
		}
		else
		{
			if (RATINGVALUE_MPAA(u32RatingValue)
				== RATINGVALUE_MPAA(g_RatingList_US[i].u32RatingValue))
			{
				return g_RatingList_US[i].u32RatingMsg;
			}
		}
	}

	return AL_PC_TV_NULL;
}

static al_uint32 _AI_PC_GetCANRatingDimen(UINT8 Ch0,UINT8 Ch1, UINT32 RatingSystem)
{
	if ((Ch0 == 0) && (RatingSystem == AI_PC_Rating_CANE))
	{
		return AL_PC_CAN_ENG|AL_PC_ENG_EXEMPT;
	}
	else if ((Ch1 == 0) && (RatingSystem == AI_PC_Rating_CANF))
	{
		return AL_PC_CAN_FRA |AL_PC_FRA_EXEMPT;
	}
	else if (Ch0 > 0 &&(RatingSystem == AI_PC_Rating_CANE))
	{
		return AL_PC_CAN_ENG|(AL_PC_ENG_NULL+ Ch0);
	}
	else if (Ch1 > 0 && (RatingSystem == AI_PC_Rating_CANF))
	{
		return AL_PC_CAN_FRA |(AL_PC_FRA_NULL + Ch1);
	}
	return AL_PC_ENG_NULL;
}

 /**
* @brief API to compare Ratings of Stream & User Set;
*
* @param ch_rat[input] channel rating
*
* @param user_rat[input] user rating
*
* @return AL_RATING_ALLOWED / AL_RATING_BLOCKED 
*/
static AL_Return_t	_AI_PC_CheckRating(al_uint8 *ch_rat, al_uint32 user_rat, AI_PC_Rating_System_t RatingSystem)
{
	/*NEED TO MODIFY LOGIC*/
	al_uint32 temp_rat = 0;
	AL_PC_region_list_t region = 0;
	if (ch_rat == NULL)
	{
		PARENT_CONTROL_ERROR_MSG("NULL Parameter\n");
		return AL_FAILURE;
	}
#ifdef CONFIG_ATSC_SYSTEM
	if (AL_SUCCESS != AI_PC_GetCurrentRegion(&region))
	{
		PARENT_CONTROL_ERROR_MSG("FAILED TO GET CURREN REGION\n");
		return AL_FAILURE;
	}
#else
    switch(RatingSystem)
    {
        case AI_PC_Rating_MPAA:
        case AI_PC_Rating_TVPG:
            region = AL_PC_REG_USA;
            break;
        case AI_PC_Rating_CANE:
        case AI_PC_Rating_CANF:
            region = AL_PC_REG_CANADA;
            break;
        case AI_PC_Rating_MAX:
        default:
            break;
    }
#endif
	g_CurrLockDimen = AL_PC_TV_NULL;
	g_OriginalLockDimen = AL_PC_TV_NULL;

	switch((AL_PC_region_list_t)region)
	{
		case AL_PC_REG_USA:
			g_OriginalLockDimen = _AI_PC_GetUSRatingDimen(
				RATINGVALUE_US_BLOCK(ch_rat[0], ch_rat[1], ch_rat[2],
				ch_rat[3], ch_rat[4], ch_rat[5], ch_rat[6], ch_rat[7]));
			if((ch_rat[0]== 0) && (ch_rat[5]== 0) && (ch_rat[7]== 0))
			{
				return AL_RATING_ALLOWED;
			}
			else if(ch_rat[0] != 0)
			{

				if (ch_rat[0] == 1)
				{
					return AL_RATING_ALLOWED;
				}
				else if (ch_rat[0] == 2)
				{
					temp_rat = (ch_rat[0] - 1 );
					if((((user_rat & 0x0F0000) >> 16) > 0)
						&& temp_rat >= ((user_rat & 0x0F0000) >> 16))
					{
						g_CurrLockDimen = _AI_PC_GetUSRatingDimen(
							RATINGVALUE_US_BLOCK(ch_rat[0], ch_rat[1], ch_rat[2], 
							ch_rat[3], ch_rat[4], ch_rat[5], ch_rat[6], ch_rat[7]));
						return AL_RATING_BLOCKED;
					}	
				}		
				else if ((ch_rat[0] > 2)&&(ch_rat[1] == 0)&&(ch_rat[2] == 0) 
					&& (ch_rat[3] == 0)&&(ch_rat[4] == 0))
				{
					temp_rat = (ch_rat[0] - 1);
					if ((((user_rat & 0x0F0000) >> 16) > 0)
						&& temp_rat >= ((user_rat & 0x0F0000) >> 16))
					{
						g_CurrLockDimen = _AI_PC_GetUSRatingDimen(
							RATINGVALUE_US_BLOCK(ch_rat[0], ch_rat[1], ch_rat[2], 
							ch_rat[3], ch_rat[4], ch_rat[5], ch_rat[6], ch_rat[7]));
						return AL_RATING_BLOCKED;
					}				
				}
				else	if ((((user_rat&0x7) > 0) && ((ch_rat[0] -2)*ch_rat[1]) >= (al_uint8)(user_rat&0x7))
					|| ((((user_rat&0x38)>> 3) > 0) && ((ch_rat[0] -2)*ch_rat[2]) >= (al_uint8)((user_rat&0x38)>> 3)) 
					|| ((((user_rat&0x1C0) >> 6) > 0) && ((ch_rat[0] -2)*ch_rat[3]) >= (al_uint8)((user_rat&0x1C0) >> 6))
					|| ((((user_rat&0xE00) >> 9) > 0) && ((ch_rat[0] -2)*ch_rat[4]) >= (al_uint8)((user_rat&0xE00) >> 9)))
				{
					g_CurrLockDimen = _AI_PC_GetUSRatingDimen(
						RATINGVALUE_US_BLOCK(ch_rat[0], ch_rat[1], ch_rat[2], 
						ch_rat[3], ch_rat[4], ch_rat[5], ch_rat[6], ch_rat[7]));
					return AL_RATING_BLOCKED;							
				}
			}
			if (ch_rat[5] != 0)
			{
				temp_rat = (ch_rat[5] + ch_rat[6]);
				if ((((user_rat & 0x07000) >> 12) > 0)
					&& temp_rat >= ((user_rat & 0x07000) >> 12))
				{
					g_CurrLockDimen = _AI_PC_GetUSRatingDimen(
						RATINGVALUE_US_BLOCK(ch_rat[0], ch_rat[1], ch_rat[2], 
						ch_rat[3], ch_rat[4], ch_rat[5], ch_rat[6], ch_rat[7]));
					return AL_RATING_BLOCKED;
				}
			}
			if (ch_rat[7] != 0)
			{
				temp_rat = (ch_rat[7]);
				if ((temp_rat == AL_PC_MPAA_NR))
				{
					return AL_RATING_ALLOWED;
				}
				else if ((temp_rat < AL_PC_MPAA_NR) 
					&& (((user_rat & 0xF00000) >> 20) > 0)
					&& (temp_rat >= ((user_rat & 0xF00000) >> 20)))
				{
					g_CurrLockDimen = _AI_PC_GetUSRatingDimen(
						RATINGVALUE_US_BLOCK(ch_rat[0], ch_rat[1], ch_rat[2], 
						ch_rat[3], ch_rat[4], ch_rat[5], ch_rat[6], ch_rat[7]));
					return AL_RATING_BLOCKED;
				}
			}
			return AL_RATING_ALLOWED;
		case AL_PC_REG_CANADA:
			g_OriginalLockDimen = _AI_PC_GetCANRatingDimen(ch_rat[0], ch_rat[1],RatingSystem);
			if ((ch_rat[0] == 0) && ((((user_rat & 0xF000000) >> 24) & 0x8) > 0) && (RatingSystem == AI_PC_Rating_CANE))
			{
				g_CurrLockDimen = AL_PC_CAN_ENG|AL_PC_ENG_EXEMPT;
				return AL_RATING_BLOCKED;
			}
			else if ((ch_rat[1] == 0) && ((((user_rat & 0xF0000000) >> 28) & 0x8) > 0) && (RatingSystem == AI_PC_Rating_CANF))
			{
				g_CurrLockDimen = AL_PC_CAN_FRA |AL_PC_FRA_EXEMPT;
				return AL_RATING_BLOCKED;
			}
			else if ((ch_rat[0] == 0) && (ch_rat[1] == 0))
			{
				return AL_RATING_ALLOWED;
			}
			else if ((((user_rat & 0xF000000) >> 24) & 0x7) > 0 && ch_rat[0] >= (((user_rat & 0xF000000) >> 24) & 0x7)) 
			{
				g_CurrLockDimen = AL_PC_CAN_ENG|(AL_PC_ENG_NULL+ ch_rat[0]);
				return AL_RATING_BLOCKED;
			}
			else if ((((user_rat & 0xF0000000) >> 28) & 0x7) > 0 && ch_rat[1] >= (((user_rat & 0xF0000000) >> 28) & 0x7))
			{
				g_CurrLockDimen = AL_PC_CAN_FRA |(AL_PC_FRA_NULL + ch_rat[1]);
				return AL_RATING_BLOCKED;
			}
			else
			{
				return AL_RATING_ALLOWED;
			}
			break;
		default:
			return AL_FAILURE;
	}
}

/**
* @brief check rating value according to content advisory XDS data, refer to CEA608C 9.5.1.5.
*
* @param pu8Data[input] the content advisory XDS data which has 2-byte data.
*
* @param bLocked[output] geted lock state.
*
* @return AL_SUCCESS check rating successed, other value check rating failed.
*/
AL_Return_t AI_PC_CheckXDSRating(al_uint8 *pu8Data, al_bool *bLocked)
{
    AI_PC_Rating_System_t RatingSystem = AI_PC_Rating_MAX;
	al_uint8	pc_ratval[8];
	al_uint32	pc_user = 0;
	
	if (pu8Data == al_null)
	{
		return AL_INVALID_PARAM;
	}
	memset(pc_ratval, 0, sizeof(pc_ratval));
	/* Transform XDS data to digital format */
	/* Check MPA '--00' or '--10' */
	if ((XDS_RATINGSYSTEM_FIELD(pu8Data) & 0x03) == 0
		|| (XDS_RATINGSYSTEM_FIELD(pu8Data) & 0x03) == 2)
	{
		pc_ratval[7] =  XDS_MPAA_FIELD(pu8Data) + 1;
        RatingSystem = AI_PC_Rating_MPAA;
	}
	/* Check US TVPG 'LD01' */
	else if ((XDS_RATINGSYSTEM_FIELD(pu8Data) & 0x03) == 1)
	{
		/* Check TV-Y '001' */
		if (XDS_TVPG_FIELD(pu8Data) == 1)
		{
			pc_ratval[5] = 1;
		}
		/* Check TV-Y7 '010' */
		else if (XDS_TVPG_FIELD(pu8Data) == 2)
		{
			pc_ratval[5] = 2;
			/* Assign FV value */
			pc_ratval[6] = XDS_FV_FIELD(pu8Data);
		}
		/* Check TV-G '011' */
		else if (XDS_TVPG_FIELD(pu8Data) == 3)
		{
			pc_ratval[0] = 2;
		}
		/* Check TV-PG '100' or TV-14 '101'*/
		else if (XDS_TVPG_FIELD(pu8Data) == 4
			|| XDS_TVPG_FIELD(pu8Data) == 5)
		{
			pc_ratval[0] = XDS_TVPG_FIELD(pu8Data) - 1;
			pc_ratval[1] = XDS_DIA_FIELD(pu8Data);
			pc_ratval[2] = XDS_LAN_FIELD(pu8Data);
			pc_ratval[3] = XDS_SEX_FIELD(pu8Data);
			pc_ratval[4] = XDS_VIO_FIELD(pu8Data);
		}
		/* Check TV-MA '110' */
		else if (XDS_TVPG_FIELD(pu8Data) == 6)
		{
			pc_ratval[0] = 5;
			pc_ratval[2] = XDS_LAN_FIELD(pu8Data);
			pc_ratval[3] = XDS_SEX_FIELD(pu8Data);
			pc_ratval[4] = XDS_VIO_FIELD(pu8Data);
		}
		/* TV-NONE */
		else
		{
			pc_ratval[0] = 1;
		}
        RatingSystem = AI_PC_Rating_TVPG;
	}
	/* Check Canadian English Language Rating '0011' */
	else if (XDS_RATINGSYSTEM_FIELD(pu8Data) == 3)
	{
		pc_ratval[0] = XDS_CAN_FIELD(pu8Data);
        RatingSystem = AI_PC_Rating_CANE;
	}
	/* Check Canadian French Language Rating '0111' */
	else if (XDS_RATINGSYSTEM_FIELD(pu8Data) == 7)
	{
		pc_ratval[1] = XDS_CAN_FIELD(pu8Data);
        RatingSystem = AI_PC_Rating_CANF;
	}
	if (AL_SUCCESS != _AI_PC_GetUserRatingLevel(&pc_user))
	{
		return AL_FAILURE;
	}
    if(AL_RATING_BLOCKED ==  _AI_PC_CheckRating(pc_ratval, pc_user, RatingSystem))
	{
		*bLocked = al_true;
	}
	return AL_SUCCESS;
}

#ifdef CONFIG_ATSC_SYSTEM
/**
* @brief regist to mid psi monitor callback function for get and parse RRT information.
*
* @param pData[output] RRT information.
*
* @return none.
*/
al_void AI_PC_RrtCallback(al_void *pData)
{
	printf("[%s:%d] ENTERED !!!!!!!!!!!!!!\n",__FUNCTION__,__LINE__);
	MID_PSIP_RRTSection_t *pRRT = (MID_PSIP_RRTSection_t *)pData;
	al_uint8 uCount1 = 0;
	al_uint8 uCount2 = 0;
	al_void *pMemery = al_null;

	if (pRRT == al_null)
	{
		return;
	}

	/**< Only dispose DRRT, because for RRT rating only support TV-Rating/MPAA static rating information */
	if (pRRT->enRatingRegionValue != REG_DOWNLOADABLE_USA)
	{
		return;
	}

	PARENTCONTROL_MUTEX_LOCK(g_ParentControlMutex);
	
	/**< Free old rrt data memery */
	if (g_stRRTInfo.RatingDimensions != al_null)
	{
		_AI_PC_ManageMem((al_void *)(&(g_stRRTInfo.RatingDimensions)), 
			g_stRRTInfo.NumOfDimensions, AI_PARENTCONTROL_MEM_DIMEN);
	}

	g_stRRTInfo.NumOfDimensions = pRRT->ucNumOfDimensions;
	
	if (pRRT->ucNumOfDimensions == 0)
	{
		PARENTCONTROL_MUTEX_UNLOCK(g_ParentControlMutex);
		return;
	}

	/**< Alloc memery for new rrt data */
	pMemery = al_null;
	if (AL_SUCCESS != _AI_PC_ManageMem(&pMemery, 
		g_stRRTInfo.NumOfDimensions, AI_PARENTCONTROL_MEM_DIMEN))
	{
		PARENTCONTROL_MUTEX_UNLOCK(g_ParentControlMutex);
		return;
	}
	
	g_stRRTInfo.RatingDimensions = (AI_PC_RatingDimension_t *)pMemery;
	
	for (uCount1 = 0; uCount1 < pRRT->ucNumOfDimensions; uCount1++)
	{
		pMemery = al_null;
		if (AL_SUCCESS == _AI_PC_ManageMem(&pMemery, 
			MAX_DIMENNAME_LEN, AI_PARENTCONTROL_MEM_NAME))
		{
			g_stRRTInfo.RatingDimensions[uCount1].stDimensionName.String =
				(al_uint8 *)pMemery;
			g_stRRTInfo.RatingDimensions[uCount1].stDimensionName.StrLen = 
				pRRT->pstRatingDimensions[uCount1].stDimensionName.usStrLen;
			AI_MultiStr_GetExtMsg(pRRT->pstRatingDimensions[uCount1].stDimensionName.pString,
				al_null, 0, al_null, g_stRRTInfo.RatingDimensions[uCount1].stDimensionName.String, 
				(al_uint16 *)&(g_stRRTInfo.RatingDimensions[uCount1].stDimensionName.StrLen));
		}

		pMemery = al_null;
		if (AL_SUCCESS == _AI_PC_ManageMem(&pMemery, 
			pRRT->pstRatingDimensions[uCount1].ucNumOfValues, AI_PARENTCONTROL_MEM_RATING))
		{
			g_stRRTInfo.RatingDimensions[uCount1].RatingValue =
				(AI_PC_RatingValue_t *)pMemery;
			g_stRRTInfo.RatingDimensions[uCount1].NumOfValues = 
				pRRT->pstRatingDimensions[uCount1].ucNumOfValues;
		}
				
		for (uCount2 = 0; uCount2 < pRRT->pstRatingDimensions[uCount1].ucNumOfValues; uCount2++)
		{
			pMemery = al_null;
			if (AL_SUCCESS == _AI_PC_ManageMem(&pMemery, 
				MAX_RATINGNAME_LEN, AI_PARENTCONTROL_MEM_NAME))
			{
				g_stRRTInfo.RatingDimensions[uCount1].RatingValue[uCount2].String =
					(al_uint8 *)pMemery;
				g_stRRTInfo.RatingDimensions[uCount1].RatingValue[uCount2].StrLen = 
					pRRT->pstRatingDimensions[uCount1].pstRatingValues[uCount2].stAbbrevRatingValueTxt.usStrLen;
				AI_MultiStr_GetExtMsg(pRRT->pstRatingDimensions[uCount1].pstRatingValues[uCount2].stAbbrevRatingValueTxt.pString,
					al_null, 0, al_null, g_stRRTInfo.RatingDimensions[uCount1].RatingValue[uCount2].String, 
				(al_uint16 *)&(g_stRRTInfo.RatingDimensions[uCount1].RatingValue[uCount2].StrLen));
			}
		}

		g_stRRTInfo.RatingDimensions[uCount1].GraduatedScale = 
			pRRT->pstRatingDimensions[uCount1].bGraduatedScale;
	}

	if (g_pfPCCallbks != al_null)
	{
		g_pfPCCallbks(AI_PC_DRRT_UPDATE, 0);
	}
#ifdef RRT_DUMP_FLAG
		printf("===== dump rrt Begin =====\n");
		printf("Num of dim = %d\n", g_stRRTInfo.NumOfDimensions);
		al_uint8 ii = 0;
		al_uint8 jj = 0;
		al_uint8 kk = 0;
		RatingDimensions_t *pstDimension = al_null;
		RatingValues_t *pstRatingValue = al_null;
		
		for(ii = 0; ii < pRRT->ucNumOfDimensions; ii++) 
		{
			pstDimension = &(pRRT->pstRatingDimensions[ii]);
			printf("-- Dim %d, Grad_Scale = %d, Rating Value= %d --\nDim Name =", ii, pstDimension->bGraduatedScale, pstDimension->ucNumOfValues);
			// dump dim name
			for(jj = 0; jj < pstDimension->stDimensionName.usStrLen; jj++) 
			{
				printf("%c", pstDimension->stDimensionName.pString[jj]);
			}
			printf("(len = %d)\n", pstDimension->stDimensionName.usStrLen);
	
			// dump value
			for(jj = 0; jj < pstDimension->ucNumOfValues; jj++) 
			{
				printf("Value %d = ", jj);
				pstRatingValue = &(pstDimension->pstRatingValues[jj]);
				for(kk = 0; kk < pstRatingValue->stAbbrevRatingValueTxt.usStrLen; kk++) 
				{
					printf("%c", pstRatingValue->stAbbrevRatingValueTxt.pString[kk]);
				}
				printf("(len=%d)\n", pstRatingValue->stAbbrevRatingValueTxt.usStrLen);
			}
		}
		printf("===== dump RRT End =====\n");
#endif
	PARENTCONTROL_MUTEX_UNLOCK(g_ParentControlMutex);
	printf("[%s:%d] EXITED !!!!!!!!!!!!!!\n",__FUNCTION__,__LINE__);
}
#endif

/**
* @brief parent control init function.
*
* @param pfPCCallbks[input] parent control notify framwork callback function.
*
* @return AL_SUCCESS if initialization is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_PC_Init(AI_pfPCCallback pfPCCallbks)
{
#ifdef CONFIG_ATSC_SYSTEM
	AI_PC_details_t pc_detail = {AL_PC_REG_NONE, 0};
#endif
	frmwrk_pfOpConext_t pfGetContext = al_null;
	
	memset(&g_stRRTInfo, 0, sizeof(AI_PC_RRT_t));
	
	if(g_ParentControlMutex == al_null)
	{
		if (GL_SUCCESS != GL_MutexCreate("ParentControlMutex", &g_ParentControlMutex))
		{
			PARENT_CONTROL_ERROR_MSG("parental control create mutex failed.\n");
			return AL_FAILURE;
		}
	}

	if (pfPCCallbks != al_null)
	{
		g_pfPCCallbks = pfPCCallbks;
	}

	AL_FW_GetContextCb(&pfGetContext);

#ifdef CONFIG_ATSC_SYSTEM
	if (pfGetContext != al_null)
	{
		pfGetContext(FW_CONTEXT_TYPE_REGION, FW_CONTEXT_OP_TYPE_READ,
				(al_void *)&pc_detail.pc_reg_id ,0);
	}

	if ((pc_detail.pc_reg_id != AL_PC_REG_USA) && (pc_detail.pc_reg_id != AL_PC_REG_CANADA))
	{
		/* US and Canada only */
		PARENT_CONTROL_ERROR_MSG("Invalid Region!  Plz Check...\n");
		return AL_FAILURE;
	}
#endif
	return AL_SUCCESS;
}

/**
* @brief parent control uninit function.
*
* @param none.
*
* @return AL_SUCCESS if initialization is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_PC_Uninit(al_void)
{
	if (g_ParentControlMutex != al_null)
	{
		if (GL_SUCCESS != GL_MutexDelete(g_ParentControlMutex))
		{
			PARENT_CONTROL_ERROR_MSG("parental control delete mutex failed.\n");
		}
	}

	g_ParentControlMutex = al_null;

	/**< Free old rrt data memery */
	if (g_stRRTInfo.RatingDimensions != al_null)
	{
		_AI_PC_ManageMem((al_void *)(&(g_stRRTInfo.RatingDimensions)), 
			g_stRRTInfo.NumOfDimensions, AI_PARENTCONTROL_MEM_DIMEN);
	}

	return AL_SUCCESS;
}
#ifdef CONFIG_ATSC_SYSTEM
/**
* @brief set current region set by user
*
* @param region_id[input] specify the region.
*
* @return AL_SUCCESS if set region success, AL_FAILURE otherwise.
*/
AL_Return_t AI_PC_SetCurrentRegion(AL_PC_region_list_t region_id)
{
	frmwrk_pfOpConext_t pfGetContext = al_null;

	AL_FW_GetContextCb(&pfGetContext);
	
	if (pfGetContext != al_null)
	{
		pfGetContext(FW_CONTEXT_TYPE_REGION, FW_CONTEXT_OP_TYPE_WRITE,
				(al_void *)&region_id ,0);
	}

	return AL_SUCCESS;
}
/**
* @brief get current region set by user
*
* @param region_id[input] specify the region.
*
* @return AL_SUCCESS if set region success, AL_FAILURE otherwise.
*/
AL_Return_t AI_PC_GetCurrentRegion(AL_PC_region_list_t *region_id)
{
	frmwrk_pfOpConext_t pfGetContext = al_null;

	AL_FW_GetContextCb(&pfGetContext);
	
	if (pfGetContext != al_null)
	{
		pfGetContext(FW_CONTEXT_TYPE_REGION, FW_CONTEXT_OP_TYPE_READ,
				(al_void *)region_id ,0);
	}
	return AL_SUCCESS;
}
#endif
/**
* @brief get dimension details
*
* @param pstDime[output] pointer to the demension data.
*
* @return AL_SUCCESS if get demension success, AL_FAILURE otherwise.
*/
AL_Return_t AL_PC_GetRating(AL_PC_dime_t *pstDime)
{
	al_uint32	user_rat =0;
	
	if (pstDime == NULL)
	{
		PARENT_CONTROL_ERROR_MSG("INVALID INPUT PARAMS\n");
		return AL_FAILURE;
	}
	
	if (AL_SUCCESS != _AI_PC_GetUserRatingLevel(&user_rat))
	{
		PARENT_CONTROL_ERROR_MSG("FAILED TO GET USER RATING LEVEL\n");
		return AL_FAILURE;
	}
#ifdef CONFIG_ATSC_SYSTEM
	if (AL_SUCCESS != AI_PC_GetCurrentRegion(&pstDime->region))
	{
		PARENT_CONTROL_ERROR_MSG("Unable to get Current Region\n");
		return	AL_FAILURE;
	}
#endif
	switch (pstDime->region)
	{
		/* Rating Value stored 
		** b0-b2 => Dialog
		** b3-b5 => Language
		** b6-b8 => Sex
		** b9-b11 => Violence
		** b12-b14 => Child
		** b16-b19 => TV
		** b20-b23 => MPAA
		** b24-b27 => CANADA Eng
		** b28-b31 => Canada French
		*/
		case AL_PC_REG_USA:
			pstDime->us_mem.us_dia = user_rat & 0x7;
			pstDime->us_mem.us_lan = (user_rat & 0x38) >> 3;
			pstDime->us_mem.us_sex = (user_rat & 0x1c0) >> 6;
			pstDime->us_mem.us_vio = (user_rat & 0xe00) >> 9;
			pstDime->us_mem.us_child = (user_rat & 0x7000) >> 12;
			pstDime->us_mem.us_tv = (user_rat & 0xf0000) >> 16;
			pstDime->us_mem.us_mpaa = (user_rat & 0xf00000) >> 20;
			break;

		case AL_PC_REG_CANADA:
			pstDime->can_mem.can_eng = (user_rat & 0xf000000) >> 24;
			pstDime->can_mem.can_fra = (user_rat & 0xf0000000) >> 28;
			break;
			
		default:
			break;
	}
	
	return AL_SUCCESS;
}

/**
* @brief API to  store User Set Rating level to flash
*
* @param pststDime[iutput] the demension data.
* 
* @return AL_SUCCESS if encode success, AL_FAILURE otherwise.
*/
AL_Return_t AL_PC_StoreRating(AL_PC_dime_t *pststDime)
{
	al_uint32 user_rat = 0;
	al_uint32 old_rat = 0;
	
	if (AL_SUCCESS != _AI_PC_GetUserRatingLevel(&old_rat))
	{
		PARENT_CONTROL_ERROR_MSG("FAILED TO GET USER RATING LEVEL\n");
		return AL_FAILURE;
	}
#ifdef CONFIG_ATSC_SYSTEM
	if (AL_SUCCESS != AI_PC_GetCurrentRegion(&pststDime->region))
	{
		PARENT_CONTROL_ERROR_MSG("Unable to get Current Region\n");
		return	AL_FAILURE;
	}
#endif
	switch(pststDime->region)
	{
		case AL_PC_REG_USA:
			user_rat = user_rat |(pststDime->us_mem.us_dia << 0);
			user_rat = user_rat |(pststDime->us_mem.us_lan << 3);
			user_rat = user_rat |(pststDime->us_mem.us_sex << 6);
			user_rat = user_rat |(pststDime->us_mem.us_vio << 9);
			user_rat = user_rat |(pststDime->us_mem.us_child << 12);
			user_rat = user_rat |(pststDime->us_mem.us_tv << 16);
			user_rat = user_rat |(pststDime->us_mem.us_mpaa << 20);
			user_rat = user_rat |(old_rat & 0xff000000);
			break;

		case AL_PC_REG_CANADA:
			user_rat = user_rat |(pststDime->can_mem.can_eng <<24);
			user_rat = user_rat |(pststDime->can_mem.can_fra << 28);
			user_rat = user_rat |(old_rat & 0x00ffffff);
			break;
			
		default:
			break;
	}

	PARENT_CONTROL_DEBUG_MSG("STORING USER RATING == %X\n\n\n", user_rat);
	
	return _AI_PC_SetUserRatingLevel(user_rat);
}

al_uint32 AL_PC_GetCurrRatingDimen(void)
{
	return g_CurrLockDimen;
}

al_uint32 AL_PC_GetOriginalRatingDimen(void)
{
	return g_OriginalLockDimen;
}

/**
* @brief API to Encode User Set Rating level
*
* @param pc_app[output] the demension data.
*
* @param RatingDime[input] specify which dimension
*
* @param DimeValue[input]demension value
*
* @Lock[input] al_true if locked, al_false if unlocked.
* 
* @return AL_SUCCESS if encode success, AL_FAILURE otherwise.
*/
AL_Return_t AL_PC_SetRating(AL_PC_dime_t *pc_app, AL_PC_dimen_all_t RatingDime, 
	al_uint8 DimeValue, al_bool Lock)
{
	if (pc_app == NULL)
	{
		PARENT_CONTROL_ERROR_MSG("INVALID PARAMETERS\n");
		return AL_FAILURE;
	}
	
	switch (pc_app->region)
	{
		case AL_PC_REG_USA:
			if (!Lock)
			{
				switch (RatingDime)
				{
					case AL_PC_US_TV:
						pc_app->us_mem.us_tv = DimeValue+1;
						if (pc_app->us_mem.us_dia <= DimeValue)
						{
							pc_app->us_mem.us_dia = DimeValue;
						}
						if (pc_app->us_mem.us_lan <= DimeValue)
						{
							pc_app->us_mem.us_lan= DimeValue;
						}
						if (pc_app->us_mem.us_sex <= DimeValue)
						{
							pc_app->us_mem.us_sex= DimeValue;
						}
						if (pc_app->us_mem.us_vio <= DimeValue)
						{
							pc_app->us_mem.us_vio= DimeValue;
						}
						break;
					case AL_PC_US_DIA:
						pc_app->us_mem.us_dia = DimeValue + 1;

						if ((al_uint8)pc_app->us_mem.us_tv <= DimeValue+1)
						{
							pc_app->us_mem.us_tv = DimeValue+2;
						}
						break;
					case AL_PC_US_LAN:
						pc_app->us_mem.us_lan = DimeValue + 1;

						if ((al_uint8)pc_app->us_mem.us_tv <= DimeValue+1)
						{
							pc_app->us_mem.us_tv = DimeValue+2;
						}
						break;
					case AL_PC_US_SEX:
						pc_app->us_mem.us_sex = DimeValue + 1;

						if ((al_uint8)pc_app->us_mem.us_tv <= DimeValue+1)
						{
							pc_app->us_mem.us_tv = DimeValue+2;
						}
						break;
					case AL_PC_US_VIO:
						pc_app->us_mem.us_vio = DimeValue + 1;

						if ((al_uint8)pc_app->us_mem.us_tv <= DimeValue+1)
						{
							pc_app->us_mem.us_tv = DimeValue+2;
						}
						break;
					case AL_PC_US_CHILD:
						if (DimeValue == AL_PC_TV_Y7)
						{
							pc_app->us_mem.us_child = DimeValue +2;
						}
						else
						{
							pc_app->us_mem.us_child = DimeValue +1;
						}
						break;
					case AL_PC_US_MPAA:
						pc_app->us_mem.us_mpaa = DimeValue + 1;
						break;
					default: break;
				}
			}
			else
			{
				switch (RatingDime)
				{
					case AL_PC_US_TV:
						pc_app->us_mem.us_tv = DimeValue;
						if (pc_app->us_mem.us_dia >= DimeValue
							|| pc_app->us_mem.us_dia == 0)
						{
							pc_app->us_mem.us_dia = (DimeValue == AL_PC_TV_G) ? DimeValue : (DimeValue - 1);
						}
						if (pc_app->us_mem.us_lan >= DimeValue
							|| pc_app->us_mem.us_lan == 0)
						{
							pc_app->us_mem.us_lan = (DimeValue == AL_PC_TV_G) ? DimeValue : (DimeValue - 1);
						}
						if (pc_app->us_mem.us_sex >= DimeValue
							|| pc_app->us_mem.us_sex == 0)
						{
							pc_app->us_mem.us_sex = (DimeValue == AL_PC_TV_G) ? DimeValue : (DimeValue - 1);
						}
						if (pc_app->us_mem.us_vio >= DimeValue
							|| pc_app->us_mem.us_vio == 0)
						{
							pc_app->us_mem.us_vio = (DimeValue == AL_PC_TV_G) ? DimeValue : (DimeValue - 1);
						}
						break;
					case AL_PC_US_DIA:
						pc_app->us_mem.us_dia = DimeValue;
						break;
					case AL_PC_US_LAN:
						pc_app->us_mem.us_lan = DimeValue;
						break;
					case AL_PC_US_SEX:
						pc_app->us_mem.us_sex = DimeValue;
						break;
					case AL_PC_US_VIO:
						pc_app->us_mem.us_vio = DimeValue;
						break;	
					case AL_PC_US_CHILD:
						pc_app->us_mem.us_child = DimeValue;
						break;	
					case AL_PC_US_MPAA:
						pc_app->us_mem.us_mpaa = DimeValue;
						break;
					default: break;
                }
			}
			break;

		case AL_PC_REG_CANADA:
			if (RatingDime == AL_PC_CAN_ENG)
			{
				if (DimeValue == AL_PC_ENG_EXEMPT)
				{
					if (Lock)
					{
						pc_app->can_mem.can_eng &= 0x7;
						pc_app->can_mem.can_eng |= DimeValue;
					}
					else
					{
						pc_app->can_mem.can_eng &= 0x7;
					}
				}
				else
				{
					if (Lock)
					{
						pc_app->can_mem.can_eng &= 0x8;
						pc_app->can_mem.can_eng |= DimeValue;
					}
					else
					{
						pc_app->can_mem.can_eng &= 0x8;
						pc_app->can_mem.can_eng |= DimeValue + 1;
					}
				}
			}
			else if (RatingDime == AL_PC_CAN_FRA)
			{
				if (DimeValue == AL_PC_FRA_EXEMPT)
				{
					if (Lock)
					{
						pc_app->can_mem.can_fra &= 0x7;
						pc_app->can_mem.can_fra|= DimeValue;
					}
					else
					{
						pc_app->can_mem.can_fra &= 0x7;
					}
				}
				else
				{
					if (Lock)
					{
						pc_app->can_mem.can_fra &= 0x8;
						pc_app->can_mem.can_fra |= DimeValue;
					}
					else
					{
						pc_app->can_mem.can_fra &= 0x8;
						pc_app->can_mem.can_fra |= DimeValue + 1;
					}
				}
			}
			break;
			
		default: 
			break;
	}
	
	return AL_SUCCESS;
}
#ifdef CONFIG_ATSC_SYSTEM
/**
* @brief get dimension number from DRRT information.
*
* @param pDimenNum[output] dimension total number.
*
* @return AL_SUCCESS if get dimension number success, AL_FAILURE otherwise.
*/
AL_Return_t AL_PC_GetDRRTDimenNum(al_uint8 *pDimenNum)
{
	if (pDimenNum == al_null)
	{
		return AL_FAILURE;
	}

	PARENTCONTROL_MUTEX_LOCK(g_ParentControlMutex);
	
	*pDimenNum = g_stRRTInfo.NumOfDimensions;

	PARENTCONTROL_MUTEX_UNLOCK(g_ParentControlMutex);
	
	return AL_SUCCESS;
}

/**
* @brief get one dimension information of Dimenindex.
*
* @param DimenIndex[input] dimension index.
*
* @param pGradScale[output] the garduated scale of the dimension of dimension index.
*
* @param pDimenName[output] the dimension name of the dimension of dimension index.
*
* @param pDimenNameLen[output] the dimension name length of the dimension of dimension index.
*
* @param pRatingNum[output] the rating value total number of the dimension of dimension index.
*
* @return AL_SUCCESS if get dimension information success, AL_FAILURE otherwise.
*/
AL_Return_t AL_PC_GetDRRTDimenInfo(al_uint8 DimenIndex, 
	al_bool *pGradScale, al_uint8 *pDimenName, al_uint8 *pDimenNameLen, al_uint8 *pRatingNum)
{
	AI_PC_RatingDimension_t *pstDimension = al_null;

	PARENTCONTROL_MUTEX_LOCK(g_ParentControlMutex);
	
	if (((pRatingNum == al_null) && (pGradScale == al_null) 
		&& (pGradScale == al_null) && (pDimenNameLen == al_null)) 
		|| (DimenIndex >= g_stRRTInfo.NumOfDimensions)
		|| (g_stRRTInfo.RatingDimensions == al_null))
	{
		PARENTCONTROL_MUTEX_UNLOCK(g_ParentControlMutex);
		return AL_FAILURE;
	}

	pstDimension = &(g_stRRTInfo.RatingDimensions[DimenIndex]);

	if (pGradScale != al_null)
	{
		*pGradScale = pstDimension->GraduatedScale;
	}

	if (pRatingNum != al_null)
	{
		*pRatingNum = pstDimension->NumOfValues;
	}

	if (pDimenNameLen != al_null)
	{
		*pDimenNameLen = pstDimension->stDimensionName.StrLen;
	}
	
	if ((pstDimension->stDimensionName.String != al_null) && (pDimenName != al_null))
	{
		UINT8* pStr = NULL;
		INT32 i32Len = pstDimension->stDimensionName.StrLen;

		i32Len--;
		pStr = UNI_StringToUtf8(UTF16_BE, &pstDimension->stDimensionName.String[1], &i32Len, FALSE);
		if (pStr != NULL)
		{
			if (i32Len >= MAX_DIMENNAME_LEN)
			{
				i32Len = MAX_DIMENNAME_LEN-1;
			}
			memcpy(pDimenName, pStr, i32Len);
			free(pStr);
			pStr = NULL;
		}
	}

	PARENTCONTROL_MUTEX_UNLOCK(g_ParentControlMutex);
	
	return AL_SUCCESS;
}

/**
* @brief get one rating value information of Dimenindex and rating index.
*
* @param DimenIndex[input] dimension index.
*
* @param RatingIndex[input] the rating index of the dimension of dimension index.
*
* @param pRatingName[output] the rating name of the rating of dimension index and rating index.
*
* @param pRatingNamLen[output] the rating name length of the rating  of dimension index and rating index.
*
* @return AL_SUCCESS if get rating information success, AL_FAILURE otherwise.
*/
AL_Return_t AL_PC_GetDRRTRatingInfo(al_uint8 DimenIndex, 
	al_uint8 RatingIndex, al_uint8 *pRatingName, al_uint8 *pRatingNamLen)
{
	AI_PC_RatingDimension_t *pstDimension = al_null;
	AI_PC_RatingValue_t *pstRatingValue = al_null;

	PARENTCONTROL_MUTEX_LOCK(g_ParentControlMutex);
	
	if (((pRatingName == al_null) && (pRatingNamLen == al_null))
		|| (DimenIndex >= g_stRRTInfo.NumOfDimensions)
		|| (g_stRRTInfo.RatingDimensions == al_null))
	{
		PARENTCONTROL_MUTEX_UNLOCK(g_ParentControlMutex);
		return AL_FAILURE;
	}

	pstDimension = &(g_stRRTInfo.RatingDimensions[DimenIndex]);
	
	if ((RatingIndex >= pstDimension->NumOfValues)
		|| (pstDimension->RatingValue == al_null))
	{
		PARENTCONTROL_MUTEX_UNLOCK(g_ParentControlMutex);
		return AL_FAILURE;
	}

	pstRatingValue = &(pstDimension->RatingValue[RatingIndex]);
	
	if (pRatingNamLen != al_null)
	{
		*pRatingNamLen = pstRatingValue->StrLen;
	}

	if ((pstRatingValue->String != al_null) && (pRatingName != al_null))
	{
		UINT8* pStr = NULL;
		INT32 i32Len = pstRatingValue->StrLen;

		i32Len--;
		pStr = UNI_StringToUtf8(UTF16_BE, &pstRatingValue->String[1], &i32Len, FALSE);
		if (pStr != NULL)
		{
			if (i32Len >= MAX_RATINGNAME_LEN)
			{
				i32Len = MAX_RATINGNAME_LEN-1;
			}
			memcpy(pRatingName, pStr, i32Len);
			free(pStr);
			pStr = NULL;
		}
	}

	PARENTCONTROL_MUTEX_UNLOCK(g_ParentControlMutex);
	
	return AL_SUCCESS;
}
/**
* @brief Set the lock flag for dimension index and rating index form user setting valuses.
*
* @param DrrtUserSeting[output] user setting valuses.
*
* @param DimenIndex[input] the dimension index
*
* @param RatingIndex[input] the rating index of the dimension of dimension index.
*
* @param bLock[input] the lock flag of the rating of dimension index and rating index.
*
* @return AL_SUCCESS if get demension success, AL_FAILURE otherwise.
*/
AL_Return_t AL_PC_SetDRRTRatingLock(AL_PC_DimenUserSet_t *pDimenUserSeting, 
	al_uint8 DimenIndex, al_uint8 RatingIndex, al_bool bLock)
{
	al_uint8 DimenNum = 0;
	al_uint8 RatingNum = 0;
	al_bool GradScale = al_false;
	al_uint8 Count = 0;
	
	if (pDimenUserSeting == al_null)
	{
		return AL_FAILURE;
	}

	AL_PC_GetDRRTDimenNum(&DimenNum);
	if (DimenIndex > DimenNum)
	{
		return AL_FAILURE;
	}

	AL_PC_GetDRRTDimenInfo(DimenIndex, &GradScale, al_null, al_null, &RatingNum);
	if (RatingIndex > RatingNum)
	{
		return AL_FAILURE;
	}
	
	/**< if value in grad scaled dim, it should modify relative values in the same dim. */
	if (GradScale)
	{
		/**< disable values under given value. */
		if (bLock)
		{
			for (Count = RatingIndex; Count < RatingNum; Count++)
			{
				_AI_PC_SetDrrtLockFlag(pDimenUserSeting, DimenIndex, Count, bLock);
			}
		}
		/**< enable values above given value. */
		else
		{
			for (Count = 0; Count <= RatingIndex; Count++)
			{
				_AI_PC_SetDrrtLockFlag(pDimenUserSeting, DimenIndex, Count, bLock);
			}
		}
	}
	/**< it only update the given value. */
	else
	{
		_AI_PC_SetDrrtLockFlag(pDimenUserSeting, DimenIndex, RatingIndex, bLock);
	}

	
	return AL_SUCCESS;
}

/**
* @brief Get the lock flag for dimension index and rating index form user setting valuses.
*
* @param DrrtUserSeting[input] user setting valuses.
*
* @param DimenIndex[input] the dimension index
*
* @param RatingIndex[input] the rating index of the dimension of dimension index.
*
* @param bLock[output] the lock flag of the rating of dimension index and rating index.
*
* @return AL_SUCCESS if get demension success, AL_FAILURE otherwise.
*/
AL_Return_t AL_PC_GetDRRTRatingLock(AL_PC_DimenUserSet_t DrrtUserSeting, 
	al_uint8 DimenIndex, al_uint8 RatingIndex, al_bool *bLock)
{
	al_uint8 TempRating = 0;
	al_uint8 DimenNum = 0;
	al_uint8 RatingNum = 0;

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

	AL_PC_GetDRRTDimenNum(&DimenNum);
	if (DimenIndex > DimenNum)
	{
		return AL_FAILURE;
	}

	AL_PC_GetDRRTDimenInfo(DimenIndex, al_null, al_null, al_null, &RatingNum);
	if (RatingIndex > RatingNum)
	{
		return AL_FAILURE;
	}
	
	if (RatingIndex < 8) 
	{
		TempRating = DrrtUserSeting.u8aDrrtUserPerference[DimenIndex][0];
		*bLock = (TempRating<<RatingIndex)&0x80;
	}
	else 
	{
		TempRating = DrrtUserSeting.u8aDrrtUserPerference[DimenIndex][1];
		RatingIndex = RatingIndex - 8;
		*bLock = (TempRating<<RatingIndex)&0x80;
	}

	return AL_SUCCESS;
}
#endif
AL_Return_t AL_PC_Reset(al_void)
{
	g_CurrLockDimen = AL_PC_TV_NULL;
	return AL_SUCCESS;
}
#ifdef CONFIG_ATSC_SYSTEM
/**
* @brief check rating value according to current program's content advisory descriptor.
*
* @param pstContentAdvDesc[input] the content advisory descriptor of current program.
*
* @param bLocked[output] geted lock state.
*
* @return AL_SUCCESS check rating successed, other value check rating failed.
*/
AL_Return_t AL_PC_CheckRating(ContentAdvDesc_t *pstContentAdvDesc, al_bool *bLocked)
{
	al_uint8 uNumOfRatingRegion = 0;
	al_uint8 uCount1 = 0;
	al_uint8 uCount2 = 0;
	al_uint8 uNumOfDimension = 0;
	al_uint8 uValue = 0;
	AL_PC_DimenUserSet_t stDimenUserSet;
	al_bool bUserLock = 0;
	frmwrk_pfOpConext_t pfGetContext = al_null;
	al_uint8	pc_ratval[MAX_RATING_DIM];
	al_uint32	pc_user = 0;
    AI_PC_Rating_System_t RatingSystem = AI_PC_Rating_MAX;
    
	if (pstContentAdvDesc == al_null)
	{
		return AL_INVALID_PARAM;
	}

	memset(&stDimenUserSet, 0, sizeof(AL_PC_DimenUserSet_t));
	memset(pc_ratval, 0, sizeof(pc_ratval));
	
	uNumOfRatingRegion = pstContentAdvDesc->ucNumOfRatingRegion;
	for (uCount1 = 0; uCount1 < uNumOfRatingRegion; uCount1++)
	{
		/**< 1. check rating for DRRT */
		if (pstContentAdvDesc->pstRegionDimension[uCount1].ucRatingRegion == REG_DOWNLOADABLE_USA)
		{//printf("[%s:%d] ++++++++++++++++++++++++++++++\n",__FUNCTION__,__LINE__);
			/**< add get dimension user set from up layer */
			AL_FW_GetContextCb(&pfGetContext);
			if (pfGetContext != al_null)
			{
				pfGetContext(FW_CONTEXT_TYPE_DRRT_USERSET, FW_CONTEXT_OP_TYPE_READ,
						(al_void *)&stDimenUserSet ,0);
			}
			
			uNumOfDimension = pstContentAdvDesc->pstRegionDimension[uCount1].ucNumOfDimension;

			for( uCount2 = 0; uCount2 < uNumOfDimension; uCount2++ )
			{
				uValue = pstContentAdvDesc->pstRegionDimension[uCount1].pstDimensionRating[uCount2].ucRatingValue;
				if (0 != uValue)
				{
					if(AL_SUCCESS == _AI_PC_GetDrrtLockFlag(stDimenUserSet, uCount2, uValue, &bUserLock))
					{
						if (al_true == bUserLock)
						{
							*bLocked = al_true;
							//printf("[%s:%d] ++++++++++++++++++++++++++++++\n",__FUNCTION__,__LINE__);
							break;
						}
					}
				}
			}
		}
		/**< 2. check rating for RRT */
		else
		{//printf("[%s:%d] ++++++++++++++++++++++++++++++\n",__FUNCTION__,__LINE__);
			uNumOfDimension = pstContentAdvDesc->pstRegionDimension[uCount1].ucNumOfDimension;
            UINT8   ucDimension;
			for( uCount2 = 0; uCount2 < uNumOfDimension; uCount2++ )
			{
				uValue = pstContentAdvDesc->pstRegionDimension[uCount1].pstDimensionRating[uCount2].ucRatingValue;
				ucDimension = pstContentAdvDesc->pstRegionDimension[uCount1].pstDimensionRating[uCount2].ucDimension;
				pc_ratval[ucDimension] = uValue;
			}
	
			if (AL_SUCCESS != _AI_PC_GetUserRatingLevel(&pc_user))
			{
				return AL_FAILURE;
			}
            if(pstContentAdvDesc->pstRegionDimension[uCount1].ucRatingRegion == REG_USA)
            {
                if(ucDimension == 7)
                {
                    RatingSystem = AI_PC_Rating_MPAA;
                }
                else if((ucDimension >= 0) && (ucDimension <= 6))
                {
                    RatingSystem = AI_PC_Rating_TVPG;
                }
            }
            else if(pstContentAdvDesc->pstRegionDimension[uCount1].ucRatingRegion == REG_CANADA)
            {
                if(ucDimension == 0)
                {
                    RatingSystem = AI_PC_Rating_CANE;
                }
                else if(ucDimension == 1)
                {
                    RatingSystem = AI_PC_Rating_CANF;
                }
            }
			//{
				//int i = 0;
				//for (i = 0; i< MAX_RATING_DIM; i++)
					//printf("i: %d, pc_ratval: %d\n",i,pc_ratval[i]);
			//}
			//printf("[%s:%d] pc_user =============== 0x%x\n",__FUNCTION__,__LINE__,pc_user);
			if(AL_RATING_BLOCKED ==  _AI_PC_CheckRating(pc_ratval, pc_user, RatingSystem))
			{
				*bLocked = al_true;
				break;
			}
		}
	}
	
	return AL_SUCCESS;
}
#endif
