// SchemeView.cpp : implementation of the CSchemeView class
//

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

#include "SchemeDoc.h"
#include "SchemeView.h"
#include "SchemeTreeView.h"

#include "BlockItem_Input.h"
#include "BlockItem_Output.h"
#include "BlockItem_Real.h"
#include "MainFrm.h"
#include "ViewersDoc.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define __BLOCKSPACINGTOP				2
#define __BLOCKSPACINGTEXT				14
#define __BLOCKSPACINGUNDERTEXT			4
#define __BLOCKSPACINGBOTTOMTEXT		14
#define __BLOCKSPACINGBOTTOMTEXTTOP		2
#define __BLOCKSPACINGBOTTOM			2
#define __PORTHEIGHT					7
#define __PORTWIDTH					7
#define __PORTSPACING					3
#define __BLOCKWIDTH					64

#define __MOUSETHRESHOLD				1

#define __STATE_NONE					0
#define __STATE_SELECTION				1
#define __STATE_MOVE					2
#define __STATE_CONNECT					3

#define __BLOCKSTATE_SELECTED			1
#define __BLOCKSTATE_RUN				2
#define __BLOCKSTATE_AUTOTRIGGER		4

// CSchemeView

BOOL ExtendRect(LPRECT rc, int nValue)
{
	rc->bottom += nValue + 1;
	rc->left -= nValue;
	rc->right += nValue + 1;
	rc->top -= nValue;
	return TRUE;
}

Rect CorrectRect(Point p, Size s)
{
	Rect ret;
	if ( s.Width >= 0 )
	{
		ret.Width = s.Width;
		ret.X = p.X;
	}
	else
	{
		ret.Width = -s.Width;
		ret.X = p.X + s.Width;
	}
	if ( s.Height >= 0 )
	{
		ret.Height = s.Height;
		ret.Y = p.Y;
	}
	else
	{
		ret.Height = -s.Height;
		ret.Y = p.Y + s.Height;
	}
	return ret;
}

RECT CorrectRECT(Point p, Size s)
{
	RECT ret;
	ZeroMemory(&ret, sizeof(ret));
	if ( s.Width >= 0 )
	{
		ret.left = p.X;
		ret.right = s.Width + p.X + 1;
	}
	else
	{
		ret.left = p.X + s.Width;
		ret.right = p.X + 1;
	}
	if ( s.Height >= 0 )
	{
		ret.top = p.Y;
		ret.bottom = s.Height + p.Y + 1;
	}
	else
	{
		ret.top = p.Y + s.Height;
		ret.bottom = p.Y + 1;
		
	}
	return ret;
}

IMPLEMENT_DYNCREATE(CSchemeView, CView)

BEGIN_MESSAGE_MAP(CSchemeView, CView)
ON_WM_ERASEBKGND()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
//ON_WM_MBUTTONDBLCLK()
ON_WM_LBUTTONDBLCLK()
ON_WM_RBUTTONDOWN()
ON_UPDATE_COMMAND_UI(ID_POPUP1_PROPERTIE, &CSchemeView::OnUpdatePopup1Propertie)
ON_COMMAND(ID_POPUP1_PROPERTIE, &CSchemeView::OnPopup1Propertie)
ON_UPDATE_COMMAND_UI(ID_POPUP1_DELETE, &CSchemeView::OnUpdatePopup1Delete)
ON_COMMAND(ID_POPUP1_DELETE, &CSchemeView::OnPopup1Delete)
ON_COMMAND(ID_POPUP1_EXECUTEWHENPROCESS, &CSchemeView::OnPopup1Executewhenprocess)
ON_UPDATE_COMMAND_UI(ID_POPUP1_EXECUTEWHENPROCESS, &CSchemeView::OnUpdatePopup1Executewhenprocess)
ON_COMMAND(ID_POPUP1_HAVEOWNTRIGGER, &CSchemeView::OnPopup1Haveowntrigger)
ON_UPDATE_COMMAND_UI(ID_POPUP1_HAVEOWNTRIGGER, &CSchemeView::OnUpdatePopup1Haveowntrigger)
ON_MESSAGE(WM_UPDATEVIEW, &CSchemeView::OnUpdateView)
END_MESSAGE_MAP()

// CSchemeView construction/destruction

CSchemeView::CSchemeView()
{
	m_sUserData.dwState = __STATE_NONE;
}

CSchemeView::~CSchemeView()
{
}

BOOL CSchemeView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CView::PreCreateWindow(cs);
}

// CSchemeView drawing

void CSchemeView::OnDraw(CDC* pDC)
{
	CSchemeDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	CDC dcMemory;
	CBitmap bmp;
	RECT rc;
	GetClientRect(&rc);
	bmp.CreateCompatibleBitmap(pDC, rc.right, rc.bottom);
	dcMemory.CreateCompatibleDC(pDC);
	CBitmap* pOldBitmap = dcMemory.SelectObject(&bmp);

	dcMemory.BitBlt(0, 0, rc.right, rc.bottom, NULL, 0, 0, WHITENESS);

	POSITION pos = m_pThisBlock->GetFirstBlock();
	while ( pos )
	{
		CBlockItem * ptr = m_pThisBlock->GetNextBlock(pos);
		std::set<CBlockItem*>::iterator it;
		DWORD dwState = 0;
		if ( m_sUserData.setSelection.find(ptr) != m_sUserData.setSelection.end() )
			dwState |= __BLOCKSTATE_SELECTED;
		if ( pDoc->m_setOwnTrigger.find(ptr) != pDoc->m_setOwnTrigger.end() )
			dwState |= __BLOCKSTATE_AUTOTRIGGER;
		if ( pDoc->m_setRun.find(ptr) != pDoc->m_setRun.end() )
			dwState |= __BLOCKSTATE_RUN;
		DrawBlock(&dcMemory, ptr, dwState);
	}

	pos = m_pThisBlock->GetFirstBlock();
	while ( pos )
	{
		CBlockItem * ptr = m_pThisBlock->GetNextBlock(pos);
		std::set<CBlockItem*>::iterator it;
		DrawWires(&dcMemory, ptr);
	}

	DrawSelection(&dcMemory);

	pDC->BitBlt(0, 0, rc.right, rc.bottom, &dcMemory, 0, 0, SRCCOPY);

	dcMemory.SelectObject(pOldBitmap);
}

