#include "VOS_API/DX_VOS_TimeUtils.h"
#include "VOS_API/DX_VOS_Time.h"
#include "VOS_API/DX_VOS_Mem.h"

/* Internal function no need for parameter check */
static DxStatus DX_VOS_2DigitsStrToInt(const DxUint8 *aString, DxUint32* val)
{
	if ((DxUint8)(aString[0]  - '0') > 9 || (DxUint8)(aString[1] - '0') > 9)
		RETURN_NEW_ERROR(DX_VOS_TIME_ERROR);
	*val = (aString[0]  - '0') * 10 + (aString[1] - '0');
	DX_RETURN(DX_SUCCESS);
}

static void DX_VOS_IntTo2DigitsStr(DxUint32 val, DxUint8 *aString)
{
	aString[1] = '0' + (DxUint8)(val % 10);
	aString[0] = '0' + (DxUint8)((val / 10) % 10);
}

DxStatus DX_VOS_GetUTCTime(DxUtcTime_t *aUtcTime)
{
    DX_DECLARE(DxStatus, result, DX_SUCCESS);
    result = DX_VOS_SecsToUTCTime(DX_VOS_GetTime(), aUtcTime);
    if (result != DX_SUCCESS)
    	RETURN_OLD_ERROR(result);
    DX_RETURN(DX_SUCCESS);
}

DxStatus DX_VOS_GetGeneralizedTime(DxGeneralizedTime_t *aGenTime)
{
    DX_DECLARE(DxStatus, result, DX_SUCCESS);
    result = DX_VOS_SecsToGenTime(DX_VOS_GetTime(), aGenTime);
    if (result != DX_SUCCESS)
    	RETURN_OLD_ERROR(result);
    DX_RETURN(DX_SUCCESS);
}

DxInt DX_VOS_UTCTimeCompare(const DxUtcTime_t *aUtc1, const DxUtcTime_t *aUtc2)
{
	if (aUtc1 == DX_NULL)
	{
		if (aUtc2 == DX_NULL)
			return 0;
		return -1;
	}
	if (aUtc2 == DX_NULL)
		return 1;
	if (aUtc1->year_m >= '5' && aUtc2->year_m < '5')
		return -1;  
	if (aUtc2->year_m >= '5' && aUtc1->year_m < '5')
		return 1;  

    // We don't compare Zulu & endOfStr
	return DX_VOS_MemCmp(aUtc1, aUtc2, sizeof(DxUtcTime_t) - 2);
}

DxInt DX_VOS_GenTimeCompare(const DxGeneralizedTime_t *aTm1, const DxGeneralizedTime_t *aTm2)
{
    // We don't compare Zulu & endOfStr
	return DX_VOS_MemCmp(aTm1, aTm2, sizeof(DxGeneralizedTime_t) - 2);
}

DxStatus DX_VOS_UTCTimeToSecs(const DxUtcTime_t* aUtcTime, DxTime_t* aTime)
{
	DX_DECLARE(DxStatus, result, DX_SUCCESS);
	DxTimeStruct_t timeStruct;

    DX_ASSERT_PARAM(aUtcTime != DX_NULL);
    DX_ASSERT_PARAM(aTime != DX_NULL);

	result |= DX_VOS_2DigitsStrToInt(&(aUtcTime->seconds_m), &(timeStruct.tm_sec));       
	result |= DX_VOS_2DigitsStrToInt(&(aUtcTime->minutes_m), &(timeStruct.tm_min));       
	result |= DX_VOS_2DigitsStrToInt(&(aUtcTime->hours_m), &(timeStruct.tm_hour));       
	result |= DX_VOS_2DigitsStrToInt(&(aUtcTime->day_m), &(timeStruct.tm_mday));       
	result |= DX_VOS_2DigitsStrToInt(&(aUtcTime->months_m), &(timeStruct.tm_mon));       
	result |= DX_VOS_2DigitsStrToInt(&(aUtcTime->year_m), &(timeStruct.tm_year));       
	if (result != DX_SUCCESS)
	  RETURN_OLD_ERROR(result);

	if (timeStruct.tm_year < 50)  /* if year is 00-50 (i.e. 2000-2050) */
	    timeStruct.tm_year += 2000; 
    else 
        timeStruct.tm_year += 1900;

	result = DX_VOS_GlobalTimeToSecs(&timeStruct, aTime);
    if (result != DX_SUCCESS)
    	RETURN_OLD_ERROR(result);
    
    DX_RETURN(DX_SUCCESS);
}


DxStatus DX_VOS_SecsToUTCTime(DxTime_t aTime, DxUtcTime_t* aUtcTime)
{
	DX_DECLARE(DxStatus, result, DX_SUCCESS) ;
	DxTimeStruct_t timeStruct;

    DX_ASSERT_PARAM(aUtcTime != DX_NULL);
    if (aTime > DX_MAX_INT32) // invalid time value
        RETURN_NEW_ERROR(DX_OVERFLOW);

	result = DX_VOS_GetGlobalTime(aTime, &timeStruct);
	if (result != DX_SUCCESS)
		RETURN_OLD_ERROR(result);

	DX_VOS_IntTo2DigitsStr(timeStruct.tm_year ,  &(aUtcTime->year_m));
	DX_VOS_IntTo2DigitsStr(timeStruct.tm_mon  ,  &(aUtcTime->months_m));
	DX_VOS_IntTo2DigitsStr(timeStruct.tm_mday ,  &(aUtcTime->day_m));      /* day of the month         - [1, 31] */
	DX_VOS_IntTo2DigitsStr(timeStruct.tm_hour ,  &(aUtcTime->hours_m));    /* hours after midnight     - [0, 23] */
	DX_VOS_IntTo2DigitsStr(timeStruct.tm_min  ,  &(aUtcTime->minutes_m));  /* minutes after the hour   - [0, 59] */
	DX_VOS_IntTo2DigitsStr(timeStruct.tm_sec  ,  &(aUtcTime->seconds_m));  /* seconds after the minute - [0, 59] */
	aUtcTime->Zulu = 'Z';
    aUtcTime->endOfStr = 0;
	DX_RETURN(DX_SUCCESS);
}

