//---------------------------------------------------------------------------

#ifndef ResynthesisH
#define ResynthesisH
//---------------------------------------------------------------------------

class Resynthesis {
    private:
			// parameters
		unsigned int method;		// Select the selection method. 0 = random, 1 = fanin
		bool improvement;		// if true, only better networks are accepted
		unsigned int optcrit;	// 0 = nodes, 1 = literals
		unsigned int stoplimit;		// multiple of the numbre of source nodes, after which is unssuccessful search for a connected circuit terminated
		float sizelimit;			// relative or absolute (>1) size limit
		unsigned int size;			// for method 4 and 5
		unsigned int limit;			// computed absolute window size limit

		unsigned int fanin, fanout, c_size, r_size;		// fanin and fanout of the currently resynthesized network, nodes in cut, nodes in resynthesized
		unsigned int real_fanin_rad, real_fanout_rad;	// for m4 - real fan-in and fan-out radius
		bool accept;
		
		Network *source;    // original (and processed) network
		Network *stripped;	// stripped network going to resynthesis

		list<list<Node>::iterator> neighbors;		// list of candidates for inclusion - neighbors of "stripped" nodes in "source"

		bool Nondisjoint( const list<Node>::iterator ndi1, const list<Node>::iterator ndi2 ) const;	// do have the two nodes non-disjoint support?
		bool Nondisjoint( Network *net, const list<Node>::iterator ndi ) const;			// do have the node and the network common variables?
		void EspressoResynth(void);
		bool FeedsNode( const string &name );
		void GenerateNeighbors( list<Node>::iterator ndi );
		bool RandomSelect(void);
		bool RandomSelect2(void);
		bool FaninSelect(void);
		bool FaninSelect2(void);
		bool FanoutSelect(void);
		bool FanoutSelect2(void);
		bool FaninFanoutSelect(void);
		bool FaninFanoutSelect2(void);
		void RadiusSelect(void);
		void WindowingSelect(void);

		void MultilevelResynth(void);

    public:
        Resynthesis( Network *src );
        ~Resynthesis(void);

		void SetMethod( const unsigned int m ) { method = m; };
		void SetImpr( const bool impr ) { improvement = impr; };
		void SetOptCrit( const unsigned int crit ) { optcrit = crit; };
		void SetSize( const unsigned int _size ) { size = _size; };
		void SetSizeLimit( const float _sizelimit ) { sizelimit = _sizelimit; };

		unsigned int GetFanin(void) const { return fanin; };			// return number of inputs of the currently resynthesized cut
		unsigned int GetFanout(void) const { return fanout; };			// return number of outputs of the currently resynthesized cut
		unsigned int GetCutSize(void) const { return c_size; };			// return number of nodes of the cut before resynthesis
		unsigned int GetResynthSize(void) const { return r_size; };		// return number of nodes of the cut after resynthesis
		bool GetAccept(void) const { return accept; };					// was the iteration accepted?
		unsigned int GetRealFaninRadius(void) const { return real_fanin_rad; };		// return real fan-in radius (m4)
		unsigned int GetRealFanoutRadius(void) const { return real_fanout_rad; };		// return real fan-in radius (m4)
		
		void Run(void);
		Network *GetNetwork(void) { return source; };

};


#endif
