// SchemeDoc.cpp : implementation of the CSchemeDoc class
//

#include "stdafx.h"
#include "xpeluc01.h"

#include "SchemeDoc.h"
#include "MainFrm.h"
#include "SchemeView.h"
#include "ProcessThread.h"
#include "..\\global\\iblock.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define __FONTSIZE		8
#define __PORTFONTSIZE	7

// CSchemeDoc

IMPLEMENT_DYNCREATE(CSchemeDoc, CDocument)

BEGIN_MESSAGE_MAP(CSchemeDoc, CDocument)
	ON_COMMAND(ID_PROCESS_TRIGGER, &CSchemeDoc::OnProcessTrigger)
	ON_UPDATE_COMMAND_UI(ID_PROCESS_TRIGGER, &CSchemeDoc::OnUpdateProcessTrigger)
	ON_COMMAND(ID_PROCESS_START, &CSchemeDoc::OnProcessStart)
	ON_UPDATE_COMMAND_UI(ID_PROCESS_START, &CSchemeDoc::OnUpdateProcessStart)
	ON_COMMAND(ID_PROCESS_STOP, &CSchemeDoc::OnProcessStop)
	ON_UPDATE_COMMAND_UI(ID_PROCESS_STOP, &CSchemeDoc::OnUpdateProcessStop)
END_MESSAGE_MAP()


// CSchemeDoc construction/destruction

CSchemeDoc::CSchemeDoc() : m_fontText(L"Tahoma", __FONTSIZE), m_fontPortText(L"Tahoma", __PORTFONTSIZE)
{
	// TODO: add one-time construction code here
	m_pBlockRoot = NULL;
//	m_pProcessThread = NULL;
	m_dwLastProcessId = 0;
//	CRuntimeClass *pRuntimeClass(RUNTIME_CLASS(CProcessThread));
	m_pProcessThread = new CProcessThread(this);//(CProcessThread*)pRuntimeClass->CreateObject();
	//m_pProcessThread->SetDocumentPtr(this);
	m_bRunningAuto = FALSE;
	m_pWndMain = AfxGetMainWnd();
	InitializeCriticalSection(&m_csViewer);
}

CSchemeDoc::~CSchemeDoc()
{

}

BOOL CSchemeDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	((CMainFrame*)AfxGetMainWnd())->DocumentAdd(this);

	m_pBlockRoot = CBlockItem_Virtual::CreateInstance();//new CBlockItem_Virtual;
	m_pBlockRoot->SetDocPtr(this);
	
//	m_setVirtualBlocks.insert(m_pBlockRoot);

	return TRUE;
}




// CSchemeDoc serialization

void CSchemeDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		//ar << m_pBlockRoot;
		m_pBlockRoot->Serialize(ar);
	}
	else
	{
		m_pBlockRoot = CBlockItem_Virtual::CreateInstance();//new CBlockItem_Virtual();
		m_pBlockRoot->SetDocPtr(this);
		//ar >> m_pBlockRoot;
		m_pBlockRoot->Serialize(ar);
	}
}


// CSchemeDoc diagnostics

#ifdef _DEBUG
void CSchemeDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CSchemeDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG


// CSchemeDoc commands

void CSchemeDoc::OnCloseDocument()
{
	((CMainFrame*)AfxGetMainWnd())->DocumentRemove(this);

	EnterCriticalSection(&m_csViewer);
	std::set<LPVIEWERSETDATA>::iterator it;
	while ( (it = m_setViewers.begin()) != m_setViewers.end() )
	{
		(*it)->pViewer->Release();
	}
	LeaveCriticalSection(&m_csViewer);


	if ( m_bRunningAuto )
		OnProcessStop();

	if ( m_pProcessThread )
		m_pProcessThread->Release();


	DeleteCriticalSection(&m_csViewer);


	if ( m_pBlockRoot )
		m_pBlockRoot->Release();//delete(m_pBlockRoot);






	CDocument::OnCloseDocument();
}
/*
BOOL CSchemeDoc::TestBlockPointer(CBlockItem_Virtual *ptr)
{
	if ( m_setVirtualBlocks.find(ptr) != m_setVirtualBlocks.end() )
		return TRUE;
	else
		return FALSE;
}*/
/*
VOID CSchemeDoc::Update(CView* pSender)
{
	POSITION pos = GetFirstViewPosition();
	while ( pos != NULL )
	{
		CView* pView = GetNextView(pos);
		if ( pView->GetRuntimeClass() == RUNTIME_CLASS(CSchemeView) )
		{
			if ( !TestBlockPointer(((CSchemeView*)pView)->GetThisBlock()) )
				RemoveView(pView);
		}
	}
	UpdateAllViews(pSender);
	}*/