// CSchemeView diagnostics

#ifdef _DEBUG
void CSchemeView::AssertValid() const
{
	CView::AssertValid();
}

void CSchemeView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CSchemeDoc* CSchemeView::GetDocument() const // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSchemeDoc)));
	return (CSchemeDoc*)m_pDocument;
}
#endif //_DEBUG


// CSchemeView message handlers

void CSchemeView::OnInitialUpdate()
{
	m_oleDropTgt.Register(this);
	m_nClipboardFormat = RegisterClipboardFormat(L"XPELUC01_CLIPBOARD_FORMAT");
	m_pThisBlock = GetDocument()->m_pBlockRoot;
	CView::OnInitialUpdate();

	// TODO: Add your specialized code here and/or call the base class
}

DROPEFFECT CSchemeView::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
	if ( pDataObject->IsDataAvailable(m_nClipboardFormat) )
		return DROPEFFECT_COPY;
	return DROPEFFECT_NONE;
}

void CSchemeView::OnDragLeave()
{
	CView::OnDragLeave();
}

DROPEFFECT CSchemeView::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
	if ( pDataObject->IsDataAvailable(m_nClipboardFormat) )
		return DROPEFFECT_COPY;
	return DROPEFFECT_NONE;
}

BOOL CSchemeView::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)
{
	STGMEDIUM stgmed;
	pDataObject->GetData(m_nClipboardFormat, &stgmed);
	LPVOID pData = GlobalLock(stgmed.hGlobal);
	DWORD dwSize = GlobalSize(stgmed.hGlobal);
	CSchemeDoc* pDoc = GetDocument();

	CBlockItem *ptr = NULL;

	CMemFile file((BYTE*)pData, dwSize);
	CArchive ar(&file, CArchive::load);

	ar >> ptr;

	ar.Close();
	file.Close();

	GlobalUnlock(stgmed.hGlobal);

	RECT rc;
	GetClientRect(&rc);
	POINTF pos;
	pos.x = (float)point.x / rc.right;
	pos.y = (float)point.y / rc.bottom;
	ptr->SetPos(&pos);

	m_pThisBlock->InsertBlock(ptr);
	ptr->Release();//delete(ptr);

	pDoc->SetModifiedFlag();
	pDoc->UpdateAllViews(NULL);

	return TRUE;
}

void CSchemeView::OnUpdate(CView* /*pSender*/, LPARAM /*lHint*/, CObject* /*pHint*/)
{
	CSchemeDoc* pDoc = GetDocument();
	Invalidate();

}

CBlockItem_Virtual* CSchemeView::GetThisBlock()
{
	return m_pThisBlock;
}

BOOL CSchemeView::SetThisBlock(CBlockItem_Virtual *ptr)
{
	m_pThisBlock = ptr;
	this->Invalidate(FALSE);
	return TRUE;
}

