blubs=[];
blubhash=[];
nextId=0;
var gsvgEl=null;
var BLUB_SIZE_SMALL=0.6;
var BLUB_EXP_DISTANCE_DEL=82;
var BLUB_EXP_DISTANCE=2.2;
var BLUB_EXPLOSION_DELTA=6;

var svgNS="http://www.w3.org/2000/svg";
var xlinkNS="http://www.w3.org/1999/xlink";
var anNS="http://rdf.desire.org/vocab/recommend.rdf#";
var rdfNS="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
var imgNS="http://jibbering.com/2002/3/svg/#";
var DCNS="http://purl.org/dc/elements/1.1/";
var foafNS="http://xmlns.com/foaf/0.1/";
var wordnetNS="http://xmlns.com/wordnet/1.6/";
var svgrNS="http://www.w3.org/2001/svgRdf/axsvg-schema.rdf#";
var jimNS="http://jibbering.com/foaf/jim.rdf#";



Relationships=[];
Relationships.push({NS:foafNS,name:"knows",prefix:"foaf"})
Relationships.push({NS:jimNS,name:"isKnownBy",prefix:"jim"})

  startURL="cache/";
  startURLsha1="cache/";
  endURL=".xml";

function Blub(x, y, startx, starty, name, link, nick) {
	if (blubhash[name]) {
		return blubhash[name];
	}
	this.x=x;
	this.y=y;
  this.id='blub_'+nextId++;
  this.name=name;
  this.neighbours=[];
  this.outNeighbours=[];
  this.inlines=[];
  this.outlines=[];
  this.mboxes=[];
	this.count_knows=0;
	this.count_isKnownBy=0;
  this.realName='';
  this.link=link;
  this.startx=startx;
  this.starty=starty;
  blubs[this.id]=this;
  blubs.push(this);
	blubhash[name]=this;
  if (nick+''=='undefined' || nick==''){
		nick=name.substr(7,name.indexOf('@')-7);
	}
	if (nick.indexOf('.')>3) {
		nick=nick.substr(0,nick.indexOf('.'));
	}
  str=nick.toUpperCase();
  if (nick+''=='undefined') {
		nick='??';
	}
  this.nick=nick;
	this.group=createBlub(this);
	setTimeout("moveBlub('" + this.id + "')", 10);
}

function moveBlubTo(blub,x,y) {
	blub.group.style.left=x+"px";
	blub.group.style.top=y+"px";
	blub.groupx=x;
	blub.groupy=y;
	if (document.body.addBehavior) {
		var bi=blub.inlines;
		var bil=bi.length;
		for (var i=0; i<bil; i++) {
			var bili=bi[i];
			try {
				bili.from=pos(blub);
			} catch (e) {}
		}
		var bi=blub.outlines;
		var bil=bi.length;
		for (var i=0; i<bil; i++) {
			var bili=bi[i];
			try {
				bili.to=pos(blub);
			} catch (e) {}
		}
	} else {
		if (window.SVGElement) {
			var bi=blub.inlines;
			var bil=bi.length;
			for (var i=0; i<bil; i++) {
				var bili=bi[i];
				try {
					bili.setAttribute('x1',svgposX(blub));
					bili.setAttribute('y1',svgposY(blub));
				} catch (e) {}
			}
			var bi=blub.outlines;
			var bil=bi.length;
			for (var i=0; i<bil; i++) {
				var bili=bi[i];
				try {
					bili.setAttribute('x2',svgposX(blub));
					bili.setAttribute('y2',svgposY(blub));
				} catch (e) {}
			}
		}
	}
}

function selectBlub(id) {
  var blub=blubs[id];
	var name=document.getElementById('name');
	name.innerHTML=blub.realName;
	var email=document.getElementById('email');
	email.innerHTML=blub.mboxes.join('<br>');
	var details=document.getElementById('details');
	details.innerHTML="KNOWS "+blub.count_knows+" PEOPLE<br>KNOWN BY "+blub.count_isKnownBy+" PEOPLE<br>"

}

function deleteBlub(id) {
  var blub=blubs[id];
	blub.group.parentNode.removeChild(blub.group);
	var bi=blub.inlines;
	var bil=bi.length;
	for (var i=0; i<bil; i++) {
		var bili=bi[i];
		bili.parentNode.removeChild(bili);
	}
	var bi=blub.outlines;
	var bil=bi.length;
	for (var i=0; i<bil; i++) {
		var bili=bi[i];
		bili.parentNode.removeChild(bili);
	}
	blub.deleted=1;
}

