var dragFillerBorderWidth = 2;

var draggableNodes;
var intersectedIndex;

var dragNode;
var dragFiller;
var savedNodePosition;
var oldMousePosition;

var requester;
var savedDataArray;

function getNextSibling(node)
{
	node = node.nextSibling;
	while (node && node.nodeType == 3) //Node.TEXT_NODE - not supported in IE
	{
		node = node.nextSibling;
	}
	
	return node;
}

function getPreviousSibling(node)
{
	node = node.previousSibling;
	while (node && node.nodeType == 3) //Node.TEXT_NODE - not supported in IE
	{
		node = node.previousSibling;
	}
	
	return node;
}

function getFirstChild(node)
{	
	var i = 0;
	nodes = node.childNodes;
	while (i < nodes.length && nodes[i].nodeType == 3) //Node.TEXT_NODE - not supported in IE
	{
		i++;
	}

	var child;
	if (i < nodes.length)
	{
		child = nodes[i];
	}
	
	return child;
}

function getMousePosition(event)
{
	var position = new Array();
	
	if (window.event)
	{
		position["x"] = window.event.clientX + document.documentElement.scrollLeft;
		position["y"] = window.event.clientY + document.documentElement.scrollTop;
	}
	else
	{
		position["x"] = event.pageX;
		position["y"] = event.pageY;
	}
	
	return position;
}

function getNodePosition(node)
{
	//Get current left/top positions
	var left = 0;
	var top = 0;
	while (node)
	{
		left += node.offsetLeft;
		top += node.offsetTop;
		node = node.offsetParent;			
	}
	
	var position = new Array();
	position["left"] = left;
	position["top"] = top;
	
	return position;
}

function setNodePosition(node, left, top)
{
	var position = new Array();
	position["left"] = left;
	position["top"] = top;
	
	node.position = position;
	
	//Set the height
	node.style.left = left + "px";
	node.style.top = top + "px";	
}

function resetDragNodeSize(node)
{
	node.style.width = "";
	node.style.height = "";
}

function setDragNodeSize(node)
{
	node.style.width = node.offsetWidth + "px";
	
	var height = Math.max(node.offsetHeight, getFirstChild(node).offsetHeight);
	node.style.height = height + "px";

	updateDraggablePositions();
}

function setOpacity(node, amount)
{
	if (document.all)
	{
		node.style.filter = "alpha(opacity=" + (amount * 100) + ")";
	}
	else
	{
		node.style.opacity = amount;
	}
}

function intersectDraggableNodes(x, y)
{
	var intersected = false;
	var i = 0;
	while (i < draggableNodes.length && !intersected)
	{
		if (draggableNodes[i] != dragNode)
		{
			var left = draggableNodes[i].position["left"];
			var top = draggableNodes[i].position["top"];
			var right = left + draggableNodes[i].offsetWidth;
			var bottom = top + draggableNodes[i].offsetHeight;
			
			intersected = (y > top && y < bottom && x > left && x < right);
		}
		
		i++;
	}
	
	if (intersected)
	{
		return (i - 1);
	}
	else
	{
		return -1;
	}
}

function updateDraggablePositions()
{	
	//Update positions of all draggableNodes
	for (var i = 0; i < draggableNodes.length; i++)
	{		
		var nodePosition = getNodePosition(draggableNodes[i]);
		setNodePosition(draggableNodes[i], nodePosition["left"], nodePosition["top"]);
	}
}

function loadDrag()
{
	draggableNodes = new Array();
	intersectedIndex = -1;
	
	document.onmousedown = null;

	//Load all draggable div tags from the content div
	var contentNode = document.getElementById("content");
	if (contentNode)
	{
		var divNodes = contentNode.getElementsByTagName("div");
		
		var j = 0;
		for (var i = 0; i < divNodes.length; i++)
		{
			if (divNodes[i].className.indexOf("draggable") != -1)
			{
				draggableNodes[j] = divNodes[i];
				
				//IE didn't like getting the left/top offsets without having this width/height set first
				draggableNodes[j].style.width = draggableNodes[j].offsetWidth + "px";
				draggableNodes[j].style.height = draggableNodes[j].offsetHeight + "px";
				
				var nodePosition = getNodePosition(draggableNodes[j]);
				setNodePosition(draggableNodes[j], nodePosition["left"], nodePosition["top"]);

				j++;
			}
		}
		
		if (j > 0)
		{
			document.onmousedown = startDrag;
		}
	}
}