BOOL CSchemeView::DrawBlock(CDC *pDC, CBlockItem *ptr, DWORD dwState)
{
	RECT rc;
	CSchemeDoc* pDoc = GetDocument();
	GetBlockRect(ptr, &rc);
	Graphics myGraphics(pDC->m_hDC);
	RectF rcf;
	rcf.X = (REAL)(rc.left);
	rcf.Y = (REAL)(rc.top);
	rcf.Width = (REAL)(rc.right - rc.left);
	rcf.Height = (REAL)(rc.bottom - rc.top);

	if ( dwState & __BLOCKSTATE_SELECTED ) // vyber
		myGraphics.FillRectangle(&SolidBrush(Color(224, 224, 248)), rcf);
	else
		myGraphics.FillRectangle(&SolidBrush(Color(248,248,248)), rcf);
//	if ( dwState & __BLOCKSTATE_RUN )
//		myGraphics.FillRectangle(&HatchBrush(HatchStyleWeave, Color(64, 255, 192, 128), Color(0, 0, 0, 0)), rcf);

	myGraphics.DrawRectangle(&Pen(Color(128,128,128), 1.0f), rcf);

	StringFormat sFormat;
	sFormat.SetAlignment(StringAlignmentNear);

	for ( DWORD i = 0; i < ptr->GetInputCount(); i++ )
	{
		Rect rcPort;
		GetPortRect(ptr, i, &rcPort, FALSE);
		myGraphics.FillRectangle(&SolidBrush(Color(255,255,255)), rcPort);
		myGraphics.DrawRectangle(&Pen(Color(128,128,128)), rcPort);
		RectF rcPortF((REAL)(rcPort.X + __PORTWIDTH + 1), (REAL)(rcPort.Y - 1), __BLOCKWIDTH - __PORTWIDTH, __PORTHEIGHT + __PORTSPACING);
		myGraphics.DrawString(ptr->GetInputPortName(i), -1, &pDoc->m_fontPortText, rcPortF, &sFormat, &SolidBrush(Color(0, 0, 0)));
	}

	sFormat.SetAlignment(StringAlignmentFar);

	for ( DWORD i = 0; i < ptr->GetOutputCount(); i++ )
	{
		Rect rcPort;
		GetPortRect(ptr, i, &rcPort, TRUE);
		myGraphics.FillRectangle(&SolidBrush(Color(255,255,255)), rcPort);
		myGraphics.DrawRectangle(&Pen(Color(128,128,128)), rcPort);
		RectF rcPortF((REAL)(rcPort.X + rcPort.Width - __BLOCKWIDTH), (REAL)(rcPort.Y - 1), __BLOCKWIDTH - __PORTWIDTH, __PORTHEIGHT + __PORTSPACING);
		myGraphics.DrawString(ptr->GetOutputPortName(i), -1, &pDoc->m_fontPortText, rcPortF, &sFormat, &SolidBrush(Color(0, 0, 0)));
	}

	rcf.Width -= 1;
	rcf.X += 1;

	sFormat.SetAlignment(StringAlignmentCenter);
	rcf.Y = (REAL)(rc.top + __BLOCKSPACINGTOP);
	rcf.Height = (REAL)(__BLOCKSPACINGTEXT) - 1;
	if ( ptr->IsKindOf(RUNTIME_CLASS(CBlockItem_Input)) ||
		ptr->IsKindOf(RUNTIME_CLASS(CBlockItem_Output)) )
		myGraphics.FillRectangle(&LinearGradientBrush(rcf, Color(128, 255, 192, 128), Color(192, 255, 224, 224), LinearGradientModeHorizontal), rcf);
	else if ( ptr->IsKindOf(RUNTIME_CLASS(CBlockItem_Real)) )
		myGraphics.FillRectangle(&LinearGradientBrush(rcf, Color(128, 128, 255, 192), Color(192, 224, 255, 224), LinearGradientModeHorizontal), rcf);
	else
		myGraphics.FillRectangle(&LinearGradientBrush(rcf, Color(128, 128, 128, 255), Color(192, 224, 224, 255), LinearGradientModeHorizontal), rcf);
	myGraphics.DrawString(ptr->GetName(), -1, &pDoc->m_fontText, rcf, &sFormat, &SolidBrush(Color(0, 0, 0)));
	
	sFormat.SetAlignment(StringAlignmentFar);
	rcf.Y = (REAL)(rc.bottom - __BLOCKSPACINGBOTTOM - __BLOCKSPACINGBOTTOMTEXT);
	rcf.Height = (REAL)(__BLOCKSPACINGBOTTOMTEXT) - 1;

	CString strXtra;
	if ( dwState & __BLOCKSTATE_RUN )
		strXtra += "(r)";
	if ( dwState & __BLOCKSTATE_AUTOTRIGGER )
		strXtra += "(a)";
	strXtra += ptr->GetStatus();
	myGraphics.DrawString(strXtra, -1, &pDoc->m_fontText, rcf, &sFormat, &SolidBrush(Color(0, 0, 0)));

	return TRUE;
}

BOOL CSchemeView::DrawWires(CDC* pDC, CBlockItem* ptr)
{
	Graphics myGraphics(pDC->m_hDC);
	myGraphics.SetSmoothingMode(SmoothingModeAntiAlias);
	Pen penLine(Color(0, 0, 0));
	for ( DWORD i = 0; i < ptr->GetInputCount(); i++ )
	{
		
		CBlockItem* pTgtBlock;
		DWORD dwTgtPort;
		if ( ptr->GetInConnectorTarget(i, &pTgtBlock, &dwTgtPort) )
		{
			Point p1 = GetPortCenter(ptr, i, FALSE);
			Point p2 = GetPortCenter(pTgtBlock, dwTgtPort, TRUE);
			myGraphics.DrawLine(&penLine, p1, p2);
		}
	}
	return TRUE;
}

BOOL CSchemeView::GetPortRect(CBlockItem* ptr, DWORD dwPort, Rect *rc, BOOL bOutput)
{
	RECT rcBlk;
	GetBlockRect(ptr, &rcBlk);
	switch ( bOutput )
	{
	case TRUE:
		// vystupni port
		ASSERT(dwPort < ptr->GetOutputCount());
		rc->X = rcBlk.right - __PORTWIDTH;
		rc->Width = __PORTWIDTH;
		rc->Y = rcBlk.top + __BLOCKSPACINGTOP + __BLOCKSPACINGTEXT + __BLOCKSPACINGUNDERTEXT + dwPort * __PORTHEIGHT + (dwPort-1) * __PORTSPACING;
		rc->Height = __PORTHEIGHT;
		break;
	default:
		ASSERT(dwPort < ptr->GetInputCount());
		rc->X = rcBlk.left;
		rc->Width = __PORTWIDTH;
		rc->Y = rcBlk.top + __BLOCKSPACINGTOP + __BLOCKSPACINGTEXT + __BLOCKSPACINGUNDERTEXT + dwPort * __PORTHEIGHT + (dwPort-1) * __PORTSPACING;
		rc->Height = __PORTHEIGHT;
		// vstupni port
		break;
	}
	return TRUE;
}

BOOL CSchemeView::GetPortRect(CBlockItem* ptr, DWORD dwPort, CRect *rc, BOOL bOutput)
{
	RECT rcBlk;
	GetBlockRect(ptr, &rcBlk);
	switch ( bOutput )
	{
	case TRUE:
		// vystupni port
		ASSERT(dwPort < ptr->GetOutputCount());
		rc->left = rcBlk.right - __PORTWIDTH;
		rc->right = rc->left + __PORTWIDTH;
		rc->top = rcBlk.top + __BLOCKSPACINGTOP + __BLOCKSPACINGTEXT + __BLOCKSPACINGUNDERTEXT + dwPort * __PORTHEIGHT + (dwPort-1) * __PORTSPACING;
		rc->bottom = rc->top + __PORTHEIGHT;
		break;
	default:
		ASSERT(dwPort < ptr->GetInputCount());
		rc->left = rcBlk.left;
		rc->right = rc->left + __PORTWIDTH;
		rc->top = rcBlk.top + __BLOCKSPACINGTOP + __BLOCKSPACINGTEXT + __BLOCKSPACINGUNDERTEXT + dwPort * __PORTHEIGHT + (dwPort-1) * __PORTSPACING;
		rc->bottom = rc->top + __PORTHEIGHT;
		// vstupni port
		break;
	}
	return TRUE;
}


