/**@@@+++@@@@******************************************************************
**
** Microsoft Windows Media
** Copyright (C) Microsoft Corporation. All rights reserved.
**
***@@@---@@@@******************************************************************
*/

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "drmcommon.h"

#include "tclib.h"
#include "apiParams.h"
#include "logger.h"
#include "tstutils.h"
#include "tOEMIMP.h"


#define MAX_LINE_SIZE 2000
#define NO_LOG			"-nolog"
#define RUN_BVT_ONLY	"-bvt"
#define RUN_FUNC_ONLY	"-func"

#define BVT_END_LINE "BVT ends here"

#ifdef SIXTEEN_BIT_ADDRESSING
#define tGETTCFILELIST(x1,x2,x3)  tGetTCFileList_pfd(x1,x2,x3)
#define tFREEFILENAMELIST(x) tFreeFileNameList_pfd(x)
#else
#define tGETTCFILELIST(x1,x2,x3)  tGetTCFileList(x1,x2,x3)
#define tFREEFILENAMELIST(x) tFreeFileNameList(x)
#endif




#if defined(PK_TEST)
	#define SUPPORTED_TEST_PLATFORMS {".tc.", ".pk.", NULL}

#elif defined(WINCE_TEST)
	#if defined(WINCE_TEST_PMC)
		#define SUPPORTED_TEST_PLATFORMS {".tc.", ".ce.", ".pm.", NULL}

	#elif defined(WINCE_TEST_CALLISTO)
		#define SUPPORTED_TEST_PLATFORMS {".tc.", ".ce.", ".ca.", NULL}

	#else
		#define SUPPORTED_TEST_PLATFORMS {".tc.", ".ce.", NULL}
	#endif

#else 
	/* assume PC_TEST is defined */
	#define SUPPORTED_TEST_PLATFORMS {".tc.", ".pc.", NULL}
#endif

DRM_RESULT StartTestCase(long lTCID, char *szTCName, LPFNPRETESTCASE lpfnPreTestCase)
{
	DRM_RESULT dr;

	LogStart(lTCID);
	if (DRM_FAILED(dr = lpfnPreTestCase(lTCID, szTCName)))
		Log("Trace", "PreTestCase failed with 0X%X.", dr);
	return dr;
}

DRM_RESULT EndTestCase(long lTCID, DRM_BOOL fPass, char *szTCName, char*szTrace, LPFNPOSTTESTCASE lpfnPostTestCase)
{
	DRM_RESULT dr;
	
	if (DRM_FAILED(dr = lpfnPostTestCase(lTCID, szTCName))) {
		Log("Trace", "PostTestCase failed with 0X%X.", dr);
		fPass = FALSE;
	}
	LogEnd((int)fPass, szTCName, szTrace);
	return fPass? DRM_SUCCESS: DRM_E_FAIL;
}

DRM_RESULT RunAPI(char *szAPIName, long lParams, char **pParams, TAPIMapEntry *apiMap)
{
	int i = 0;
	while (apiMap[i].m_szAPI && DX_VOS_StrCmp(apiMap[i].m_szAPI, szAPIName))
		i++;
	
	if (apiMap[i].m_szAPI)
		return (apiMap[i].m_pAPI)(lParams, pParams);
	else
		return DRM_E_NOTIMPL;
}

#if DBG
void DRM_API RefTestTraceCallback(DRM_CHAR* szMessage, ...)
{
	if (szMessage) {
		va_list va;
		va_start(va, szMessage);
		vLog("DevTrace", szMessage, va);
		va_end(va);
	}
}
#endif

