function Spider(aDivId)
{
	var ht;
	var divId = aDivId;
	var firstLoad = true;
	var currentRoot;

	function addEvent(obj, type, fn) {
	    if (obj.addEventListener) obj.addEventListener(type, fn, false);
	    else obj.attachEvent('on' + type, fn);
	};


	function init(){
	    var canvas = new Canvas('mycanvas', {
	        'injectInto': divId,
	        'width': 600,
	        'height': 600
	    });
	    ht = new RGraph(canvas, {
	        Node: {
				height: "50",
				width: "50",
	            color: "#f00",
				type: "none"
	        },

	        Edge: {
	            lineWidth: 2,
	            color: "#CCCCCC"
	        },
			     duration:1000,  
			     fps: 30,
			     levelDistance: 250,

	        onBeforeCompute: function(node){
	        },
	        onCreateLabel: function(domElement, node){
				var objectKey = node.id;
				var cat = objectKey.split("/")[0];
	            domElement.innerHTML = "<img src='" + urldecode(node.data.image) + "' onError='ExploreUtils.glueOnImageError(this, \"" + cat + "\", \"" + objectKey + "\")' /><br/><span>" + maxLength(urldecode(node.name), 20) + "</span>";
	            $(domElement).click(function () {
					if(currentRoot == node.id)
					{
                        ExploreUtils.showPane( node.id, node.data.link ? urldecode(node.data.link) : null, "SPIDER");
                    } else {
						ht.onClick(node.id, { hideLabels: false});
					}
	            }).hover(function() {
					$(this).css({'z-index' : '10'}); /*Add a higher z-index value so this image stays on top*/ 
					$(this).find('img').css({
							marginTop: '-15px', 
							marginLeft: '-3px',
							top: '50%',
							left: '50%',
							width: '50px',
							height: '50px',
							padding: '0px'
						});
					} , function() {
					$(this).css({'z-index' : '0'});
					$(this).find('img').css({
							marginTop: '0',
							marginLeft: '0',
							top: '0',
							left: '0',
							width: '35px',
							height: '35px',
							padding: '0px'
						});
				});
	        },
	        //Change node styles when labels are placed
	        //or moved.
	        onPlaceLabel: function(domElement, node){
	            var style = domElement.style;
	            style.cursor = 'pointer';


	            var left = parseInt(style.left);
	            var w = domElement.offsetWidth;
	            style.left = (left - w / 2) + 'px';

	            var top = parseInt(style.top);
	            var h = domElement.offsetHeight;
	            style.top = (top - h / 2) + 'px';
	        },

	        onAfterCompute: function(){
	           var node = Graph.Util.getClosestNodeToOrigin(ht.graph, "pos");

				if(currentRoot != node.id)
				{
					displayGraph(node.id, true);
				}
	        }
	    });
	}

	function urldecode( str ) {
	    // http://kevin.vanzonneveld.net
	    // +   original by: Philip Peterson
	    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	    // +      input by: AJ
	    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	    // +   improved by: Brett Zamir (http://brett-zamir.me)
	    // +      input by: travc
	    // +      input by: Brett Zamir (http://brett-zamir.me)
	    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	    // +   improved by: Lars Fischer
	    // %          note 1: info on what encoding functions to use from: http://xkr.us/articles/javascript/encode-compare/
	    // *     example 1: urldecode('Kevin+van+Zonneveld%21');
	    // *     returns 1: 'Kevin van Zonneveld!'
	    // *     example 2: urldecode('http%3A%2F%2Fkevin.vanzonneveld.net%2F');
	    // *     returns 2: 'http://kevin.vanzonneveld.net/'
	    // *     example 3: urldecode('http%3A%2F%2Fwww.google.nl%2Fsearch%3Fq%3Dphp.js%26ie%3Dutf-8%26oe%3Dutf-8%26aq%3Dt%26rls%3Dcom.ubuntu%3Aen-US%3Aunofficial%26client%3Dfirefox-a');
	    // *     returns 3: 'http://www.google.nl/search?q=php.js&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:en-US:unofficial&client=firefox-a'

	    var histogram = {}, ret = str.toString(), unicodeStr='', hexEscStr='';

	    var replacer = function(search, replace, str) {
	        var tmp_arr = [];
	        tmp_arr = str.split(search);
	        return tmp_arr.join(replace);
	    };

	    // The histogram is identical to the one in urlencode.
	    histogram["'"]   = '%27';
	    histogram['(']   = '%28';
	    histogram[')']   = '%29';
	    histogram['*']   = '%2A';
	    histogram['~']   = '%7E';
	    histogram['!']   = '%21';
	    histogram['%20'] = '+';
	    histogram['\u00DC'] = '%DC';
	    histogram['\u00FC'] = '%FC';
	    histogram['\u00C4'] = '%D4';
	    histogram['\u00E4'] = '%E4';
	    histogram['\u00D6'] = '%D6';
	    histogram['\u00F6'] = '%F6';
	    histogram['\u00DF'] = '%DF'; 
	    histogram['\u20AC'] = '%80';
	    histogram['\u0081'] = '%81';
	    histogram['\u201A'] = '%82';
	    histogram['\u0192'] = '%83';
	    histogram['\u201E'] = '%84';
	    histogram['\u2026'] = '%85';
	    histogram['\u2020'] = '%86';
	    histogram['\u2021'] = '%87';
	    histogram['\u02C6'] = '%88';
	    histogram['\u2030'] = '%89';
	    histogram['\u0160'] = '%8A';
	    histogram['\u2039'] = '%8B';
	    histogram['\u0152'] = '%8C';
	    histogram['\u008D'] = '%8D';
	    histogram['\u017D'] = '%8E';
	    histogram['\u008F'] = '%8F';
	    histogram['\u0090'] = '%90';
	    histogram['\u2018'] = '%91';
	    histogram['\u2019'] = '%92';
	    histogram['\u201C'] = '%93';
	    histogram['\u201D'] = '%94';
	    histogram['\u2022'] = '%95';
	    histogram['\u2013'] = '%96';
	    histogram['\u2014'] = '%97';
	    histogram['\u02DC'] = '%98';
	    histogram['\u2122'] = '%99';
	    histogram['\u0161'] = '%9A';
	    histogram['\u203A'] = '%9B';
	    histogram['\u0153'] = '%9C';
	    histogram['\u009D'] = '%9D';
	    histogram['\u017E'] = '%9E';
	    histogram['\u0178'] = '%9F';

	    for (unicodeStr in histogram) {
	        hexEscStr = histogram[unicodeStr]; // Switch order when decoding
	        ret = replacer(hexEscStr, unicodeStr, ret); // Custom replace. No regexing
	    }

	    // End with decodeURIComponent, which most resembles PHP's encoding functions
	    ret = decodeURIComponent(ret);

	    return ret;
	}

	function maxLength( str, len ) {
	    return ( str.length > len ) ? str.substring( 0, len ) + "..." : str;
	};
	
	function displayGraph(objectKey, morph, cb)
	{
			$.ajax({
                type: "GET",
                url: "../api/graphjson.php?objectId=" + objectKey,
                dataType: "json",
                success: function(json) {
					if(morph)
					{
						var node = Graph.Util.getNode(ht.graph, currentRoot);
						var newNode = new Object();
						newNode.id = node.id;
						newNode.title = node.title;
						newNode.data = node.data;
						newNode.children = new Array();
						json.children.push(newNode);
						ht.op.morph(json, {  
						  type: 'fade:con',  
						  duration: 1500,
						  hideLabels: false
						});
						currentRoot = objectKey;
					} else {		
						ht.loadJSON(json);
				    	ht.fx.clearLabels();  
						ht.refresh();
						currentRoot = objectKey;
					}
					if(cb && cb.call)
						cb.call(null, this);
				}
			});
	}
	
	this.displayGraph = displayGraph;
	
	init();
}



