#include <stdio.h>
#include "graph.h"
#include "bool.h"

bool member (int x, edgenode *edgelist) {
	return edgelist && (edgelist->y == x || member(x, edgelist->next)); 
}

bool is_edge(graph *gp, int u, int v) {
	return u < gp->nvertices && member(v, gp->edges[u]);
}

// larger test cases.
void rand_edges(graph *gp, int n1, int n2, int m);

// how likely is it that a random graph has bases and sponges?
void rand_graph(graph *gp, int n, int m) {
	if (n > MAXV) {
		printf("I can't do that, Dave (n = %d, MAXV = %d)\n", n, MAXV);
		exit(1);
	}
	initialize_graph(gp, TRUE);
    gp->nvertices=n;
	rand_edges(gp, 1, n, m);
}

void rand_edges(graph *gp, int n1, int n2, int m) {
// Requires nvertices >= n2 >= n1 >= 1.
// Add m edges randomly among vertices [n1,n2).  
    int i, u, v;
	int n = n2 - n1; // number of vertices
	for (i = 0; i < m; ++i) {
		do {
			u = n1 + rand()%n;
			v = n1 + rand()%n;
		} while (u == v || is_edge(gp, u, v));
		insert_edge(gp, u, v, gp->directed);
	}
}
void rand_strong(graph *gp, int n1, int n2, int m) {
	int n = n2 - n1;// (number of vertices).
/* 
Requires: n <= m <= n^2 - n. Initially *gp has no edges on [n1,n2).
Promises:  Make *gp a strongly connected graph on vertices [n1,n2) with m edges.
*/
    // make a cycle
	int i;
	for (i = n1; i < n2-1; ++i)
		insert_edge(gp, i, i+1, gp->directed);
	if (n1 < n2) insert_edge(gp, n2-1, n1, gp->directed);
    // add random edges
	rand_edges(gp, n1, n2, m-n);
}

void rand_perm(int *a, int n){ 
// Requires: Array a is of length at least n+1.
// Promises: a[1]..a[n] are a random permutation of 1..n
  if (n > 0) a[1] = 1;
  int i;
  for (i = 2; i <= n; ++i) {
    int j = 1+rand(i);
    a[i] = a[j];
    a[j] = i;
  }
}
			
void rand_buckle(graph *gp, int n, int m) {
// Builds a graph whose strong component dag has the form 
// a<----b---->c
// |     |     |
// v     v     v
// c---->s<----d
// Requires: 13 <= n and n+6 <= m <= (1/4)n^2 - 9n + 34 (slightly conservative).
/*
k=(m-15)/4 <= ((n-9)/4)((n-9)/4 - 1)
k=m-15 <= (n-9)((n-9)/4 - 1)
4m <= 60 + (n-9)((n-9) - 4)
4m <= 60 + n^2 - 2*18n + 81 - 4 = n^2 - 4*9n + 137 
m <= n^2/4 - 9n + 34
*/
	initialize_graph(gp, TRUE);
    gp->nvertices=n;
	if (n > MAXV || n < 13 || m < n+6 || m > (n*n/4-9*n + 34)) {
		printf("randbuckle can't do n = %d, m = %d, MAXV = %d\n", n, m, MAXV);
		exit(1);
	}
	rand_strong(gp, 1, 6, 5);
	rand_strong(gp, 6, 10, 4);
    int n2 = n - 9;
	int m2 = m - 9 - 6;
	int a = n2/4, b = m2/4;
	rand_strong(gp, 10, 10 + a, b); 
	rand_strong(gp, 10 + a, 10 + 2*a, b); 
	rand_strong(gp, 10 + 2*a, 10 + 3*a, b); 
	rand_strong(gp, 10 + 3*a, 10 + n2, m2 - 3*b); 
    insert_edge(gp, 3, 10, gp->directed);
    insert_edge(gp, 10, 10 + a, gp->directed);
    insert_edge(gp, 10 + a, 7, gp->directed);
    insert_edge(gp, 4, 10 + 2*a, gp->directed);
    insert_edge(gp, 10 + 2*a, 10 + 3*a, gp->directed);
    insert_edge(gp, 10 + 3*a, 8, gp->directed);
}

void write_graph(graph *gp){
	printf("%d   %d\n", gp->nvertices, gp->nedges);
    int i; edgenode *jp;
	for (i = 1; i <= gp->nvertices; ++i)
		for (jp = gp->edges[i]; jp != NULL; jp = jp->next)
			if (gp->directed || i < jp->y) printf("%d %d\n", i, jp->y);
}

int main(int ac, char* av[]) {
	graph g; 
	//rand_graph(&g, 1000, 30000);
	//rand_buckle(&g, 13, 19); 
	//rand_buckle(&g, 100, 100*25 - 900 + 34);
	rand_buckle(&g, 1000, 1006);
	//rand_buckle(&g, 1000, 1000*250 - 9000 + 34);
	//rand_buckle(&g, 4000, 4000000 - 36000 + 34);
	write_graph(&g);
	
}
