﻿function DragNDrop(containerId, containerClass, normalClass, dragClass)
{
    var isIE6 = navigator.userAgent.indexOf("MSIE 6.0") >= 0;

    var dragId;
    var container = document.getElementById(containerId);
    var dragContainer = null;
    var dragObject = null;
    
    var dragObjectParent = null;
    var dragObjectSibling = null;
    var dragOffset = null;
    var dragObjectWidth = 0;
    var dragObjectHeight = 0;
    var self = this;

    this.OnDrop = function(id, column, row) { }

    var getMousePos = function(ev)
    {
        //alert(ev.clientY + ":" + document.documentElement.scrollTop + ":" + document.body.clientTop + ":" + ev.pageX + ":" + ev.pageY);
        
        if (ev.pageX || ev.pageY)
        {
            return { x: ev.pageX, y: ev.pageY };
        }
        return {
            x: ev.clientX + document.documentElement.scrollLeft, // - document.body.clientLeft,
            y: ev.clientY + document.documentElement.scrollTop // - document.body.clientTop
        };
    };

    var getMouseOffset = function(target, ev)
    {
        ev = ev || window.event;

        var objectPos = getObjectPos(target);
        var mousePos = getMousePos(ev);
        
        return { x: mousePos.x - objectPos.x, y: mousePos.y - objectPos.y };
    };

    var getObjectPos = function(e)
    {
        var x = 0, y = 0;

        while (e.offsetParent)
        {
            x += e.offsetLeft;
            y += e.offsetTop;
            e = e.offsetParent;
        }

        x += e.offsetLeft;
        y += e.offsetTop;

        return { x: x, y: y };
    };

    this.Drag = function(id, obj, ev)
    {
        if (!dragObject)
        {
            container = document.getElementById(containerId);

            // Make sure this object should be dragged (not a click inside a-tag)
            ev = ev || window.event;
            var o = ev.target || ev.srcElement;

            while (obj != o)
            {
                if (o.tagName == "A" || o.tagName == "INPUT") return true;
                o = o.parentNode;
            }

            // Prepare container
            dragId = id;
            dragObject = obj;

            dragContainer.appendChild(dragObject.cloneNode(true));
            dragContainer.style.display = 'block';

            // Get size and position info for the dragged object
            dragObjectWidth = dragObject.offsetWidth;
            dragObjectHeight = dragObject.offsetHeight;

            dragObjectParent = dragObject.parentNode;
            dragObjectSibling = dragObject.siblingNode;

            var mousePos = getMousePos(ev);
            dragOffset = getMouseOffset(dragObject, ev);

            dragContainer.style.left = (mousePos.x - dragOffset.x) + "px";
            dragContainer.style.top = (mousePos.y - dragOffset.y) + "px";

            // Set the min-height of the containers to the maximum of all of them
            var max = 50;

            for (var i = 0; i < container.childNodes.length; i++)
                if (container.childNodes[i].offsetHeight > max)
                max = container.childNodes[i].clientHeight;

            max -= 15; // A bottom-padding on the containers have to be subtracted

            for (var i = 0; i < container.childNodes.length; i++)
            {
                if (isIE6)
                    container.childNodes[i].style.height = max + "px";
                else
                    container.childNodes[i].style.minHeight = max + "px";
            }

            dragObject.className = normalClass + " " + dragClass;

            // Trick IE to update
            if (dragObject.parentNode != null)
                dragObject.parentNode.insertBefore(dragObject, dragObject);
        }

        return false;
    };

    var mouseMove = function(ev)
    {
        if (dragObject)
        {
            ev = ev || window.event;

            var target = ev.target || ev.srcElement;
            var mousePos = getMousePos(ev);


            dragContainer.style.left = (mousePos.x - dragOffset.x) + "px";
            dragContainer.style.top = (mousePos.y - dragOffset.y) + "px";

            var x = mousePos.x - dragOffset.x + Math.floor(dragObjectWidth / 2);
            var y = mousePos.y - dragOffset.y + Math.floor(dragObjectHeight / 2);

            for (var i = 0; i < container.childNodes.length; i++)
            {
                var column = container.childNodes[i];
                if (column.className != containerClass) continue;

                var pos = getObjectPos(column);

                if (pos.x < x && pos.y < y && x < (pos.x + column.clientWidth) && y < (pos.y + column.clientHeight))
                {
                    for (var j = 0; j < column.childNodes.length; j++)
                    {
                        var box = column.childNodes[j];
                        if (dragObject == box) continue;
                        if (box.className && box.className.indexOf('noDragAbove') >= 0) continue;
                        
                        var pos = getObjectPos(box);

                        if (y <= (pos.y + Math.floor(box.offsetHeight / 2)))
                        {
                            if (j == 0 || column.childNodes[j - 1] != dragObject)
                                column.insertBefore(dragObject, box);

                            break;
                        }
                    }

                    if (j == column.childNodes.length && column.lastChild != dragObject)
                        column.appendChild(dragObject);

                    break;
                }
            }

            if (i == container.childNodes.length)
                dragObject.style.display = "none";
            else
                dragObject.style.display = "";

            return false;
        }
    };

    var mouseUp = function()
    {
        if (dragObject)
        {
            dragContainer.style.display = "none";

            if (dragObject.style.display == "none")
            {
                if (dragObjectSibling)
                    dragObjectParent.insertBefore(dragObject, dragObjectSibling);
                else
                    dragObjectParent.appendChild(dragObject);
            }

            dragObject.style.display = "";
            dragObject.className = normalClass;

            for (var i = 0; i < container.childNodes.length; i++)
            {
                if (isIE6)
                    container.childNodes[i].style.height = "";
                else
                    container.childNodes[i].style.minHeight = "";
            }

            var columnNumber = 1;
            
            for (var i = 0; i < container.childNodes.length; i++)
            {
                var column = container.childNodes[i];
                if (column.className != containerClass) continue;
                
                for (var j = 0; j < column.childNodes.length; j++)
                {
                    if (column.childNodes[j] == dragObject)
                        self.OnDrop(dragId, columnNumber, j+1);
                }
                
                columnNumber++;
            }

            if (dragContainer.firstChild)
                dragContainer.removeChild(dragContainer.firstChild);    
        }

        dragObject = null;
    };
    
    this.Start = function()
    {    
        dragContainer = document.createElement("div");
        dragContainer.style.position = "absolute";
        dragContainer.style.display = "none";

        container.parentNode.parentNode.appendChild(dragContainer);
    
        document.onmouseup = mouseUp;
        document.onmousemove = mouseMove;
    };
}