#include "StdAfx.h"
#include "Block.h"
#include "CommonObject.h"


CBlock::CBlock(CStringList &slIns, CStringList &slOuts, CString strName, CStringA strOrigin, CPoint TopLeftOrigin)
	: CGate((int)slIns.GetSize(), (int)slOuts.GetSize(), TopLeftOrigin, strName, strOrigin), m_nBlockWidth(0), m_nBlockHeigth(0)
{
	Init();
	//CreateTextGPath(strName);

//	m_nObjType = 2;
	m_pointTopLeft = TopLeftOrigin;
	m_pPen = new Pen(Color(0,0,0), 0.25);
	
	m_pointTL.X = 0;
	m_pointTL.Y = 0;
	m_strOrigin = strOrigin;

	m_pTextBrush = new SolidBrush((ARGB)Color::Black);
	m_pPen = new Pen(Color(0,0,0), 1);

	m_strInTags = new CString[m_nIn];
	m_strOutTags = new CString[m_nOut];
	POSITION pos = slIns.GetHeadPosition();
	int i=0;
	while(pos){
		m_strInTags[i++] = slIns.GetNext(pos);
	}
	pos = slOuts.GetHeadPosition();
	i=0;
	while(pos){
		m_strOutTags[i++] = slOuts.GetNext(pos);
	}
	
	ResetGPath();
	GetBounds();
//	InitInOutRectangles();

	Matrix *pMat = new Matrix();
	pMat->Translate((REAL)m_pointTopLeft.x+50, (REAL)m_pointTopLeft.y+50);
	TransformCObject(pMat);
	SAFE_DELETE(pMat);
	CreateTags();
}

CBlock::CBlock(CString *strIns, CString *strOuts, int nIn, int nOut, CPoint TopLeftOrigin, CString strName, CStringA strOrigin, GraphicsPath *gp, CPoint *pntIn, CPoint *pntOut, bool *bInvIn, bool*bInvOut, int *dirIn, int *dirOut)
: CGate(nIn, nOut, TopLeftOrigin, strName, strOrigin, gp, pntIn, pntOut, bInvIn, bInvOut, dirIn, dirOut) 
{
	m_strInTags = new CString[m_nIn];
	m_strOutTags = new CString[m_nOut];
	for(int i = 0; i < m_nIn; i++)
	{
		m_strInTags[i] = strIns[i];
	}
	for(int i = 0; i < m_nOut; i++)
	{
		m_strOutTags[i] = strOuts[i];
	}
	Init();
}

CBlock::CBlock(CPoint TopLeftOrigin, CString strName, CStringA strOrigin, GraphicsPath *gp, 
				  vector<CPoint> pntIn, vector<CPoint> pntOut, vector<bool> bInvIn, vector<bool> bInvOut, vector<int> dirIn, vector<int> dirOut)
	: CGate(TopLeftOrigin, strName, strOrigin, gp, pntIn, pntOut, bInvIn, bInvOut, dirIn, dirOut), m_nBlockWidth(0), m_nBlockHeigth(0)
{
	Init();
/*	m_nObjType = 2;
	m_pointTopLeft = TopLeftOrigin;
	m_pPen = new Pen(Color(0,0,0), 0.25);
	
	m_pointTL.X = 0;
	m_pointTL.Y = 0;
	m_strOrigin = strOrigin;

	m_pTextBrush = new SolidBrush((ARGB)Color::Black);

	m_strInTags = new CString[m_nIn];
	m_strOutTags = new CString[m_nOut];
	for(int i=0; i<m_nIn; i++){
		m_strInTags[i] = strIns[i];
	}

	for(int i=0; i<m_nOut; i++){
		m_strOutTags[i] = strOuts[i];
	}
	//ResetGPath();
	if(gp)
		m_gPath = gp->Clone();
	if(gpText){
		m_gpText = gpText->Clone();
	}
	else {
		m_gpText = new GraphicsPath();
		CreateTags();
	}

	
	GetBounds();

	for(int i=0; i<m_nOut; i++){
		//m_Connection.m_rectOuts[i].CopyRect(rectOut[i]);
		m_Connection.m_rectOuts[i] = rectOut[i];
	}
	for(int i=0; i<m_nIn; i++){
		//m_Connection.m_rectIns[i].CopyRect(rectIn[i]);
		m_Connection.m_rectIns[i] = rectIn[i];
	}
	Matrix *pMat = new Matrix();
	pMat->Translate((REAL)m_pointTopLeft.x, (REAL)m_pointTopLeft.y);
	TransformCObject(pMat);
	SAFE_DELETE(pMat);*/
}

