/*

Na zacatku tohoto souboru je nastaveni chovani bloku. Pote jsou zde funkce
nezvytne k vytvoreni instance COMu, a funkce, ktera vraci ukazatele na
rozhrani bloku. Prozatim se predpokladaji pouze 2 pridavna rozhrani k tomuto
objektu. 

-- IBlockConfig --
je urcene ke konfiguraci bloku. Je pouzito
v pripade, kdyz uzivatel klikne pravym tlacitkem mysi na blok a vybere
volbu "properties...". Melo by se otevrit okno s nastavenim, ktere musi
byt implementovano

-- IBlockAutoTrigger --
slouzi k automatickemu spousteni procesu. Vyuzije se napriklad pri realtime
zpracovani zvuku a videa, kdy potrebujeme pravidelne zpracovavat useky dat

*/


#include "stdafx.h"
#include "imp_block.h"
#include "imp_config.h"
#include "imp_autotrigger.h"
#include <deque>

// jmeno, popis a cesta k bloku
const LPWSTR g_pName = L"Signal Mirror";
const LPWSTR g_pDesc = L"Copies selected reverse signal to output port";
const LPWSTR g_pPath = L"General";
// jestli ma blok rohrani, odkomentujte prislusny radek
#define __BLOCKHAVECONFIGWINDOW
//#define __BLOCKHAVEAUTOTRIGGER
// pocty vstupnich a vystupnich portu
const DWORD g_dwInPortCount = 0;
const DWORD g_dwOutPortCount = 1;
// nazvy vstupnich a vystupnich portu
const WCHAR *g_pInputNameArray[] = {NULL};
const WCHAR *g_pOutputNameArray[] = {L"SIG"};

// Tyto funkce nemenit !!!
// funkce volana klientskym programem k vytvoreni instance tridy

HRESULT CreateBlockInstance(REFIID riid, void **ppv)
{
	return CImpBlock::CreateInstance(riid, ppv);
}
// staticka funkce, ktera vytvari instanci tridy
HRESULT CImpBlock::CreateInstance(const IID &riid, void **ppv)
{
	CImpBlock* pObj; 
	pObj = new CImpBlock();
	if (pObj == NULL) 
		return E_OUTOFMEMORY; 
	HRESULT hr; 
	if ( FAILED(hr = pObj->QueryInterface(riid, (void**)ppv))) 
		delete pObj ; 
	return hr; 
}
// funkce, ktera vraci adresu rozhrani
void* CImpBlock::GetInterface(REFIID riid)
{
#ifdef __BLOCKHAVECONFIGWINDOW
	if ( IID_IBlockConfig == riid )
		return m_pxConfig;
#endif
#ifdef __BLOCKHAVEAUTOTRIGGER
	if ( IID_IBlockAutoTrigger == riid )
		return m_pxAutoTrigger;
#endif
	return NULL;
}
// konstruktor
CImpBlock::CImpBlock() : m_pxConfig(NULL), m_pxAutoTrigger(NULL)
{
#ifdef __BLOCKHAVECONFIGWINDOW
	m_pxConfig = new CImpBlockConfig(this);
#endif
#ifdef __BLOCKHAVEAUTOTRIGGER
	m_pxAutoTrigger = new CImpBlockAutoTrigger(this);
#endif
	m_dwInPortCount = g_dwInPortCount;
	m_dwOutPortCount = g_dwOutPortCount;
	m_pName = g_pName;
	m_pDesc = g_pDesc;
	m_pPath = g_pPath;
	m_pInputNameArray = g_pInputNameArray;
	m_pOutputNameArray = g_pOutputNameArray;

	// inicializace promennych

	m_dwSigNum = 0;
}
// destruktor
CImpBlock::~CImpBlock()
{
	if ( m_pxAutoTrigger )
		delete ( m_pxAutoTrigger );
	if ( m_pxConfig )
		delete ( m_pxConfig );
}

///////////////////////////////
// TYTO FUNKCE IMPLEMENTOVAT //
///////////////////////////////

STDMETHODIMP CImpBlock::InitInstance()
{
	CBlock::InitInstance();
	return S_OK;
}

STDMETHODIMP CImpBlock::ExitInstance()
{
	CBlock::ExitInstance();
	return S_OK;
}

STDMETHODIMP CImpBlock::ProcessRev(const DWORD dwProcessId, REVDATAMAP &rRevDataMap)
{
	EnterCriticalSection(&m_cs);
	DWORD dwSigNum = m_dwSigNum;
	LeaveCriticalSection(&m_cs);
	REVDATAMAP::iterator it = rRevDataMap.find(dwSigNum);
	if ( it == rRevDataMap.end() )
	{
		m_rd.dwDataLen = 0;
		m_rd.pData = NULL;
	}
	else
	{
		m_rd.dwDataLen = it->second.dwDataLen;
		m_rd.pData = it->second.pData;
	}
	return S_OK;
}

STDMETHODIMP CImpBlock::ClearRevMap(REVDATAMAP &rRevDataMapClean)
{
	return S_OK;
}

STDMETHODIMP CImpBlock::ProcessData(const LPBLOCKDATA pInputData)
{
	LPVOID data = NULL;
	if ( m_rd.dwDataLen )
	{
		data = malloc(m_rd.dwDataLen);
		memcpy(data, m_rd.pData, m_rd.dwDataLen);
	}
	LockBlockData();
	DeleteBlockData();
	PrepareBlockData();
	NewBlockPortData(0, 1); // jedna vrstva
	SetDataPtr(0, 0, data, m_rd.dwDataLen);
	UnlockBlockData();
	return S_OK;
}

STDMETHODIMP_(void) CImpBlock::Serialize(CArchive &ar)
{
	if ( ar.IsStoring() )
	{
		ar << m_dwSigNum;
	}
	else
	{
		ar >> m_dwSigNum;
	}
}