
#include "StdAfx.h"
#include "PSCreator.h"
#include "ElementContainer.h"
#include "INKS.h"
#include "CommonObject.h"
#include "Wire.h"
#include "Tag.h"
#include "Block.h"
#include "Inv.h"
#define PAPER_HEIGTH 840
CPSCreator::CPSCreator()
{
	m_pContainer = new CElementContainer();
	
}

CPSCreator::~CPSCreator()
{
	SAFE_DELETE(m_pContainer);
}

stringstream& CPSCreator::WriteScheme(CList<CCommonObject*, CCommonObject*> *pList)
{
	CMap<CString, LPCTSTR, CString, LPCTSTR>::CPair *strDef;
	
	
	POSITION pos = pList->GetHeadPosition();
	CCommonObject *pObj = NULL;
	while(pos){
		pObj = pList->GetNext(pos);
		if(HasDefinition((CString)pObj->m_strOrigin)){
			if(pObj->m_nObjType == 5){
				WriteTag((CTag*)pObj);
			}
			else if(pObj->m_nObjType == 6){
				WriteInv((CInv*)pObj);
			}
			else{
				strDef = m_mapDefinitionsPro.PLookup((CString)pObj->m_strOrigin);
				if(strDef){
					ss_elements << endl;
					ss_elements << "gsave" << endl;
					ss_elements << "newpath" << endl;
					ss_elements << pObj->m_pointTopLeft.x << " " << pObj->m_pointTopLeft.y << " translate " << pObj->m_strOrigin << endl;
					//CStringA str = (CStringA)strDef->value;
					//ss_elements << str;
					if(pObj->m_gpText){
						WriteText(pObj);
					}
					ss_elements << "stroke" << endl;
					ss_elements << "grestore" << endl;
					ss_elements << endl;
				}
				else{
					strDef = m_mapDefinitionsApp.PLookup((CString)pObj->m_strOrigin);
					if(strDef){
						ss_elements << endl;
						ss_elements << "gsave" << endl;
						ss_elements << "newpath" << endl;
						ss_elements << pObj->m_pointTopLeft.x << " " << pObj->m_pointTopLeft.y << " translate " << pObj->m_strOrigin << endl;
						//CStringA str = (CStringA)strDef->value;
						//ss_elements << str;
						ss_elements << "stroke" << endl;
						ss_elements << "grestore" << endl;
						ss_elements << endl;
					}
				}
			}
		}
		else if(pObj->m_nObjType == 4){ //wire
			WriteWire((CWire*)pObj);
		}
	}
	WriteHeader();
	WriteDefinitions();
	ss_out <<  ss_text.str() << ss_header.str() << ss_definitions.str() << endl << ss_elements.str() << endl << "showpage" << endl;
	return ss_out;
}

void CPSCreator::WriteText(CCommonObject *pObj)
{
	ss_text << "gsave" << endl;
	ss_text << "newpath" << endl;
	ss_text << "/Arial findfont" << endl;
	ss_text << "10 scalefont setfont" << endl;
///Helvetica findfont
//12 scalefont setfont
//288 720 moveto
//(ABC) show
	int nOutStart = 0;
	if(pObj->m_nObjType == 2){ // Block
		ss_text << pObj->m_pointTL.X+3 << " " << (PAPER_HEIGTH - (pObj->m_pointTL.Y-4)) << " moveto" << endl;
		ss_text << "(" << (CStringA)((CBlock*)pObj)->m_strOrigin << ") show" << endl;
		for(int i=0; i<pObj->m_nIn; i++){
			ss_text << pObj->m_pointTL.X+3 << " " << (PAPER_HEIGTH - (pObj->m_pointTL.Y+i*20+20)) << " moveto" << endl;
			ss_text << "(" << (CStringA)((CBlock*)pObj)->m_strInTags[i] << ") show" << endl;
			if(nOutStart < ((CBlock*)pObj)->m_strInTags[i].GetLength())
				nOutStart = ((CBlock*)pObj)->m_strInTags[i].GetLength();
		}
		nOutStart *= 6;
		for(int i=0; i<pObj->m_nOut; i++){
			ss_text << pObj->m_pointTL.X+3+nOutStart << " " << (PAPER_HEIGTH - (pObj->m_pointTL.Y+i*20+20)) << " moveto" << endl;
			ss_text << "(" << (CStringA)((CBlock*)pObj)->m_strOutTags[i] << ") show" << endl;
		}
	}
	else if(pObj->m_nObjType == 5){ // Tag
		Rect *boundRect = new Rect;
		pObj->m_gpText->GetBounds(boundRect);
		ss_text << (int)boundRect->GetLeft() + 4 << " " << (PAPER_HEIGTH - (pObj->m_pointTL.Y+5)) << " moveto" << endl;
		ss_text << "(" << (CStringA)((CTag*)pObj)->m_strUniqueName << ") show" << endl;
		SAFE_DELETE(boundRect);
	}
	ss_text << "stroke" << endl;
	ss_text << "grestore" << endl;
}

