#include "Gate.h"
#include <stdlib.h>

std::set<Gate*> Gate::toRelease;
#ifdef _DEBUG
std::set<Gate*> Gate::openedGates;
#endif

bool GateComp::operator()(const Gate* u,const Gate* v) const
{
	return Gate::gateComparator(u,v)<0;
}

Gate::GateCache::GateCache()
{
	_isProduct=-1;
	_isSumOfProducts=-1;
	_isCubeFree=-1;

	_cubesCount=-1;
	_literalsCount=-1;
}

Gate::GateCache::~GateCache()
{
}

void Gate::GateCache::ClearCache()
{
	_isProduct=-1;
	_isSumOfProducts=-1;
	_isCubeFree=-1;

	_cubesCount=-1;
	_literalsCount=-1;
}

bool Gate::exitOnPortsCount(std::map<int,int>& _portsCount,int exitCount,bool usesDisabling)
{
	if (usesDisabling)
	{
		if (disabled) return false;

		switch (type)
		{
		case FALSE:
		case TRUE:
			return false;
		case PORT:
			if (++_portsCount[portNumber]>=exitCount) return true;
			return false;
		case INVPORT:
			if (++_portsCount[-portNumber]>=exitCount) return true;
			return false;
		case BUF:
		case INV:
			return (!(*inputs.begin())->disabled && (*inputs.begin())->exitOnPortsCount(_portsCount,exitCount,true));
		case AND:
		case OR:
		case XOR:
		case NAND:
		case NOR:
		case XNOR:
			for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
				if (!(*iG)->disabled && (*iG)->exitOnPortsCount(_portsCount,exitCount,true))
					return true;
			return false;
		default:
			return false;
		}
	}

	switch (type)
	{
	case FALSE:
	case TRUE:
		return false;
	case PORT:
		if (++_portsCount[portNumber]>=exitCount) return true;
		return false;
	case INVPORT:
		if (++_portsCount[-portNumber]>=exitCount) return true;
		return false;
	case BUF:
	case INV:
		return (*inputs.begin())->exitOnPortsCount(_portsCount,exitCount);
	case AND:
	case OR:
	case XOR:
	case NAND:
	case NOR:
	case XNOR:
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			if ((*iG)->exitOnPortsCount(_portsCount,exitCount))
				return true;
		return false;
	default:
		return false;
	}
}

void Gate::replaceFunctions(int functionsOffset,Gate** functions,int functionsCount)
{
	switch (type)
	{
	case FALSE:
	case TRUE:
		return;
	case PORT:
		if (portNumber>=functionsOffset && (portNumber-functionsOffset)<functionsCount)
		{
			type=BUF;
			addInput(functions[portNumber-functionsOffset]);
		}
		return;
	case INVPORT:
		if (portNumber>=functionsOffset && (portNumber-functionsOffset)<functionsCount)
		{
			type=INV;
			addInput(functions[portNumber-functionsOffset]);
		}
		return;
	default:
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			(*iG)->replaceFunctions(functionsOffset,functions,functionsCount);
	}
}

bool Gate::disablePort(int _portNumber)
{
	switch (type)
	{
	case FALSE:
	case TRUE:
		return false;
	case PORT:
		if (portNumber==_portNumber) disabled=true;
		return portNumber==_portNumber;
	case INVPORT:
		if (portNumber==-_portNumber) disabled=true;
		return portNumber==-_portNumber;
	default:
		bool exists=false;
		int enabledCount=0;
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++) 
		{
			if ((*iG)->disablePort(_portNumber)) exists=true;
			if (!(*iG)->disabled) enabledCount++;
		}

		if (!exists) 
			disablingPorts.insert(_portNumber);

		if (!disablingPorts.empty() || enabledCount==0)
			disabled=true;

		return exists;
	}
}