function moveBlub(id) {

  // The recursively called moveBlub function
  // creates the explosions.
  // BLUB_EXPLOSION_DELTA effects the number of steps it takes.
  
  var theBlub=blubs[id];
  nowX=theBlub.group.offsetLeft;
  nowY=theBlub.group.offsetTop;
  var toX=theBlub.x;
  var toY=theBlub.y;
  var dx=toX-nowX;
  var dy=toY-nowY;
  
  if (dx > -10 && dx < 10 && dy > -10 && dy < 10) {
    var nowToX=toX;
    var nowToY=toY;
  } else {
    var nowToX=nowX + dx/BLUB_EXPLOSION_DELTA;
    var nowToY=nowY + dy/BLUB_EXPLOSION_DELTA;
    setTimeout("moveBlub('" + id + "')", 10);
  }
  moveBlubTo(theBlub, nowToX, nowToY);
}
function createBlub(obj) {
	var str="<div class=head onclick='getMoreInfo(\""+obj.id+"\")'>+</div><div class=bodyTop></div><div class=apron onmousedown='startDrag(event)'>"+obj.nick+"</div><div class=bodyBottom></div><div class=feet onclick='deleteBlub(\""+obj.id+"\")'>-</div>";
	var div=document.createElement('div');
	div.className="blub";
	div.innerHTML=str;
	div.id=obj.id;
	document.body.appendChild(div);
	var apron=div.childNodes.item(2);
	div.style.left=obj.startx+"px";
	div.style.top=obj.starty+"px";
	return div;
}
function HTTP() {
	var xmlhttp;
	if (typeof XMLHttpRequest != 'undefined') {
		xmlhttp=new XMLHttpRequest();
	} else {
		if (typeof ActiveXObject !='undefined') {
			try {
				xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
			} catch (e) {}
		}
	}
	return xmlhttp;
}

