var Graph = {
	Create: function(data, rootId, param, callback) {
		window.GraphElements = new Array( );

		Graph.Iterate(data, rootId, null, {xPos: 400, yPos: 180, root: true}, callback);
		
		for(var n in window.GraphElements) {
			if(window.GraphElements[n].line) {
				Silverlight.AddElement(window.GraphElements[n].rId, window.GraphElements[n].line);
			}
		}

		for(var n in window.GraphElements) {
			Silverlight.AddElement(window.GraphElements[n].rId, window.GraphElements[n].element);
			Silverlight.AddElement(window.GraphElements[n].rId, window.GraphElements[n].text);
		}
		
		window.GraphElements = null;		
	},

	Iterate: function(item, rootId, pParam, param, callback) {
		var xOff = parseInt(param.xPos);
		var yOff = parseInt(param.yPos);
		var xParent = parseInt(param.xPos);
		var yParent = parseInt(param.yPos);
		
		var parentId;
		if(item.name) {
			parentId = Graph.ShowItem(item, rootId, pParam, param, callback);
		}

		if(item.children && item.children.length > 0) {
			var angle = 360 / item.children.length;
			var len = 150;
			var n = 0;
			for(var i in item.children) {
			    // Just some manipulation to make it look more natural
			    // ... otherwise the lines are just at boring symmetrical angles.
				var randAngleFlux = Math.round(Math.random() * 180 / item.children.length);

				n++;
				var netAngle = (angle) * n;
				if(pParam && pParam.pAngle) {
					var lineAlign = (45 + (45 / (pParam.pChildCount-1)));
					var parentAlign = pParam.pAngle - 90;
					netAngle = 45 * n / item.children.length;
					netAngle += lineAlign + parentAlign;
				}

				netAngle += randAngleFlux;
				var nX = xOff + (len * Math.sin(netAngle * Math.PI / 180));
				var nY = yOff + (len * Math.cos(netAngle * Math.PI / 180));
				var param = {xPos: nX, yPos: nY, xPar: xParent, yPar: yParent};

				if(!item.children[i].fontFamily) { item.children[i].fontFamily = item.fontFamily; }
				if(!item.children[i].fontSize) { item.children[i].fontSize = item.fontSize; }
				if(!item.children[i].fontColor) { item.children[i].fontColor = item.fontColor; }
				if(!item.children[i].fillColor) { item.children[i].fillColor = item.fillColor; }
				if(!item.children[i].lineColor) { item.children[i].lineColor = item.lineColor; }

				if(!pParam) {
					pParam = new Object( );
					pParam.pAngle = 0;
				}

				Graph.Iterate(item.children[i], rootId, {pId: parentId, pAngle: netAngle, pChildCount: item.children.length, gAngle: pParam.pAngle}, param, callback);
			}
		}
	},

	ShowItem: function(item, rootId, pParam, param, callback) {
		if(!pParam) { pParam = new Object( ); }

		var randId = Math.round(Math.random() * 10000000);
		
		var fillColor = param.root ? 'Red' : 'Blue';

		var element = {
			'Ellipse': {
				'xmlns': 'http://schemas.microsoft.com/client/2007',
				'xmlns:x': 'http://schemas.microsoft.com/winfx/2006/xaml',
				'x:Name': 'Ellipse' + randId,
				'Canvas.Left': param.xPos,
				'Canvas.Top': param.yPos,
				Height: Configuration.ItemHeight,
				Width: Configuration.ItemWidth,
				Stroke: item.fillColor,
				StrokeThickness: Configuration.StrokeThickness,
				Fill: item.fillColor
			}
		};
		
		var text = {
			'TextBlock': {
				'xmlns': 'http://schemas.microsoft.com/client/2007',
				'xmlns:x': 'http://schemas.microsoft.com/winfx/2006/xaml',
				'x:Name': 'TextBlock' + randId,
				'Canvas.Left': param.xPos + Configuration.ItemWidth,
				'Canvas.Top': param.yPos + Configuration.ItemHeight,
				'Text': item.name,
				'FontFamily': Configuration.FontFamily,
				'FontSize': Configuration.FontSize
			}
		};

		var line = {
			'Line': {
				'xmlns': 'http://schemas.microsoft.com/client/2007',
				'xmlns:x': 'http://schemas.microsoft.com/winfx/2006/xaml',
				'x:Name': 'Line' + randId,
				'X1': param.xPos + (Configuration.ItemWidth / 2),
				'Y1': param.yPos + (Configuration.ItemHeight / 2),
				X2: param.xPar + (Configuration.ItemWidth / 2),
				Y2: param.yPar + (Configuration.ItemHeight / 2),
				'Line.Stroke': {
					LinearGradientBrush : {
						GradientStop__1: {
							Color: Color.Navy,
							Offset: 0
						},
						GradientStop__2: {
							Color: Color.Blue,
							Offset: 0.2
						},
						GradientStop__3: {
							Color: Color.Navy,
							Offset: 1
						}
					}
				},
				StrokeThickness: 1
			}
		};

		if(pParam && pParam.pId) {
			if(!window.ObjectRegistry) { window.ObjectRegistry = new Array( ) ; }
			if(!window.ObjectRegistry[pParam.pId]) { window.ObjectRegistry[pParam.pId] = new Array( ) ; }
			window.ObjectRegistry[pParam.pId].push(parseInt(randId));
		}
			
		var lineObj = null;
		if(!param.root) {
			var lineXaml = Silverlight.CreateXamlFromJSON(line);
			lineObj = Silverlight.CreateElement(lineXaml);
		}

		var textXaml = Silverlight.CreateXamlFromJSON(text);
		var textObj = Silverlight.CreateElement(textXaml);

		var elemXaml = Silverlight.CreateXamlFromJSON(element);
		var elemObj = Silverlight.CreateElement(elemXaml);
		
		// Save all elements for now.  Later we will show them all
		// at once.  This will make absolutely sure that the elements
		// are on top of the lines.
		window.GraphElements[randId] = {rId: rootId, element: elemObj, text: textObj, line: lineObj};
		elemObj.addEventListener('MouseLeftButtonDown', 'OnMouseDown');

		return randId;
	}
};