
/* 
* A very cool and handy debugging function 
* FIXME: how about placing this in easydb.js??
*/
function debug (txt) {
    var dbg = document.getElementById('debugger');
    if (!dbg) {
        dbg = document.createElement('div');
        var body = document.getElementsByTagName('BODY')[0];
        body.appendChild(dbg);
        dbg.innerHTML = '<div id="debugger" style="height:100px;border:solid '
                    + '1px #000;overflow:auto;white-space:nowrap;'
                    + 'font-size:11px;font-family:Sans-serif;">'
                    + 'Debugging console [' + navigator.appVersion + ']:<br />'
                    + '</div>';
        dbg = document.getElementById('debugger');
    }
    dbg.innerHTML += ': ' + txt + '<br />';
    dbg.scrollTop += dbg.scrollHeight;
}

function DivDragger_unlock (name) {
    g_divDraggerParents[name].inputIsLocked = false;
}

function DivDragger_move (name) {
    obj = g_divDraggerParents[name];
    var temp = $(obj.parentID).removeChild($(obj.dragChildID));
    if (obj.dragTargetAtBottom) {
        $(obj.parentID).appendChild(temp);
    } else {
        $(obj.parentID).insertBefore(temp,$(obj.dragTargetID));
    }
    obj.dragging = false;
    obj.dragChildID = null;
    obj.dragTargetID = null;
    obj.markDiv      = null;
    obj.dragTargetAtBottom = false;
}

function DivDragger_ajaxResponseFunction (ok) {
    eval(ok.responseText); 
}

function DivDragger_ajaxErrorFunction (nee) {
    g_divDraggerParents[ok.responseText].inputIsLocked = false;
}

function DivDragger_getChildDIVCount (e) {
    var child = e.firstChild;
    var count = 0;

    while (child) {
        if (child.nodeName == 'DIV') {
            count = count + 1;
        }
        child = child.nextSibling;
    }

    return count;
}

function DivDragger_checkForParentDOMObject (current, potentialParent) {
    if (!current.parentNode)
        return false ; 
    if (current.parentNode == potentialParent)
        return true ; 
    return DivDragger_checkForParentDOMObject(current.parentNode, potentialParent);
}

function DivDragger_draggerIsParent (dragger, thisDragger) {
    return DivDragger_checkForParentDOMObject($(thisDragger.getParentID()), $(dragger.getParentID()));
}

g_divDraggerParents = new Object();

DivDraggerParent = Class.create();