bool Gate::enablePort(int _portNumber)
{
	switch (type)
	{
	case FALSE:
	case TRUE:
		return false;
	case PORT:
		if (portNumber==_portNumber) disabled=false;
		return portNumber==_portNumber;
	case INVPORT:
		if (portNumber==-_portNumber) disabled=false;
		return portNumber==-_portNumber;
	default:
		bool exists=false;
		int enabledCount=0;
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
		{
			if ((*iG)->enablePort(_portNumber)) exists=true;
			if (!(*iG)->disabled) enabledCount++;
		}

		if (!exists)
			disablingPorts.erase(_portNumber);

		if (disablingPorts.empty() && enabledCount>0)
			disabled=false;

		return exists;
	}
}

void Gate::setDisabled(bool _disabled)
{
	disabled=_disabled;
	for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
		(*iG)->setDisabled(_disabled);
}

Gate::Gate(GateType _type,int _portNumber)
{
	type=_type;
	portNumber=_portNumber;

	disabled=false;

	net=NULL;

#ifdef _DEBUG
	openedGates.insert(this);
#endif
}

Gate::~Gate()
{
	inputs.clear();
#ifdef _DEBUG
	openedGates.erase(this);
#endif
}

void Gate::addInput(Gate* input)
{
	inputs.insert(input);
	cache.ClearCache();
}

void Gate::removeInput(Gate* input)
{
	inputs.erase(input);
	cache.ClearCache();

	input->setRelease(true);
}
void Gate::setRelease(bool release)
{
	if (release)
		toRelease.insert(this);
	else
		toRelease.erase(this);

	for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
		(*iG)->setRelease(release);
}

std::string Gate::toString()
{
	std::string ret("");

	bool first=true;
	switch (type)
	{
	case FALSE:
		ret+="0";
		break;
	case TRUE:
		ret+="1";
		break;
	case PORT:
		ret+='a'+portNumber-1;
		break;
	case INVPORT:
		ret+="!";
		ret+='a'+portNumber-1;
		break;
	case BUF:
		ret+=(*inputs.begin())->toString();
		break;
	case INV:
		ret+="!";
		ret+=(*inputs.begin())->toString();
		break;
	case AND:
		ret+="(";
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
		{
			if (!first)	ret+="*"; else first=false;
			ret+=(*iG)->toString();
		}
		ret+=")";
		break;
	case OR:
		ret+="(";
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
		{
			if (!first)	ret+="+"; else first=false;
			ret+=(*iG)->toString();
		}
		ret+=")";
		break;
	case XOR:
		ret+="(";
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
		{
			if (!first) ret+="^"; else first=false;
			ret+=(*iG)->toString();
		}
		ret+=")";
		break;
	case NAND:
		ret+="(";
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
		{
			if (!first) ret+="&"; else first=false;
			ret+=(*iG)->toString();
		}
		ret+=")";
		break;
	case NOR:
		ret+="(";
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
		{
			if (!first) ret+="|"; else first=false;
			ret+=(*iG)->toString();
		}
		ret+=")";
		break;
	case XNOR:
		ret+="(";
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
		{
			if (!first) ret+="@"; else first=false;
			ret+=(*iG)->toString();
		}
		ret+=")";
		break;
	}

	return ret;
}

bool Gate::isProduct(bool usesDisabling)
{
	if (usesDisabling)
	{
		if (disabled) return false;
		if (type!=AND)
			return (type==PORT || type==INVPORT || type==FALSE || type==TRUE);

		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++) 
			if (!(*iG)->disabled && (*iG)->type!=PORT && (*iG)->type!=INVPORT && (*iG)->type!=FALSE && (*iG)->type!=TRUE)
				return false;

		return true;
	}

	if (cache._isProduct!=-1) return cache._isProduct;

	if (type!=AND)
		return cache._isProduct=(type==PORT || type==INVPORT || type==FALSE || type==TRUE);

	for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++) 
		if (!(*iG)->disabled && (*iG)->type!=PORT && (*iG)->type!=INVPORT && (*iG)->type!=FALSE && (*iG)->type!=TRUE)
			return cache._isProduct=false;

	return cache._isProduct=true;
}