BOOL CSchemeView::GetBlockRect(CBlockItem *ptr, LPRECT pRcTgt)
{
	RECT rc;
	GetClientRect(&rc);
	POINTF ptf;
	ptr->GetPos(&ptf);
	POINTF ptcenter;
	ptcenter.x = ptf.x * rc.right;
	ptcenter.y = ptf.y * rc.bottom;

	DWORD dwBlockHeight = __BLOCKSPACINGTOP + __BLOCKSPACINGTEXT + __BLOCKSPACINGUNDERTEXT + __BLOCKSPACINGBOTTOM + __BLOCKSPACINGBOTTOMTEXT + __BLOCKSPACINGBOTTOMTEXTTOP;
	DWORD dwMaxPorts = ( (dwMaxPorts = ptr->GetInputCount()) > ptr->GetOutputCount() ) ? dwMaxPorts : ptr->GetOutputCount();
	dwBlockHeight += dwMaxPorts * __PORTHEIGHT + (dwMaxPorts-1) * __PORTSPACING;

	pRcTgt->left = (LONG)(ptcenter.x - __BLOCKWIDTH);
	pRcTgt->right = (LONG)(ptcenter.x + __BLOCKWIDTH);
	pRcTgt->top = (LONG)(ptcenter.y - dwBlockHeight / 2);
	pRcTgt->bottom = (LONG)(ptcenter.y + dwBlockHeight / 2);
	return TRUE;
}
BOOL CSchemeView::OnEraseBkgnd(CDC* pDC)
{
	return FALSE;
}

void CSchemeView::OnLButtonDown(UINT nFlags, CPoint point)
{
	CBlockItem* pItem;
	m_sUserData.bMoved = FALSE;
	m_sUserData.bSelectOnBtnRls = FALSE;
	if ( !(pItem = GetBlockOnPos(point)) )
	{	// nejsem na bloku
		if ( !(nFlags & MK_CONTROL) )
		{	// nezmacknuto CTRL - smazat vyber
			std::set<CBlockItem*>::iterator it;
			for ( it = m_sUserData.setSelection.begin(); it != m_sUserData.setSelection.end(); it++ )
			{
				RECT rc;
				GetBlockRect((*it), &rc);
				ExtendRect(&rc, 1);
				InvalidateRect(&rc, FALSE);
			}
			m_sUserData.setSelection.clear();
		}
		m_sUserData.dwState = __STATE_SELECTION;
		m_sUserData.selPoint.X = point.x;
		m_sUserData.selPoint.Y = point.y;
		m_sUserData.selSize.Height = 0;
		m_sUserData.selSize.Width = 0;
		SetCapture();
	}
	else
	{	// jsem na bloku
		DWORD dwPort;
		BOOL bOutput;
		if ( IsPortOnPos(point, pItem, &dwPort, &bOutput) )
		{	// jsem na portu
			if ( bOutput )
			{	// na vystupnim portu
				m_sUserData.dwPortFrom = dwPort;
				m_sUserData.pConFrom = pItem;
				m_sUserData.dwPortTo = -1;
				m_sUserData.pConTo = NULL;
			}
			else
			{	// na vstupnim portu
				m_sUserData.dwPortFrom = -1;
				m_sUserData.pConFrom = NULL;
				m_sUserData.dwPortTo = dwPort;
				m_sUserData.pConTo = pItem;
			}
			m_sUserData.selPoint = GetPortCenter(pItem, dwPort, bOutput);
			m_sUserData.dwState = __STATE_CONNECT;
		}
		else
		{
			m_sUserData.selPoint.X = point.x;
			m_sUserData.selPoint.Y = point.y;
			m_sUserData.dwState = __STATE_MOVE;
			std::set<CBlockItem*>::iterator it;
			if ( (nFlags & MK_CONTROL) )
			{	// zmacknuto CTRL
				if ( (it = m_sUserData.setSelection.find(pItem)) != m_sUserData.setSelection.end() )
				{	// blok je ve vyberu / rusim ho
					m_sUserData.setSelection.erase(it);
				}
				else
				{	// blok neni ve vyberu / pridam ho
					m_sUserData.setSelection.insert(pItem);
				}
				RECT rc;
				GetBlockRect(pItem, &rc);
				ExtendRect(&rc, 1);
				InvalidateRect(&rc);
			}
			else
			{	// neni zmacknuto CTRL
				if ( (it = m_sUserData.setSelection.find(pItem)) != m_sUserData.setSelection.end() )
				{	// blok je ve vyberu - pockam na pusteni mysi
					//m_sUserData.setSelection.erase(it);
					m_sUserData.bSelectOnBtnRls = TRUE;
				}
				else
				{	// blok neni ve vyberu - oznacim pouze jej
					std::set<CBlockItem*>::iterator it;
					for ( it = m_sUserData.setSelection.begin(); it != m_sUserData.setSelection.end(); it++ )
					{
						RECT rc;
						GetBlockRect((*it), &rc);
						ExtendRect(&rc, 1);
						InvalidateRect(&rc, FALSE);
					}
					m_sUserData.setSelection.clear();
					m_sUserData.setSelection.insert(pItem);
					RECT rc;
					GetBlockRect(pItem, &rc);
					ExtendRect(&rc, 1);
					InvalidateRect(&rc);
				}			
			}
		}
		SetCapture();
	}
	CView::OnLButtonDown(nFlags, point);
}