CBlock::~CBlock()
{
/*	SAFE_DELETE(m_gpText);
	SAFE_DELETE_ARRAY(m_Connection.m_pbInvIn);
	SAFE_DELETE_ARRAY(m_Connection.m_pnInvOut);
	SAFE_DELETE_ARRAY(*m_Connection.m_pObjectIn);
	SAFE_DELETE_ARRAY(*m_Connection.m_pObjectOut);
	SAFE_DELETE(m_Connection.m_pObjectIn);
	SAFE_DELETE(m_Connection.m_pObjectOut);
	SAFE_DELETE_ARRAY(m_Connection.m_rectIns);
	SAFE_DELETE_ARRAY(m_Connection.m_rectOuts);
	SAFE_DELETE(m_pPen);
	SAFE_DELETE(m_gPath);

	SAFE_DELETE_ARRAY(m_strInTags);
	SAFE_DELETE_ARRAY(m_strOutTags);
	SAFE_DELETE(m_pTextBrush);*/
}

void CBlock::CreateTextGPath(CString strTag)
{
	SAFE_DELETE(m_gpText);

	FontFamily ff(_T("Arial"));
	StringFormat sf;
	m_gpText = new GraphicsPath();
	m_gpText->AddString(strTag, strTag.GetLength(), &ff, FontStyleBold , 10, Point(3, 5), &sf);
	m_gpText->CloseAllFigures();

	Rect textBound;
	m_gpText->GetBounds(&textBound);
	Size textSize;
	textBound.GetSize(&textSize);
	int nX = (int)textSize.Width;
	int nY = (int)textSize.Height;

	int x = -5;
	int y = -5;

	Matrix *pMat = new Gdiplus::Matrix();
	pMat->Translate(x - nX / 2, y - nY / 2);
	m_gpText->Transform(pMat);

	SAFE_DELETE(pMat);
}

void CBlock::SetRotation(int nRotation)
{
	CGate::SetRotation(nRotation);
	//CreateTextGPath(m_strUniqueName);
	CreateTags();
}

void CBlock::Init()
{
	m_pTextBrush = new SolidBrush((ARGB)Color::Black);
}

void CBlock::CreateTags()
{
	if(!m_gpText)
		m_gpText = new GraphicsPath();
	FontFamily ff(_T("Arial"));
	StringFormat sf;
	CString text;
	int nMaxIn = 0;
	for(int i=0; i<m_nIn; i++){
		text = m_strInTags[i];
		m_gpText->AddString(text, text.GetLength(), &ff, FontStyleRegular , 10, Point(0+3, 0+i*20+13), &sf);
	}
	Rect rectBound;
	m_gpText->GetBounds(&rectBound);
	nMaxIn = rectBound.Width;
	int nMaxOut = 0;
	int nPos = 0;
	for(int i=0; i<m_nOut; i++){
		int nLen = m_strOutTags[i].GetLength();
		if(nLen > nMaxOut){
			nMaxOut = nLen;
			nPos = i;
		}
	}
	GraphicsPath gpTemp;
	gpTemp.AddString(m_strOutTags[nPos], m_strOutTags[nPos].GetLength(), &ff, FontStyleRegular , 10, Point(0,0), &sf);
	gpTemp.GetBounds(&rectBound);
	nMaxOut = rectBound.Width;

	sf.SetFormatFlags(StringFormatFlagsDirectionRightToLeft);
	for(int i=0; i<m_nOut; i++){
		text = m_strOutTags[i];
		m_gpText->AddString(text, text.GetLength(), &ff, FontStyleRegular , 10, Point(nMaxIn+nMaxOut+5, 0+i*20+13), &sf);
	}
	m_gpText->GetBounds(&rectBound);
	m_nBlockWidth = rectBound.Width+8;
	m_nBlockHeigth = rectBound.Height+30;

	StringFormat sf2;
	m_gpText->AddString(m_strUniqueName, m_strUniqueName.GetLength(), &ff, FontStyleBold, 12, Point(0, 0-15), &sf2);
}

void CBlock::OutScreen(Graphics &g)
{
/*	g.DrawPath(m_pPen, m_gPath);
	if(m_gpText){
		//g.DrawPath(m_pPen, m_gpText);
		g.FillPath(m_pTextBrush, m_gpText);
	}*/
	CGate::OutScreen(g);
	Matrix *pMat = new Matrix();
	pMat->Translate((REAL)m_pointTopLeft.x, (REAL)m_pointTopLeft.y);
	m_gpText->Transform(pMat);
	g.FillPath(m_pTextBrush, m_gpText);
	pMat->Reset();
	pMat->Translate(-(REAL)m_pointTopLeft.x, -(REAL)m_pointTopLeft.y);
	m_gpText->Transform(pMat);
	SAFE_DELETE(pMat);

}

