//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
////////////////////////////////////////////////////////////////////////////////

#ifndef EVENTLOGGER_H
#define EVENTLOGGER_H

#include <tchar.h>
#include "globals.h"
#include "Position.h"
#include "GraphEvent.h"
#include "TapFilter.h"
#include "FrameRecognizer.h"
#include "RemoteEvent.h"

class ILogger;
class TestGraph;

#include <map>

using namespace std;

enum EventLoggerType {
	// Generic sample logger
	SampleProperties,

	// Audio/Video specific loggers
	VideoFrameData,
	VideoTimeStamps,	
	AudioFrameData,
	AudioTimeStamps,

	LogFrameNumbers,
	StreamData,
	GraphEvents,
	RemoteEvents,

	// Instrumeters
	InsertFrameNumbers,


	// End marker
	EventLoggerEndMarker
};

// The event logger interface
class IEventLogger
{
public:
	virtual ~IEventLogger() {};
	virtual HRESULT Init(TestGraph* pTestGraph, EventLoggerType type, void *pEventLoggerData) = 0;
	virtual HRESULT ProcessEvent(GraphEvent event, void* pEventData, void* pTapCallbackData) = 0;
	virtual HRESULT Start() = 0;
	virtual void Stop() = 0;
	virtual void Reset() = 0;
};

// EventLogger list is a list of <EventLoggerType, > pairs
typedef map<int, IEventLogger*> EventLoggerList;
typedef pair <int, IEventLogger*> EventLoggerPair;

// Factory method to create verifiers given a pointer to verification data
typedef HRESULT (*EventLoggerFactory)(EventLoggerType type, void* pEventLoggerData, TestGraph* pTestGraph, IEventLogger** ppEventLogger);
HRESULT GenericLoggerCallback(GraphEvent event, void* pGraphEventData, void* pTapCallbackData, void *pObject);

struct EventLoggerFactoryTableEntry
{
	EventLoggerType type;
	EventLoggerFactory fn;
};

// EventLogger data strcutures
// This contains the actual sample that was tapped
struct SampleEventData
{
	LONGLONG currpos;
	LONGLONG pts;
	LONGLONG dts;
	LONGLONG ats;
	DWORD buflen;
	BYTE* pBuffer;
};

// This contains the sample time-stamps
struct TimeStampEventData
{
	LONGLONG currpos;
	LONGLONG pts;
	LONGLONG dts;
	LONGLONG ats;
};

const TCHAR* GetEventLoggerString(EventLoggerType type);

// Is this verification possible
bool IsLoggable(EventLoggerType type);

// Factory method for verifiers
HRESULT CreateEventLogger(EventLoggerType type, void* pVerificationData, TestGraph* pTestGraph, IEventLogger** ppGraphVerifier);
HRESULT CreateVideoDecoderOutputLogger(EventLoggerType type, void* pEventLoggerData, TestGraph* pTestGraph, IEventLogger** ppEventLogger);
HRESULT CreateSampleLogger(EventLoggerType type, void* pEventLoggerData, TestGraph* pTestGraph, IEventLogger** ppEventLogger);
HRESULT CreateGraphEventLogger(EventLoggerType type, void* pEventLoggerData, TestGraph* pTestGraph, IEventLogger** ppEventLogger);
HRESULT CreateRemoteEventLogger(EventLoggerType type, void* pEventLoggerData, TestGraph* pTestGraph, IEventLogger** ppEventLogger);
HRESULT CreateFrameNumberInstrumenter(EventLoggerType type, void* pEventLoggerData, TestGraph* pTestGraph, IEventLogger** ppEventLogger);
HRESULT CreateFrameNumberLogger(EventLoggerType type, void* pEventLoggerData, TestGraph* pTestGraph, IEventLogger** ppEventLogger);
HRESULT CreateStreamLogger(EventLoggerType type, void* pEventLoggerData, TestGraph* pTestGraph, IEventLogger** ppEventLogger);

// Loggers
class VideoDecoderOutputLogger : public IEventLogger
{
public:
	VideoDecoderOutputLogger();
	virtual ~VideoDecoderOutputLogger();
	virtual HRESULT Init(TestGraph* pTestGraph, EventLoggerType type, void *pEventLoggerData);
	virtual void ProcessEvent(GraphEvent event, void* pGraphEventData);
	virtual HRESULT Start();
	virtual void Stop();
	virtual void Reset();

private:
	EventLoggerType m_EventLoggerType;
	TCHAR m_szLogFile[MAX_PATH];
	HANDLE m_hFile;
};

struct SampleLoggerData
{
	DWORD filterType;
	GUID mediaType;
	TCHAR szLogFile[MAX_PATH];
	PIN_DIRECTION pindir;