void CSchemeView::OnLButtonUp(UINT nFlags, CPoint point)
{
	switch ( m_sUserData.dwState )
	{
	case __STATE_SELECTION:
		{
			if ( !m_sUserData.bMoved && !(nFlags & MK_CONTROL) )
			{
				std::set<CBlockItem*>::iterator it;
				for ( it = m_sUserData.setSelection.begin(); it != m_sUserData.setSelection.end(); it++ )
				{
					RECT rc;
					GetBlockRect((*it), &rc);
					ExtendRect(&rc, 1);
					InvalidateRect(&rc, FALSE);
				}
				m_sUserData.setSelection.clear();
			}
			m_sUserData.dwState = __STATE_NONE;
			UpdateSelection();
			m_sUserData.selSize.Width = point.x - m_sUserData.selPoint.X;
			m_sUserData.selSize.Height = point.y - m_sUserData.selPoint.Y;
			RECT r = CorrectRECT(m_sUserData.selPoint, m_sUserData.selSize);
			m_sUserData.selSize.Height = 0;
			m_sUserData.selSize.Width = 0;
			InvalidateRect(&r);
			ReleaseCapture();
		}
		break;
	case __STATE_MOVE:
		{
			if ( m_sUserData.bSelectOnBtnRls )
			{	// kdyz se ma selekce provest az po pusteni mysi
				if ( !m_sUserData.bMoved )
				{	// nebyl zaznamenan pohyb mysi
					CBlockItem *p;
					CPoint pt;
					pt.x = m_sUserData.selPoint.X;
					pt.y = m_sUserData.selPoint.Y;
					if ( p = GetBlockOnPos(pt) )
					{	// vybereme pouze tento jeden blok
						std::set<CBlockItem*>::iterator it;
						for ( it = m_sUserData.setSelection.begin(); it != m_sUserData.setSelection.end(); it++ )
						{
							RECT rc;
							GetBlockRect((*it), &rc);
							ExtendRect(&rc, 1);
							InvalidateRect(&rc, FALSE);
						}
						m_sUserData.setSelection.clear();
						m_sUserData.setSelection.insert(p);
						RECT rc;
						GetBlockRect(p, &rc);
						ExtendRect(&rc, 1);
						InvalidateRect(&rc);
					}
				}
			}
			m_sUserData.dwState = __STATE_NONE;
			ReleaseCapture();
		}
		break;
	case __STATE_CONNECT:
		{
			RECT rc = CorrectRECT(m_sUserData.selPoint, m_sUserData.selSize);
			ExtendRect(&rc, __PORTWIDTH + 1);
			//InvalidateRect(&rc, FALSE);	
			Invalidate(FALSE);

			DWORD dwPort;
			BOOL bOutput;
			CBlockItem* p;
			if ( (p = GetBlockOnPos(point)) && (IsPortOnPos(point, p, &dwPort, &bOutput)) && (bOutput == (m_sUserData.pConFrom == NULL) ) )
			{
				if ( bOutput )
				{
					m_sUserData.pConFrom = p;
					m_sUserData.dwPortFrom = dwPort;
				}
				else
				{
					m_sUserData.pConTo = p;
					m_sUserData.dwPortTo = dwPort;
				}
				// mame vyplneny info o vstupu i o vystupu
				m_sUserData.pConTo->SetInConnectorTarget(m_sUserData.dwPortTo, m_sUserData.pConFrom, m_sUserData.dwPortFrom);
			}
			else if ( m_sUserData.pConTo )
			{
				m_sUserData.pConTo->SetInConnectorTarget(m_sUserData.dwPortTo, NULL, -1);
			}

			ReleaseCapture();
			m_sUserData.dwState = __STATE_NONE;
		}
		break;
	}
	CView::OnLButtonUp(nFlags, point);
}

