

var DragAndDrop = {

	Object: null,
	MouseOffset: null,
	Offset: null,
	Order: "",
	Pos: null,
	Skip: false,
	
	Id: null,
	Save: null,
	
	/* Original z-index of item. */
	Origzindex: 0,
	/* Margin between items. */
	MarginHorizontal: 0,
	MarginVertical: 0,
	/* If objects will appear, when draged, outside the dragable item. */
	DragOut: true,
	
	ItemsPerRow: 0,
	ItemHeight: 0,
	ItemWidth: 0,
	MaxX: 0,
	MaxY: 0,

	Drag: function(event)
	{
		var obj = DragAndDrop.Object
		if (!obj) return
		
		event = event || window.event
		obj.style.zIndex = 100
		
		var pos = DragAndDrop.GetMousePosition(event)
		DragAndDrop.DragMove(pos, true)

		return false
	},
	
	DragMove: function(pos, bool)
	{
		var obj = DragAndDrop.Object
		var ret = DragAndDrop.CheckPosition(pos, bool)
		var mouse = DragAndDrop.MouseOffset
		
		if (ret.x) obj.style.left = (pos.x - mouse.x) + "px"
		else obj.style.left = (pos.x - mouse.x - ret.pos.x) + "px"
		
		if (ret.y) obj.style.top = (pos.y - mouse.y) + "px"
		else obj.style.top = (pos.y - mouse.y - ret.pos.y) + "px"
		
		return
	},
	
	CheckPosition: function(mouse, bool)
	{
		var pos = { x: mouse.x, y: mouse.y }
		pos.x -= DragAndDrop.Pos.x
		pos.x -= DragAndDrop.Offset.x
		pos.y -= DragAndDrop.Pos.y
		pos.y -= DragAndDrop.Offset.y
		
		var ret = DragAndDrop.CheckMoveOutside(pos)
		pos.x -= ret.pos.x
		pos.y -= ret.pos.y
		
		if (bool) DragAndDrop.CheckItemPosition(pos, mouse)
		
		return ret;
	},
	
	NewHoverPosition: function(pos)
	{
		var hposition = 1
		var marhor = DragAndDrop.MarginHorizontal
		var marver = DragAndDrop.MarginVertical
		var width_ = DragAndDrop.ItemWidth
		var height = DragAndDrop.ItemHeight
		
		hposition += Math.floor((pos.x / (width_ + marhor)) + ((width_ / 2) / (width_ + marhor)))
		hposition += Math.floor((pos.y / (height + marver)) + ((height / 2) / (height + marver))) * DragAndDrop.ItemsPerRow
		
		return hposition
	},
	
	CheckItemPosition: function(pos, mouse)
	{
		var hposition = DragAndDrop.NewHoverPosition(pos)
		var obj = DragAndDrop.Object
		var name = DragAndDrop.GetName(obj)
		var order = DragAndDrop.Order.split("|")
		var tmp2 = parseInt(DragAndDrop.ArraySearch(name, order, true))
		
		if ((tmp2 + 1) == hposition) return
		if (hposition > order.length) return
		
		obj.style.visibility = 'hidden'
		obj.style.left = 0
		obj.style.top = 0
		
		var list = document.getElementById(DragAndDrop.Id)
		if (hposition == order.length)
		{
			list.insertBefore(list.children[tmp2], list.children[order.length - 1])
			list.insertBefore(list.children[order.length - 1], list.children[order.length - 2])
		}
		else if (hposition > tmp2 && hposition < order.length) list.insertBefore(list.children[tmp2], list.children[hposition])
		else list.insertBefore(list.children[tmp2], list.children[hposition - 1])
		
		var pos = DragAndDrop.GetPosition(obj)
		pos.x += DragAndDrop.Offset.x
		pos.y += DragAndDrop.Offset.y
		DragAndDrop.MouseOffset = pos
		DragAndDrop.DragMove(mouse, false)
		
		obj.style.visibility = 'visible'
		DragAndDrop.FetchOrder()
		
		return
	},
	
	ArraySearch: function(needle, haystack, argStrict)
	{
		/* http://phpjs.org/functions/array_search */
		var strict = !!argStrict
		var key = ""
		
		for (key in haystack)
		{
			if ((strict && haystack[key] === needle) || (!strict && haystack[key] == needle))
			{
				return key
			}
		}
		
		return false
	},

	CheckMoveOutside: function(pos)
	{
		var ret = { x: true, y: true, pos: { x: 0, y: 0 } }
		
		if (pos.x < 0)
		{
			ret.x = false
			ret.pos.x = pos.x
		}
		else if (pos.x > DragAndDrop.MaxX) 
		{
			ret.x = false
			ret.pos.x = pos.x - DragAndDrop.MaxX
		}
		
		if (pos.y < 0)
		{
			ret.y = false
			ret.pos.y = pos.y
		}
		else if (pos.y > DragAndDrop.MaxY)
		{
			ret.y = false
			ret.pos.y = pos.y - DragAndDrop.MaxY
		}
		
		if (DragAndDrop.DragOut)
		{
			ret.x = true
			ret.y = true
		}
		
		return ret
	},

	ReleaseDrag: function(event)
	{
		DragAndDrop.Skip = false
		
		var obj = DragAndDrop.Object
		if (!obj) return
		
		obj.style.zIndex = DragAndDrop.Origzindex
		obj.style.left = 0
		obj.style.top = 0
		DragAndDrop.Object = null
		
		return false
	},

	DragActive: function(event)
	{
		if (DragAndDrop.Skip)
		{
			DragAndDrop.Skip = false
			return true
		}
		
		DragAndDrop.Skip = false
		var event = event || window.event
		var mouse = DragAndDrop.GetMousePosition(event)
		var pos = DragAndDrop.GetPosition(this)
		
		DragAndDrop.Offset = { x: mouse.x - pos.x, y: mouse.y - pos.y }
		DragAndDrop.Object = this
		DragAndDrop.MouseOffset = { x: mouse.x, y: mouse.y }
		
		return false
	},
	
	DragDeactivate: function(event)
	{
		DragAndDrop.Skip = true
		return true
	},

	GetMousePosition: function(event)
	{
		if (event.pageX || event.pageY)
		{
			return { x: event.pageX, y: event.pageY }
		}
		else
		{
			return {
				x: event.clientX + document.body.scrollLeft - document.body.clientLeft,
				y: event.clientY + document.body.scrollTop  - document.body.clientTop
			}
		}
	},
	
	GetName: function(item)
	{
		return item.getAttribute('name')
	},
	
	FetchOrder: function()
	{
		var items = document.getElementById(DragAndDrop.Id).getElementsByTagName("li")
		var order = null
		var tmp
		
		for (i = 0, n = items.length; i < n; i++)
		{
			tmp = DragAndDrop.GetName(items[i])
			
			if (order) order += "|" + tmp
			else order = tmp
		}
		
		DragAndDrop.Order = order
		document.getElementById(DragAndDrop.Save).value = order
		
		return
	},
	
	GetPosition: function(target)
	{
		var left = 0
		var top  = 0

		while (target.offsetParent)
		{
			left += target.offsetLeft
			top  += target.offsetTop
			target = target.offsetParent
		}

		if (target.offsetLeft) left += target.offsetLeft
		if (target.offsetTop)  top  += target.offsetTop

		return { x: left, y: top }
	},

	InsertEvent: function(items)
	{
		var pos = DragAndDrop.GetPosition(items[0])
		var pos2
		var inputs
		var hrefs
		
		for (i = 0, n = items.length; i < n; i++)
		{
			inputs = items[i].getElementsByTagName("input")
			for (j = 0, k = inputs.length; j < k; j++)
			{
				inputs[j].onmousedown = DragAndDrop.DragDeactivate
			}
			
			if (DragAndDrop.ItemsPerRow == 0 && i != 0)
			{
				pos2 = DragAndDrop.GetPosition(items[i])
				
				if (pos.y != pos2.y) DragAndDrop.ItemsPerRow = i
			}
			items[i].onmousedown = DragAndDrop.DragActive
			
			hrefs = items[i].getElementsByTagName("a")
			for (l = 0, m = hrefs.length; l < m; l++)
			{
				if (hrefs[l].name != "")
				{
					hrefs[l].style.display = "none"
				}
			}
		}
		
		if (DragAndDrop.ItemsPerRow == 0) DragAndDrop.ItemsPerRow = items.length
		
		return
	},
	
	MakeDragAble: function(list, save)
	{
		DragAndDrop.Object = null
		DragAndDrop.Id = list
		DragAndDrop.Save = save
		DragAndDrop.FetchOrder()
		
		list = document.getElementById(list)
		DragAndDrop.Pos = DragAndDrop.GetPosition(list)
		var items = list.getElementsByTagName("li")
		
		DragAndDrop.ItemHeight = items[0].offsetHeight
		DragAndDrop.ItemWidth = items[0].offsetWidth
		
		DragAndDrop.InsertEvent(items)
		
		var rows = Math.ceil(items.length / DragAndDrop.ItemsPerRow) - 1
		var columns = DragAndDrop.ItemsPerRow - 1
		
		DragAndDrop.MaxX = (columns * DragAndDrop.ItemWidth) + (columns * DragAndDrop.MarginHorizontal)
		DragAndDrop.MaxY = (rows * DragAndDrop.ItemHeight) + (rows * DragAndDrop.MarginVertical)
		
		return
	}
}