/*
void CBlock::ResetGPath()
{
	SAFE_DELETE(m_gPath);
	SAFE_DELETE(m_gpText);
	m_gPath = new GraphicsPath();
	m_gpText = new GraphicsPath();

	CreateTags();

	int nHeight = m_nIn > m_nOut ? m_nIn : m_nOut;
	////SAFE_DELETE(m_gPath);
	////SAFE_DELETE(m_gpText);
	////m_gPath = new GraphicsPath();
	////m_gpText = new GraphicsPath();
	////m_gPath->AddLine(0,0,50,0);
	////m_gPath->AddLine(50,0,50,20+nHeight*20);
	////m_gPath->AddLine(50,20+nHeight*20,0,20+nHeight*20);
	////m_gPath->AddLine(0,20+nHeight*20,0,0);
	////m_gPath->CloseFigure();
	////int nHeight = m_nIn > m_nOut ? m_nIn : m_nOut;

	m_gPath->AddLine(0,0,50,0);
	m_gPath->AddLine(50,0,50,20+nHeight*20);
	m_gPath->AddLine(50,20+nHeight*20,0,20+nHeight*20);
	m_gPath->AddLine(0,20+nHeight*20,0,0);
	m_gPath->CloseFigure();
}
*/
/*
void CBlock::InitInOutRectangles()
{
	for(int i=0; i<this->m_nIn; i++){
		m_Connection.m_rectIns[i].SetRect(0,0,8,8);
		m_Connection.m_rectIns[i].OffsetRect(-24+m_pointTopLeft.x, i*20+m_pointTopLeft.y+6);
	}
	for(int i=0; i<this->m_nOut; i++){
		m_Connection.m_rectOuts[i].SetRect(0,0,8,8);
		m_Connection.m_rectOuts[i].OffsetRect(70+m_pointTopLeft.x, i*20+m_pointTopLeft.y+6);
	}

}
*/

/*
void CBlock::TransformCObject(Matrix* pMat)
{

	m_gPath->Transform(pMat);
	if(m_gpText)
		m_gpText->Transform(pMat);
	// need to translate in/out rectangles
	GetBounds();
	Point temppoint = m_pointTL;
	pMat->TransformPoints(&temppoint);
	m_pointTopLeft.x = temppoint.X;
	m_pointTopLeft.y = temppoint.Y;
	m_pointTL.X = temppoint.X;
	m_pointTL.Y = temppoint.Y;
	for(int i=0; i<this->m_nIn; i++){
		temppoint.X = m_Connection.m_rectIns[i].left;
		temppoint.Y = m_Connection.m_rectIns[i].top;
		pMat->TransformPoints(&temppoint);
		m_Connection.m_rectIns[i].MoveToXY(temppoint.X,temppoint.Y);

		if(m_Connection.m_pObjectIn[i] && m_Connection.m_pObjectIn[i]->m_nObjType == 4){	// wire
			m_Connection.m_pObjectIn[i]->DisconnectCObject(this);
			DisconnectCObject(m_Connection.m_pObjectIn[i]);
		}
	}
	for(int i=0; i<this->m_nOut; i++){
		temppoint.X = m_Connection.m_rectOuts[i].left;
		temppoint.Y = m_Connection.m_rectOuts[i].top;
		pMat->TransformPoints(&temppoint);
		m_Connection.m_rectOuts[i].MoveToXY(temppoint.X,temppoint.Y);

		if(m_Connection.m_pObjectOut[i] && m_Connection.m_pObjectOut[i]->m_nObjType == 4){	// wire
			m_Connection.m_pObjectOut[i]->DisconnectCObject(this);
			DisconnectCObject(m_Connection.m_pObjectOut[i]);
		}
	}
}
*/
/*
bool CBlock::HitTest(CPoint point)
{
	if (m_gPath->IsOutlineVisible(point.x, point.y, m_pPen) || m_gPath->IsVisible(Point(point.x, point.y)))
		return true;
	return false;
	return NULL;
}
*/