function getMoreInfo(id) {
	closeHelp();
	selectBlub(id);
	var blub=blubs[id];
	blub.group.firstChild.innerHTML='o';
	blub.group.firstChild.onclick=function() {}
	blub.group.firstChild.onclick=new Function("selectBlub('"+id+"')");
	getPerson(blub.link,id);
}
function getPerson(link,id) {
	var xmlhttp=new HTTP();
	xmlhttp.open("GET",link,true);
	xmlhttp.onreadystatechange=function() {
		if (xmlhttp.readyState==4) {
			doc=xmlhttp.responseXML;
			if (!doc || !doc.documentElement) {
				try {
					doc=new ActiveXObject ("Microsoft.XMLDOM");
					doc.async=false;
					doc.validateOnParse=false;
					doc.resolveExternals=false;
					doc.loadXML(xmlhttp.responseText);
				} catch (e) {
					Document.prototype.loadXML = function (s) {
						var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
						while (this.hasChildNodes()) this.removeChild(this.lastChild);
						for (var i = 0; i < doc2.childNodes.length; i++) {
							this.appendChild(this.importNode(doc2.childNodes[i], true));
						}
					}
					doc=document.implementation.createDocument('', '', null);
					doc.loadXML(xmlhttp.responseText);
				}
			} 
			var dirList=[];
			var tmp=[];
			var count=0;
			var blub=blubs[id];
			for (var j=0;j<Relationships.length;j++) {
				var locRelationshipNS=Relationships[j].NS;
				var locRelationshipName=Relationships[j].name;
				var prefix=Relationships[j].prefix;
				if (doc.getElementsByTagNameNS) {
					dirs=doc.getElementsByTagNameNS(locRelationshipNS,locRelationshipName);
				} else {
					dirs=doc.getElementsByTagName(prefix+":"+locRelationshipName);
				}
				blub['count_'+locRelationshipName]=dirs.length;;
				for (var i=0;i<dirs.length;i++) {
					var d=dirs.item(i);
					if (d.getAttributeNS) {
						var r=d.getAttributeNS(foafNS, "mbox_sha1sum");
					} else {
						var r=d.getAttribute("foaf:mbox_sha1sum");
					}
					if (!tmp[r]) {
						if (d.getAttributeNS) {
							var t=d.getAttributeNS(rdfNS, "type");
						} else {
							var t=d.getAttribute("rdf:type");
						}
						if (!t) {
							t="http://xmlns.com/foaf/0.1/Person";
						}
						if (d.getAttributeNS) {
							var thenick=d.getAttributeNS(foafNS, "nick");
						} else {
							thenick=d.getAttribute("foaf:nick");
						}
						tmp[count]={a:r,b:[locRelationshipNS+locRelationshipName],c:thenick,e:t};
						tmp[r]=tmp[count];
						count++;
					} else {
						tmp[r].b.push([locRelationshipNS+locRelationshipName]);
					}
				}
			}
			for (var i=0;i<tmp.length;i++) {
				var ti=tmp[i];
				dirList[i]={name:ti.a,link:startURL+ti.a+endURL,type:ti.b,nick:ti.c,img:ti.d,blubType:ti.e};
			}
			if (doc.getElementsByTagNameNS) {
				dirs=doc.getElementsByTagNameNS(foafNS,"mbox");
			} else {
				dirs=doc.getElementsByTagName("foaf:mbox");
			}
			blub.mboxes=[];
			for (var i=0;i<dirs.length;i++) {
				d=dirs.item(i);
				if (d.getAttributeNS) {
					var mbox=d.getAttributeNS(rdfNS, "resource").replace('mailto:','');
				} else {
					mbox=d.getAttribute("rdf:resource").replace('mailto:','');
				}
				blubhash[mbox]=blub;
				blub.mboxes[blub.mboxes.length]=mbox;
			}
			if (doc.getElementsByTagNameNS) {
				dirs=doc.getElementsByTagNameNS(foafNS,"mbox_sha1sum");
			} else {
				dirs=doc.getElementsByTagName("foaf:mbox_sha1sum");
			}
			for (var i=0;i<dirs.length;i++) {
				var sha=dirs.item(i).firstChild.data;
				blubhash[sha]=blub;
			}			
			addDirs(blub.id,dirList);
			if (doc.getElementsByTagNameNS) {
				blub.realName=doc.getElementsByTagNameNS(foafNS,"name").item(0).firstChild.data;
			} else {
				blub.realName=doc.getElementsByTagName("foaf:name").item(0).firstChild.data;
			}
			blub.nick=blub.realName.substr(0,15);
			try {
				if (doc.getElementsByTagNameNS) {
					blub.nick=doc.getElementsByTagNameNS(foafNS,"nick").item(0).firstChild.data.toUpperCase();
				} else {
					blub.nick=doc.getElementsByTagName("foaf:nick").item(0).firstChild.data.toUpperCase();
				}
			} catch (e) {			}
			try {
				if (doc.getElementsByTagNameNS) {
					blub.homepage=doc.getElementsByTagNameNS(foafNS,"homepage").item(0).firstChild.data;
				} else {
					blub.homepage=doc.getElementsByTagName("foaf:homepage").item(0).firstChild.data;
				}
			} catch (e) { }
			try {
				if (doc.getElementsByTagNameNS) {
					rootNodeFS=doc.getElementsByTagNameNS(rdfNS,"RDF").item(0).firstChild;
				} else {
					rootNodeFS=doc.getElementsByTagName("rdf:RDF").item(0).firstChild;
				}
				while (rootNodeFS.nodeType!=1) rootNodeFS=rootNodeFS.nextSibling;
				blub.blubType=rootNodeFS.namespaceURI+rootNodeFS.localName;
			} catch (e) { }
			
			// Do Image stuff
			
			if (doc.getElementsByTagNameNS) {
				var img=doc.getElementsByTagNameNS(foafNS,"depiction");
			} else {
				var img=doc.getElementsByTagName("foaf:depiction");
			}
			if (img.item(0)) {
				var i=img.item(0);
				if (i.getAttributeNS) {
					var imgurl=i.getAttributeNS(rdfNS, "resource");
				} else {
					var imgurl=i.getAttribute("rdf:resource");
				}
				blub.depiction={img:imgurl};
			} else {
				blub.depiction={img:''};
			}	
			selectBlub(id);
		}
	}
	xmlhttp.send(null);
}



function findBlub(name) {
  return (blubhash[name]);
}