function startDrag(event)
{
	if (!draggableNodes)
	{
		return;
	}

	if (!event)
		event = window.event;
		
	if (event.srcElement)
		var node = event.srcElement;
	else
		var node = event.target;
		
	//Start at <img> tag and work down to the draggable div tag (img -> span - > div -> div)
	if (node.className == "dragger")
	{			
		dragNode = node.parentNode.parentNode.parentNode;
		
		//Get current mouse position
		oldMousePosition = getMousePosition(event);
		
		//Get position of dragNode so we can later tell if it moved or not
		savedNodePosition = getNodePosition(dragNode);

		//Set the node moveable
		dragNode.style.position = "absolute";
		dragNode.style.cursor = "move";
		
		//Set the node partially transparent
		setOpacity(dragNode, .75);

		//Create a new div tag in place of the current node tag as a filler
		dragFiller = document.createElement("div");
		dragFiller.className = "dragFiller";
		dragFiller.style.width = (dragNode.offsetWidth - (dragFillerBorderWidth * 2))  + "px";
		dragFiller.style.height = (dragNode.offsetHeight - (dragFillerBorderWidth * 2)) + "px";	

		//Insert dragFiller
		dragNode.parentNode.insertBefore(dragFiller, getNextSibling(dragNode));

		//Set the event callbacks for dragging and ending the drag
		document.onmouseup = endDrag;
		document.onmousemove = drag;
		
		return false;
	}
	else
	{
		return true;
	}
}

function endDrag(event)
{
	if (!draggableNodes)
	{
		return;
	}
	
	//dragNode should be moved to dragFiller
	dragFiller.parentNode.insertBefore(dragNode, dragFiller);
	
	//Update dragNode position to match dragFiller
	var nodePosition = getNodePosition(dragFiller);
	setNodePosition(dragNode, nodePosition["left"], nodePosition["top"]);

	//Remove the dragFiller
	dragFiller.parentNode.removeChild(dragFiller);

	//TODO: hackish way to determine the column
	var column = dragNode.parentNode.className.indexOf("columnLeft") != -1 ? 0 : 1;
	dragNode.setAttribute("dragColumn", column);
	
	setOpacity(dragNode, 1);

	dragNode.style.position = "static";
	dragNode.style.cursor = "";
	
	dragNode = null;
	
	intersectedIndex = -1;
	
	document.onmouseup = null;
	document.onmousemove = null;
	
	if (savedNodePosition["left"] != nodePosition["left"] || savedNodePosition["top"] != nodePosition["top"])
	{
		savePosition();
	}
	
	return true;
}