bool Gate::isSumOfProducts(bool usesDisabling)
{
	if (usesDisabling)
	{
		if (disabled) return false;
		if (type!=OR)
			return isProduct(true);

		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++) 
			if (!(*iG)->disabled && !(*iG)->isProduct(true))
				return false;

		return true;
	}

	if (cache._isSumOfProducts!=-1) return cache._isSumOfProducts;

	if (type!=OR)
		return cache._isSumOfProducts=isProduct();

	for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
		if (!(*iG)->isProduct())
			return cache._isSumOfProducts=false;

	return cache._isSumOfProducts=true;
}

bool Gate::isCubeFree(bool usesDisabling)
{
	if (usesDisabling)
	{
		if (disabled || !isSumOfProducts(true) || isProduct(true)) return false;

		int enabledInputsCount=0;

		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++) 
			if (!(*iG)->disabled)
				enabledInputsCount++;

		if (enabledInputsCount<2) return false;

		std::map<int,int> portsCount;
		if (exitOnPortsCount(portsCount,enabledInputsCount,true)) return cache._isCubeFree=false;

		return true;
	}

	if (cache._isCubeFree!=-1) return cache._isCubeFree;

	if (!isSumOfProducts() || isProduct() || inputs.size()<2) return cache._isCubeFree=false;

	std::map<int,int> portsCount;
	if (exitOnPortsCount(portsCount,inputs.size())) return cache._isCubeFree=false;

	return cache._isCubeFree=true;
}

void Gate::getUsedPorts(std::set<int>& usedPorts)
{
	switch (type)
	{
	case FALSE:
	case TRUE:
		return;
	case PORT:
		usedPorts.insert(portNumber);
		return;
	case INVPORT:
		usedPorts.insert(-portNumber);
		return;
	case BUF:
	case INV:
	case AND:
	case OR:
	case XOR:
	case NAND:
	case NOR:
	case XNOR:
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			(*iG)->getUsedPorts(usedPorts);
		return;
	}
}

void Gate::getPortsCount(std::map<int,int>& portsCount,bool usesDisabling,bool disablePorts)
{
	if (usesDisabling && disabled) return;

	switch (type)
	{
	case FALSE:
	case TRUE:
		return;
	case PORT:
		portsCount[portNumber]++;
		if (disablePorts) disabled=true;
		return;
	case INVPORT:
		portsCount[-portNumber]++;
		if (disablePorts) disabled=true;
		return;
	case BUF:
	case INV:
	case AND:
	case OR:
	case XOR:
	case NAND:
	case NOR:
	case XNOR:
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			(*iG)->getPortsCount(portsCount,usesDisabling,disablePorts);
		return;
	}
}

int Gate::cubesCount(bool usesDisabling)
{
	if (usesDisabling)
	{
		if (disabled) return -1;

		if (isProduct(true)) return 1;
		if (!isSumOfProducts(true)) return -1;

		int cubesCount=0;
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			if (!(*iG)->disabled)
				cubesCount++;

		return cubesCount;
	}

	if (cache._cubesCount!=-1) return cache._cubesCount;

	if (isProduct()) return cache._cubesCount=1;
	if (!isSumOfProducts()) return cache._cubesCount=-1;

	return cache._cubesCount=inputs.size();
}

int Gate::literalsCount(bool usesDisabling)
{
	if (usesDisabling)
	{
		if (disabled) return 0;

		switch (type)
		{
		case FALSE:
		case TRUE:
			return 0;
		case PORT:
		case INVPORT:
			return 1;
		case BUF:
		case INV:
		case AND:
		case OR:
		case XOR:
		case NAND:
		case NOR:
		case XNOR:
			int ret=0;
			for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
				ret+=(*iG)->literalsCount();
			return ret;
		}

		return 0;
	}

	if (cache._literalsCount!=-1) return cache._literalsCount;

	switch (type)
	{
	case FALSE:
	case TRUE:
		return cache._literalsCount=0;
	case PORT:
	case INVPORT:
		return cache._literalsCount=1;
	case BUF:
	case INV:
	case AND:
	case OR:
	case XOR:
	case NAND:
	case NOR:
	case XNOR:
		cache._literalsCount=0;
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			cache._literalsCount+=(*iG)->literalsCount();
		return cache._literalsCount;
	default:
		return cache._literalsCount=0;
	}
}