DxStatus DX_VOS_SecsToGenTime(DxTime_t aTime, DxGeneralizedTime_t* aGenTime)
{
	DX_DECLARE(DxStatus, result, DX_SUCCESS) ;
	DxTimeStruct_t timeStruct;

    DX_ASSERT_PARAM(aGenTime != DX_NULL);

    if (aTime > DX_MAX_INT32) // invalid time value
        RETURN_NEW_ERROR(DX_OVERFLOW);

	result = DX_VOS_GetGlobalTime(aTime, &timeStruct);
	if (result != DX_SUCCESS)
		RETURN_OLD_ERROR(result);


	DX_VOS_IntTo2DigitsStr(timeStruct.tm_year / 100,  &(aGenTime->year_m1));
	DX_VOS_IntTo2DigitsStr(timeStruct.tm_year ,  &(aGenTime->year_m2));
	DX_VOS_IntTo2DigitsStr(timeStruct.tm_mon  ,  &(aGenTime->months_m));
	DX_VOS_IntTo2DigitsStr(timeStruct.tm_mday ,  &(aGenTime->day_m));      /* day of the month         - [1, 31] */
	DX_VOS_IntTo2DigitsStr(timeStruct.tm_hour ,  &(aGenTime->hours_m));    /* hours after midnight     - [0, 23] */
	DX_VOS_IntTo2DigitsStr(timeStruct.tm_min  ,  &(aGenTime->minutes_m));  /* minutes after the hour   - [0, 59] */
	DX_VOS_IntTo2DigitsStr(timeStruct.tm_sec  ,  &(aGenTime->seconds_m));  /* seconds after the minute - [0, 59] */
	aGenTime->Zulu = 'Z';
    aGenTime->endOfStr = 0;
    DX_RETURN(DX_SUCCESS);
}

DxStatus DX_VOS_GenTimeToSecs(const DxGeneralizedTime_t* aGenTime, DxTime_t* aTime)
{
	DX_DECLARE(DxStatus, result, DX_SUCCESS);
	DxTimeStruct_t timeStruct;
	DxUint32 year_m = 0, year_l = 0;

    DX_ASSERT_PARAM(aGenTime != DX_NULL);
    DX_ASSERT_PARAM(aTime != DX_NULL);

	result |= DX_VOS_2DigitsStrToInt(&(aGenTime->seconds_m), &(timeStruct.tm_sec));       
	result |= DX_VOS_2DigitsStrToInt(&(aGenTime->minutes_m), &(timeStruct.tm_min));       
	result |= DX_VOS_2DigitsStrToInt(&(aGenTime->hours_m), &(timeStruct.tm_hour));       
	result |= DX_VOS_2DigitsStrToInt(&(aGenTime->day_m), &(timeStruct.tm_mday));       
	result |= DX_VOS_2DigitsStrToInt(&(aGenTime->months_m), &(timeStruct.tm_mon));       
	result |= DX_VOS_2DigitsStrToInt(&(aGenTime->year_m1), &(year_m));       
	result |= DX_VOS_2DigitsStrToInt(&(aGenTime->year_m2), &(year_l));       
	if (result != DX_SUCCESS)
		RETURN_OLD_ERROR(result);

	timeStruct.tm_year = year_m * 100 + year_l;

    result = DX_VOS_GlobalTimeToSecs(&timeStruct, aTime);
    if (result != DX_SUCCESS)
    	RETURN_OLD_ERROR(result);
    DX_RETURN(DX_SUCCESS);
}

#ifdef DX_USE_LEGACY_VOS

DxInt DX_VOS_DRM_UTCTimeCompare(const DxUtcTime_t *aUtc1, const DxUtcTime_t *aUtc2)
{
    DxInt compare = DX_VOS_UTCTimeCompare(aUtc1,aUtc2);
    if (compare > 0) 
        DX_RETURN(TIME_1_IS_AFTER);
    else if (compare < 0)
        DX_RETURN(TIME_2_IS_AFTER);
    else 
        DX_RETURN(IDENTICAL_TIME);
}

DxInt DX_VOS_DRM_generalizedTimeCompare(const DxGeneralizedTime_t *aTm1, const DxGeneralizedTime_t *aTm2)
{
    DxInt compare = DX_VOS_GenTimeCompare(aTm1,aTm2);
    if (compare > 0) 
        DX_RETURN(TIME_1_IS_AFTER);
    else if (compare < 0)
        DX_RETURN(TIME_2_IS_AFTER);
    else 
        DX_RETURN(IDENTICAL_TIME);
}

#endif