function drag(event)
{	
	if (!draggableNodes)
	{
		return;
	}
	
	if (dragNode && oldMousePosition)
	{
		var mousePosition = getMousePosition(event);

		var left = parseInt(dragNode.style.left) + (mousePosition["x"] - oldMousePosition["x"]);
		var top = parseInt(dragNode.style.top) + (mousePosition["y"] - oldMousePosition["y"]);
		
		setNodePosition(dragNode, left, top);
		
		oldMousePosition = mousePosition;
		
		var newIntersectedIndex = intersectDraggableNodes(mousePosition["x"], mousePosition["y"]);
		//Don't allow elements to continually swap positions if they overlap on moving
		if (intersectedIndex != newIntersectedIndex)
		{
			intersectedIndex = newIntersectedIndex;
			
			if (intersectedIndex != -1)
			{					
				//Don't try to move to a dragBottom node that is in the same column
				if (draggableNodes[intersectedIndex].className.indexOf("dragBottom") == -1 || draggableNodes[intersectedIndex].parentNode.className != dragFiller.parentNode.className)
				{
					if (draggableNodes[intersectedIndex].previousSibling == dragFiller)
					{
						draggableNodes[intersectedIndex].parentNode.insertBefore(dragFiller, getNextSibling(draggableNodes[intersectedIndex]));
					}
					else
					{
						draggableNodes[intersectedIndex].parentNode.insertBefore(dragFiller, draggableNodes[intersectedIndex]);
					}

					//Update positions of all draggableNodes except the dragNode
					for (var i = 0; i < draggableNodes.length; i++)
					{		
						if (draggableNodes[i] != dragNode)
						{
							var nodePosition = getNodePosition(draggableNodes[i]);
							setNodePosition(draggableNodes[i], nodePosition["left"], nodePosition["top"]);
						}
					}

					//Get the new currently intersected node and store it so we don't try to swap immediately
					intersectedIndex = intersectDraggableNodes(mousePosition["x"], mousePosition["y"]);	
				}
			}
		}
		
		return false;
	}
	
	return true;
}

function expandOptions(event)
{
	if (!draggableNodes)
	{
		return;
	}
	
	if (!event)
		event = window.event;
		
	//img tag
	if (event.srcElement)
		var expandNode = event.srcElement;
	else
		var expandNode = event.target;
		
	var rootNode = expandNode.parentNode.parentNode;
	resetDragNodeSize(rootNode);
		
	expandNode.style.display = "none";
	
	var spanNodes = rootNode.getElementsByTagName("span");
	for (var i = 0; i < spanNodes.length; i++)
	{
		if (spanNodes[i].className.indexOf("dragExpandable") != -1)
		{
			spanNodes[i].style.display = "inline";
		}
	}
	
	setDragNodeSize(rootNode);
}

function shrinkOptions(event)
{
	if (!draggableNodes)
	{
		return;
	}
	
	if (!event)
		event = window.event;
		
	//img tag -> span tag
	if (event.srcElement)
		var shrinkNode = event.srcElement.parentNode;
	else
		var shrinkNode = event.target.parentNode;
	
	var rootNode = shrinkNode.parentNode.parentNode;
	resetDragNodeSize(rootNode);
	
	getPreviousSibling(shrinkNode).style.display = "inline";

	var spanNodes = rootNode.getElementsByTagName("span");
	for (var i = 0; i < spanNodes.length; i++)
	{
		if (spanNodes[i].className.indexOf("dragExpandable") != -1)
		{
			spanNodes[i].style.display = "none";
		}
	}
	
	setDragNodeSize(rootNode);
}

function closeDraggable(event)
{
	if (!draggableNodes)
	{
		return;
	}
	
	if (!event)
		event = window.event;
		
	//img tag
	if (event.srcElement)
		var closeNode = event.srcElement;
	else
		var closeNode = event.target;

	//Start at <img> tag and work down to the draggable div tag (img -> span - > div -> div)
	var draggableNode = closeNode.parentNode.parentNode.parentNode;
	draggableNode.parentNode.removeChild(draggableNode);
	
	//Reinitialize everything since an element has been removed
	loadDrag();
	
	savePosition();
}

function minimizeDraggable(event)
{
	if (!draggableNodes)
	{
		return;
	}
	
	if (!event)
		event = window.event;
		
	//img tag
	if (event.srcElement)
		var minNode = event.srcElement;
	else
		var minNode = event.target;
		
	var rootNode = minNode.parentNode.parentNode;		
	rootNode.setAttribute("dragMinimized", 1);	
		
	minNode.style.display = "none";
	getNextSibling(minNode).style.display = "inline";
	
	resetDragNodeSize(rootNode);
	
	var ulNodes = rootNode.getElementsByTagName("ul");
	if (ulNodes.length > 0)
	{
		ulNodes[0].style.display = "none";
	}
		
	setDragNodeSize(rootNode);
	
	savePosition();
}