	SampleLoggerData(DWORD filterType, PIN_DIRECTION pindir, GUID mediaType, TCHAR* szLogFile)
	{
		this->filterType = filterType;
		this->mediaType = mediaType;
		this->pindir = pindir;
		_tcsncpy(this->szLogFile, szLogFile, countof(this->szLogFile));
	}
};


class SampleLogger : public IEventLogger
{
public:
	SampleLogger();
	virtual ~SampleLogger();
	virtual HRESULT Init(TestGraph* pTestGraph, EventLoggerType type, void *pEventLoggerData);
	virtual HRESULT ProcessEvent(GraphEvent event, void* pEventData, void* pTapCallbackData);
	virtual HRESULT Start();
	virtual void Stop();
	virtual void Reset();

private:
	int m_nSamples;
	AM_MEDIA_TYPE m_mt;
	EventLoggerType m_EventLoggerType;
	TCHAR m_szLogFile[MAX_PATH];
	HANDLE m_hFile;
	HRESULT m_hr;
};


struct GraphEventLoggerData
{
	DWORD filterType;
	GUID mediaType;
	TCHAR szLogFile[MAX_PATH];
	PIN_DIRECTION pindir;

	GraphEventLoggerData(DWORD filterType, PIN_DIRECTION pindir, GUID mediaType, TCHAR* szLogFile)
	{
		this->filterType = filterType;
		this->mediaType = mediaType;
		this->pindir = pindir;
		_tcsncpy(this->szLogFile, szLogFile, countof(this->szLogFile));
	}
};

class GraphEventLogger : public IEventLogger
{
public:
	GraphEventLogger();
	virtual ~GraphEventLogger();
	virtual HRESULT Init(TestGraph* pTestGraph, EventLoggerType type, void *pEventLoggerData);
	virtual HRESULT ProcessEvent(GraphEvent event, void* pEventData, void* pTapCallbackData);
	virtual HRESULT Start();
	virtual void Stop();
	virtual void Reset();

private:
	int m_nSamples;
	AM_MEDIA_TYPE m_mt;
	EventLoggerType m_EventLoggerType;
	TCHAR m_szLogFile[MAX_PATH];
	HANDLE m_hFile;
	HRESULT m_hr;
};

struct RemoteEventLoggerData
{
	TCHAR szLoggerName[FILTER_NAME_LEN];
	DWORD filterType;
	GUID mediaType;
	PIN_DIRECTION pindir;
	IPin* pTapPin;
	ILogger* pLogger;
    
	RemoteEventLoggerData(TCHAR* szLoggerName, DWORD filterType, PIN_DIRECTION pindir, GUID mediaType, ILogger* pLogger)
	{
		this->filterType = filterType;
		this->mediaType = mediaType;
		this->pindir = pindir;
		this->pTapPin = NULL;
		this->pLogger = pLogger;
		_tcsncpy(this->szLoggerName, szLoggerName, countof(this->szLoggerName));
	}

	RemoteEventLoggerData(TCHAR* szLoggerName, IPin* pTapPin, ILogger* pLogger)
	{
		this->pTapPin = pTapPin;
		this->pLogger = pLogger;
		_tcsncpy(this->szLoggerName, szLoggerName, countof(this->szLoggerName));
	}
};

class RemoteEventLogger : public IEventLogger
{
public:
	RemoteEventLogger();
	virtual ~RemoteEventLogger();
	virtual HRESULT Init(TestGraph* pTestGraph, EventLoggerType type, void *pEventLoggerData);
	virtual HRESULT ProcessEvent(GraphEvent event, void* pEventData, void* pTapCallbackData);
	virtual HRESULT Start();
	virtual void Stop();
	virtual void Reset();

private:
	enum {
		GRAPH_EVENT_BUFFER_SIZE = 512,
		REMOTE_EVENT_BUFFER_SIZE = 512
	};

	TCHAR szLoggerName[FILTER_NAME_LEN];
	int m_nSamples;
	AM_MEDIA_TYPE m_mt;
	EventLoggerType m_EventLoggerType;
	ILogger* m_pLogger;
	HRESULT m_hr;
	BYTE m_GraphEventBuffer[GRAPH_EVENT_BUFFER_SIZE];
	BYTE m_RemoteEventBuffer[REMOTE_EVENT_BUFFER_SIZE];
};


struct FrameNumberInstrumenterData
{
	DWORD filterType;
	GUID mediaType;
	PIN_DIRECTION pindir;

	FrameNumberInstrumenterData(DWORD filterType, PIN_DIRECTION pindir, GUID mediaType)
	{
		this->filterType = filterType;
		this->mediaType = mediaType;
		this->pindir = pindir;
	}
};