void CSchemeView::OnMouseMove(UINT nFlags, CPoint point)
{
	CSchemeDoc* pDoc = GetDocument();
	switch ( m_sUserData.dwState )
	{
	case __STATE_SELECTION:
		{
			RECT r;
			r = CorrectRECT(m_sUserData.selPoint, m_sUserData.selSize);
			InvalidateRect(&r, FALSE);
			m_sUserData.selSize.Width = point.x - m_sUserData.selPoint.X;
			m_sUserData.selSize.Height = point.y - m_sUserData.selPoint.Y;
			r = CorrectRECT(m_sUserData.selPoint, m_sUserData.selSize);
			InvalidateRect(&r, FALSE);
		}
		break;
	case __STATE_MOVE:
		if ( m_sUserData.bMoved )
		{	// kdyz pohybujeme s bloky
			int dX = point.x - m_sUserData.selPoint.X;
			int dY = point.y - m_sUserData.selPoint.Y;
			std::map<CBlockItem*, POINTF>::iterator it;
			RECT rcClient;
			GetClientRect(&rcClient);
			for ( it = m_sUserData.mapMoveData.begin(); it != m_sUserData.mapMoveData.end(); it++ )
			{
				RECT rc;
				GetBlockRect(it->first, &rc);
				ExtendRect(&rc, 1);
				InvalidateRect(&rc, FALSE);
				POINTF pos;
				pos = (*it).second;
				pos.x += (float)dX / rcClient.right;
				pos.y += (float)dY / rcClient.bottom;
				if ( pos.x <= 0 )
					pos.x = 0;
				else if (pos.x >= 1)
					pos.x = 1;
				if ( pos.y <= 0 )
					pos.y = 0;
				else if (pos.y >= 1)
					pos.y = 1;
				(*it).first->SetPos(&pos);
				GetBlockRect(it->first, &rc);
				ExtendRect(&rc, 1);
				InvalidateRect(&rc, FALSE);
			}
		}
		else
		{
			if ( abs(point.x - m_sUserData.selPoint.X) >= __MOUSETHRESHOLD ||
				abs(point.y - m_sUserData.selPoint.Y) >= __MOUSETHRESHOLD )
			{
				m_sUserData.bMoved = TRUE;
				m_sUserData.mapMoveData.clear();
				std::set<CBlockItem*>::iterator it;
				for ( it = m_sUserData.setSelection.begin(); it != m_sUserData.setSelection.end(); it++)
				{
					POINTF ptf;
					(*it)->GetPos(&ptf);
					m_sUserData.mapMoveData.insert( std::pair<CBlockItem*, POINTF> (*it, ptf) );
				}
			}
		}
		
		pDoc->SetModifiedFlag();
		pDoc->UpdateAllViews(NULL);
		break;
	case __STATE_CONNECT:
		{
			RECT rc = CorrectRECT(m_sUserData.selPoint, m_sUserData.selSize);
			ExtendRect(&rc, __PORTWIDTH + 1);
			InvalidateRect(&rc, FALSE);
			ASSERT(m_sUserData.pConFrom || m_sUserData.pConTo);
			if ( m_sUserData.pConFrom )
			{
				m_sUserData.selPoint = GetPortCenter(m_sUserData.pConFrom, m_sUserData.dwPortFrom, TRUE);
			}
			else
			{
				m_sUserData.selPoint = GetPortCenter(m_sUserData.pConTo, m_sUserData.dwPortTo, FALSE);
			}
			m_sUserData.selSize.Width = point.x - m_sUserData.selPoint.X;
			m_sUserData.selSize.Height = point.y - m_sUserData.selPoint.Y;
			rc = CorrectRECT(m_sUserData.selPoint, m_sUserData.selSize);
			ExtendRect(&rc, __PORTWIDTH + 1);
			InvalidateRect(&rc, FALSE);
		}
		break;
	}
	CView::OnMouseMove(nFlags, point);
}

BOOL CSchemeView::DrawSelection(CDC *pDC)
{
	switch ( m_sUserData.dwState )
	{
	case __STATE_SELECTION:
		{
			Rect r = CorrectRect(m_sUserData.selPoint, m_sUserData.selSize);
			Graphics myGraphics(pDC->m_hDC);
			myGraphics.FillRectangle(&SolidBrush(Color(64, 0, 0, 255)), r);
			myGraphics.DrawRectangle(&Pen(Color(0, 0, 0)), r);
		}
		break;
	case __STATE_CONNECT:
		{
			Point tgt = m_sUserData.selPoint + m_sUserData.selSize;
			Graphics myGraphics(pDC->m_hDC);
			Pen penLine(Color(128,128,128));
			CBlockItem *p;
			DWORD dwPort;
			BOOL bOutput;
			CPoint pt;
			pt.x = tgt.X;
			pt.y = tgt.Y;
			myGraphics.SetSmoothingMode(SmoothingModeAntiAlias);
			if ( (p = GetBlockOnPos(pt)) && (IsPortOnPos(pt, p, &dwPort, &bOutput)) && (bOutput == (m_sUserData.pConFrom == NULL) ) )
			{
				myGraphics.DrawLine(&penLine, m_sUserData.selPoint, GetPortCenter(p, dwPort, bOutput));
			}
			else
				myGraphics.DrawLine(&penLine, m_sUserData.selPoint, tgt);
		}
		break;
	}
	return TRUE;
}

BOOL CSchemeView::UpdateSelection()
{
	POSITION pos = m_pThisBlock->GetFirstBlock();
	RECT rc = CorrectRECT(m_sUserData.selPoint, m_sUserData.selSize);
	CRect rcSel = rc;
	
	while ( pos )
	{
		CBlockItem * ptr = m_pThisBlock->GetNextBlock(pos);
		RECT rcBlk;
		GetBlockRect(ptr, &rcBlk);
		if ( rcSel.PtInRect(CRect(rcBlk).TopLeft())
			&& rcSel.PtInRect(CRect(rcBlk).BottomRight()) )
		{
			std::set<CBlockItem*>::iterator it;
			if ( (it = m_sUserData.setSelection.find(ptr)) != m_sUserData.setSelection.end() )
				m_sUserData.setSelection.erase(it);
			else
				m_sUserData.setSelection.insert(ptr);
		}

	}
	return TRUE;
}

CBlockItem* CSchemeView::GetBlockOnPos(CPoint p)
{
	POSITION pos = m_pThisBlock->GetLastBlock();
	while ( pos )
	{
		CBlockItem * ptr = m_pThisBlock->GetPrevBlock(pos);
		RECT rcBlk;
		GetBlockRect(ptr, &rcBlk);
		if ( ((CRect)rcBlk).PtInRect(p) )
		{
			return ptr;
		}

	}
	return NULL;
}

BOOL CSchemeView::IsPortOnPos(CPoint p, CBlockItem* ptr, LPDWORD pdwPort, LPBOOL pbOutput)
{
	DWORD dwPorts = ptr->GetInputCount();
	for ( DWORD i = 0; i < dwPorts; i++ )
	{
		CRect rc;
		if ( GetPortRect(ptr, i, &rc, FALSE) )
		{
			if ( rc.PtInRect(p) )
			{
				*pdwPort = i;
				*pbOutput = FALSE;
				return TRUE;
			}
		}
	}

	dwPorts = ptr->GetOutputCount();
	for ( DWORD i = 0; i < dwPorts; i++ )
	{
		CRect rc;
		if ( GetPortRect(ptr, i, &rc, TRUE) )
		{
			if ( rc.PtInRect(p) )
			{
				*pdwPort = i;
				*pbOutput = TRUE;
				return TRUE;
			}
		}
	}
	return FALSE;
}

