#include "StdAfx.h"
#include "Tag.h"
#include "INKS.h"

CTag::CTag(CPoint TopLeftOrigin, CString strName, bool bInTag)
	: CCommonObject(1, 0, strName, bInTag ? "InTag" : "OutTag"), m_bParentMove(false)
{
	m_Connection.m_pObjectOut = NULL;
	if(bInTag)
		m_nTagType = 1;
	else m_nTagType = 2;
	m_gPath = NULL;
	m_nObjType = 5;
	m_pointTopLeft = TopLeftOrigin;
	m_pointTL.X = 0;
	m_pointTL.Y = 0;
	
	//m_Connection.m_rectIns[0] = new CRect(m_pointTopLeft.x-4, m_pointTopLeft.y-4, m_pointTopLeft.x+4, m_pointTopLeft.y+4);
	m_Connection.m_rectIns[0] = new CRect(0,0,0,0);
	m_Connection.m_rectIns[0].InflateRect(4,4);

	m_pPen = new Pen(Color(0,0,0), 0.25);
	m_pTextBrush = new SolidBrush((ARGB)Color::Black);
	
	CreateGPath(strName, m_nRotation);

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

CTag::~CTag()
{
	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(m_pTextBrush);
	SAFE_DELETE(m_gpText);
}

CCommonObject* CTag::Clone(CPoint TopLeftOrigin, CString strNewName, int nRotation)
{
	CTag *pNewObj = new CTag(TopLeftOrigin, strNewName, m_nTagType == 1);
	//pNewObj->SetRotation(nRotation);
	pNewObj->SetRotation(m_nTagType == 1 ? 0 : 180);
	return pNewObj;
}

void CTag::OutScreen(Graphics &g)
{
	g.DrawPath(m_pPen, m_gPath);
	g.FillPath(m_pTextBrush, m_gpText);
}

void CTag::TransformCObject(Matrix* pMat)
{
	m_gPath->Transform(pMat);
	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;

	temppoint.X = m_Connection.m_rectIns[0].left;
	temppoint.Y = m_Connection.m_rectIns[0].top;
	pMat->TransformPoints(&temppoint);
	m_Connection.m_rectIns[0].MoveToXY(temppoint.X,temppoint.Y);
	if(m_Connection.m_pObjectIn[0] && !m_bParentMove){
		m_Connection.m_pObjectIn[0]->DisconnectCObject(this);
		m_Connection.m_pObjectIn[0] = NULL;
	}
}

Rect* CTag::GetBounds()
{
	int nPntCount = (int)m_gPath->GetPointCount();
	Point *pnts = new Point[nPntCount];
	m_gPath->GetPathPoints(pnts, nPntCount);
	int nXmin, nXmax, nYmin, nYmax;
	nXmax = nXmin = pnts[0].X;
	nYmax = nYmin = pnts[0].Y;
	for(int i=1; i<nPntCount; i++){
		if(pnts[i].X < nXmin)
			nXmin = pnts[i].X;
		if(pnts[i].Y < nYmin)
			nYmin = pnts[i].Y;
		if(pnts[i].X > nXmax)
			nXmax = pnts[i].X;
		if(pnts[i].Y > nYmax)
			nYmax = pnts[i].Y;
	}
	SAFE_DELETE_ARRAY(pnts);
	m_rectBounding.X = nXmin+10;
	m_rectBounding.Y = nYmin;
	m_rectBounding.Width = nXmax-nXmin-10;
	m_rectBounding.Height = nYmax-nYmin;
	return &m_rectBounding;
}

bool CTag::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;
}

void CTag::OutXml(stringstream &ss)
{
    //<TYPE>Gate</TYPE>
    //<NAME>AndGate0</NAME>
    //<ORIGIN>AND</ORIGIN>
    //<POSITION tlx1="50" tly1="50"></POSITION>
    //<CONNECTIONS>
    //  <INCONNECTIONS nCount ="2">
    //    <IN Name ="InTag0">in</IN>
    //    <IN Name ="InTag1">in</IN>
    //  </INCONNECTIONS>

    //  <OUTCONNECTIONS nCount ="1">
    //    <OUT Name="Wire0">out</OUT>
    //  </OUTCONNECTIONS>
    //</CONNECTIONS>

	ss << "<TYPE>Gate</TYPE>\n";
	ss << "<NAME>" << (CStringA)m_strUniqueName << "</NAME>\n";
	ss << "<ORIGIN>" << m_strOrigin << "</ORIGIN>\n";
	ss << "<POSITION tlx1 = '" <<  m_pointTopLeft.x << "'" << " tly1 = '" << m_pointTopLeft.y << "'" << "></POSITION>\n";
	ss << "<CONNECTIONS>\n";
	ss << "<INCONNECTIONS nCount=\"" << m_nIn << "\">" << endl;
	for(int i=0; i<m_nIn; i++){
		ss << "<IN Name=\"" << this->m_Connection.m_pObjectIn[i]->m_strUniqueName << "\">in</IN>" << endl;
	}
	ss << "</INCONNECTIONS>" << endl;

	ss << "<OUTCONNECTIONS nCount=\"" << m_nOut << "\">" << endl;
	for(int i=0; i<m_nOut; i++){
		ss << "<OUT Name=\"" << this->m_Connection.m_pObjectOut[i]->m_strUniqueName << "\">out</IN>" << endl;
	}
	ss << "</OUTCONNECTIONS>" << endl;
	ss << "</CONNECTIONS>\n";

}

