/*

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>
#include "..\\global\\headers.h"

// jmeno, popis a cesta k bloku
const LPWSTR g_pName = L"Histogram";
const LPWSTR g_pDesc = L"Generates histogram from grayscale bitmap";
const LPWSTR g_pPath = L"Analysis";
// jestli ma blok rohrani, odkomentujte prislusny radek
//#define __BLOCKHAVECONFIGWINDOW
//#define __BLOCKHAVEAUTOTRIGGER
// pocty vstupnich a vystupnich portu
const DWORD g_dwInPortCount = 1;
const DWORD g_dwOutPortCount = 1;
// nazvy vstupnich a vystupnich portu
const WCHAR *g_pInputNameArray[] = {L"GRAYIMG"};
const WCHAR *g_pOutputNameArray[] = {L"HIST"};

// 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
}
// 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)
{
	return S_OK;
}

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

STDMETHODIMP CImpBlock::ProcessData(const LPBLOCKDATA pInputData)
{
	std::deque<std::pair<void*, DWORD> > dqLayers;
	DWORD dwLayers = 0;

	PLOTHEADER phEnd;
	phEnd.dataType = DATATYPE_EOP;
	phEnd.dwDataLen = 0;
	phEnd.itemType = ITEMTYPE_BYTE;
	PLOTFILEHEADER pfhEnd;
	ZeroMemory(&pfhEnd, sizeof(pfhEnd));

	// zpracovani dat

	for ( DWORD dwLayer = 0; dwLayer < pInputData->dwLayersArray[0]; dwLayer++ )
	{
		if ( pInputData->dwDataLenArrayArray[0][dwLayer] >= sizeof(BITMAPFILEHEADER) )
		{
			BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)pInputData->pDataArrayArray[0][dwLayer];
			if ( bfh->bfType == 0x4d42 )
			{	// jedna se o BMP soubor
				BITMAPINFOHEADER *bih = (BITMAPINFOHEADER*)&((BYTE*)((BITMAPINFOHEADER*)pInputData->pDataArrayArray[0][dwLayer]))[sizeof(BITMAPFILEHEADER)];
				if ( bih->biBitCount == 8 )
				{	// jedna se o 8bit obrazek
					BYTE* bdata = &((BYTE*)((BITMAPINFOHEADER*)pInputData->pDataArrayArray[0][dwLayer]))[sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
					DWORD dwLen = sizeof(PLOTFILEHEADER)	// hlavicka souboru
						+ sizeof(PLOTHEADER)				// hlavicka plotu	- hodnoty Y
						+ 256*sizeof(DWORD)					// jednotlive prvky
						+ sizeof(PLOTHEADER)				// hlavicka plotu	- hodnoty X
						+ 256*sizeof(DWORD)					// jednotlive prvky
						+ sizeof(PLOTHEADER)				// konec plotu
						+ sizeof(PLOTFILEHEADER);			// konec souboru
 					BYTE* data = (BYTE*)malloc(dwLen);

					// hlavicka souboru

					PLOTFILEHEADER* pfh = (PLOTFILEHEADER*)data;
					memcpy(pfh->type, "plot", 4);

					// hlavicka plotu

					PLOTHEADER *ph = (PLOTHEADER*)&data[sizeof(PLOTFILEHEADER)];
					ph->dataType = DATATYPE_YVALUES;
					ph->itemType = ITEMTYPE_DWORD;
					ph->dwDataLen = 256;

					DWORD* datahist = (DWORD*)&ph[1];
					ZeroMemory(datahist, sizeof(DWORD)*256);
					for ( int i = 0; i < bih->biHeight * bih->biWidth; i++ )
					{
						datahist[*bdata]++;
						bdata++;
					}

					BYTE* datatmp = (BYTE*)&datahist[256]; // posunuti data na konec
					
					ph = (PLOTHEADER*)datatmp;
					ph->dataType = DATATYPE_XVALUES;
					ph->dwDataLen = 256;
					ph->itemType = ITEMTYPE_BYTE;

					datatmp = (BYTE*)&ph[1];

					for ( DWORD i = 0; i < 256; i++ )
					{
						*(BYTE*)datatmp = (BYTE)i;
						datatmp += sizeof(BYTE);
					}

//					*((DATATYPE*)datatmp) = DATATYPE_EOP;
//					datatmp += sizeof(DATATYPE);

					*(PLOTHEADER*)datatmp = phEnd;
					datatmp += sizeof(PLOTHEADER);
					*(PLOTFILEHEADER*)datatmp = pfhEnd;

					dqLayers.push_back(std::pair<LPVOID, DWORD>(data, dwLen));
					dwLayers++;
				}
			}
		}
	}

	LockBlockData();
	DeleteBlockData();
	PrepareBlockData();
	NewBlockPortData(0, dwLayers);
	dwLayers = 0;
	while ( !dqLayers.empty() )
	{
		SetDataPtr(0, dwLayers++, dqLayers.front().first, dqLayers.front().second);
		dqLayers.pop_front();		
	}
	UnlockBlockData();
	return S_OK;
}

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