// Gate.cpp : implementation file
//

#include "stdafx.h"
#include "INKS.h"
#include "Gate.h"
#include "CommonObject.h"
#include "Tag.h"
#include "Node.h"

CGate::CGate(int nIn, int nOut, CPoint TopLeftOrigin, CString strName, CStringA strOrigin) 
	: CCommonObject(nIn, nOut, strName, strOrigin)
{
	m_nObjType = 3;
	m_pointTopLeft = TopLeftOrigin;
	m_pointTL.X = 0;
	m_pointTL.Y = 0;
	m_strOrigin = strOrigin;
	m_pPen = new Pen(Color(0,0,0), 0.25);

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

CGate::CGate(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)
				  :CCommonObject(pntIn.size(), pntOut.size(), strName, strOrigin)
{
	Init(TopLeftOrigin, strName, strOrigin, gp, pntIn, pntOut, bInvIn, bInvOut, dirIn, dirOut);
}

void CGate::Init(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)
{
	m_nObjType = 3;
	m_pointTopLeft = TopLeftOrigin;
	m_pointTL.X = 0;
	m_pointTL.Y = 0;
	m_strOrigin = strOrigin;
	m_pPen = new Pen(Color(0,0,0), 0.25);

	if(gp){
		m_gPath = gp->Clone();
	}
	else{
		m_gPath = new GraphicsPath();
	}

	m_vPntIn = pntIn;
	m_vPntOut = pntOut;
	m_vInvIn = bInvIn;
	m_vInvOut = bInvOut;
	m_vDirIn = dirIn;
	m_vDirOut = dirOut;
	m_nIn = pntIn.size();
	m_nOut = pntOut.size();
	GetBounds();
	Matrix *pMat = new Matrix();
	pMat->Translate((REAL)m_pointTopLeft.x, (REAL)m_pointTopLeft.y);
	TransformCObject(pMat);
	SAFE_DELETE(pMat);
}

CGate::CGate(int nIn, int nOut, CPoint TopLeftOrigin, CString strName, CStringA strOrigin, GraphicsPath *gp, 
				  CPoint *pntIn, CPoint *pntOut, bool *bInvIn, bool*bInvOut, int *dirIn, int *dirOut)
	: CCommonObject(nIn, nOut, strName, strOrigin)
{
	vector<bool> vInvIn;
	vector<bool> vInvOut;
	vector<CPoint> vPntIn;
	vector<CPoint> vPntOut;
	vector<int> vDirIn;
	vector<int> vDirOut;
	
	if(pntIn){
		for(int i=0; i<nIn; i++){
			vPntIn.push_back(pntIn[i]);
			vDirIn.push_back(dirIn[i]);
			vInvIn.push_back(bInvIn[i]);
		}
	}
	if(pntOut){
		for(int i=0; i<nOut; i++){
			vPntOut.push_back(pntOut[i]);
			vDirOut.push_back(dirOut[i]);
			vInvOut.push_back(bInvOut[i]);
		}
	}
	Init(TopLeftOrigin, strName, strOrigin, gp, vPntIn, vPntOut, vInvIn, vInvOut, vDirIn, vDirOut);
}

CGate::~CGate()
{
	SAFE_DELETE(m_pPen);
	SAFE_DELETE(m_gPath);
}

CCommonObject* CGate::Clone(CPoint TopLeftOrigin, CString strNewName, int nRotation)
{
	CGate *pNewObj = new CGate(TopLeftOrigin, strNewName, m_strOrigin, m_gPath, m_vPntIn, m_vPntOut, m_vInvIn, m_vInvOut, m_vDirIn, m_vDirOut);
	pNewObj->SetRotation(nRotation);
	return pNewObj;
}

void CGate::OutScreen(Graphics &g)
{
	g.DrawPath(m_pPen, m_gPath);
}

void CGate::TransformCObject(Matrix* pMat)
{
	m_gPath->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 < m_vPntIn.size(); i++){
		temppoint.X = m_vPntIn[i].x;
		temppoint.Y = m_vPntIn[i].y;
		pMat->TransformPoints(&temppoint);
		m_vPntIn[i].x = temppoint.X;
		m_vPntIn[i].y = temppoint.Y;
	}
	for(int i=0; i< m_vPntOut.size(); i++){
		temppoint.X = m_vPntOut[i].x;
		temppoint.Y = m_vPntOut[i].y;
		pMat->TransformPoints(&temppoint);
		m_vPntOut[i].x = temppoint.X;
		m_vPntOut[i].y = temppoint.Y;
	}

}


