#include <stdlib.h>
#include <strstream.h>
#include <LINK/graph/Attribute.h>
#include <LINK/graph/Graph.h>
#include <LINK/graph/UBinGraph.h>
#include <LINK/graph/Vertex.h>
#include <LINK/graph/Edge.h>
#include <LINK/basic/Set.h>
#include<stdio.h>

#define MAX_REG_TRY 100

int AttemptRegularGeneration(Graph *, int, int, int, int);
Set<Vertex*> EligibleNeighbors(Graph*, int, int, int, int);
MUBinGraph *CreateRegularGraph(int k, int low, int high, int jump);

/*
int create_unbalanced_reg_graph(int num, int k1, int k2)
{
    while (1) {
	if (CreateRegularGraph(k1, 0, num/2 - 1, 0) != 1) {
		continue;
	} 
	if (CreateRegularGraph(k1, num/2, num - 1, 0) != 1) {
		continue;
	} 
	if (CreateRegularGraph(k1+k2, 0, num/2 - 1, 1) != 1) {
		continue;
	}
	break;
    }
    return(1);
}
*/

/*****************************************************************************/
/* CreateRegularGraph              					    **/
/*****************************************************************************/
/** k 			- regular					    **/
/** (high-low+1) 	- number of vertices (if jump is 0)                 **/
/** jump                - if 1, n is double  (high-low+1) (for unbalanced)  **/
/*****************************************************************************/
MUBinGraph *CreateRegularGraph(int k, int low, int high, int jump)
{
	cout << "GenRegular: CreateRegularGraph" <<endl;
	MUBinGraph *g = new MUBinGraph;
	int attempts, last_attempt;
	int n = (jump) ? 2 * (high-low+1) : high-low+1;
	int gcount;
	 
	if ( ((n % 2) != 0)  && ((k % 2) != 0) ) {
		cerr << "Create Graph: Error, both num and k are odd" << endl;
		return g;
	}
	g->addVertices(n);
	cout << "GenRegular: " << *g <<endl;
	last_attempt = FALSE;
	attempts = 0;  /* Number of failed attempts at generating this Graph. */
	 
	while ( attempts <= MAX_REG_TRY ) {
		cout << "GenRegular: while loop" <<endl;
		if ( AttemptRegularGeneration(g, k,low,high,jump) == FALSE ) {
			cerr << "** Attempt failed. Will try " <<
				 MAX_REG_TRY-attempts << " more times" << endl;
			attempts++;
			delete g;
			g = new MUBinGraph;
			g->addVertices(n);
		} else {
			last_attempt = attempts + 1;
			//if (!Unbalanced_Regular_Graphs ||
			//     (Unbalanced_Regular_Graphs && (jump == 1)
			//			&& (last_attempt == 1))) {
			//}
			break;
		}
	}
	gcount++;
	return g;
}


/* ---------------------------------------------------------------------- */

/**************************************************************************/
/** AttemptRegularGeneration **********************************************/
/**************************************************************************/
/**   This function fills the adjacency matrix at the first 'num'	 **/
/**   vertices with edges randomly, trying to make a k-regular graph.	 **/
/**************************************************************************/
int AttemptRegularGeneration(Graph *g, int k, int low, int high, int jump)
{
	int ct, i, num_eligible;
	int all_ok = TRUE;
	int rnd;
	int start=low;
	int finish=high;
	int n = high-low+1;
	cout << "GenRegular: AttemptRegularGeneration" <<endl;

	if (jump) {			/** make bipartite-regular **/
		start = n - 1;
		finish = finish + n;
		high += 1;
	} 

	/* For each v, connect it to k vertices of higher number. */
	cout << "GenRegular: lion" <<endl;
	Vertex **vertices = g->vertexStart();
	cout << "GenRegular: low: " << low << ", high: " << high <<endl;
	for (i=low; i < high; i++) {
	        cout << "GenRegular: i: " << i <<endl;
		cout << "GenRegular: " << *g <<endl;
		cout << vertices[i]->degree() << endl;
	        cout << "GenRegular: made it " <<endl;

		while ( vertices[i]->degree() < k ) {
			cout << "GenRegular: adding " <<endl;
			Set<Vertex*> eligible_neighs = 
			     EligibleNeighbors(g, i,  k, start, finish);
			cout << "GenRegular: elig " <<endl;
			if ( eligible_neighs.emptyQ()) {
				all_ok = FALSE;
				break;
			}
			rnd = (Link_randomLong() % eligible_neighs.size());

			if (!jump)  start = i;

			Vertex *rand_eligible_neigh = eligible_neighs.ref(rnd);
			Set<Vertex*> vs;
			vs.insert(vertices[i]); 
			vs.insert(rand_eligible_neigh);
			cout << "GenRegular: adding an edge " <<endl;
			g->addEdge(vs);
		}
		if ( all_ok == FALSE )
		break;
	}

	/* Last v might not have proper degree. */
	cout << "GenRegular: " << finish << endl;
	cout << "GenRegular: " << *vertices[finish] << endl;
	cout << "GenRegular: " << vertices[finish]->degree() << endl;
 	if ( vertices[finish]->degree() != k)
    		all_ok = FALSE;

 	return(all_ok);
}
   
Set<Vertex*> EligibleNeighbors(Graph* g, int v_rank, int k, int low, int high)
{
	Set<Vertex*> result;
	Vertex **vertices = g->vertexStart();
	int i;
	
	for (i = (v_rank + 1); i <= high; i++ ) {
		if (!g->adjacentQ(vertices[v_rank], vertices[i]) &&
                    vertices[i]->degree() < k)
			result.insert(vertices[i]);
	}
	return(result);
}

MUBinGraph *GenRegularGraph(int n, int k)
{
	return CreateRegularGraph(k, 0, n-1, 0);
}
