#include <LINK/userobj/PostAnalyze.h>


#define SCREEN_LOWER_Y 0.1
#define SCREEN_UPPER_Y 0.9

char* label_v(Graph *g, Vertex* v, int cost);

void LayoutPlacedVertices(Graph *g, List<Vertex*> *vertex_list, int g_order, 
			  int num_placed, double placed_ratio, 
			  double placed_lower_bd)
{
	double y_inc = (SCREEN_UPPER_Y - placed_lower_bd)/num_placed;
	double left_x_pos=0.2, right_x_pos=0.7;
	Vertex *v;
	Iterator<Vertex*> traverse_list(vertex_list);
	int temp,placed=0,cnt=0, Grdy_way, placement, cost, rank;
	char *v_cost;
	double rand_place, x, y;
	y = SCREEN_UPPER_Y;
	traverse_list.reset();
	int displayed;
	while(traverse_list(v))
	{
		getAttribute((GraphObject*) v, "displayed", displayed);
		if (displayed == 1) {
			y -= y_inc;
			continue;
		}
		getAttribute((GraphObject*) v, "placed", placed);
		if (!placed)
			continue;
		cnt = cnt + 1;
		getAttribute((GraphObject*) v, "greediness", Grdy_way);
		getAttribute((GraphObject*) v, "partition", placement);
		getAttribute((GraphObject*) v, "cost", cost);
		getAttribute((GraphObject*) v, "rank", rank);

		v_cost = label_v(g, v, cost);
		setAttribute((GraphObject*) v, "label", v_cost);

		rand_place = Link_randomDouble0_1() * .1;

		if (placement == LEFT)
		{
			x = left_x_pos + rand_place;
			temp = 0;
		}
		else {
			x = right_x_pos + rand_place;
			temp = 1;
		}
		setAttribute((GraphObject*) v, "x", x);
		setAttribute((GraphObject*) v, "y", y);	

		if (Grdy_way)
			setAttribute((GraphObject*) v, "color", BLACK); 
		else 
			setAttribute((GraphObject*) v, "color", WHITE); 
		
		y -= y_inc;
		setAttribute((GraphObject*) v, "displayed", 1); 
	}
}

void LayoutUnplacedVertices(Graph *g, double placed_lower_y, 
			    List<Vertex*> *vertex_list, int g_order, 
			    int num_placed)
{
	int num_unplaced = g_order - num_placed;
	double y_inc = (placed_lower_y - SCREEN_LOWER_Y)/num_unplaced;
	double upper_y = placed_lower_y - y_inc;
	double radius = (upper_y - SCREEN_LOWER_Y)/2;
	double ycenter = SCREEN_LOWER_Y + radius;
	Vertex *v;
	Iterator<Vertex*> traverse_list(vertex_list);
	int placed = 0, Grdy_way, cost, rank;
	char *v_cost;
	double x, y;
	y = SCREEN_UPPER_Y;

	double xcenter = 0.5;
	double pi = 3.14159;
	double two_pi = 2*pi;
 
	double angle_inc = two_pi/(double)num_unplaced;
	 
	double angle = 0.0;
	double wx, wy;
	traverse_list.reset();
	while (traverse_list(v))
		;
	traverse_list.reset();
	while (traverse_list(v)) {
		getAttribute((GraphObject*) v, "placed", placed);
		if (placed)
			continue;
    		wx = xcenter + (radius*cos(angle));
    		wy = ycenter + (radius*sin(angle));
    		//setAttribute((GraphObject*) v, "x", wx);
    		//setAttribute((GraphObject*) v, "y", wy);
    		angle += angle_inc;

		getAttribute((GraphObject*) v, "greediness", Grdy_way);
		getAttribute((GraphObject*) v, "cost", cost);
		getAttribute((GraphObject*) v, "rank", rank);
		v_cost = label_v(g, v, cost);
		setAttribute((GraphObject*) v, "label", v_cost);
	}
}

void
PartitioningLayout(Graph *g)
{
	char* v_cost;
	int cost;
	Set<Vertex*> vs = g->vertices();
	int g_order= g->order();
	int placed;
	int rank = 0, num_placed=0;

	Iterator<Vertex*> traverse_set(&vs);
	Vertex* v;
	List<Vertex*> vertex_list;
	while(traverse_set(v)) {
		vertex_list.insert(v);
		getAttribute((GraphObject*) v, "placed", placed);
		if (placed) num_placed++;
	}
	int num_unplaced = g_order - num_placed;
	vertex_list.sort(rank_comparison);

	double placed_ratio = num_placed/(double)g_order;
	double placed_lower_bd = 0.9 - 
                      ((SCREEN_UPPER_Y-SCREEN_LOWER_Y) * placed_ratio);

	LayoutPlacedVertices(g, &vertex_list, g_order, num_placed, 
			     placed_ratio, placed_lower_bd);
	LayoutUnplacedVertices(g, placed_lower_bd, &vertex_list, 
			       g_order, num_placed);
}


int
rank_comparison(const VertexPtr& v1, const VertexPtr& v2)
{
	int num1, num2;
	getAttribute((GraphObject*) v1, "rank", num1);
	getAttribute((GraphObject*) v2, "rank", num2);
	return (num1 - num2);
}


char*
label_v(Graph *g, Vertex* v, int cost)
{
	String name;
	getAttribute((GraphObject*) v, "name", name);
	char* buf;
	ostrstream oss;

	oss << name << ": " << cost << "/" << g->degree(v);
	oss << ends;
	buf = oss.str();
	return buf;
}