BOOL CSchemeDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
	if (!CDocument::OnOpenDocument(lpszPathName))
		return FALSE;

	((CMainFrame*)AfxGetMainWnd())->DocumentAdd(this);

	m_pBlockRoot->SetDocPtr(this);

	return TRUE;
}

BOOL CSchemeDoc::UpdateViewerData(LPVIEWERSETDATA pViewerSetData)
{
	if ( m_setAllBlocks.find(pViewerSetData->pBlock) == m_setAllBlocks.end() )
		return FALSE;
	DWORD dwPort = pViewerSetData->dwPort;
	LPCRITICAL_SECTION pCs;

	//odalokujeme stara data vieweru

	if ( pViewerSetData->vdData.ppData )
	{
		for ( DWORD i = 0; i < pViewerSetData->vdData.dwLayers; i++ )
		{
			if ( pViewerSetData->vdData.ppData[i] )
				free(pViewerSetData->vdData.ppData[i]);
		}
		delete[](pViewerSetData->vdData.ppData);
	}

	if ( pViewerSetData->vdData.dwDataLenArray )
		delete[] (pViewerSetData->vdData.dwDataLenArray);
	pViewerSetData->vdData.ppData = NULL;
	pViewerSetData->vdData.dwLayers = 0;
	pViewerSetData->vdData.dwDataLenArray = NULL;

	switch ( pViewerSetData->bOutput )
	{
	case TRUE:
		pCs = pViewerSetData->pBlock->GetOutputCriticalSectionPtr(pViewerSetData->dwPort);
		if ( pCs )
		{
			EnterCriticalSection(pCs);

			PORTDATA portData = pViewerSetData->pBlock->GetOutputPortData(pViewerSetData->dwPort);
			
			pViewerSetData->vdData.ppData = new void*[portData.dwLayers];
			pViewerSetData->vdData.dwDataLenArray = new DWORD[portData.dwLayers];
			pViewerSetData->vdData.dwLayers = portData.dwLayers;
			for ( DWORD dwLayer = 0; dwLayer < portData.dwLayers; dwLayer++ )
			{
				pViewerSetData->vdData.ppData[dwLayer] = malloc(portData.dwDataLenArray[dwLayer]);
				memcpy(pViewerSetData->vdData.ppData[dwLayer], portData.pDataArray[dwLayer], portData.dwDataLenArray[dwLayer]);
				pViewerSetData->vdData.dwDataLenArray[dwLayer] = portData.dwDataLenArray[dwLayer];
			}
			LeaveCriticalSection(pCs);
		}
		break;
	case FALSE:
		CBlockItem *pBlock;
		if ( pViewerSetData->pBlock->GetInConnectorTarget(pViewerSetData->dwPort, &pBlock, &dwPort) )
		{
			pCs = pBlock->GetOutputCriticalSectionPtr(pViewerSetData->dwPort);
			if ( pCs )
			{
				EnterCriticalSection(pCs);

				PORTDATA portData = pBlock->GetOutputPortData(pViewerSetData->dwPort);
				
				pViewerSetData->vdData.ppData = new void*[portData.dwLayers];
				pViewerSetData->vdData.dwDataLenArray = new DWORD[portData.dwLayers];
				pViewerSetData->vdData.dwLayers = portData.dwLayers;
				for ( DWORD dwLayer = 0; dwLayer < portData.dwLayers; dwLayer++ )
				{
					pViewerSetData->vdData.ppData[dwLayer] = malloc(portData.dwDataLenArray[dwLayer]);
					memcpy(pViewerSetData->vdData.ppData[dwLayer], portData.pDataArray[dwLayer], portData.dwDataLenArray[dwLayer]);
					pViewerSetData->vdData.dwDataLenArray[dwLayer] = portData.dwDataLenArray[dwLayer];
				}
				LeaveCriticalSection(pCs);
			}
		}
		break;
	}
	return TRUE;
}

BOOL CSchemeDoc::UpdateViewers_Safe()
{
	m_pWndMain->PostMessage(WM_DATAUPDATE, (WPARAM)this, 0);
	return TRUE;
}