int DoTest(int argc, char **argv, char **szTCFileNameList, TAPIMapEntry *apiMap, LPFNPRETESTCASE lpfnPreTestCase, LPFNPOSTTESTCASE lpfnPostTestCase, LPFNWRAPTESTRUN lpfnWrapTestRun)
{
	DRM_RESULT dr, drActual;
	int i;
	DRM_BOOL fLoggerEnabled = TRUE, fTCFilePresent = FALSE;
	enum {eRunAll, eRunBVTOnly, eRunFuncOnly} eRunWhat = eRunAll;

	long lTCID = 0, lCurrentTCID = 0, lNextTCID;
	char *pLine, *pNextTCTitle; 
	char szTraceMessage[500]={0};
	
	/* These variables need to be released at the end */
	DxVosFile fTestCase = NULL;
	char *szLine = NULL, *pTCTitle = NULL;
	TAPIParams APIParams = {0};
	char **szTestScriptFiles = 0;

/*for non COM LOG version*/
#ifndef USE_DRM_HARNESS_LOGGER
	/*save application name*/
extern char g_szExeNameWithExtension[256];
	DX_VOS_MemSet(g_szExeNameWithExtension, '\0', 256);

/*Since command line arguments are not available on 16-bit TI platform, we cannot
use argv[0] for 16-bit*/
#if __TMS320C55X__
        strncpy(g_szExeNameWithExtension, "Console",256);
#else
	DX_VOS_StrNCopy(g_szExeNameWithExtension,sizeof(g_szExeNameWithExtension), argv[0]);	 
#endif /* __TMS320C55X__ */

#endif

	/* The following optional flags are supported; otherwise it is a test case number:
		-nolog to allow disable COM log system;
		-bvt run BVT test cases only;
		-func run Functional test cases only.
	*/
#if __TMS320C55X__
	/*Since command line arguments are not available, we ignore it*/
	argc = 0;
#endif
	for(i = 1; i < argc; i++ ){
		if (!DX_VOS_StrCmp(argv[i], NO_LOG))
			fLoggerEnabled = FALSE;
		else if (!DX_VOS_StrCmp(argv[i], RUN_BVT_ONLY))
			eRunWhat = eRunBVTOnly;
		else if (!DX_VOS_StrCmp(argv[i], RUN_FUNC_ONLY))
			eRunWhat = eRunFuncOnly;
		else /* assume it is a test case number */
			lTCID = OEM_atol(argv[i]);
	}
 		 
	InitLogger(fLoggerEnabled);

#if DBG
	DrmDebugHookTrace(RefTestTraceCallback);
#endif

    if(lpfnWrapTestRun)
    {
    	ChkDR(lpfnWrapTestRun(lTCID, TRUE));
    }
	ChkMem(szLine = (char*)OEM_malloc(MAX_LINE_SIZE));
	
	for (;*szTCFileNameList; szTCFileNameList++) {
		char **pTestScriptFile, *szSupportedPlatforms[] = SUPPORTED_TEST_PLATFORMS;

		tFREEFILENAMELIST(szTestScriptFiles);
		
		szTestScriptFiles = 0;

		ChkDR(tGETTCFILELIST(*szTCFileNameList, szSupportedPlatforms, &szTestScriptFiles));
		
		for (pTestScriptFile = szTestScriptFiles; *pTestScriptFile; pTestScriptFile++) {
			DRM_BOOL fSkipBVTCases = (eRunWhat == eRunFuncOnly);

			DX_VOS_FOpen(&fTestCase,*pTestScriptFile, "rt");

			if (!fTestCase)
				continue;

			fTCFilePresent = TRUE;

			while (!DX_VOS_FEof(fTestCase) && !DX_VOS_FGets(fTestCase,szLine, MAX_LINE_SIZE)) {
				pLine = DX_VOS_Trim(szLine);
				
				/* comment line starts with ', don't process a comment line or an empty line */
				if (!*pLine || *pLine == '\'') 
					continue;
					
				/* separation line */
				if (*pLine == '-') {
					if (DX_VOS_FindStr(pLine, BVT_END_LINE)) {
						if (eRunWhat == eRunBVTOnly) /* We only want to run BVT. So stop here. */
							break;
						if (eRunWhat == eRunFuncOnly) /* We can start functional cases now. */
							fSkipBVTCases = FALSE;
					}
					continue;
				}

				if (fSkipBVTCases)
					continue;

				if (ParseTCID(pLine, &lNextTCID, &pNextTCTitle)) {
					if (lCurrentTCID) { 
						/* Test case CurrentTCID is finished and passed, log it */
						dr = EndTestCase(lCurrentTCID, TRUE, pTCTitle,NULL, lpfnPostTestCase);
						lCurrentTCID = 0;

						if (lTCID) /* We just ran the required test case, no more left, so leave now. */
							goto ErrorExit;
					}

					if (!lTCID || lTCID == lNextTCID) {
						/* save the test case info and start to run api tests for this test case */
						lCurrentTCID = lNextTCID;
                                                SAFE_OEM_FREE(pTCTitle);

						ChkMem(pTCTitle = StringDup(pNextTCTitle));
						if (DRM_FAILED(dr = StartTestCase(lCurrentTCID, pTCTitle, lpfnPreTestCase))) {
							dr = EndTestCase(lCurrentTCID, FALSE, pTCTitle,NULL, lpfnPostTestCase);
							lCurrentTCID = 0;
						}
					}
				
				} else if (lCurrentTCID && ParseAPI(pLine, &APIParams)) {
					DRM_BOOL fFail = FALSE;

					Log("Running_API", APIParams.m_szAPIName);
					drActual = RunAPI(APIParams.m_szAPIName, APIParams.m_lParamCount, APIParams.m_szParams, apiMap);
					DX_VOS_MemSet(szTraceMessage, '\0', sizeof(szTraceMessage)); 
					/* api returns a value which is explicitly rejected. */
					if (APIParams.m_fExcept && (drActual == APIParams.m_drExpected)) {
						Log("API_Failure", "API %s unexpectedly returns %d(0X%X).", APIParams.m_szAPIName, drActual, drActual);
						DX_VOS_SPrintf(szTraceMessage,sizeof(szTraceMessage), "API_Failure: api returns a value which is explicitly rejected. API %s unexpectedly returns %d(0X%X).", APIParams.m_szAPIName, drActual, drActual);
						fFail = TRUE;

					/* api returns a value which does not match the expected. */
					} else if (!APIParams.m_fExcept && drActual != APIParams.m_drExpected) { 
						Log("API_Failure", "API %s returns %d(0X%X). Expecting %d(0X%X).", APIParams.m_szAPIName, drActual, drActual, APIParams.m_drExpected, APIParams.m_drExpected);
						DX_VOS_SPrintf(szTraceMessage,sizeof(szTraceMessage), "API_Failure: api returns a value which does not match the expected. API %s returns %d(0X%X). Expecting %d(%X).", APIParams.m_szAPIName, drActual, drActual, APIParams.m_drExpected, APIParams.m_drExpected);
						fFail = TRUE;
					}

					if (fFail) { /* api test failed, so the test case fails*/
						dr = EndTestCase(lCurrentTCID, FALSE, pTCTitle,szTraceMessage, lpfnPostTestCase);
						lCurrentTCID = 0;
						if (lTCID) /* We just ran the required test case, no more left, so leave now.*/
							goto ErrorExit;
					}
				}
			}

			if (lCurrentTCID) { 
				/* Test case CurrentTCID is finished and passed, log it*/
				dr = EndTestCase(lCurrentTCID, TRUE, pTCTitle, NULL, lpfnPostTestCase);
				lCurrentTCID=0;
				if (lTCID) /* We just ran the required test case, no more left, so leave now.*/
					goto ErrorExit;
			}

			DX_VOS_FClose(fTestCase);
			fTestCase = NULL;
		}
	}

	if (!fTCFilePresent)
		DX_VOS_Printf("Cannot find any test case file.\n");
ErrorExit:
        SAFE_OEM_FREE(pTCTitle);
	tFREEFILENAMELIST(szTestScriptFiles);
	FreeAPIParams(&APIParams);
 	SAFE_OEM_FREE(szLine);
	if (fTestCase)
		DX_VOS_FClose(fTestCase);
	lpfnWrapTestRun(lTCID, FALSE);
	UninitLogger();
	 
	return DRM_SUCCEEDED(dr)? 0: -1;
}