Point CSchemeView::GetPortCenter(CBlockItem *ptr, DWORD dwPort, BOOL bOutput)
{
	Point ret;
	Rect rc;
	GetPortRect(ptr, dwPort, &rc, bOutput);
	ret.X = rc.X + rc.Width / 2;
	ret.Y = rc.Y + rc.Height / 2;
	return ret;
}

void CSchemeView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
	CBlockItem* ptr = GetBlockOnPos(point);
	if ( ptr )
	{
		if ( ptr->IsKindOf(RUNTIME_CLASS(CBlockItem_Virtual)) )
		{
			SetThisBlock((CBlockItem_Virtual*)ptr);
			((CSchemeTreeView*)((CSplitterWnd*)GetParent())->GetPane(0, 0))->Select((CBlockItem_Virtual*)ptr);
		}
	}
	CView::OnLButtonDblClk(nFlags, point);
}

void CSchemeView::OnRButtonDown(UINT nFlags, CPoint point)
{
	CSchemeDoc* pDoc = GetDocument();
	CBlockItem* ptr = GetBlockOnPos(point);
	if ( ptr )
	{	// jsem na nejakem bloku
		DWORD dwPort;
		BOOL bOutput;
		if ( IsPortOnPos(point, ptr, &dwPort, &bOutput) )
		{	// jsem na portu
			CMainFrame* pWndMainFrame = (CMainFrame*)AfxGetMainWnd();
			ASSERT(pWndMainFrame &&
				pWndMainFrame->m_pDocViewers);
			CMenu menu;
			menu.CreatePopupMenu();
			CViewersDoc *pViewersDoc = pWndMainFrame->m_pDocViewers;

			std::map<CString, VIEWERITEM>::iterator it = pViewersDoc->m_mapViewers.begin();
			WORD wID = 1;
			for ( it; it != pViewersDoc->m_mapViewers.end(); it++ )
			{
				MENUITEMINFO mii;
				ZeroMemory(&mii, sizeof(mii));
				mii.cbSize = sizeof(mii);
				mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE | MIIM_ID;
				mii.fType = MFT_STRING;
				mii.fState = MFS_ENABLED;
				mii.dwItemData = (ULONG_PTR)it->second.cp;
				mii.cch = 0;
				mii.wID = wID;
				mii.dwTypeData = (LPWSTR)it->first.GetString();
				menu.InsertMenuItem(0, &mii);
				wID++;
			}
			CPoint pointCopy = point;
			ClientToScreen(&pointCopy);
			BOOL x = menu.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, pointCopy.x, pointCopy.y, this, NULL);
			if ( x )
			{
				it = pViewersDoc->m_mapViewers.begin();
				for ( WORD s = 1; s < x; s++ )
				{
					it++;
				}
				IViewer *pViewer;
				if ( S_OK == it->second.cp(IID_IViewer, (void**)&pViewer) )
				{	// povedlo se vytvorit instanci vieweru
					LPVIEWERSETDATA pViewerSetData = new VIEWERSETDATA;
					pViewerSetData->dwPort = dwPort;
					pViewerSetData->pBlock = ptr;
					pViewerSetData->pViewer = pViewer;
					pViewerSetData->bOutput = bOutput;
					ZeroMemory(&pViewerSetData->vdData, sizeof(VIEWERDATA));
					pDoc->m_setViewers.insert(pViewerSetData);
					((CSchemeDoc*)m_pDocument)->UpdateViewerData(pViewerSetData);
					pViewer->ShowViewer(GetDocument(), AfxGetMainWnd());
					pViewer->SetData(&pViewerSetData->vdData);
					pViewer->Refresh(0);
				}
			}
		}
		else
		{	// nejsem na portu
			if ( m_sUserData.setSelection.find(ptr) == m_sUserData.setSelection.end() )
			{	// jsem na bloku, ktery NENI vybran, vyberu tedy pouze tento blok
				m_sUserData.setSelection.clear();
				m_sUserData.setSelection.insert(ptr);
			}
			Invalidate(FALSE);
			CMenu contextMenu;
			CMenu* tracker;
			contextMenu.LoadMenu(IDR_POPUP);
			CPoint pointCopy = point;
			ClientToScreen(&pointCopy);
			tracker = contextMenu.GetSubMenu(0);
			tracker->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, pointCopy.x, pointCopy.y, AfxGetMainWnd());
		}
	}
	CView::OnRButtonDown(nFlags, point);
}

void CSchemeView::OnUpdatePopup1Propertie(CCmdUI *pCmdUI)
{
	std::set<CBlockItem*>::iterator it;
	for ( it = m_sUserData.setSelection.begin(); it != m_sUserData.setSelection.end(); it++)
	{
		if ( (*it)->ShowProperties(TRUE) )
		{
			pCmdUI->Enable();
			return;
		}
	}
	pCmdUI->Enable(FALSE);
}

void CSchemeView::OnPopup1Propertie()
{
	std::set<CBlockItem*>::iterator it;
	for ( it = m_sUserData.setSelection.begin(); it != m_sUserData.setSelection.end(); it++)
	{
		if ( (*it)->ShowProperties(TRUE) )
		{
			(*it)->ShowProperties();
		}
	}
}

void CSchemeView::OnUpdatePopup1Delete(CCmdUI *pCmdUI)
{
	if ( !m_sUserData.setSelection.empty() )
		pCmdUI->Enable();
}