function addDirs(id,dirList) { 
  var theBlub=blubs[id];
  var numBlubsToCreate=dirList.length;
  for (var i=0; i <dirList.length; i++) {
    var dir=dirList[i];
    var existing=findBlub(dir.name);
    if (typeof existing=='undefined' || existing == null) {
      newX=theBlub.group.offsetLeft + Math.round(Math.cos(2*Math.PI/numBlubsToCreate*(i%numBlubsToCreate)) * (numBlubsToCreate*BLUB_EXP_DISTANCE+BLUB_EXP_DISTANCE_DEL));
      newY=theBlub.group.offsetTop + 1.2*Math.round(Math.sin(2*Math.PI/numBlubsToCreate*(i%numBlubsToCreate)) * (numBlubsToCreate*BLUB_EXP_DISTANCE+BLUB_EXP_DISTANCE_DEL));
      var blub=new Blub(newX, newY, theBlub.group.offsetLeft, theBlub.group.offsetTop, dir.name, dir.link,dir.nick,dir.blubType);
      theBlub.neighbours.push(blub);
      theBlub.neighbours[blub.id]=theBlub.neighbours[theBlub.neighbours.length-1];
      blub.neighbours.push(theBlub);
      blub.neighbours[theBlub.id]=blub.neighbours[blub.neighbours.length-1];
      addLine(theBlub, blub,dir.type,dir.img,false);
		} else {
      if (existing.deleted != 1) {
				// Add the lines to an existing blub.
				theBlub.neighbours.push(existing);
				theBlub.neighbours[existing.id]=theBlub.neighbours[theBlub.neighbours.length-1];
				existing.neighbours.push(theBlub);
				existing.neighbours[theBlub.id]=existing.neighbours[existing.neighbours.length-1];
				addLine(theBlub, existing,dir.type,dir.img,true);
      } else {
				
				// This is where you would bring a deleted blub back to life,
				// then add the existing lines etc.
   
      }
    }
  }  
  theBlub.expanded=1;
}

function addLine(from, to,type,img,existing) {
	if (document.body.addBehavior) {
		var shp=document.createElement('v:line');
		shp.style.position="absolute";
		shp.style.height="5000px";
		shp.style.width="5000px";
		shp.strokecolor="#ff0000";
		shp.opacity=0.5;
		shp.strokeweight="2px";
		shp.from=pos(from);
		shp.to=pos(to);
		document.body.appendChild(shp);
		from.outlines.push(shp);
		to.inlines.push(shp);
		from.outNeighbours.push(to);
	}
	if (window.SVGElement) {
		var shp=document.createElementNS(svgNS,'line');
		shp.setAttributeNS(null,"stroke","#ff0000");
		shp.setAttributeNS(null,"stroke-width","2px");
		shp.setAttributeNS(null,'x1',svgposX(from)+"px");
		shp.setAttributeNS(null,'y1',svgposY(from)+"px");
		shp.setAttributeNS(null,'x2',svgposX(to)+"px");
		shp.setAttributeNS(null,'y2',svgposY(to)+"px");
		gsvgEl.appendChild(shp);
		from.outlines.push(shp);
		to.inlines.push(shp);
		from.outNeighbours.push(to);

	}
}
 function pos(grp) {
	 var gg=grp.group;
	 return (gg.offsetLeft+Math.floor(gg.offsetWidth/2)-12)+","+(gg.offsetTop+Math.floor(gg.offsetHeight/2)-12);
 }

 function svgposX(grp) {
	 var gg=grp.group;
	 return (gg.offsetLeft+Math.floor(gg.offsetWidth/2)-12);
 }

 function svgposY(grp) {
	 var gg=grp.group;
	 return (gg.offsetTop+Math.floor(gg.offsetHeight/2)-12);
 }

function getDragParent(el) {
	var oldEl=el;
	while (el) {
		el=el.parentNode;
		if (el.className=="blub" || el.nodeName.toUpperCase()=='BODY') {
			return el;
		}
		oldEl=el;
	}
}

var offsetX,offsetY,draggingThing;
function startDrag(e) {
	draggingThing=getDragParent(e.srcElement || e.target); 
	offsetX=e.clientX-draggingThing.offsetLeft;
	offsetY=e.clientY-draggingThing.offsetTop;
	draggingThing=blubs[draggingThing.id];
	draggingThing.group.onmousemove=moveDrag;
	draggingThing.group.onmouseup=endDrag;
	document.onselectionchange=clearSel;
	document.body.onmousemove=moveDrag;
	document.body.onmouseup=endDrag;
	return false;
}
function clearSel() {
	document.selection.clear();
}

function nullFunc(e) {
	return false;
}
function moveDrag(e) {
	e=e || event;
	if (draggingThing) {
		moveBlubTo(draggingThing,e.clientX-offsetX,e.clientY-offsetY);
		return true;
	}
}
function endDrag(e) {
	draggingThing.group.onmousemove=null;
	draggingThing.group.onmouseup=null;
	draggingThing.group.onselectstart=null;
	draggingThing=null;
	document.body.onmousemove=null;
	document.body.onmouseup=null;
	document.onselectstart=null;
}

function start() {
	if (document.createElementNS) {
		gsvgEl=document.createElementNS(svgNS,'svg');
		gsvgEl.setAttributeNS(null,'height',"5000px");
		gsvgEl.setAttributeNS(null,'width',"5000px");
		document.body.appendChild(gsvgEl);
	}
	document.onselectstart=nullFunc;
}

function closeHelp() {
	var help=document.getElementById('help');
	help.style.display="none";
}