bool CGate::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 CGate::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=\"" << m_PinNodes[i]->GetWires()[0]->GetObjectName() << "\">in</IN>" << endl;
	}
	ss << "</INCONNECTIONS>" << endl;

	ss << "<OUTCONNECTIONS nCount=\"" << m_nOut << "\">" << endl;
	for(int i=0; i<m_nOut; i++){
		ss << "<OUT Name=\"" << m_PinNodes[m_nIn+i]->GetWires()[0]->GetObjectName() << "\">out</IN>" << endl;
	}
	ss << "</OUTCONNECTIONS>" << endl;

	ss << "</CONNECTIONS>" << endl;
}

void CGate::SetConnection(bool bIn, int nPos, CCommonObject* pConnectTo)
{
}

void CGate::DisconnectCObject(CCommonObject *pObject)
{
}

void CGate::Disconnect()
{

}

void CGate::SetRotation(int nRotation)
{
	CCommonObject::SetRotation(nRotation);
	Matrix *pMat = new Matrix();
	for(int i=0; i<m_nIn; i++){
		Gdiplus::Point p = Gdiplus::Point(m_vPntIn[i].x, m_vPntIn[i].y);
		Gdiplus::Point oldP = p;
		pMat->Translate((REAL)-m_pointTopLeft.x, (REAL)-m_pointTopLeft.y);
		pMat->TransformPoints(&p);
		pMat->Reset();
		pMat->Rotate((REAL)nRotation);
		pMat->TransformPoints(&p);
		pMat->Reset();
		pMat->Translate((REAL)m_pointTopLeft.x, (REAL)m_pointTopLeft.y);
		pMat->TransformPoints(&p);
		pMat->Reset();
		m_vPntIn[i].x = p.X;
		m_vPntIn[i].y = p.Y;
		//m_Connection.m_rectIns[i].OffsetRect(p.X - oldP.X, p.Y - oldP.Y);
	}
	for(int i=0; i<m_nOut; i++){
		Gdiplus::Point p = Gdiplus::Point(m_vPntOut[i].x, m_vPntOut[i].y);
		Gdiplus::Point oldP = p;
		pMat->Translate((REAL)-m_pointTopLeft.x, (REAL)-m_pointTopLeft.y);
		pMat->TransformPoints(&p);
		pMat->Reset();
		pMat->Rotate((REAL)nRotation);
		pMat->TransformPoints(&p);
		pMat->Reset();
		pMat->Translate((REAL)m_pointTopLeft.x, (REAL)m_pointTopLeft.y);
		pMat->TransformPoints(&p);
		pMat->Reset();
		m_vPntOut[i].x = p.X;
		m_vPntOut[i].y = p.Y;
//		m_Connection.m_rectOuts[i].OffsetRect(p.X - oldP.X, p.Y - oldP.Y);
	}
	SAFE_DELETE(pMat);
}

vector<CNode *> CGate::CreatePinNodes()
{
	m_PinNodes.clear();
	for(int i=0; i<m_nIn; i++){
		CNode *node = new CNode(m_vPntIn[i]);
		node->AttachObject(this, (m_vDirIn[i] + m_nRotation / 90) % 4);
		m_PinNodes.push_back(node);
	}
	for(int i=0; i<m_nOut; i++){
		CNode *node = new CNode(m_vPntOut[i]);
		node->AttachObject(this, (m_vDirOut[i] + m_nRotation / 90) % 4);
		m_PinNodes.push_back(node);
	}
	return m_PinNodes;
}

std::vector<CCommonObject *> CGate::GetConnectedObjs(bool in)
{
	std::vector<CCommonObject *> objs;
	if(in)
	{
		for(int i = 0; i < m_nIn; i++)
		{
			std::vector<CWire *>wires = m_PinNodes[i]->GetWires();
			if(wires.size() > 0)
			{
				objs.push_back(wires[0]);
			}else{
				objs.push_back(NULL);
			}
		}
	}else{
		for(int i = 0; i < m_nOut; i++)
		{
			std::vector<CWire *>wires = m_PinNodes[i+m_nIn]->GetWires();
			if(wires.size() > 0)
			{
				objs.push_back(wires[0]);
			}else{
				objs.push_back(NULL);
			}
		}
	}
	return objs;
}

// CGate message handlers