int Gate::gatesCount(bool addInvPorts,bool disableGates)
{
	if (disableGates && disabled) return 0;

	int ret=0;

	switch (type)
	{
	case FALSE:
	case TRUE:
	case PORT:
	case INVPORT:
		ret=0;
		break;
	case BUF:
	case INV:
		ret=(*inputs.begin())->gatesCount(false,disableGates)+1;
		break;
	case AND:
	case OR:
	case XOR:
	case NAND:
	case NOR:
	case XNOR:
		ret=1;
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			ret+=(*iG)->gatesCount(false,disableGates);
		break;
	default:
		return 0;
	}

	if (addInvPorts)
	{
		std::set<int> usedPorts;
		getUsedPorts(usedPorts);

		for (std::set<int>::iterator port=usedPorts.begin();port!=usedPorts.end();port++)
			if ((*port)<0)
				ret++;
	}

	if (disableGates) disabled=true;

	return ret;
}

int Gate::getLevels()
{
	int levels,maxLevels=0;

	switch (type)
	{
	case FALSE:
	case TRUE:
	case PORT:
	case INVPORT:
		return 0;
	case BUF:
	case INV:
		return (*inputs.begin())->getLevels();
	case AND:
	case OR:
	case XOR:
	case NAND:
	case NOR:
	case XNOR:
	default:
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			if ((levels=(*iG)->getLevels())>maxLevels)
				maxLevels=levels;
		return maxLevels+1;
	}
}