void CSchemeView::OnPopup1Delete()
{
	std::set<CBlockItem*>::iterator it;
	for ( it = m_sUserData.setSelection.begin(); it != m_sUserData.setSelection.end(); it++)
	{
		m_pThisBlock->DeleteBlock(*it);
	}
	m_sUserData.setSelection.clear();
	CSchemeDoc *pDoc = GetDocument();
	pDoc->UpdateAllViews(NULL);
	pDoc->SetModifiedFlag();
}

void CSchemeView::OnPopup1Executewhenprocess()
{
	std::set<CBlockItem*>::iterator it, it2;
	CSchemeDoc* pDoc = GetDocument();
	DWORD dwResult = 0;
	for ( it = m_sUserData.setSelection.begin(); it != m_sUserData.setSelection.end(); it++)
	{
		if ( pDoc->m_setRun.find(*it) != pDoc->m_setRun.end() )
		{	// blok jiz ma flag nastaveny
			dwResult |= 0x01;
		}
		else
			dwResult |= 0x02;
		if ( dwResult == 3 )
			break;
	}
	for ( it = m_sUserData.setSelection.begin(); it != m_sUserData.setSelection.end(); it++)
	{
		switch ( dwResult )
		{
		case 0x01:
			it2 = pDoc->m_setRun.find(*it);
			if ( it2 != pDoc->m_setRun.end() )
				pDoc->m_setRun.erase(it2);
			break;
		case 0x03:
		case 0x02:
			pDoc->m_setRun.insert(*it);
			break;
		}
	}
	pDoc->UpdateAllViews(NULL);
	pDoc->SetModifiedFlag();
}

void CSchemeView::OnUpdatePopup1Executewhenprocess(CCmdUI *pCmdUI)
{
	std::set<CBlockItem*>::iterator it;
	CSchemeDoc* pDoc = GetDocument();
	DWORD dwResult = 0;
	for ( it = m_sUserData.setSelection.begin(); it != m_sUserData.setSelection.end(); it++)
	{
		if ( pDoc->m_setRun.find(*it) != pDoc->m_setRun.end() )
		{	// blok jiz ma flag nastaveny
			dwResult |= 0x01;
		}
		else
			dwResult |= 0x02;
		if ( dwResult == 3 )
			break;
	}
	switch ( dwResult )
	{
	case 0x01:
		pCmdUI->SetCheck(1);
		break;
	case 0x02:
		pCmdUI->SetCheck(0);
		break;
	case 0x03:
		pCmdUI->SetCheck(2);
		break;
	}
	pCmdUI->Enable(TRUE);
}

void CSchemeView::OnPopup1Haveowntrigger()
{
	std::set<CBlockItem*>::iterator it, it2;
	CSchemeDoc* pDoc = GetDocument();
	DWORD dwResult = 0;
	for ( it = m_sUserData.setSelection.begin(); it != m_sUserData.setSelection.end(); it++)
	{
		if ( pDoc->m_setOwnTrigger.find(*it) != pDoc->m_setOwnTrigger.end() )
		{	// blok jiz ma flag nastaveny
			dwResult |= 0x01;
		}
		else
			dwResult |= 0x02;
		if ( dwResult == 3 )
			break;
	}
	for ( it = m_sUserData.setSelection.begin(); it != m_sUserData.setSelection.end(); it++)
	{
		switch ( dwResult )
		{
		case 0x01:
			it2 = pDoc->m_setOwnTrigger.find(*it);
			if ( it2 != pDoc->m_setOwnTrigger.end() )
				pDoc->m_setOwnTrigger.erase(it2);
			break;
		case 0x03:
		case 0x02:
			pDoc->m_setOwnTrigger.insert(*it);
			break;
		}
	}
	pDoc->UpdateAllViews(NULL);
	pDoc->SetModifiedFlag();
}

void CSchemeView::OnUpdatePopup1Haveowntrigger(CCmdUI *pCmdUI)
{
	std::set<CBlockItem*>::iterator it;
	CSchemeDoc* pDoc = GetDocument();
	DWORD dwResult = 0;
	for ( it = m_sUserData.setSelection.begin(); it != m_sUserData.setSelection.end(); it++)
	{
		if ( pDoc->m_setOwnTrigger.find(*it) != pDoc->m_setOwnTrigger.end() )
		{	// blok jiz ma flag nastaveny
			dwResult |= 0x01;
		}
		else
			dwResult |= 0x02;
		if ( dwResult == 3 )
			break;
	}
	switch ( dwResult )
	{
	case 0x01:
		pCmdUI->SetCheck(1);
		break;
	case 0x02:
		pCmdUI->SetCheck(0);
		break;
	case 0x03:
		pCmdUI->SetCheck(2);
		break;
	}
	pCmdUI->Enable(TRUE);
}

LRESULT CSchemeView::OnUpdateView(WPARAM wParam, LPARAM lParam)
{
	Invalidate(FALSE);
	return 0;
}

BOOL CSchemeView::RefreshAllViewers(DWORD dwType)
{
	CSchemeDoc* pDoc = GetDocument();
	std::set<LPVIEWERSETDATA>::iterator it;
	for ( it = pDoc->m_setViewers.begin(); it != pDoc->m_setViewers.end(); it++)
	{
		(*it)->pViewer->Refresh(REFRESHTYPE_TRIGGER);
	}
	return TRUE;
}
//void CSchemeView::OnUpdateProcessStart(CCmdUI *pCmdUI)
//{
//	// TODO: Add your command update UI handler code here
//}

//void CSchemeView::OnProcessStart()
//{
//	// TODO: Add your command handler code here
//}

//void CSchemeView::OnUpdateProcessStop(CCmdUI *pCmdUI)
//{
//	// TODO: Add your command update UI handler code here
//}

//void CSchemeView::OnProcessStop()
//{
//	// TODO: Add your command handler code here
//}