void CPSCreator::WriteWire(CWire *pWire)
{
	ss_elements << endl;
	ss_elements << "gsave" << endl;
	ss_elements << "newpath" << endl;
	CPoint *pPoint = NULL;
	CPoint *pPoint2 = NULL;
	POSITION pos = pWire->m_Anchors.GetHeadPosition();
	if(pos){
		pPoint = &pWire->m_Anchors.GetNext(pos).m_PointMain;
		ss_elements << pPoint->x << " " << pPoint->y << " moveto" << endl;
	}
	while(pos){
		pPoint2 = &pWire->m_Anchors.GetNext(pos).m_PointMain;
		ss_elements << pPoint2->x << " " << pPoint2->y << " lineto" << endl;
	}
	ss_elements << pPoint2->x << " " << pPoint2->y << " moveto" << endl;
	ss_elements << "stroke" << endl;
	ss_elements << "grestore" << endl;
	ss_elements << endl;
}

	//m_gPath = new GraphicsPath();
	//m_gPath->AddLine(0,0,-8,-8);
	//m_gPath->AddLine(-8,-8,-(nX+20),-8);
	//m_gPath->AddLine(-(nX+20),-8,-(nX+20),8);
	//m_gPath->AddLine(-(nX+20),8,-8,8);
	//m_gPath->AddLine(-8,8,0,0);
	//m_gPath->CloseAllFigures();

void CPSCreator::WriteTag(CTag *pTag)
{
	ss_elements << endl;
	ss_elements << "gsave" << endl;
	ss_elements << "newpath" << endl;

	int pointCount = (int)pTag->m_gPath->GetPointCount();
	Point *pPoints = new Point[pointCount];
	pTag->m_gPath->GetPathPoints(pPoints, pointCount);
	ss_elements << pPoints[0].X << " " << pPoints[0].Y << " moveto" << endl;
	for(int i=1; i<pointCount; i++){
		ss_elements << pPoints[i].X << " " << pPoints[i].Y << " lineto" << endl;
	}
	ss_elements << pPoints[pointCount-1].X << " " << pPoints[pointCount-1].Y << " moveto" << endl;
	ss_elements << "stroke" << endl;
	ss_elements << "grestore" << endl;
	ss_elements << endl;
	WriteText(pTag);
}

void CPSCreator::WriteInv(CInv *pInv)
{
	ss_elements << endl;
	ss_elements << "gsave" << endl;
	ss_elements << "newpath" << endl;

	int pointCount = (int)pInv->m_gPath->GetPointCount();
	Point *pPoints = new Point[pointCount];
	pInv->m_gPath->GetPathPoints(pPoints, pointCount);
	ss_elements << pPoints[0].X << " " << pPoints[0].Y << " moveto" << endl;
	for(int i=1; i<pointCount; i++){
		ss_elements << pPoints[i].X << " " << pPoints[i].Y << " lineto" << endl;
	}
	ss_elements << pPoints[pointCount-1].X << " " << pPoints[pointCount-1].Y << " moveto" << endl;
	ss_elements << "stroke" << endl;
	ss_elements << "grestore" << endl;
	ss_elements << endl;
	WriteText(pInv);
}

