#include "stdafx.h"
#include "Block.h"

CBlock::CBlock() : m_refcount(0), m_dwInPortCount(0), m_dwOutPortCount(0), m_pDesc(L""), m_pPath(L""), m_pName(L"")
{
	m_pUnkOuter = this;
	ZeroMemory(&m_blockData, sizeof(m_blockData));
	m_bModified = FALSE;
}

CBlock::~CBlock()
{
	DeleteBlockData();
}

void* CBlock::GetInterface(const IID &riid)
{
	return NULL;
}

/////////////////////////////////////////////////////////////

STDMETHODIMP CBlock::QueryInterface(const IID &riid, void **ppvObject)
{
	if ( riid == IID_IUnknown )
		*ppvObject = (IUnknown*)this;
	else if ( riid == IID_IBlock )
		*ppvObject = (IBlock*)this;
	else *ppvObject = GetInterface(riid);
	if ( !*ppvObject )
		return E_NOINTERFACE;
	((IUnknown*)*ppvObject)->AddRef();
	return S_OK;
}

STDMETHODIMP_(ULONG) CBlock::AddRef(void)
{
	return InterlockedIncrement(&m_refcount);
}

STDMETHODIMP_(ULONG) CBlock::Release()
{
	if ( 0 == InterlockedDecrement(&m_refcount) )
	{
		delete(this);
		return 0;
	}
	return m_refcount;
}

STDMETHODIMP CBlock::GetInputCount(DWORD *pdwTarget)
{
	*pdwTarget = m_dwInPortCount;
	return S_OK;
}

STDMETHODIMP CBlock::GetOutputCount(DWORD *pdwTarget)
{
	*pdwTarget = m_dwOutPortCount;
	return S_OK;
}

STDMETHODIMP CBlock::GetName(CString &rstrName)
{
	rstrName = m_pName;
	return S_OK;
}

STDMETHODIMP CBlock::GetDescription(CString &rstrDescription)
{
	rstrDescription = m_pDesc;
	return S_OK;
}

STDMETHODIMP CBlock::GetInputPortName(DWORD dwPort, CString &rstrName)
{
	rstrName = m_pInputNameArray[dwPort];
	return S_OK;
}

STDMETHODIMP CBlock::GetOutputPortName(DWORD dwPort, CString &rstrName)
{
	rstrName = m_pOutputNameArray[dwPort];
	return S_OK;
}

STDMETHODIMP CBlock::InitInstance()
{
	MultiThreadInit();
	InitializeCriticalSection(&m_cs);
	return S_OK;
}

STDMETHODIMP CBlock::ExitInstance()
{
	MultiThreadRelease();
	DeleteCriticalSection(&m_cs);
	return S_OK;
}

STDMETHODIMP CBlock::ProcessData(const LPBLOCKDATA pInputData)
{
	return S_OK;
}

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

STDMETHODIMP CBlock::ProcessRev(const DWORD dwProcessId, REVDATAMAP &rRevDataMap)
{
	return S_OK;
}

STDMETHODIMP_(const PORTDATA) CBlock::GetOutputPortData(DWORD dwPort) const
{
	PORTDATA ret;
	ASSERT ( dwPort < m_dwOutPortCount );
	if ( m_blockData.pDataArrayArray )
	{
		ret.dwDataLenArray = m_blockData.dwDataLenArrayArray[dwPort];
		ret.dwLayers = m_blockData.dwLayersArray[dwPort];
		ret.pDataArray = m_blockData.pDataArrayArray[dwPort];
		return ret;
	}
	ZeroMemory(&ret, sizeof(ret));
	return ret;
}

STDMETHODIMP CBlock::GetBlockPath(CString &rstrPath)
{
	rstrPath = m_pPath;
	return S_OK;
}

STDMETHODIMP_(void) CBlock::Serialize(CArchive &ar)
{
}

STDMETHODIMP_(LPCRITICAL_SECTION) CBlock::GetCriticalSectionPtr()
{
	return &m_csData;
}

STDMETHODIMP_(BOOL) CBlock::GetModifiedFlag()
{
	return m_bModified;
}

STDMETHODIMP_(VOID) CBlock::SetModifiedFlag(BOOL bModified)
{
	m_bModified = bModified;
}

BOOL CBlock::DeleteBlockData()
{
	if ( m_blockData.pDataArrayArray )
	{
		ASSERT( m_blockData.pDataArrayArray &&
			m_blockData.dwLayersArray &&
			m_blockData.dwDataLenArrayArray );
		for ( DWORD i = 0; i < m_dwOutPortCount; i++ )
		{
			for ( DWORD j = 0; j < m_blockData.dwLayersArray[i]; j++ )
			{
				if ( m_blockData.pDataArrayArray[i][i] )
					free(m_blockData.pDataArrayArray[i][j]);
			}
			ASSERT( m_blockData.pDataArrayArray[i] );
			delete[](m_blockData.pDataArrayArray[i]);
			delete[](m_blockData.dwDataLenArrayArray[i]);
		}
		delete(m_blockData.dwLayersArray);
		delete[](m_blockData.pDataArrayArray);
		delete[](m_blockData.dwDataLenArrayArray);
	}
	else
	{
		ASSERT( NULL == m_blockData.pDataArrayArray &&
			NULL == m_blockData.dwLayersArray &&
			NULL == m_blockData.dwDataLenArrayArray);
	}
	m_blockData.dwDataLenArrayArray = NULL;
	m_blockData.dwLayersArray = NULL;
	m_blockData.pDataArrayArray = NULL;
	return TRUE;
}

