/** 
 * \file Media.cpp
 * \brief CMedia class member functions implementation. CMedia is encapsulation class for 
 * DirectShow. It manages graphBuilder for playing mp3 and avi files. Providing user
 * simple 'Init and Play' interface.
 * 
 * \author Petar Bajic, MPE (C) All Rights Reserved, Homepage: www.mystic-peanut.com
 * \date January, 16 2007.
 */

#include "Media.h"

/**
 * \brief Standard constructor.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
CMedia::CMedia()
{
	m_graphBuilder = NULL;
	m_mediaControl = NULL;
	m_mediaSeeking = NULL;
	m_mediaEvent = NULL;
	m_Paused = false;
	m_Looping = false;
}

/**
 * \brief Standard destructor.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
CMedia::~CMedia()
{
	SAFE_RELEASE(m_graphBuilder);
	SAFE_RELEASE(m_mediaControl);
	SAFE_RELEASE(m_mediaSeeking);
	SAFE_RELEASE(m_mediaEvent);
}

/**
 * \brief Loads music file and creates GraphBuilder.
 * \param filename - media file
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
bool CMedia::Init(HWND hWnd, LPCWSTR filename)
{
	HRESULT hr;

	CoInitialize(NULL); //Initialise COM
	//Next we need to create our filter graph manager, this provides the interfaces 
	//needed to create the other two objects

	//Create the Filter Graph Manager
	if(FAILED(hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_graphBuilder)))
		return false;
	//Instantiate our media control object:
	if(FAILED(hr = m_graphBuilder->QueryInterface(IID_IMediaControl, (void **)&m_mediaControl)))
		return false;
	//Instantiate our media event object:
	if(FAILED(hr = m_graphBuilder->QueryInterface (IID_IMediaEvent, (void **)&m_mediaEvent)))
		return false;
	//Instantiate our media event object:
	if(FAILED(hr = m_graphBuilder->QueryInterface (IID_IMediaSeeking, (void **)&m_mediaSeeking)))
		return false;
	if (FAILED(hr = m_graphBuilder->RenderFile(filename, NULL)))
		return false;

	return true;
}

/**
 * \brief Plays music file.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
bool CMedia::Play()
{
	//Play music/video
	HRESULT hr = m_mediaControl->Run(); //Run the graph - note: starts a new thread
	if(!m_Paused)
	{
		m_mediaSeeking->GetCurrentPosition(&m_begin);
	}
	m_Paused = false;
	if (FAILED(hr))
	{
		return false;
	}

	return true;
}

/**
 * \brief Sets loop option for playing file.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CMedia::SetLoop()
{
	m_Looping = true;
}

/**
 * \brief Pause music file.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
bool CMedia::Pause()
{
	//Stop music/video
	HRESULT hr = m_mediaControl->Stop();
	m_Paused = true;
	if (FAILED(hr))
	{
		return false;
	}
	return true;
}

/**
 * \brief Stops music file.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
bool CMedia::Stop()
{
	m_Looping = false;
	//Stop music/video
	HRESULT hr = m_mediaControl->Stop();
	if (FAILED(hr))
	{
		return false;
	}
	m_Paused = false;
	hr = m_mediaSeeking->SetPositions(&m_begin,AM_SEEKING_AbsolutePositioning,0,0);
	if (FAILED(hr))
	{
		return false;
	}
	return true;
}

/**
 * \brief This function catches graph events.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CMedia::OnGraphEvent()
{
	long EventCode, Param1, Param2;
	HRESULT hr;
	m_mediaEvent->GetEvent(&EventCode, &Param1, &Param2, 0);
	{
		switch (EventCode)
		{
		// react to specific events here
		case EC_COMPLETE:
			// here when media is completely done playing
			if (!m_Looping)
	        	hr = m_mediaControl->Stop();
			hr = m_mediaSeeking->SetPositions(&m_begin,AM_SEEKING_AbsolutePositioning,0,0);
			break;
		default:
			break;
		}	
		m_mediaEvent->FreeEventParams(EventCode, Param1, Param2);
	}
}