void CPSCreator::WriteHeader()
{
	ss_header << "0 840 translate" << endl;
	ss_header << "1 -1 scale" << endl << endl;
}

void CPSCreator::WriteDefinitions()
{
	POSITION pos = m_mapDefinitionsPro.GetStartPosition();
	CString strName;
	CString strKey;
	while(pos){
		m_mapDefinitionsPro.GetNextAssoc(pos, strName, strKey);
		if(strKey){
			ss_definitions << "/" << (CStringA)strName << endl << "{" << endl << (CStringA)strKey << "closepath" << endl << "} def" << endl << endl;
		}
	}

	pos = m_mapDefinitionsApp.GetStartPosition();
	strName.Empty();
	strKey.Empty();
	while(pos){
		m_mapDefinitionsApp.GetNextAssoc(pos, strName, strKey);
		if(strKey){
			ss_definitions << "/" << (CStringA)strName << endl << "{" << endl << (CStringA)strKey << "closepath" << endl << "} def" << endl << endl;
		}
	}
}

bool CPSCreator::HasDefinition(CString strName)
{
	if(m_mapDefinitionsApp.PLookup(strName) || m_mapDefinitionsPro.PLookup(strName))
		return true;

	if(!theApp.m_pOpenedProjectDoc)
		return false;

	CString strPro = theApp.m_pOpenedProjectDoc->m_ProjectDoc.m_strProjectPath;
	strPro.Append(_T("Content\\"));

	// is element in project directory?
	CString strProFile = m_pContainer->AssociateFile(strName, strPro);
	if(strProFile.GetLength()){
		AddDefinition(m_mapDefinitionsPro, strProFile);
		return true;
	}

	CString strProGates = strPro + _T("Gates\\");
	strProFile = m_pContainer->AssociateFile(strName, strProGates);
	if(strProFile.GetLength()){
		AddDefinition(m_mapDefinitionsPro, strProFile);
		return true;
	}

	strPro.Append(_T("Blocks\\"));
	strProFile = m_pContainer->AssociateFile(strName, strPro);
	if(strProFile.GetLength()){
		AddDefinition(m_mapDefinitionsPro, strProFile);
		return true;
	}

	// or in app directory?
	if(strName == _T("InTag") || strName == _T("OutTag") || strName == _T("Invertor"))
		return true;

	CString strApp = theApp.m_strAppPath;
	strApp.Append(_T("Additional\\"));

	CString strAppFile = m_pContainer->AssociateFile(strName, strApp);
	if(strAppFile.GetLength()){
		AddDefinition(m_mapDefinitionsApp, strAppFile);
		return true;
	}
	CString strAppGates = strApp + _T("Gates\\");
	strAppFile = m_pContainer->AssociateFile(strName, strAppGates);
	if(strAppFile.GetLength()){
		AddDefinition(m_mapDefinitionsApp, strAppFile);
		return true;
	}

	strApp.Append(_T("Blocks\\"));
	strAppFile = m_pContainer->AssociateFile(strName, strApp);
	if(strAppFile.GetLength()){
		AddDefinition(m_mapDefinitionsApp, strAppFile);
		return true;
	}
	return false;
}

