#include "hub\location.h"
#include "hub\structural.h"
#include <set>
#include <map>

enum GateType
{
	FALSE=0,
	TRUE,
	PORT,
	INVPORT,
	BUF,
	INV,
	AND,
	OR,
	XOR,
	NAND,
	NOR,
	XNOR
};

class Gate;

struct GateComp
{
	bool operator()(const Gate* u,const Gate* v) const;
};

typedef std::set<Gate*,GateComp> Gates;

class Gate
{
	friend class Decomposer;

	GateType type;
	int portNumber;
	Gates inputs;

	bool disabled;
	std::set<int> disablingPorts;

	hub::Net* net;

	struct GateCache
	{
		GateCache();
		~GateCache();

		signed char _isProduct;
		signed char _isSumOfProducts;
		signed char _isCubeFree;

		int _cubesCount;
		int _literalsCount;

		void ClearCache();
	} cache;

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

	bool exitOnPortsCount(std::map<int,int>& _portsCount,int exitCount,bool usesDisabling=false);
	void replaceFunctions(int functionsOffset,Gate** functions,int functionsCount);

	bool disablePort(int _portNumber);
	bool enablePort(int _portNumber);

	void setDisabled(bool _disabled);

public:
	Gate(GateType _type,int _portNumber=0);
	~Gate();

	void addInput(Gate* input);
	void removeInput(Gate* input);

	void setRelease(bool release);

	std::string toString();

	bool isProduct(bool usesDisabling=false);
	bool isSumOfProducts(bool usesDisabling=false);
	bool isCubeFree(bool usesDisabling=false);

	void getUsedPorts(std::set<int>& usedPorts);
	void getPortsCount(std::map<int,int>& portsCount,bool usesDisabling,bool disablePorts=false);

	int cubesCount(bool usesDisabling=false);
	int literalsCount(bool usesDisabling=false);

	int gatesCount(bool addInvPorts=false,bool disableGates=false);
	int getLevels();

	void reduceGates();
	void convertTo2Input();
	void convertToNAND();

	bool process(const char* inputValues);

	static int gateComparator(const Gate* u,const Gate* v);
	static void getGateName(GateType type,int inPortCount,std::string& out);
	static void releaseGates();
};

