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

//#include <stdlib.h>

#include "drmcommon.h"
#include "drmutilities.h"
#include "drmcrt.h"
#include "drmcontextsizes.h"
#include "drmmanager.h"
#include "drmblackbox.h"
#include "drmpkcrypto.h"
#include "drmheaderparser.h"
#include "drmlicenseparser.h"
#include "drmlicacq.h"
#include "drmcipher.h"
#include "drmviewprops.h"
#include "oemimpl.h"
#if DRM_SUPPORT_APP_REVOCATION
	#include "drmrevocation.h"
#endif
#include "drmchain.h"
#include "drmdevcertacq.h"
#include "drmsecureclock.h"
#include "drmsyncstore.h"
#include "drmsecurestore.h"
#include "drmlicreason.h"
#include "tOEMIMP.h"


#include "tclib.h"
#include "tLicGen.h"
#include "tResponsegen.h"
#include "tstutils.h"
#include "tGetClientID.h"


/*global variables*/
DRM_BB_CONTEXT g_oBBContext;
DRM_SECSTORE_CONTEXT g_oGlobalSecStoreContext, g_oLIDSecStoreContext, g_oContentRevSecStoreContext;
DRM_LICSTORE_CONTEXT g_oLicStoreContext;

#if DRM_MAX_LICENSE_CHAIN_DEPTH != 2
#err "This only supports max chain depth of 2"
#endif

DRM_LICSTOREENUM_CONTEXT g_oLicEnumContext;
DRM_LICSTOREENUM_CONTEXT g_oLicEnumContext2;
DRM_LICEVAL_CONTEXT g_oLicEvalContext;
DRM_VIEW_RIGHTS_CONTEXT g_oViewRightsContext;
static DRM_HDS_CONTEXT *g_pHdsContext = NULL;

DRM_LICENSE_STATE_DATA *g_pStateData = NULL;
DRM_DWORD g_dwStateData = 0;

#define MAX_SANDBOX_SIZE 10000