function maximizeDraggable(event)
{
	if (!draggableNodes)
	{
		return;
	}
	
	if (!event)
		event = window.event;
		
	//img tag
	if (event.srcElement)
		var maxNode = event.srcElement;
	else
		var maxNode = event.target;
		
	var rootNode = maxNode.parentNode.parentNode;	
	rootNode.setAttribute("dragMinimized", 0);	
		
	maxNode.style.display = "none";
	getPreviousSibling(maxNode).style.display = "inline";	
	
	resetDragNodeSize(rootNode);	
	
	var ulNodes = rootNode.getElementsByTagName("ul");
	if (ulNodes.length > 0)
	{
		ulNodes[0].style.display = "block";
	}
	
	setDragNodeSize(rootNode);
	
	savePosition();
}

function saveDraggableLength(event)
{
	if (!draggableNodes)
	{
		return;
	}
	
	if (!event)
		event = window.event;
		
	//img tag
	if (event.srcElement)
		var checkNode = event.srcElement;
	else
		var checkNode = event.target;	
	
	var selectNode = getPreviousSibling(checkNode);
	var rootNode = selectNode.parentNode.parentNode.parentNode;
	
	if (rootNode.getAttribute("dragLength") != selectNode[selectNode.selectedIndex].value)
	{
		rootNode.setAttribute("dragLength", selectNode[selectNode.selectedIndex].value);	
		
		resetDragNodeSize(rootNode);	
		
		var liNodes = rootNode.getElementsByTagName("li");
		for (var i = 0; i < liNodes.length && i < selectNode[selectNode.selectedIndex].value; i++)
		{
			liNodes[i].style.display = "block";
		}	

		for (var i = selectNode[selectNode.selectedIndex].value; i < liNodes.length; i++)
		{
			liNodes[i].style.display = "none";
		}	
		
		setDragNodeSize(rootNode);
		
		savePosition();
	}
}

function getDraggableDataArray()
{
	var value = "";

	//Get all nodes again
	var contentNode = document.getElementById("content");
	var divNodes = contentNode.getElementsByTagName("div");

	for (var i = 0; i < divNodes.length; i++)
	{
		if (divNodes[i].className.indexOf("draggable") != -1 && divNodes[i].className.indexOf("dragBottom") == -1)
		{
			var type = divNodes[i].getAttribute("dragType");
			var id = divNodes[i].getAttribute("dragID");			
			var length = divNodes[i].getAttribute("dragLength");
			var column = divNodes[i].getAttribute("dragColumn");
			var minimized = divNodes[i].getAttribute("dragMinimized");
			
			//Appending filler at the end
			value += type + "-" + id + "-" + length + "-" + column + "-" + minimized + "-0-0|";		
		}
	}

	return value;
}

function savePosition()
{
	var dataArray = encodeURI(getDraggableDataArray());

	if (dataArray != savedDataArray)
	{
		if (requester != null && requester.readyState != 0 && requester.readyState != 4)
		{
			requester.onreadystatechange = null;
			requester.abort();
		}
		
		savedDataArray = dataArray;
		
		try
		{
			requester = new XMLHttpRequest();
		}
		catch (error)
		{
			try
			{
				requester = new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch (error)
			{
				try
				{
					requester = new ActiveXObject("Microsoft.XMLHTTP");
				}
				catch (error)
				{
					requester = null;
				}
			}
		}

		if (requester != null)
		{
			requester.open("GET", "/save.php?content=" + dataArray, true);
			requester.onreadystatechange = savePositionDone;
			
			requester.send(null);
		}
	}
}

function savePositionDone()
{
	if (requester == null || requester.readyState != 4)
		return;
		
	if (requester.status == 200 && requester.responseText == "1")
	{
		document.cookie = 'AG_CONTENT=' + savedDataArray + '; expires=Fri, 22 Aug 2025 12:00:00 UTC; path=/; domain=.atomicgamer.com';
	}
}