DivDraggerParent.prototype = 
{
	initialize : function(parentID, markerClass, draggerClass, order, ajaxURL)
    // Set ajaxURL to null if you dont need an ajax backend ! 
	{
		g_mouseDevice.registerListener(this);
        this.parentID      = parentID;      // ID of parent element. All DIV-childs of this element are dragable. 
        this.dragging      = false;         // Are we currently dragging ?  
        this.floatVisible  = false;         // Is floating DIV already visible ? 
        this.dragChildID   = null;          // ID of the DIV-child that is dragged around.   
        this.dragDivID     = null;          // ID of the floating DIV that is visualizing the drag.   
        this.dragTargetID  = null;          // ID of the DIV-child next to the mouse pointer while draggin(target position). 
        this.markDiv       = null;          // Reference to the marker DIV that is added to the parent element. 
        this.mouseX        = 0;             // Previous mouse position (X). 
        this.mouseY        = 0;             // Previous mouse position (Y). 
        this.markerClass   = markerClass;   // CSS class of the marker DIV. 
        this.draggerClass  = draggerClass;  // CSS class of the dragger DIV. 
        this.order         = order;         // 'horizontal' or 'vertical'. In which way the items are ordered. 
        this.ajaxURL       = ajaxURL;       // URL of ajax backend script. 
        this.dragTargetAtBottom = false;    // Special case : drag target position is at very end of DIV-child sequence. 
        this.inputIsLocked      = false;    // While waiting for an ajax response the input to this element is locked. 
        this.treeChilds = new Array();
        this.treeParent = null;

        $(parentID).setAttribute('DivDragger',parentID);
                
        this.scrollOffsX    = 0;
        this.scrollOffsY    = 0;
        /*this.scrollInterval = 0;
        this.autoScrolling  = 0;*/
        
        g_divDraggerParents[this.parentID] = this;
	},

    getParentID : function () 
    {
        return this.parentID;
    },
	
    onKeyPress : function(e)
	{
        alert('E: ' + e);
    },
    
	onMouseDown : function(e)
	{
        var cancel=false;   // return value
        
        if ( ! this.parentID ) 
            return false;

        divs = $(this.parentID).getElementsByTagName("DIV");
        for (var i = 0; i < divs.length; i++) {
            if (divs[i].getAttribute("DivDragger")) {

                g_divDraggerParents[divs[i].getAttribute("DivDragger")].onMouseDown(e); 
                if (e.divDraggerWasHere)
                    return false;
            }
        
        }

        if (this.inputIsLocked)
            return false;

        var toDelete = $(this.dragDivID);
        if (toDelete) {
            document.getElementsByTagName('BODY')[0].removeChild(toDelete);
        }

        var parentNode = $(this.parentID); // Get reference to parent node. 
        if (!parentNode)
            return false;
        
        childCount = DivDragger_getChildDIVCount(parentNode);

        if (childCount <= 1)
            return false;

        // start scrolling interval
        /*var self = this;
        this.scrollInterval = window.setInterval(function() {
            self.scrollIntervalCallback();
        }, 100);*/

        var child = parentNode.firstChild;

        while (child) {
            if (child.nodeName == 'DIV') {
                // walk up parent chain and calculate scroll offset for the
                // current child div
                this.scrollOffsX = 0;
                this.scrollOffsY = 0;
                var p = child.parentNode;
                while (p != undefined) {
                    if (p.nodeName == 'DIV') {
                        this.scrollOffsX += p.scrollLeft;
                        this.scrollOffsY += p.scrollTop;
                    }
                    p = p.parentNode;
                }
                // check if the current mouse coords are within the element
                if (g_pointWithinElement(g_mouseDevice.getMousePosX() + this.scrollOffsX, 
                    g_mouseDevice.getMousePosY() + this.scrollOffsY, child )) {

                    // if SHIFT is not pressed, exit
                    if (!e.shiftKey) { return false; }

                    this.dragging = true;
                    this.dragChildID = child.id;
                    this.dragDivID = this.parentID + '___dragDiv';
                    
                    var dragDiv = document.createElement("DIV");
                    dragDiv.id = this.dragDivID;

                    // make a complete copy of the child's div here
                    // and then set its contents to child.innerHTML
                    dragDiv.setAttribute('style', child.getAttribute('style'));
                    dragDiv.className = child.className;

                    var inner = child.innerHTML;
                    inner = inner.replace(/<script/g, "<!--");
                    inner = inner.replace(/<\/script>/g, "-->");
                    dragDiv.innerHTML = inner;
                    dragDiv.style.position = 'absolute';
                    dragDiv.style.top = (g_getTop(child)-1)+'px';
                    dragDiv.style.left = (g_getLeft(child)-1)+'px';
                    dragDiv.style.zIndex = 0;
                    //dragDiv.style.visibility = 'hidden' ;
                    dragDiv.style.display = 'none';
                    dragDiv.setAttribute('style', dragDiv.getAttribute('style')
                        + ';-moz-opacity:0.75;opacity:0.75;'
                        + 'filter:alpha(opacity=75)');
                   
                     // some IE6 fixes (setAttribute('style', ...) doesn't work)
                    dragDiv.style.background = child.style.background;
                    dragDiv.style.width = child.style.width;
                    dragDiv.style.height = child.style.height;
                
                    // disable selection (in IE/webkit)
                    dragDiv.onselectstart = function() { return false; };
                    
                    // now add our new dragDiv to the document body
                    document.getElementsByTagName('BODY')[0].appendChild(dragDiv);
                    
                    this.mouseX = g_mouseDevice.getMousePosX();
                    this.mouseY = g_mouseDevice.getMousePosY();

                    e.divDraggerWasHere = true;
                    if (!Prototype.Browser.IE)
                        e.preventDefault();
                    cancel=true;
                    
                    break;
                }
            }
            child = child.nextSibling;
        }
        
        // Usually this must be false. Otherwise the signal is not brought to 
        // the underlying HTML element (i.e. textedit field) . But for Safari we
        // sometimes need to return true because e.preventDefault is not enough 
        // to cancel the event propagation.
        return cancel;  // 
	},
	
	onMouseMove : function(e)
	{
        if (this.inputIsLocked)
            return false;

        if (this.dragging) {
            mX = g_mouseDevice.getMousePosX() - this.scrollOffsX;
            mY = g_mouseDevice.getMousePosY() - this.scrollOffsY;
            
            /*if (!this.autoScrolling) {
                mX -= this.scrollOffsX;
                mY -= this.scrollOffsY;
            }*/
            
            difX = mX - this.mouseX;
            difY = mY - this.mouseY;
            
            var floatDiv = $( this.dragDivID );

            if (!this.floatVisible) {
                if ((abs(difX) < 10) && (abs(difY) < 10))
                    return false;
            }

            if (floatDiv) {
                this.floatVisible = true;
                //floatDiv.style.visibility = 'visible';
                floatDiv.style.display = 'block';
                floatDiv.style.top  = g_getTop ( floatDiv ) + difY + "px";
                floatDiv.style.left = g_getLeft( floatDiv ) + difX + "px";
            }

            this.mouseX = mX;
            this.mouseY = mY;

            var parentNode = $(this.parentID);

            if (!parentNode)
                return false;

            var child = parentNode.firstChild;

            while (child) {
                if (child.nodeName == 'DIV') {

                    if (child.id == 'dragMarkDiv') {
                        child = child.nextSibling;
                        continue;
                    }
                        
                    if(g_pointWithinElement(g_mouseDevice.getMousePosX() + this.scrollOffsX, 
                        g_mouseDevice.getMousePosY() + this.scrollOffsY, child)) {

                        var oldMarkerRemoved  = false;
                        var targetIsLastChild = false;
                        
                        if (this.dragTargetID != child.id) {
                            if (this.markDiv) {
                                parentNode.removeChild(this.markDiv);
                                this.markDiv = null;
                                oldMarkerRemoved = true;
                            }
                        } else {
                            if (child != getLastDIVChild(parentNode)) {
                                // Break the loop. New target is old target. Nothing to be done... 
                                // In case of child == parentNode.lastChild the marker could change position. 
                                break; 
                            } 
                            targetIsLastChild = true;
                        }

                        var oldMarkDiv = this.markDiv; // For special case... 
                        var oldDragTargetAtBottom = this.dragTargetAtBottom; // For special case...

                        this.dragTargetAtBottom = false;

                        if (targetIsLastChild) {
                            if (this.order == 'vertical') {
                                if ((g_mouseDevice.getMousePosY() + this.scrollOffsY > (g_getTop(child) + child.offsetHeight/2))) {
                                    this.dragTargetAtBottom = true;
                                }
                            } else {
                                if ((g_mouseDevice.getMousePosX() + this.scrollOffsX > (g_getLeft(child) + child.offsetWidth/2) ) ) {
                                    this.dragTargetAtBottom = true;
                                }
                            }
                            if (this.dragTargetAtBottom == oldDragTargetAtBottom) {
                                break; // Break the loop, nothing to be done here. 
                            }
                        }

                        if (!oldMarkerRemoved && oldMarkDiv) {
                            parentNode.removeChild(oldMarkDiv);
                        }

                        this.dragTargetID = child.id;
                        
                        this.markDiv = document.createElement("DIV");
                        this.markDiv.id = 'dragMarkDiv';
                        this.markDiv.className = this.markerClass;

                        if (this.dragTargetAtBottom) {
                            parentNode.appendChild(this.markDiv);
                        } else {
                            parentNode.insertBefore(this.markDiv,child);
                        }
                        
                        break;
                    }
                }

                child = child.nextSibling;

            }
            e.divDraggerWasHere = true;
            
        }
		return false; // This must be false. Otherwise the signal is not brought to the underlying HTML element (i.e. textedit field) 
	},
	
	onMouseUp : function(e)
	{

        ajaxParams = null;

        if (this.inputIsLocked)
            return false;

        el = $(this.dragDivID);
        if (el) {
            document.getElementsByTagName('BODY')[0].removeChild(el);
        }
        if (this.dragging) {
        
            // remove scroll interval
            /*if (this.scrollInterval) {
                window.clearInterval(this.scrollInterval);
                this.autoScrolling = false;
            }*/
            
            // re-activate selection
            if (el && Prototype.Browser.IE) {
                el.onselectstart = '';
            }
            
            if (this.dragTargetID) {
                if (this.dragTargetID != this.dragChildID) {

                    this.floatVisible = false;           
                    parentNode = $(this.parentID);

                    if (this.ajaxURL != null) { // Do the ajax request 
                        if (this.dragTargetAtBottom) {
                            ajaxParams = 'ajax_moveMappenDiv=1&draggerObjectName=' + this.parentID + '&moveItem=' + $(this.dragChildID).getAttribute('key_id') + '&afterItem=' + $(this.dragTargetID).getAttribute('key_id');
                        } else {
                            ajaxParams = 'ajax_moveMappenDiv=1&draggerObjectName=' + this.parentID + '&moveItem=' + $(this.dragChildID).getAttribute('key_id') + '&beforeItem=' + $(this.dragTargetID).getAttribute('key_id');
                        }

                        new Ajax.Request(this.ajaxURL, {
                            parameters:ajaxParams, 
                            onSuccess:DivDragger_ajaxResponseFunction,
                            onFailure:DivDragger_ajaxErrorFunction
                          });
                    
                        this.inputIsLocked = true;
                    } else { // Dont do an ajax request but do the job right now 
                        var temp = $(this.parentID).removeChild($(this.dragChildID));
                        if (this.dragTargetAtBottom) {
                            $(this.parentID).appendChild(temp);
                        } else {
                            $(this.parentID).insertBefore(temp,$(this.dragTargetID));
                        }
                    }

                }
            }

            if (this.markDiv) {
              $(this.parentID).removeChild(this.markDiv);
              this.markDiv = null;
            }

            if (ajaxParams == null) { // We're not waiting for ajax response so clean up now 
                this.dragging       = false;
                this.dragChildID    = null;
                this.dragTargetID   = null;
                this.markDiv        = null;
                this.dragTargetAtBottom = false;
            }

            e.divDraggerWasHere = true;
        }
		return false; // This must be false. Otherwise the signal is not brought to the underlying HTML element (i.e. textedit field) 
	}

};

/*DivDraggerParent.prototype.scrollIntervalCallback = function () {
    var scrlr   = $(this.parentID).parentNode;
    var pTop    = g_getTop($(this.parentID));  // top edge of parent div
    var cTop    = g_getTop($(this.dragDivID)); // top edge of dragged child
    var oh      = scrlr.offsetHeight;
    //debug('PARENT: ' + pTop + ', CHILD: ' + cTop);
    if (scrlr.scrollTop > 0 && cTop < 50) {
        debug('Scroll up!');
        scrlr.scrollTop -= 10;
        this.autoScrolling = true;
    } else if (scrlr.scrollHeight <= oh && cTop > oh - 50) {
        debug('Scroll down!');
        scrlr.scrollTop += 10;
        this.autoScrolling = true;
    }
    // and update scroll offset(s)
    this.scrollOffsY = scrlr.scrollTop;
    //this.scrollOffsX = scrlr.scrollLeft;
}*/