#if 0 /*DX remove unsuded code*/
#define CREATE_DRM_CONST_STRING(g_lval, rval) \
const DRM_WCHAR g_lval##CREATEDRMSTRING []= rval; \
const DRM_CONST_STRING g_lval = CREATE_DRM_STRING(g_lval##CREATEDRMSTRING);

CREATE_DRM_CONST_STRING(g_dxcvstrDRM_VERSION_STRING, (L"2.0.0.0"));
#endif

static void CleanGlobalStateData()
{
	DX_VOS_MemFree(g_pStateData);
	g_pStateData = NULL;
	g_dwStateData = 0;
}

static DRM_RESULT SetupViewRightsContext(DRM_VIEW_RIGHTS_CONTEXT *pVRContext)
{
	DRM_RESULT dr;

	DRM_BOOL fLicEval;
	DRM_SUBSTRING dasstrKID = { 0 };
	DRM_DWORD cbKID = DRM_ID_SIZE;
	DRM_BYTE szSecStorePassword[SHA_DIGEST_LEN];
	DRM_BYTE rgbBuffer[MAX_DEVICE_CERT_SIZE];    
	DRM_CONST_STRING dstrDevCert;

	DX_VOS_MemSet(pVRContext, 0, sizeof(DRM_VIEW_RIGHTS_CONTEXT));

    DSTR_FROM_PB( &dstrDevCert, rgbBuffer, SIZEOF(rgbBuffer) );

	/* Use the default KID from our test licgen */
	dasstrKID.m_ich = 0;
	dasstrKID.m_cch = DX_VOS_StrLen(szLicGenDefaultKID);

	ChkDR(DRM_B64_DecodeA(szLicGenDefaultKID, &dasstrKID, &cbKID, pVRContext->KID.rgb, 0));

	/* Initialize a blackbox context */
	/*blackbox initialized */
    ChkDR( DRM_DDC_GetDeviceCertificate( (DRM_STRING*)&dstrDevCert, 0, &g_oBBContext.CryptoContext ) );
    ChkDR( DRM_DCP_LoadPropertiesCache( &dstrDevCert, &g_oBBContext.cachedCertValues, &g_oBBContext.CryptoContext ) );
    ChkDR( DRM_BBX_Initialize( &g_oBBContext ) );
	pVRContext->pBBContext = &g_oBBContext;

	/* Talk to blackbox to get the global secure store password */
	ChkDR(DRM_SST_CreateGlobalStorePassword(szSecStorePassword, (DRM_BYTE*)&g_oBBContext));

	/* Open the global key */
    ChkDR(DRM_SST_OpenKeyTokens(&g_oGlobalSecStoreContext, &g_rgbSecStoreGlobalName, NULL,
		szSecStorePassword, DRM_SECURE_STORE_CREATE_IF_NOT_EXISTS, SECURE_STORE_GLOBAL_DATA,
		g_pHdsContext));
	pVRContext->pbGlobalSecStore = &g_oGlobalSecStoreContext;

	/* Set the LID secure store context */
	pVRContext->pbLIDSecStore = &g_oLIDSecStoreContext;
   
	/* Set the licstore and licstore enum contexts */
	ChkDR(DRM_LST_Open(&g_oLicStoreContext, g_pHdsContext));
	pVRContext->pbLicenseStoreXML = &g_oLicStoreContext;
	pVRContext->rgpLicQueryContext[0] = &g_oLicEnumContext;
    pVRContext->rgpLicQueryContext[1] = &g_oLicEnumContext2;

	/* Set the liceval context */
	DX_VOS_MemSet(&g_oLicEvalContext, 0, sizeof(DRM_LICEVAL_CONTEXT));
	g_oLicEvalContext.pcontextBBX = &g_oBBContext;
	g_oLicEvalContext.pcontextSSTRevocation = &g_oContentRevSecStoreContext;
	g_oLicEvalContext.pcontextSSTLicense = &g_oLIDSecStoreContext;
	g_oLicEvalContext.pLicStoreEnumContext = &g_oLicEnumContext;
	g_oLicEvalContext.pcontextSSTGlobal = &g_oGlobalSecStoreContext;
	g_oLicEvalContext.certinfoSDK.appSec = 2000; /* hardcode here */
	g_oLicEvalContext.fAppInfoValid = FALSE;
	g_oLicEvalContext.cbRevocationBuffer = 10*1024;// BUGBUG: MAX_REVOCATION_LIST_SIZE;
	ChkMem(g_oLicEvalContext.pbRevocationBuffer = (DRM_BYTE*)DX_VOS_MemMalloc(g_oLicEvalContext.cbRevocationBuffer));

	/* Set machine clock to the secure store. Otherwise CheckClockRollback will fail. */
	g_oLicEvalContext.fGlobalSecStoreWritable = TRUE;
	ChkDR(DRM_LEVL_EvaluateExpression(&g_oLicEvalContext, &g_dstrResetRollbackedClock, &fLicEval));

    /* todo: set more values for the global liceval context */

	pVRContext->pLicEval = &g_oLicEvalContext;

	/* Set the sandbox buffer */
	pVRContext->cbBuffer = MAX_SANDBOX_SIZE;
	ChkMem(pVRContext->pbBuffer = (DRM_BYTE*)DX_VOS_MemMalloc(MAX_SANDBOX_SIZE));

ErrorExit:
	return dr;
}

/*
	Add a license to the store
	argv[0]: dwOption value to testLicGen
	argv[1]: extra xml string to add to the license, can be NULL
	argv[2]: optional LID value
*/
DRM_RESULT TestAddLicense(long argc, char **argv)
{
	DRM_RESULT dr;
	DRM_CONST_STRING szLic;
	
	DRM_DWORD cbResponseContext = 20000, cbResponse;
	_XMBContext *pbResponseContext = NULL;
    DRM_BYTE *pbResponse = NULL;
    DRM_BYTE *pbLicenseBuffer = NULL;    
    DRM_SYNC_CONTEXT *pcontextSYN = NULL;
    ELicenseType eLicType = MAKE_SIMPLE_LICENSE;
#if DRM_SUPPORT_LICENSE_SYNC
    DRM_SYNC_CONTEXT contextSYN;
    pcontextSYN = &contextSYN;

    DRM_SNC_OpenStore( g_pHdsContext, pcontextSYN );
#endif

	ChkArg(argc >= 2 && argv[0]);

	/* Generate the test license */
 	
	ChkDR(TestLicGenInit(20000));
	if (argc > 2) {
		ChkDR(TestLicGenSetKeys("LICENSE_LID", argv[2]));
	}

    if (argc>3) 
    {
        ChkDR(TestLicGenSetKeys("LICENSE_KID",argv[3]));
    }

    if(argc>4) {
		ChkArg(argv[4]);
		eLicType = (ELicenseType)OEM_atol(argv[4]);
	}

	if (argc > 5) {
		ChkDR(TestLicGenSetKeys("LICENSE_UPLINK_KID",argv[5]));
	}
    
	ChkDR(TestLicGenMakeLicense(OEM_atol(argv[0]), argv[1], NULL,eLicType, &szLic));

	/* Build a response string */
	ChkMem(pbResponseContext = (_XMBContext*)DX_VOS_MemMalloc(cbResponseContext));
    ChkMem(pbLicenseBuffer   = (DRM_BYTE*)DX_VOS_MemMalloc(DRM_MAX_LICENSESIZE) );
	ChkDR(TestResponseInit(pbResponseContext, cbResponseContext));
	ChkDR(TestResponseAddLicense(pbResponseContext, &szLic));
	ChkDR(TestResponseGetResponse(pbResponseContext, &pbResponse, &cbResponse));

	/* Process the response string. This adds the license to the licstore and secstore */
    ChkDR(DRM_LA_ProcessResponse(pbResponse, cbResponse, &g_oLicEvalContext, &g_oLicStoreContext,
		NULL, NULL, g_pHdsContext, &g_oViewRightsContext,pbLicenseBuffer, pcontextSYN, NULL ) );

ErrorExit:
    DRM_SNC_CloseStore(pcontextSYN);
	TestLicGenShutDown();
	DX_VOS_MemFree(pbResponseContext);
    DX_VOS_MemFree(pbLicenseBuffer);
	DX_VOS_MemFree(pbResponse);
	return dr;
}

/* Test API IsAllowed
	argv[0]: action string
	argv[1]: ViewRightsContext: Normal or NULL
*/
DRM_RESULT TestIsAllowed(long argc, char **argv)
{
	DRM_RESULT dr;
	DRM_CONST_STRING wszAction;
	
	ChkArg(argc == 2);
	MakeDRMString(&wszAction, argv[0]);
	ChkDR(DRM_ASD_IsAllowed(&wszAction, argv[1]? &g_oViewRightsContext: NULL, g_pHdsContext));
ErrorExit:
	DX_VOS_MemFree((void*)wszAction.pwszString);
	return dr;
}

/* Test API GetLicenseAggregateData
	argv[0]: Status of pwszAction: Normal or NULL
	argv[1]: Status of pStateData: Normal or NULL
	argv[2]: number of actions in pwszAction
	argv[3]: Status of viewrights context:: Normal or NULL
	argv[4]...: Action strings to fill in pwszAction
*/
DRM_RESULT TestGetLicenseAggregateData(long argc, char **argv)
{
	DRM_RESULT dr = DRM_SUCCESS;
	DRM_CONST_STRING **ppwszAction = NULL;
	DRM_DWORD i;
	
	ChkArg(argc > 3);
	CleanGlobalStateData();

	/* Set up the actions */
	g_dwStateData = OEM_atol(argv[2]);
	if (argv[0]) {
		ChkMem(ppwszAction = (DRM_CONST_STRING**)DX_VOS_MemMalloc(sizeof(DRM_CONST_STRING*) * g_dwStateData));
		DX_VOS_MemSet(ppwszAction, 0, sizeof(DRM_CONST_STRING*) * g_dwStateData);
		for (i = 0; i < g_dwStateData; i++) {
			ChkMem(ppwszAction[i] = (DRM_CONST_STRING*)DX_VOS_MemMalloc(sizeof(DRM_CONST_STRING)));
			MakeDRMString(ppwszAction[i], argv[4 + i]);
		}
	}

	if (argv[1]) {
		ChkMem(g_pStateData = (DRM_LICENSE_STATE_DATA*)DX_VOS_MemMalloc(sizeof(DRM_LICENSE_STATE_DATA) * g_dwStateData));
	}

	dr = DRM_ASD_GetLicenseAggregateData((const DRM_CONST_STRING**)ppwszAction, argv[1]? g_pStateData: NULL, g_dwStateData,
		argv[3]? &g_oViewRightsContext: NULL, g_pHdsContext, FALSE, DRM_ASD_AGGREGATE_ROOT_LICENSES );

ErrorExit:
	for (i = 0; i < g_dwStateData; i++) {
		DX_VOS_MemFree((void*)ppwszAction[i]->pwszString);
		DX_VOS_MemFree(ppwszAction[i]);
	}
	DX_VOS_MemFree(ppwszAction);
	return dr;
}

/*	Verify values in g_pStateData returned from GetLicenseAggregateData
	argv[0]: the index in g_pStateData to verify
	argv[1]: the expected value of dwCategory
	argv[2]: (optional) expected value of dwVague, could be NULL
	argv[3]: (optional) expected number of counts
	argv[4]: (optional) expected value of the first count
*/
DRM_RESULT TestVerifyStateData(long argc, char **argv)
{
	DRM_RESULT dr = DRM_S_FALSE;
	DRM_DWORD dwIndex;
	long i;

	ChkArg(argc > 1 && argv[0] && g_pStateData);
	dwIndex = OEM_atol(argv[0]);
	ChkArg(dwIndex < g_dwStateData);

	/* Verify DRM_LICENSE_STATE_CATEGORY */
	if ((DRM_DWORD)OEM_atol(argv[1]) != g_pStateData[dwIndex].dwCategory)
		goto ErrorExit;
	
	/* Verify the dwVague */
	if (argc > 2 && argv[2] && (DRM_DWORD)OEM_atol(argv[2]) != g_pStateData[dwIndex].dwVague)
		goto ErrorExit;

	/* Verify the number of counts */
	if (argc > 3 && (DRM_DWORD)OEM_atol(argv[3]) != g_pStateData[dwIndex].dwNumCounts)
		goto ErrorExit;

	/* Verify the four count values */
	for (i = 4; i < argc && i < 8; i++)
		if ((DRM_DWORD)OEM_atol(argv[i]) != g_pStateData[dwIndex].dwCount[i - 4])
			goto ErrorExit;
	
	dr = DRM_SUCCESS;
ErrorExit:
	return dr;
}

DRM_RESULT VR_PreTestCase(long lTCID, char *strTCName)
{
	DRM_RESULT dr;
	CLIENTID clientID;
	DRM_CONST_STRING dstrHdsPath;
	const DRM_WCHAR devCertTemplate[] = { TWO_BYTES('d','e'), TWO_BYTES('v','c'),
									 	  TWO_BYTES('e','r'), TWO_BYTES('t','t'),
										  TWO_BYTES('e','m'), TWO_BYTES('p','l'),
										  TWO_BYTES('a','t'), TWO_BYTES('e','.'),
										  TWO_BYTES('d','a'), TWO_BYTES('t','\0') };
	const DRM_WCHAR priv[] = { TWO_BYTES('p','r'), TWO_BYTES('i','v'), TWO_BYTES('.','d'),
							   TWO_BYTES('a','t'), TWO_BYTES('\0',0) };

	ChkDR(SetDeviceEnv(devCertTemplate, priv, TRUE));
 	ChkDR(TestGetClientID(&clientID));
	ChkDR(TestLicResponseSetClientID(&clientID));
	RemoveDRMFile(RMFILE_STORE);
	tGetDeviceStorePathname(&dstrHdsPath);
	ChkDR(OpenHDS(&g_pHdsContext, dstrHdsPath.pwszString, TRUE));
	ChkDR(SetupViewRightsContext(&g_oViewRightsContext));
ErrorExit:
	return dr;
}

DRM_RESULT VR_PostTestCase(long lTCID, char *strTCName)
{
	DRM_SST_CloseKey(&g_oGlobalSecStoreContext, g_pHdsContext);
	DRM_LST_Close(&g_oLicStoreContext);
	DX_VOS_MemFree(g_oLicEvalContext.pbRevocationBuffer);
	DX_VOS_MemFree(g_oViewRightsContext.pbBuffer);
	CleanGlobalStateData();

	CloseHDS(g_pHdsContext);
	RemoveDRMFile(RMFILE_STORE);
	return DRM_SUCCESS;
}

static DRM_RESULT WrapTestRun(long lTCID, DRM_BOOL fPreTestRun)
{
	return DRM_SUCCESS;
}

/*
BEGIN_APIMAP(RefViewRightsTest_ansi, "ViewRights")	
	API_ENTRY(TestGetLicenseAggregateData)
	API_ENTRY(TestIsAllowed)
	API_ENTRY(TestAddLicense)
	API_ENTRY(TestVerifyStateData)
END_APIMAP
*/