CCommonObject* CBlock::Clone(CPoint TopLeftOrigin, CString strNewName, int nRotation)
{
	//return new CBlock(m_nIn, m_nOut, m_strInTags, m_strOutTags, strNewName, m_strOrigin, TopLeftOrigin, m_gPath, m_gpText, m_Connection.m_rectIns, m_Connection.m_rectOuts, m_Connection.m_pbInvIn, m_Connection.m_pnInvOut);
	CBlock *pNewObj = new CBlock(TopLeftOrigin, strNewName, m_strOrigin, m_gPath, m_vPntIn, m_vPntOut, m_vInvIn, m_vInvOut, m_vDirIn, m_vDirOut);
	pNewObj->m_strInTags = new CString[m_nIn];
	pNewObj->m_strOutTags = new CString[m_nOut];
	for(int i = 0; i < m_nIn; i++)
	{
		pNewObj->m_strInTags[i] = m_strInTags[i];
	}
	for(int i = 0; i < m_nOut; i++)
	{
		pNewObj->m_strOutTags[i] = m_strOutTags[i];
	}
	pNewObj->SetRotation(nRotation);
	return pNewObj;
}

void CBlock::OutXmlDrawing(stringstream &ss)
{
	Rect rectBound;
	if(m_nBlockWidth < 1 || m_nBlockHeigth < 1){
		m_gpText->GetBounds(&rectBound);
		m_nBlockWidth = rectBound.Width+8;
		m_nBlockHeigth = rectBound.Height+30;
	}
  //<DRAWING>
  //  <BODY nRecords="5">
  //    <LINE x1="0" y1="0" x2="50" y2="0">line</LINE>x
  //    <LINE x1="50" y1="0" x2="50" y2="120">line</LINE>
  //    <LINE x1="50" y1="120" x2="0" y2="120">line</LINE>
  //    <LINE x1="0" y1="120" x2="0" y2="0">line</LINE>
  //    <CLOSEFIGURE>closefigure</CLOSEFIGURE>
  //  </BODY>
	int nRecords = 5;
	ss << "\t<DRAWING>" << endl;
	ss << "\t\t<BODY nRecords=\"" << nRecords << "\">" << endl;
	ss << "\t\t\t<LINE x1=\"0\" y1=\"0\" x2=\"" << m_nBlockWidth << "\" y2=\"0\">line</LINE>" << endl;
	ss << "\t\t\t<LINE x1=\"" << m_nBlockWidth << "\" y1=\"0\" x2=\"" << m_nBlockWidth << "\" y2=\"" << m_nBlockHeigth << "\">line</LINE>" << endl;
	ss << "\t\t\t<LINE x1=\""<< m_nBlockWidth << "\" y1=\"" << m_nBlockHeigth << "\" x2=\"0\" y2=\"" << m_nBlockHeigth << "\">line</LINE>" << endl;
	ss << "\t\t\t<LINE x1=\"0\" y1=\"" << m_nBlockHeigth << "\" x2=\"0\" y2=\"0\">line</LINE>" << endl;
	ss << "\t\t\t<CLOSEFIGURE>closefigure</CLOSEFIGURE>" << endl;
	ss << "\t\t</BODY>" << endl << endl;
  //  <OUTPUTS nOut="2" nRecords="6">
  //    <LINE x1="50" y1="10" x2="70" y2="10">line</LINE>
  //    <CLOSEFIGURE>closefigure</CLOSEFIGURE>
  //    <LINE x1="50" y1="30" x2="70" y2="30">line</LINE>
  //    <CLOSEFIGURE>closefigure</CLOSEFIGURE>
  //    <TEXT pos="0" text="out0">text</TEXT>
  //    <TEXT pos="1" text="out1">text</TEXT>
  //  </OUTPUTS>
	nRecords = m_nOut*3;
	ss << "\t\t<OUTPUTS nOut=\"" << m_nOut << "\" nRecords =\"" << nRecords << "\">" << endl;
	for(int i=0; i<m_nOut; i++){
		ss << "\t\t\t<LINE x1=\"" << m_nBlockWidth << "\" y1=\"" << i*20+20 << "\" x2=\"" << m_nBlockWidth+20 << "\" y2=\"" << i*20+20 << "\">line</LINE>" << endl;
		ss << "\t\t\t<CLOSEFIGURE>closefigure</CLOSEFIGURE>" << endl;
		ss << "\t\t\t<TEXT pos=\"" << i << "\" text=\"" << (CStringA)m_strOutTags[i] << "\">text</TEXT>" << endl << endl;
	}
	ss << "\t\t</OUTPUTS>" << endl << endl;

  //  <INPUTS nIn="3" nRecords="9">
  //    <LINE x1="-20" y1="10" x2="0" y2="10">line</LINE>
  //    <CLOSEFIGURE>closefigure</CLOSEFIGURE>
  //    <LINE x1="-20" y1="30" x2="0" y2="30">line</LINE>
  //    <CLOSEFIGURE>closefigure</CLOSEFIGURE>
  //    <LINE x1="-20" y1="50" x2="0" y2="50">line</LINE>
  //    <CLOSEFIGURE>closefigure</CLOSEFIGURE>
  //    <TEXT pos="0" text="in0">text</TEXT>
  //    <TEXT pos="1" text="in1">text</TEXT>
  //    <TEXT pos="2" text="in2">text</TEXT>
  //  </INPUTS>

	nRecords = m_nIn*3;
	ss << "\t\t<INPUTS nIn=\"" << m_nIn << "\" nRecords =\"" << nRecords << "\">" << endl;
	for(int i=0; i<m_nIn; i++){
		ss << "\t\t\t<LINE x1=\"-20\" y1=\"" << i*20+20 << "\" x2=\"0\" y2=\"" << i*20+20 << "\">line</LINE>" << endl;
		ss << "\t\t\t<CLOSEFIGURE>closefigure</CLOSEFIGURE>" << endl;
		ss << "\t\t\t<TEXT pos=\"" << i << "\" text=\"" << (CStringA)m_strInTags[i] << "\">text</TEXT>" << endl << endl;
	}
	ss << "\t\t</INPUTS>" << endl << endl;
	ss << "\t</DRAWING>" << endl << endl;

  //</DRAWING>

	
  //<COBJINFO>
  //  <OUTPUTRECT nRecords="3">
  //    <OUTPUT x1="180" y1="20" inv="0">0</OUTPUT>
  //    <OUTPUT x1="180" y1="40" inv="0">0</OUTPUT>
  //    <OUTPUT x1="180" y1="60" inv="0">0</OUTPUT>
  //  </OUTPUTRECT>
  //  <INPUTRECT nRecords="6">
  //    <INPUT x1="-20" y1="20" inv="0">0</INPUT>
  //    <INPUT x1="-20" y1="40" inv="0">0</INPUT>
  //    <INPUT x1="-20" y1="60" inv="0">0</INPUT>
  //    <INPUT x1="-20" y1="80" inv="0">0</INPUT>
  //    <INPUT x1="-20" y1="100" inv="0">0</INPUT>
  //    <INPUT x1="-20" y1="120" inv="0">0</INPUT>
  //  </INPUTRECT>
  //</COBJINFO>
	ss << "\t\t<COBJINFO>" << endl;
	ss << "\t\t<INPUTRECT nRecords=\"" << m_nIn << "\">" << endl;
	for(int i=0; i<m_nIn; i++){
		ss << "\t\t\t<INPUT x1=\"-20\" y1=\"" << i*20+20 << "\" inv=\"0\">" << i << "</INPUT>" << endl;
	}
	ss << "\t\t</INPUTRECT>" << endl << endl;
	ss << "\t\t<OUTPUTRECT nRecords=\"" << m_nOut << "\">" << endl;
	for(int i=0; i<m_nOut; i++){
		ss << "\t\t\t<OUTPUT x1=\"" << m_nBlockWidth+20 << "\" y1=\"" << i*20+20 << "\" inv=\"0\">" << i << "</OUTPUT>" << endl;
	}
	ss << "\t\t</OUTPUTRECT>" << endl << endl;
	ss << "\t\t</COBJINFO>" << endl;

}
/*
void CBlock::SetConnection(bool bIn, int nPos, CCommonObject* pConnectTo)
{
	if(bIn){
		ASSERT(nPos < m_nIn);
		m_Connection.m_pObjectIn[nPos] = pConnectTo;
	}
	else{
		ASSERT(nPos < m_nOut);
		m_Connection.m_pObjectOut[nPos] = pConnectTo;
	}

}
*/
/*
void CBlock::DisconnectCObject(CCommonObject *pObject)
{
	for(int i=0; i<m_nIn; i++){
		if(m_Connection.m_pObjectIn[i] == pObject){
			m_Connection.m_pObjectIn[i] = NULL;
		}
	}
	for(int i=0; i<m_nOut; i++){
		if(m_Connection.m_pObjectOut[i] == pObject){
			m_Connection.m_pObjectOut[i] = NULL;
		}
	}
}
*/
/*
void CBlock::Disconnect()
{
	for(int i=0; i<m_nIn; i++){
		if(m_Connection.m_pObjectIn[i]){
			m_Connection.m_pObjectIn[i]->DisconnectCObject(this);
			m_Connection.m_pObjectIn[i] = NULL;
		}
	}
	for(int i=0; i<m_nOut; i++){
		if(m_Connection.m_pObjectOut[i]){
			m_Connection.m_pObjectOut[i]->DisconnectCObject(this);
			m_Connection.m_pObjectOut[i] = NULL;
		}
	}
}
*/