// Gate.cpp : implementation file
//

#include "stdafx.h"
#include "INKS.h"
#include "Gate.h"
#include "CommonObject.h"
#include "Tag.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(int nIn, int nOut, CPoint TopLeftOrigin, CString strName, CStringA strOrigin, GraphicsPath *gp, CRect *rectIn, CRect *rectOut, bool *bInvIn, bool*bInvOut)
	: 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);

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

	if(rectIn){
		for(int i=0; i<nIn; i++){
			m_Connection.m_rectIns[i].CopyRect(rectIn[i]);
		}
	}
	if(rectOut){
		for(int i=0; i<nOut; i++){
			m_Connection.m_rectOuts[i].CopyRect(rectOut[i]);
		}
	}

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

CGate::~CGate()
{
	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);
}

CCommonObject* CGate::Clone(CPoint TopLeftOrigin, CString strNewName, int nRotation)
{
	CGate *pNewObj = new CGate(m_nIn, m_nOut, TopLeftOrigin, strNewName, m_strOrigin, m_gPath, m_Connection.m_rectIns, m_Connection.m_rectOuts, m_Connection.m_pbInvIn, m_Connection.m_pnInvOut);
	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<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]);
		}
	}
	temppoint.X = m_Connection.m_rectOuts[0].left;
	temppoint.Y = m_Connection.m_rectOuts[0].top;
	pMat->TransformPoints(&temppoint);
	m_Connection.m_rectOuts[0].MoveToXY(temppoint.X,temppoint.Y);

	if(m_Connection.m_pObjectOut[0] && m_Connection.m_pObjectOut[0]->m_nObjType == 4){	// wire
		m_Connection.m_pObjectOut[0]->DisconnectCObject(this);
		DisconnectCObject(m_Connection.m_pObjectOut[0]);
	}
}


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=\"" << 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 CGate::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 CGate::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 CGate::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;
		}
	}
}

// CGate message handlers