void Gate::reduceGates()
{
	Gate* g;
	cache.ClearCache();

	switch (type)
	{
	case FALSE:
	case TRUE:
	case PORT:
	case INVPORT:
		return;
	case BUF:
		g=(*inputs.begin());
		g->reduceGates();
		g->setRelease(true);
		type=g->type;
		portNumber=g->portNumber;
		inputs=g->inputs;
		return;
	case INV:
		g=(*inputs.begin());
		g->reduceGates();
		if (g->type==PORT || g->type==INVPORT)
		{
			g->setRelease(true);
			type=(g->type==PORT)?INVPORT:PORT;
			portNumber=g->portNumber;
			inputs.clear();
		}
		else if (g->type==TRUE || g->type==FALSE)
		{
			g->setRelease(true);
			type=(g->type==TRUE)?FALSE:TRUE;
			portNumber=g->portNumber;
			inputs.clear();
		}
		else if (g->type==INV)
		{
			g->setRelease(true);
			type=(*g->inputs.begin())->type;
			portNumber=(*g->inputs.begin())->portNumber;
			inputs=(*g->inputs.begin())->inputs;
		}
		return;
	case AND:
		{
			Gates newInputs;
			for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			{
				(*iG)->reduceGates();
				newInputs.insert(*iG);
			}
			inputs=newInputs;

			std::set<Gate*> remove;

			for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			{
				if ((*iG)->type==PORT || (*iG)->type==INVPORT)
				{
					for (Gates::iterator iG2=iG;(++iG2)!=inputs.end();)
						if ((*iG2)->portNumber==(*iG)->portNumber && (((*iG2)->type==INVPORT && (*iG)->type==PORT) || ((*iG2)->type==PORT && (*iG)->type==INVPORT)))
						{
							setRelease(true);
							toRelease.erase(this);
							type=FALSE;
							portNumber=0;
							inputs.clear();

							return;
						}
				}
				else if ((*iG)->type==FALSE)
				{
					setRelease(true);
					toRelease.erase(this);
					type=FALSE;
					portNumber=0;
					inputs.clear();

					return;
				}
				else if ((*iG)->type==TRUE)
				{
					remove.insert(*iG);
				}
			}
			if (!remove.empty())
			{
				for (std::set<Gate*>::iterator iR=remove.begin();iR!=remove.end();iR++)
				{
					removeInput(*iR);
				}
			}
			if (inputs.empty())
			{
				type=TRUE;
				portNumber=0;
			}
			else if (inputs.size()==1)
			{
				g=(*inputs.begin());
				g->setRelease(true);
				type=g->type;
				portNumber=g->portNumber;
				inputs=g->inputs;
			}
		}
		return;
	case OR:
		{
			Gates newInputs;
			for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			{
				(*iG)->reduceGates();
				newInputs.insert(*iG);
			}
			inputs=newInputs;

			std::set<Gate*> remove;

			for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			{
				if ((*iG)->type==PORT || (*iG)->type==INVPORT)
				{
					for (Gates::iterator iG2=iG;(++iG2)!=inputs.end();)
						if ((*iG2)->portNumber==(*iG)->portNumber && (((*iG2)->type==INVPORT && (*iG)->type==PORT) || ((*iG2)->type==PORT && (*iG)->type==INVPORT)))
						{
							setRelease(true);
							toRelease.erase(this);
							type=TRUE;
							portNumber=0;
							inputs.clear();

							return;
						}
				}
				else if ((*iG)->type==TRUE)
				{
					setRelease(true);
					toRelease.erase(this);
					type=TRUE;
					portNumber=0;
					inputs.clear();

					return;
				}
				else if ((*iG)->type==FALSE)
				{
					remove.insert(*iG);
				}
			}
			if (!remove.empty())
			{
				for (std::set<Gate*>::iterator iR=remove.begin();iR!=remove.end();iR++)
				{
					removeInput(*iR);
				}
			}
			if (inputs.empty())
			{
				type=FALSE;
				portNumber=0;
			}
			else if (inputs.size()==1)
			{
				g=(*inputs.begin());
				g->setRelease(true);
				type=g->type;
				portNumber=g->portNumber;
				inputs=g->inputs;
			}
		}
		return;
	case XOR:
	case NAND:
	case NOR:
	case XNOR:
		//TODO: XOR,NAND,NOR,XNOR
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			(*iG)->reduceGates();
		return;
	}
}

void Gate::convertTo2Input()
{
	switch (type)
	{
	case FALSE:
	case TRUE:
	case PORT:
	case INVPORT:
		break;
	case BUF:
	case INV:
		(*inputs.begin())->convertTo2Input();
		break;
	case AND:
	case OR:
	case XOR:
		if (inputs.size()==1)
		{
			type=BUF;
			(*inputs.begin())->convertTo2Input();
		}
		else if (inputs.size()<=2)
		{
			for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
				(*iG)->convertTo2Input();
		}
		else
		{
			Gate* gate0=new Gate(type,portNumber);
			Gate* gate1=new Gate(type,portNumber);
			bool gateSelect=false;
			for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			{
				if (!gateSelect)
					gate0->addInput(*iG);
				else
					gate1->addInput(*iG);
				gateSelect=!gateSelect;
			}
			inputs.clear();
			addInput(gate0);
			addInput(gate1);
			gate0->convertTo2Input();
			gate1->convertTo2Input();
		}
		break;
	default:
		//TODO: NAND,NOR,XNOR
		break;
	}
}