LPARAM CSchemeDoc::UpdateViewers(BOOL bRefresh)
{
	EnterCriticalSection(&m_csViewer);
	std::set<LPVIEWERSETDATA>::iterator it = m_setViewers.begin();
	while ( it != m_setViewers.end() )
	{
		UpdateViewerData((*it));
		(*it)->pViewer->SetData(&(*it)->vdData);
		if ( bRefresh )
			(*it)->pViewer->Refresh(m_bRunningAuto ? REFRESHTYPE_AUTOTRIGGER : REFRESHTYPE_TRIGGER);
		it++;
	}
	LeaveCriticalSection(&m_csViewer);
	return 0;
}

LPARAM CSchemeDoc::DestroyViewer(IViewer *pViewer)
{
	EnterCriticalSection(&m_csViewer);
	std::set<LPVIEWERSETDATA>::iterator it = m_setViewers.begin();
	for ( it; it != m_setViewers.end(); it++ )
	{
		if ( (*it)->pViewer == pViewer )
		{
			(*it)->pViewer->Release();
			if ( (*it)->vdData.ppData )
			{
				for ( DWORD i = 0; i < (*it)->vdData.dwLayers; i++ )
				{
					if ( (*it)->vdData.ppData[i] )
						free((*it)->vdData.ppData[i]);
				}
				delete[]((*it)->vdData.ppData);
			}
			if ( (*it)->vdData.dwDataLenArray )
				delete[] ((*it)->vdData.dwDataLenArray);
			delete (*it);
			m_setViewers.erase(it);
			break;
		}
	}
	LeaveCriticalSection(&m_csViewer);
	return 0;
}

void CSchemeDoc::OnProcessTrigger()
{
	m_pProcessThread->Run(FALSE);
	UpdateViewers();
}

void CSchemeDoc::OnUpdateProcessTrigger(CCmdUI *pCmdUI)
{
	pCmdUI->Enable(!m_pProcessThread->IsRunning() && !m_bRunningAuto);
}

void CSchemeDoc::OnProcessStart()
{
	std::set<CBlockItem*>::iterator it = m_setOwnTrigger.begin();
	while ( it != m_setOwnTrigger.end() )
	{
		(*it)->Start();
		it++;
	}
	m_bRunningAuto = TRUE;
}

void CSchemeDoc::OnUpdateProcessStart(CCmdUI *pCmdUI)
{
	pCmdUI->Enable(!m_pProcessThread->IsRunning() && !m_bRunningAuto);
}

void CSchemeDoc::OnProcessStop()
{
	std::set<CBlockItem*>::iterator it = m_setOwnTrigger.begin();
	while ( it != m_setOwnTrigger.end() )
	{
		(*it)->Stop();
		it++;
	}
	m_bRunningAuto = FALSE;	
}

void CSchemeDoc::OnUpdateProcessStop(CCmdUI *pCmdUI)
{
	pCmdUI->Enable(m_bRunningAuto);
	// TODO: Add your command update UI handler code here
}


BOOL CSchemeDoc::TriggerProc(HANDLE h)
{
	LPAUTOTRIGGERHANDLE ath = (LPAUTOTRIGGERHANDLE)h;
	((CSchemeDoc*)(ath->pDoc))->ProcessBlock(ath->pItem);
	((CSchemeDoc*)(ath->pDoc))->UpdateViewers_Safe();
	return TRUE;
}

BOOL CSchemeDoc::ProcessBlock(CBlockItem *pBlock)
{
	REVDATAMAP r;
	return pBlock->Process(m_dwLastProcessId++, r);
}

BOOL CSchemeDoc::OnIdleCustom(LONG lCount)
{
	BOOL bModified = m_bModified;
	if ( !m_bModified && m_pBlockRoot->GetModifiedFlag() )
		this->SetModifiedFlag();
	if ( m_bModified != bModified )
	{
		CString name = GetPathName();
		name = name.Mid(name.ReverseFind(L'\\') + 1) + L"*";
		this->SetTitle(name);
	}
	return TRUE;
}
BOOL CSchemeDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
	m_pBlockRoot->SetModifiedFlag(TRUE);
	return CDocument::OnSaveDocument(lpszPathName);
}

BOOL CSchemeDoc::CanCloseFrame(CFrameWnd* pFrame)
{
	// TODO: Add your specialized code here and/or call the base class

	OnIdleCustom(0);

	return CDocument::CanCloseFrame(pFrame);
}


