package thaw.plugins.webOfTrust;
import java.awt.Color;
import java.awt.Graphics;
import java.util.Iterator;
import java.util.Random;
import java.util.Vector;
import thaw.gui.GUIHelper;
import thaw.plugins.signatures.Identity;
public class WotGraphNode {
public final static int MAX_DEPTH = 50; /* just a security */
public final static int MAX_DISTANCE = 500;
public final static int MIN_DISTANCE = 50;
public final static int NODE_RADIUS = 4;
public final static int MAX_OPTIMIZATION_CYCLES = 30;
private WebOfTrustGraph graph;
private WotIdentity identity;
private int x = -1;
private int y = -1;
private WotGraphNode[] neighbours;
private int[] trustLinks;
private final static Random random = new Random();
private boolean selected = false;
public WotGraphNode(WebOfTrustGraph graph, WotIdentity i) {
this.graph = graph;
this.identity = i;
x = -1;
y = -1;
}
public Identity getIdentity() {
return identity;
}
public void setSelected(boolean s) {
this.selected = s;
}
public void setPosition(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
private int getAValueNear(int x) {
int diff = (random.nextInt(MAX_DISTANCE-MIN_DISTANCE))+MIN_DISTANCE;
boolean pos = random.nextBoolean();
if (!pos)
return x + (-1 * diff);
return x + diff;
}
public void setAlmostRandomPosition(WotGraphNode parent) {
this.x = getAValueNear(parent.getX());
this.y = getAValueNear(parent.getY());
}
public void generateNeighbours() {
generateNeighbours(0);
}
public void generateNeighbours(int depth) {
if (depth == MAX_DEPTH)
return;
/* search neighbours */
Vector trustList = identity.getTrustList();
neighbours = new WotGraphNode[trustList.size()];
trustLinks = new int[trustList.size()];
int i = 0;
for (Iterator it = trustList.iterator() ; it.hasNext() ; ) {
WotIdentity.TrustLink link = (WotIdentity.TrustLink)it.next();
neighbours[i] = new WotGraphNode(graph, link.getDestination());
trustLinks[i] = link.getLinkTrustLevel();
i++;
}
/* synchronizing with the already existing nodes */
for (i = 0 ; i < neighbours.length ; i++) {
WotGraphNode node = graph.getNode(neighbours[i].getIdentity().getPublicKey());
if (node != null) {
neighbours[i] = node;
} else {
neighbours[i].setAlmostRandomPosition(this);
neighbours[i].generateNeighbours(depth+1); /* recursivity */
graph.addNode(neighbours[i]);
}
}
}
public int nmbNeighbours() {
return neighbours.length;
}
public int getAverageX() {
int sum = 0;
for (int i = 0 ; i < neighbours.length ; i++)
sum += neighbours[i].getX();
return sum / neighbours.length;
}
public int getAverageY() {
int sum = 0;
for (int i = 0 ; i < neighbours.length ; i++)
sum += neighbours[i].getY();
return sum / neighbours.length;
}
public void switchPosition(WotGraphNode node) {
int newX = node.getX();
int newY = node.getY();
node.setPosition(x, y);
setPosition(newX, newY);
}
public void optimizePositions() {
for (int i = 0 ; i < MAX_OPTIMIZATION_CYCLES ;i++) {
boolean hasMove = false;
for (int j = 0; j < neighbours.length ; j++) {
if (neighbours[j].nmbNeighbours() <= 0)
continue;
int x = neighbours[j].getAverageX();
int y = neighbours[j].getAverageY();
WotGraphNode nearest = graph.getNearestNode(x, y);
if (nearest != neighbours[j]) {
switchPosition(nearest);
hasMove = true;
}
}
if (!hasMove)
break;
}
for (int j = 0; j < neighbours.length ; j++) {
neighbours[j].optimizePositions();
}
}
public void paintNode(Graphics g, float zoom, int zeroX, int zeroY) {
int realX = (int)(x * zoom);
int realY = (int)(y * zoom);
g.setColor(identity.getTrustLevelColor());
if (selected) {
g.drawOval( realX - NODE_RADIUS + zeroX,
realY - NODE_RADIUS + zeroY,
2*NODE_RADIUS,
2*NODE_RADIUS);
} else {
g.fillOval( realX - NODE_RADIUS + zeroX,
realY - NODE_RADIUS + zeroY,
2*NODE_RADIUS,
2*NODE_RADIUS);
}
g.drawString(identity.toString(),
realX + zeroX,
realY + zeroY - 10);
}
private void paintLink(Graphics g, WotGraphNode neighbour, int trustLink,
int myX, int myY,
float zoom, int zeroX, int zeroY) {
int targetX = (int)(neighbour.getX()*zoom);
int targetY = (int)(neighbour.getY()*zoom);
if (trustLink < 0)
g.setColor(Color.RED);
else if (trustLink > 0)
g.setColor(Color.BLUE);
GUIHelper.paintArrow(g, targetX+zeroX, targetY+zeroY, myX, myY);
}
public void paintLinks(Graphics g, float zoom, int zeroX, int zeroY) {
int realX = (int)(x * zoom)+zeroX;
int realY = (int)(y * zoom)+zeroY;
for (int i = 0 ; i < neighbours.length ; i++) {
paintLink(g, neighbours[i], trustLinks[i], realX, realY, zoom, zeroX, zeroY);
}
}
}