void CTag::SetConnection(bool bIn, int nPos, CCommonObject* pConnectTo)
{
	m_Connection.m_pObjectIn[0] = pConnectTo;
}

void CTag::DisconnectCObject(CCommonObject *pObject)
{
	if(m_Connection.m_pObjectIn[0] == pObject){
		m_Connection.m_pObjectIn[0] = NULL;
	}
}

void CTag::Disconnect()
{
	if(m_Connection.m_pObjectIn[0]){
		m_Connection.m_pObjectIn[0]->DisconnectCObject(this);
	}
}

void CTag::CreateGPath(CString strTag, int nRot)
{
	SAFE_DELETE(m_gpText);
	SAFE_DELETE(m_gPath);

	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;

	Matrix *pMat = new Matrix();
	pMat->Translate((REAL)(-(nX+20)), (REAL)(-nY));
	m_gpText->Transform(pMat);

	//int nXPos = nX+20;
	//nXPos += (10-(nXPos%10));
	nX += (10-(nX%10));
	m_gPath = new GraphicsPath();
	m_gPath->AddLine(0,0,-10,-10);
	m_gPath->AddLine(-10,-10,-(nX+20),-10);
	m_gPath->AddLine(-(nX+20),-10,-(nX+20),10);
	m_gPath->AddLine(-(nX+20),10,-10,10);
	m_gPath->AddLine(-10,10,0,0);
	m_gPath->CloseAllFigures();

	SAFE_DELETE(pMat);
}

void CTag::SetRotation(int nRotation)
{
	CCommonObject::SetRotation(nRotation);
	REAL nRot = (REAL)nRotation;
	Matrix *pMat = new Matrix();
	
	Rect rectBound;
	m_gpText->GetBounds(&rectBound);

	pMat->Translate((REAL)-m_pointTopLeft.x, (REAL)-m_pointTopLeft.y);
	m_gpText->Transform(pMat);
	pMat->Reset();
	
	if((nRotation > 0 && nRotation <= 90) || (nRotation > 270 && nRotation < 360)){
		pMat->Rotate(nRot);
	}
	else if(nRotation > 90 && nRotation <= 270){
		pMat->Scale(-1, -1);
		pMat->Rotate(nRot);
		pMat->Translate((REAL)rectBound.Width + 23, 0);	// 20 - offset from start point
	}
	m_gpText->Transform(pMat);
	pMat->Reset();
	pMat->Translate((REAL)m_pointTopLeft.x, (REAL)m_pointTopLeft.y);
	m_gpText->Transform(pMat);
	m_gpText->GetBounds(&rectBound);
	SAFE_DELETE(pMat);
}

void CTag::SwapTag()
{
	if(m_nTagType == 1){
		SetRotation(180);
		m_nTagType = 2;
		m_strOrigin = _T("OutTag");
	}
	else{
		this;
		int nRotation = 180;
		CCommonObject::SetRotation(nRotation);

		REAL nRot = (REAL)nRotation;
		Matrix *pMat = new Matrix();
		
		Rect rectBound;
		m_gPath->GetBounds(&rectBound);

		pMat->Translate((REAL)-m_pointTopLeft.x, (REAL)-m_pointTopLeft.y);
		m_gpText->Transform(pMat);
		pMat->Reset();

		pMat->Scale(-1, -1);
		pMat->Rotate(nRot);
	
		m_gpText->Transform(pMat);
		pMat->Reset();
		pMat->Translate((REAL)m_pointTopLeft.x - rectBound.Width+5, (REAL)m_pointTopLeft.y);
		m_gpText->Transform(pMat);
		m_gpText->GetBounds(&rectBound);
		SAFE_DELETE(pMat);

		m_nTagType = 1;
		m_strOrigin = _T("InTag");
	}
}