/*for wince version*/
#ifdef WINCE_TEST

int ConvertArguments(LPTSTR lpCmdLine, char* argv[])
{
    int nIndex=0;
    DRM_WCHAR *pszCmd = NULL;
    DRM_WCHAR seps[] = L" ,\t\n";
    int argc =0;
 
    if (NULL == argv)
        return argc;
     
    // Convert it into ARGV format to be used later.
    if (lpCmdLine != NULL)
        pszCmd = wcstok(lpCmdLine, seps);

	/*the first one should be application name.*/
    argv[nIndex] = (char*)OEM_malloc((DRM_wcslen(lpCmdLine)+1) * SIZEOF(DRM_CHAR));
	if (NULL == argv[nIndex])
    {
  		goto ErrorExit; 
	}
    OEM_wcstombs(argv[nIndex], lpCmdLine,DRM_wcslen(lpCmdLine)+1);
    nIndex++;
 
    while (pszCmd)
    {
      argv[nIndex] = (char*)OEM_malloc((DRM_wcslen(pszCmd)+1) * SIZEOF(DRM_CHAR));
        if (NULL == argv[nIndex])
        {
  			goto ErrorExit; 
		}
        OEM_wcstombs(argv[nIndex], pszCmd,DRM_wcslen(pszCmd)+1);
        nIndex++;
        pszCmd = wcstok(NULL, seps);
    } 

ErrorExit:     
	argc=nIndex;
    return argc;
}

void FreeArgv(int argc, char* argv[])
{
    int i=0;
 	for (i = 0; i < argc; i++)  
    {
        if (argv [i] != NULL)
            SAFE_OEM_free(argv[i]);
        argv[i] = NULL;
    }
}

#endif