class FrameNumberInstrumenter : public IEventLogger
{
public:
	FrameNumberInstrumenter();
	virtual ~FrameNumberInstrumenter();
	virtual HRESULT Init(TestGraph* pTestGraph, EventLoggerType type, void *pEventLoggerData);
	virtual HRESULT ProcessEvent(GraphEvent event, void* pEventData, void* pTapCallbackData);
	virtual HRESULT Start();
	virtual void Stop();
	virtual void Reset();

private:
	int m_nSamples;
	AM_MEDIA_TYPE m_mt;
	EventLoggerType m_EventLoggerType;
	TCHAR m_szLogFile[MAX_PATH];
	HRESULT m_hr;
	VideoFrameInstrumenter m_Instrumenter;
};

struct FrameNumberLoggerData
{
	DWORD filterType;
	GUID mediaType;
	PIN_DIRECTION pindir;

	FrameNumberLoggerData(DWORD filterType, PIN_DIRECTION pindir, GUID mediaType)
	{
		this->filterType = filterType;
		this->mediaType = mediaType;
		this->pindir = pindir;
	}
};

class FrameNumberLogger : public IEventLogger
{
public:
	FrameNumberLogger();
	virtual ~FrameNumberLogger();
	virtual HRESULT Init(TestGraph* pTestGraph, EventLoggerType type, void *pEventLoggerData);
	virtual HRESULT ProcessEvent(GraphEvent event, void* pEventData, void* pTapCallbackData);
	virtual HRESULT Start();
	virtual void Stop();
	virtual void Reset();
	

private:
	int m_nSamples;
	AM_MEDIA_TYPE m_mt;
	EventLoggerType m_EventLoggerType;
	TCHAR m_szLogFile[MAX_PATH];
	HRESULT m_hr;
	VideoFrameRecognizer m_Recognizer;
};

class StreamLogger : public IEventLogger
    {
    public:
   	StreamLogger();
  	virtual ~StreamLogger();
  	virtual HRESULT Init(TestGraph* pTestGraph, EventLoggerType type, void *pEventLoggerData);
  	virtual HRESULT ProcessEvent(GraphEvent event, void* pEventData, void* pTapCallbackData);
  	virtual HRESULT Start();
  	virtual void Stop();
  	virtual void Reset();
  
    private:
  	TCHAR m_szCheckSumFile[MAX_PATH];
  	TCHAR m_szLogFile[MAX_PATH];
  	HANDLE m_hLogFile;
  	HANDLE m_hCheckSumFile;
    };
  
    // Since there will be a tap filter for each output pin, there will also be a corresponding StreamLoggerData object for each as well.
    class StreamLoggerData
    {
    public:
    	DWORD primaryType;			// Attempt to connect to log output of filter of this type first
   		DWORD secondaryType;		// Fall back to logging this filter's output if primaryType is not found.
    	TCHAR szOutFile[MAX_PATH];	// File name to use as a basis for output file names
  		HANDLE hStreamFile;			// handle to the file to write stream data to
   		HANDLE hChecksumFile;		// handle to the file to write checksum data to
		BOOL	bRenderStream;		// Drop the samples after logging the data or keep and render them?
		BOOL	bLogStream;			// Log the stream data to a file?
		BOOL	bLogChecksum;		// Log the checksum data to a file?
  
  	StreamLoggerData()
  	{
  		this->primaryType = -1;
  		this->secondaryType = -1;
  		memset(szOutFile, 0, sizeof(szOutFile));
  		hStreamFile = INVALID_HANDLE_VALUE;
  		hChecksumFile = INVALID_HANDLE_VALUE;
		bRenderStream = true;
		bLogStream = false;
		bLogChecksum = false;
  	}

	StreamLoggerData(StreamLoggerData * pData)
	{
		this->primaryType = pData->primaryType;
		this->secondaryType = pData->secondaryType;
		memcpy(szOutFile,pData->szOutFile, sizeof(szOutFile));
		hStreamFile = INVALID_HANDLE_VALUE;
		hChecksumFile = INVALID_HANDLE_VALUE;
		bRenderStream = pData->bRenderStream;
		bLogStream = pData->bLogStream;
		bLogChecksum = pData->bLogChecksum;
	}

  	~StreamLoggerData()
  	{
		if(INVALID_HANDLE_VALUE != hStreamFile && NULL != hStreamFile)
			CloseHandle(hStreamFile);
		if(INVALID_HANDLE_VALUE != hChecksumFile && NULL != hChecksumFile)
			CloseHandle(hChecksumFile);
  	}
  		
    };

#endif