//
// 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.
//
////////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <tchar.h>
#include "globals.h"
#include "logging.h"
#include "Index.h"

TimeStampIndex::TimeStampIndex(TCHAR* szIndexFile) :
	m_nFrames(0)
{
	_tcsncpy(m_szIndexFile, szIndexFile, countof(m_szIndexFile));
	ParseIndexFile();
}

HRESULT TimeStampIndex::ParseIndexFile()
{
	HRESULT hr = S_OK;
	
	FILE* fp = _tfopen(m_szIndexFile, TEXT("r"));
	if (!fp)
		return E_FAIL;

	TCHAR line[1024];

	// Read and discard the first line
	if (!_ftscanf(fp, TEXT("%[^\n]"), line))
	{
		LOG(TEXT("%S: ERROR %d@%s - error in parsing index file."), __FUNCTION__, __LINE__, __FILE__);
		return E_FAIL;
	}
	fgetc(fp);

	TimeStampIndexEntry entry;
	int nEntries = 0;
	while (!feof(fp))
	{
		if (!_ftscanf(fp, TEXT("%[^\n]"), line))
		{
			LOG(TEXT("%S: ERROR %d@%s - error in parsing index file."), __FUNCTION__, __LINE__, __FILE__);
			hr = E_FAIL;
			break;
		}
		fgetc(fp);

		memset(&entry, 0, sizeof(entry));

		TCHAR szSample[2];
		LONGLONG ats;
		DWORD datalen;
		TCHAR syncPoint = TEXT(' ');
		TCHAR preroll = TEXT(' ');
		TCHAR discontinuity = TEXT(' ');

		int nFieldsParsed = 0;
		nFieldsParsed = _stscanf(line, TEXT("%s %d %I64d:%I64d %I64d %d %c%c%c"), 
							szSample, &entry.framenum, &entry.start, &entry.stop, &ats, &datalen, &syncPoint, &preroll, &discontinuity);

		// We should atleast parse 6 fields - excluding the last three flags
		if (nFieldsParsed < 6)
			break;

		if (syncPoint == TEXT('K'))
			entry.bSyncPoint = true;

		if (preroll == TEXT('P'))
			entry.bPreroll = true;

		if (discontinuity == TEXT('D'))
			entry.bDiscontinuity = true;

		m_IndexList.push_back(entry);
		nEntries++;
	}

	// Save the number of frames parsed - there are some implicit assumptions here
	if (SUCCEEDED(hr))
		m_nFrames = nEntries;
	
	// Close the file
	if (fp)
		fclose(fp);

	return hr;
}

HRESULT TimeStampIndex::GetNumFrames(int* pNumFrames)
{
	if (!pNumFrames)
		return E_POINTER;

	*pNumFrames = m_nFrames;
	return S_OK;
}

HRESULT TimeStampIndex::GetTimeStamps(int framenum, LONGLONG* pStart, LONGLONG* pStop)
{
	if ((framenum < 0) || (framenum >= m_nFrames))
		return E_INVALIDARG;

	TimeStampIndexEntry entry = m_IndexList.at(framenum);
	if (pStart)
		*pStart = entry.start;
	if (pStop)
		*pStop = entry.stop;

	return S_OK;
}

HRESULT TimeStampIndex::GetNearestKeyFrames(LONGLONG start, int* pPrevKeyFrame, int* pNextKeyFrame)
{
	TimeStampIndexList::iterator iterator = m_IndexList.begin();

	int prevKeyFrame = -1;
	int nextKeyFrame = -1;

	while(iterator != m_IndexList.end())
	{
		TimeStampIndexEntry& entry = *iterator;

		// If this is a sync point, note down the frame no
		// Note it down as the prev key frame if the start time is less than the passed in start time
		// Note it down as both the next and prev key frame if it is equal
		// Note it down as the next key frame if it is greater
		if (entry.bSyncPoint)
		{
			if (entry.start == start)
				nextKeyFrame = prevKeyFrame = entry.framenum;
			else if (entry.start < start)
				prevKeyFrame = entry.framenum;
			else
				nextKeyFrame = entry.framenum;
		}

		// As soon as both the prev and next are set, break out of the loop
		if ((prevKeyFrame != -1) && (nextKeyFrame != -1))
			break;

		// Increment to the next entry
		iterator++;
	}

	if (pPrevKeyFrame)
		*pPrevKeyFrame = prevKeyFrame;

	if (pNextKeyFrame)
		*pNextKeyFrame = nextKeyFrame;

	return S_OK;
}

HRESULT TimeStampIndex::GetNearestKeyFrames(int framenum, 
							LONGLONG* pPrevStart, LONGLONG* pPrevStop, 
							LONGLONG* pNextStart, LONGLONG* pNextStop)
{
	return E_NOTIMPL;
}

FrameIndex::FrameIndex(TCHAR* szIndexFile)
{
}

HRESULT FrameIndex::VerifyFrame(int framenum, IMediaSample* pMediaSample)
{
	return E_NOTIMPL;
}

HRESULT FrameIndex::GetFrame(int framenum, IMediaSample** ppMediaSample)
{
	return E_NOTIMPL;
}