#include "hub\hub.h"
#include "hub\location.h"
#include "hub\structural.h"
#include "hub\pla.h"
#include "hub\symfunc.h"
#include "Gate.h"

typedef std::set<int> Cube;

struct CubeComp
{
	bool operator()(const Cube& x,const Cube& y) const;
};

typedef std::set<Cube,CubeComp> Kernel;
typedef std::set<Cube,CubeComp> CoKernels;

struct KernelComp
{
	bool operator()(const Kernel& x,const Kernel& y) const;
};

struct KernelValue
{
	KernelValue();

	Kernel kernel;
	Gate* function;
	CoKernels coKernels;
	Gates representation;
	int gainCache;
};

typedef std::map<Gate*,KernelValue> KernelValues;
typedef std::map<Kernel,KernelValues,KernelComp> Kernels;

struct KernelLiteralComp
{
	bool operator()(const Kernel& x,const Kernel& y) const;
};

typedef std::set<Kernel,KernelLiteralComp> KernelsSize;

class Decomposer
{
	hub::Hub* theHub;

	hub::Library* libGates;
	hub::Library* library;
	hub::Entity* entity;
	hub::Architecture* architecture;
	hub::Architecture* strArchitecture;
	hub::StructArch* strArch;

	FILE* statsFile;

	std::map<int,hub::Port<hub::Instance>*> invPorts;

	int connect(Gate* g,hub::Net** net);
	hub::Entity* getGateEntity(Gate* g);
	hub::Entity* getGateEntity(GateType type,int inPortCount);
	Gate* buildGateNetFromPLA(hub::PlaDescr* pla,int outPortNumber);
	bool verify(Gate* gate,hub::PlaDescr* pla,int outPortNumber);

	static hub::SymFunc::Func getHubFunc(GateType type);
	static bool getKernels(Gate* gate,Kernels& _kernels,std::set<int>& usedPorts,std::set<int>::iterator currentPort,Cube& currentCoKernel,KernelsSize& _kernelsSize,int _optimalizationKS);
	static void getKernels(Gate* gate,Kernels& _kernels,KernelsSize& _kernelsSize,int _optimalizationKS);
	static bool chooseKernel(Kernels& _kernels,KernelValues& _kernelValues,bool _multiGain);
	static int computeKernelGain(Kernels& _kernels,const Kernel& _kernel,bool _multiGain);
	static void removeKernel(Kernels& _kernels,Kernel& _kernel);

public:
	Decomposer(hub::Hub* _theHub);
	~Decomposer();

	int operator()(hub::Location& _locationNames,std::string& _libGatesName,bool _convertTo2Input=true,bool _convertToNAND=true,std::string statsFileName="",bool _printDebugInfo=false,int _optimalizationKS=-1,bool _multiGain=true);

	static void decomposeGates(Gate** outputs,int outputsCount,int _optimalizationKS,bool _multiGain,FILE* statsFile=NULL);
};