BOOL CBlock::PrepareBlockData()
{
	ASSERT(m_blockData.dwLayersArray == NULL &&
		m_blockData.dwDataLenArrayArray == NULL &&
		m_blockData.pDataArrayArray == NULL);
	m_blockData.dwLayersArray = new DWORD[m_dwOutPortCount];
	m_blockData.dwDataLenArrayArray = new DWORD*[m_dwOutPortCount];
	m_blockData.pDataArrayArray = new void**[m_dwOutPortCount];

	ZeroMemory(m_blockData.dwLayersArray, sizeof(DWORD) * m_dwOutPortCount);
	ZeroMemory(m_blockData.dwDataLenArrayArray, sizeof(DWORD*) * m_dwOutPortCount);
	ZeroMemory(m_blockData.pDataArrayArray, sizeof(void**) * m_dwOutPortCount);
	return TRUE;
}

BOOL CBlock::NewBlockPortData(DWORD dwPort, DWORD dwLayers)
{
	// test, zda jsou porty inicializovany
	ASSERT(m_blockData.pDataArrayArray &&
		m_blockData.dwLayersArray &&
		m_blockData.dwDataLenArrayArray);
	// test, zda na portu jiz nejsou alokovany vrstvy dat
	ASSERT(m_blockData.pDataArrayArray[dwPort] == NULL &&
		m_blockData.dwLayersArray[dwPort] == 0 &&
		m_blockData.dwDataLenArrayArray[dwPort] == 0);
	////
	m_blockData.pDataArrayArray[dwPort] = new void*[dwLayers];
	m_blockData.dwLayersArray[dwPort] = dwLayers;
	m_blockData.dwDataLenArrayArray[dwPort] = new DWORD[dwLayers];
	// nulovani naalokovanych dat
	ZeroMemory(m_blockData.pDataArrayArray[dwPort], sizeof(void*) * dwLayers);
	ZeroMemory(m_blockData.dwDataLenArrayArray[dwPort], sizeof(DWORD) * dwLayers);
	return TRUE;
}

BOOL CBlock::MultiThreadInit()
{
	InitializeCriticalSection(&m_csData);
	return TRUE;
}

BOOL CBlock::MultiThreadRelease()
{
	DeleteCriticalSection(&m_csData);
	return TRUE;
}

VOID CBlock::LockBlockData()
{
	EnterCriticalSection(&m_csData);
}

VOID CBlock::UnlockBlockData()
{
	LeaveCriticalSection(&m_csData);
}

VOID CBlock::SetDataPtr(DWORD dwPort, DWORD dwLayer, void* ptr, DWORD dwDataLen)
{
	ASSERT(m_blockData.pDataArrayArray &&
		m_blockData.dwLayersArray &&
		m_blockData.pDataArrayArray &&
		m_blockData.pDataArrayArray &&
		dwPort < m_dwOutPortCount
		&& dwLayer < m_blockData.dwLayersArray[dwPort]);
	if ( m_blockData.pDataArrayArray[dwPort][dwLayer] )
		free(m_blockData.pDataArrayArray[dwPort][dwLayer]);
	m_blockData.pDataArrayArray[dwPort][dwLayer] = ptr;
	m_blockData.dwDataLenArrayArray[dwPort][dwLayer] = dwDataLen;
}








CBlockConfig::CBlockConfig(IUnknown *pUnkOuter) : m_pUnkOuter(pUnkOuter)
{
}

CBlockConfig::~CBlockConfig()
{
}

STDMETHODIMP CBlockConfig::QueryInterface(const IID &riid, void **ppvObject)
{
	return m_pUnkOuter->QueryInterface(riid, ppvObject);
}

STDMETHODIMP_(ULONG) CBlockConfig::AddRef()
{
	return m_pUnkOuter->AddRef();
}

STDMETHODIMP_(ULONG) CBlockConfig::Release()
{
	return m_pUnkOuter->Release();
}

STDMETHODIMP CBlockConfig::ShowConfig()
{
	return S_OK;
}

STDMETHODIMP CBlockConfig::RefreshData()
{
	return S_OK;
}

CBlockAutoTrigger::CBlockAutoTrigger(IUnknown *pUnkOuter) : m_pUnkOuter(pUnkOuter)
{
}

CBlockAutoTrigger::~CBlockAutoTrigger()
{
}

STDMETHODIMP CBlockAutoTrigger::QueryInterface(const IID &riid, void **ppvObject)
{
	return m_pUnkOuter->QueryInterface(riid, ppvObject);
}

STDMETHODIMP_(ULONG) CBlockAutoTrigger::AddRef()
{
	return m_pUnkOuter->AddRef();
}

STDMETHODIMP_(ULONG) CBlockAutoTrigger::Release()
{
	return m_pUnkOuter->Release();
}

STDMETHODIMP CBlockAutoTrigger::Start(CDocument *pDoc)
{
	return S_OK;
}

STDMETHODIMP CBlockAutoTrigger::Stop()
{
	return S_OK;
}