void Gate::convertToNAND()
{
	switch (type)
	{
	case FALSE:
	case TRUE:
	case PORT:
	case INVPORT:
		break;
	case BUF:
	case INV:
		(*inputs.begin())->convertToNAND();
		break;
	case AND:
		{
			Gate* nand=new Gate(NAND);
			nand->inputs=inputs;
			type=INV;
			inputs.clear();
			addInput(nand);
			(*inputs.begin())->convertToNAND();
			break;
		}
	case OR:
		{
			type=NAND;
			Gates newInputs;
			for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			{
				(*iG)->convertToNAND();
				Gate* inv=new Gate(INV);
				inv->addInput(*iG);
				newInputs.insert(inv);
			}
			inputs=newInputs;
			break;
		}
	case XOR:
	case NAND:
	case NOR:
	case XNOR:
		//TODO: XOR,NAND,NOR,XNOR
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			(*iG)->convertToNAND();
		break;
	default:
		break;
	}
}

bool Gate::process(const char* inputValues)
{
	bool ret=false;

	switch (type)
	{
	case FALSE:
		return false;
	case TRUE:
		return true;
	case PORT:
		return inputValues[portNumber-1]=='1' || inputValues[portNumber-1]=='4';
	case INVPORT:
		return inputValues[portNumber-1]=='0';
	case BUF:
		return (*inputs.begin())->process(inputValues);
	case INV:
		return !(*inputs.begin())->process(inputValues);
	case AND:
		ret=true;
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			if (!(ret&=(*iG)->process(inputValues))) return ret;
		return ret;
	case OR:
		ret=false;
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			if (ret|=(*iG)->process(inputValues)) return ret;
		return ret;
	case XOR:
		ret=false;
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			ret^=(*iG)->process(inputValues);
		return ret;
	case NAND:
		ret=true;
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			if (!(ret&=(*iG)->process(inputValues))) return !ret;
		return !ret;
	case NOR:
		ret=false;
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			if (ret|=(*iG)->process(inputValues)) return !ret;
		return !ret;
	case XNOR:
		ret=false;
		for (Gates::iterator iG=inputs.begin();iG!=inputs.end();iG++)
			ret^=(*iG)->process(inputValues);
		return !ret;
	default:
		return ret;
	}
}

int Gate::gateComparator(const Gate* u,const Gate* v)
{
	if (u->type!=v->type) return u->type-v->type;

	switch (u->type)
	{
	case TRUE:
	case FALSE:
		return u-v;
	case PORT:
	case INVPORT:
		return u->portNumber-v->portNumber;
	case BUF:
	case INV:
		return gateComparator(*u->inputs.begin(),*v->inputs.begin());
	case AND:
	case OR:
	case XOR:
	case NAND:
	case NOR:
	case XNOR:
		for (Gates::const_iterator iG=u->inputs.begin(),iG2=v->inputs.begin();iG!=u->inputs.end();iG++,iG2++)
		{
			int ret;
			if (iG2!=v->inputs.end())
				ret=gateComparator(*iG,*iG2);
			else
				return u->inputs.size()-v->inputs.size();
			if (ret) return ret;
		}
		return 0;
	default:
		return 0;
	}
}

void Gate::getGateName(GateType type,int inPortCount,std::string& out)
{
	static char buff[4];

	switch (type)
	{
	case FALSE:
		out="GND";
		break;
	case TRUE:
		out="VCC";
		break;
	case BUF:
		out="BUF";
		break;
	case INV:
		out="INV";
		break;
	case AND:
		out=std::string("AND")+itoa(inPortCount,buff,10);
		break;
	case OR:
		out=std::string("OR")+itoa(inPortCount,buff,10);
		break;
	case XOR:
		out=std::string("XOR")+itoa(inPortCount,buff,10);
		break;
	case NAND:
		out=std::string("NAND")+itoa(inPortCount,buff,10);
		break;
	case NOR:
		out=std::string("NOR")+itoa(inPortCount,buff,10);
		break;
	case XNOR:
		out=std::string("XNOR")+itoa(inPortCount,buff,10);
		break;
	default:
		out="";
		break;
	}
}

void Gate::releaseGates()
{
	for (std::set<Gate*>::iterator iR=toRelease.begin();iR!=toRelease.end();iR++)
		delete *iR;
	toRelease.clear();
}