#ifndef _IBFS_H__
#define _IBFS_H__


//#define STATS


//#pragma warning(disable:4786)
#include <time.h>
#include <sys/timeb.h>


template <typename captype, typename tcaptype, typename flowtype> class IBFSGraph
{
public:
	typedef enum
	{
		SOURCE	= 0,
		SINK	= 1
	} termtype;
	typedef int node_id;

	IBFSGraph(int numNodes, int numEdges, void (*errorFunction)(const char*) = NULL);
	~IBFSGraph();
	int add_node(int numNodes);
	void add_edge(int nodeIndexFrom, int nodeIndexTo, captype capacity, captype reverseCapacity);
	void add_tweights(int nodeIndex, tcaptype capacityFromSource, tcaptype CapacityToSink);

	// to separate the graph creation and maximum flow for measurements,
	// call prepareGraph and then call maxflowClean
	// prepareGraph is only required because of the limited API for building the graph
	// (specifically - the degree of nodes is not given)
	void prepareGraph();
	flowtype maxflowClean();

	flowtype maxflow()
	{
		prepareGraph();
		return maxflowClean();
	}

	termtype what_segment(int nodeIndex, termtype default_segm = SOURCE);


private:

	struct node;
	struct arc;

	struct arc
	{
		node*		head;
		arc*		sister;
//		int			sister_rCap :1;
//		captype		rCap :31;
// CHANGE by ANTON:
		char		sister_rCap;
		captype		rCap;

	};

	struct node
	{
		arc			*firstArc;
		arc			*parent;
		node		*nextActive;
		node		*firstSon;
		int			nextSibling;
		int			label;		// distance to the source or the sink
								// label > 0: distance from src
								// label < 0: -distance from sink
		union
		{
			tcaptype	srcSinkCap;		// srcSinkCap > 0: capacity from the source
										// srcSinkCap < 0: -capacity to the sink
			node		*nextOrphan;
		};
	};

	struct AugmentationInfo
	{
		captype remainingDeficit;
		captype remainingExcess;
		captype flowDeficit;
		captype flowExcess;
	};

	node		*nodes, *nodeLast;
	arc			*arcs, *arcLast;
	flowtype	flow;

	void augment(arc *bridge, AugmentationInfo* augInfo);
	void adoptionSrc();
	void adoptionSink();

	node* orphanFirst;
	node* orphanLast;

	int activeLevel;
	node* activeFirst0;
	node* activeFirst1;
	node* activeLast1;

	void (*errorFunction)(const char *);
	int nNodes;

#ifdef STATS
	double numAugs;
	double grownSinkTree;
	double grownSourceTree;
	double numOrphans;

	double growthArcs;
	double numPushes;
	double orphanArcs1;
	double orphanArcs2;
	double orphanArcs3;

	double numOrphans0;
	double numOrphans1;
	double numOrphans2;
	double augLenMin;
	double augLenMax;
#endif

};





template <typename captype, typename tcaptype, typename flowtype> inline void IBFSGraph<captype, tcaptype, flowtype>::add_tweights(int nodeIndex, tcaptype capacitySource, tcaptype capacitySink)
{
	flowtype f = nodes[nodeIndex].srcSinkCap;
	if (f > 0)
	{
		capacitySource += f;
	}
	else
	{
		capacitySink -= f;
	}
	if (capacitySource < capacitySink)
	{
		flow += capacitySource;
	}
	else
	{
		flow += capacitySink;
	}
	nodes[nodeIndex].srcSinkCap = capacitySource - capacitySink;
}

template <typename captype, typename tcaptype, typename flowtype> inline void IBFSGraph<captype, tcaptype, flowtype>::add_edge(int nodeIndexFrom, int nodeIndexTo, captype capacity, captype reverseCapacity)
{
	arc *aFwd = arcLast;
	arcLast++;
	arc *aRev = arcLast;
	arcLast++;

	node* x = nodes + nodeIndexFrom;
	x->label++;
	node* y = nodes + nodeIndexTo;
	y->label++;

	aRev->sister = aFwd;
	aFwd->sister = aRev;
	aFwd->rCap = capacity;
	aRev->rCap = reverseCapacity;
	aFwd->head = y;
	aRev->head = x;
}



template <typename captype, typename tcaptype, typename flowtype> inline typename IBFSGraph<captype, tcaptype, flowtype>::termtype IBFSGraph<captype, tcaptype, flowtype>::what_segment(int nodeIndex, termtype default_segm)
{
	if (nodes[nodeIndex].parent != NULL)
	{
		if (nodes[nodeIndex].label > 0)
		{
			return SOURCE;
		}
		else
		{
			return SINK;
		}
	}
	return default_segm;
}

template <typename captype, typename tcaptype, typename flowtype> inline int IBFSGraph<captype, tcaptype, flowtype>::add_node(int numNodes)
{
	int n = nNodes;
	nNodes += numNodes;
	return n;
}

#endif