bool CPSCreator::AddDefinition(CMap<CString, LPCTSTR, CString, LPCTSTR> &map, CString strFilename)
{
	TiXmlDocument *pDoc = m_pContainer->GetDoc(strFilename);
	if(!pDoc)
		return false;
	
	CString strAction;
	CString strName;
	CString strDef;
	bool bFigureClosed = false;
	
	TiXmlElement *pRoot = pDoc->FirstChildElement();
	TiXmlElement *pDraw = pRoot->FirstChildElement("DRAWING");
	TiXmlElement *pName = pRoot->FirstChildElement("NAME");
	if(pName){
		strName.Empty();
		strName += pName->GetText();
	}
	if(pDraw){
		TiXmlElement *pBody = pDraw->FirstChildElement("BODY");
		if(pBody){
			strDef.Empty();
			TiXmlElement *pTemp = pBody->FirstChildElement();
			while(pTemp){
				strAction.Empty();
				strAction += pTemp->GetText();
				strDef.Append(ConvertAction(strAction, pTemp, bFigureClosed));
				pTemp = pTemp->NextSiblingElement();
			}
		}
		TiXmlElement *pOut = pDraw->FirstChildElement("OUTPUTS");
		if(pOut){
			TiXmlElement *pTemp = pOut->FirstChildElement();
			while(pTemp){
				strAction.Empty();
				strAction += pTemp->GetText();
				strDef.Append(ConvertAction(strAction, pTemp, bFigureClosed));
				pTemp = pTemp->NextSiblingElement();
			}
		}
		TiXmlElement *pIn = pDraw->FirstChildElement("INPUTS");
		if(pIn){
			TiXmlElement *pTemp = pIn->FirstChildElement();
			while(pTemp){
				strAction.Empty();
				strAction += pTemp->GetText();
				strDef.Append(ConvertAction(strAction, pTemp, bFigureClosed));
				pTemp = pTemp->NextSiblingElement();
			}
		}
	}
	map[strName] = strDef;
	SAFE_DELETE(pDoc);
	return true;
}

CString CPSCreator::ConvertAction(CString strAction, TiXmlElement *pElem, bool bFigureClosed)
{
	int x1, y1, x2, y2, x3, y3, x4, y4, a, b;
	CString strRet = _T("");
	if(strAction.CompareNoCase(_T("line")) == 0){
		pElem->Attribute("x1", &x1);
		pElem->Attribute("y1", &y1);
		pElem->Attribute("x2", &x2);
		pElem->Attribute("y2", &y2);
		strRet.Format(_T("%d %d moveto \n%d %d lineto\n%d %d moveto\n"), x1,y1,x2,y2,x2,y2);
	}
	else if(strAction.CompareNoCase(_T("bezier")) == 0){
		pElem->Attribute("x1", &x1);
		pElem->Attribute("y1", &y1);
		pElem->Attribute("x2", &x2);
		pElem->Attribute("y2", &y2);
		pElem->Attribute("x3", &x3);
		pElem->Attribute("y3", &y3);
		pElem->Attribute("x4", &x4);
		pElem->Attribute("y4", &y4);
		strRet.Format(_T("%d %d moveto \n%d %d %d %d %d %d curveto\n%d %d moveto\n"), x1,y1,x2,y2,x3,y3,x4,y4,x4,y4);

	}
	else if(strAction.CompareNoCase(_T("arc")) == 0){
		//<ARC rx1="40" ry1="0" rx2="50" ry2="40" nFrom="-90" nTo="180">arc</ARC>
		pElem->Attribute("rx1", &x1);		// x center
		pElem->Attribute("ry1", &y1);		// y center
		pElem->Attribute("rx2", &x2);		// width
		pElem->Attribute("ry2", &y2);		// heigth
		pElem->Attribute("nFrom", &a);		// angle From
		pElem->Attribute("nTo", &b);		// angle To
		double dRatio = (double)x2/(double)y2;
		if(dRatio){
			strRet.Format(_T("%d %d moveto 1 %f scale\n%d %d %d %d %d arc\n"), x1, y1, dRatio, x1,y1,x2,a,b);
		}
		else{
			strRet.Format(_T("%d %d moveto %d %d %d %d %d arc\n"), x1, y1, x1,y1,x2,a,b);
		}
	}
	else if(strAction.CompareNoCase(_T("ellipse")) == 0){

	}
	else if(strAction.CompareNoCase(_T("text")) == 0){
	}
	else
		return _T("");
	return strRet;
}