/* 
------------------------------------------
 Flipbox written by CrappoMan
 simonpatterson@dsl.pipex.com
------------------------------------------
*/

//modified by Wooya
function flipBox(who) {
    var tmp;
    if (document.images['b_' + who].src.indexOf('_on') == -1) {
        tmp = document.images['b_' + who].src.replace('_off', '_on');
        document.getElementById('box_' + who).style.display = 'none';
        if (document.getElementById('box_' + who + '_diff')) {
            document.getElementById('box_' + who + '_diff').style.display = 'block';
        }
        document.images['b_' + who].src = tmp;
        disply = 'none';
	     now = new Date();
	     now.setTime(now.getTime()+1000*60*60*24*365);
        expire = (now.toGMTString());
        document.cookie = "fusion_box_"+who+"=" + escape(disply) + "; expires="+expire;
    } else {
        tmp = document.images['b_' + who].src.replace('_on', '_off');
        document.getElementById('box_' + who).style.display = 'block';
        if (document.getElementById('box_' + who + '_diff')) {
            document.getElementById('box_' + who + '_diff').style.display = 'none';
        }
        document.images['b_' + who].src = tmp;
        disply = 'block';
	     now = new Date();
	     now.setTime(now.getTime()+1000*60*60*24*365);
        expire = (now.toGMTString());
        document.cookie = "fusion_box_"+who+"=" + escape(disply) + "; expires="+expire;
    }
}

//FlipBlock written by Wooya
function flipBlock(side) {
    var tmp;
    if (document.images['bl_' + side].src.indexOf('_on') == -1) {
        tmp = document.images['bl_' + side].src.replace('_off', '_on');
        document.getElementById('block_' + side).style.display = 'none';
        document.images['bl_' + side].src = tmp;
        disply = 'none'
	     now = new Date();
	     now.setTime(now.getTime()+1000*60*60*24*365);
        expire = (now.toGMTString());
        document.cookie = "fusion_block_"+side+"=" + escape(disply) + "; expires="+expire;
    } else {
        tmp = document.images['bl_' + side].src.replace('_on', '_off');
        document.getElementById('block_' + side).style.display = 'block';
        document.images['bl_' + side].src = tmp;
        disply = 'block';
	     now = new Date();
	     now.setTime(now.getTime()+1000*60*60*24*365);
        expire = (now.toGMTString());
        document.cookie = "fusion_block_"+side+"=" + escape(disply) + "; expires="+expire;
    }
}

//modified by wooya
function addText(elname, wrap1, wrap2, formname) {
	if (formname == undefined) formname = 'inputform';
   if (document.selection) {
     // for IE 
     var str = document.selection.createRange().text;
     document.forms[formname].elements[elname].focus();
     var sel = document.selection.createRange();
     sel.text = wrap1 + str + wrap2;
     return;
   } else if ((typeof document.forms[formname].elements[elname].selectionStart) != 'undefined') {
     // for Mozilla
     var txtarea = document.forms[formname].elements[elname];
     var selLength = txtarea.textLength;
     var selStart = txtarea.selectionStart;
     var selEnd = txtarea.selectionEnd;
     var oldScrollTop = txtarea.scrollTop;
     //if (selEnd == 1 || selEnd == 2)
     //selEnd = selLength;
     var s1 = (txtarea.value).substring(0,selStart);
     var s2 = (txtarea.value).substring(selStart, selEnd)
     var s3 = (txtarea.value).substring(selEnd, selLength);
     txtarea.value = s1 + wrap1 + s2 + wrap2 + s3;
     txtarea.selectionStart = s1.length;
     txtarea.selectionEnd = s1.length + s2.length + wrap1.length + wrap2.length;
     txtarea.scrollTop = oldScrollTop;
     txtarea.focus();
     return;
   } else {
     insertText(elname, wrap1 + wrap2, formname);
   }
}

//modified by Wooya
function insertText(elname, what, formname) {

   if (formname == undefined) formname == 'inputform';

   if (document.forms[formname].elements[elname].createTextRange) {
      document.forms[formname].elements[elname].focus();
      document.selection.createRange().duplicate().text = what;
   } else if ((typeof document.forms[formname].elements[elname].selectionStart) != 'undefined') {
      // for Mozilla
      var tarea = document.forms[formname].elements[elname];
      var selEnd = tarea.selectionEnd;
      var txtLen = tarea.value.length;
      var txtbefore = tarea.value.substring(0,selEnd);
      var txtafter =  tarea.value.substring(selEnd, txtLen);
      var oldScrollTop = tarea.scrollTop;
      tarea.value = txtbefore + what + txtafter;
      tarea.selectionStart = txtbefore.length + what.length;
      tarea.selectionEnd = txtbefore.length + what.length;
      tarea.scrollTop = oldScrollTop;
      tarea.focus();
   } else {
      document.forms[formname].elements[elname].value += what;
      document.forms[formname].elements[elname].focus();
   }
}

//modified by Wooya to W3C standards
function show_hide(msg_id) {
    document.getElementById(msg_id).style.display = document.getElementById(msg_id).style.display == 'none' ? 'block' : 'none';
}

//modified by Wooya to work properly with Opera
function correctPNG() {
    // correctly handle PNG transparency in Win IE 5.5 or higher.
    if (navigator.appName=="Microsoft Internet Explorer" && navigator.userAgent.indexOf("Opera")==-1) {
        for(var i=0; i<document.images.length; i++) {
            var img = document.images[i]
            var imgName = img.src.toUpperCase()
            if (imgName.substring(imgName.length-3, imgName.length) == "PNG") {
                var imgID = (img.id) ? "id='" + img.id + "' " : ""
                var imgClass = (img.className) ? "class='" + img.className + "' " : ""
                var imgTitle = (img.title) ? "title='" + img.title + "' " : "title='" + img.alt + "' "
                var imgStyle = "display:inline-block;" + img.style.cssText
                if (img.align == "left") imgStyle = "float:left;" + imgStyle
                if (img.align == "right") imgStyle = "float:right;" + imgStyle
                if (img.parentElement.href) imgStyle = "cursor:hand;" + imgStyle
                var strNewHTML = "<span " + imgID + imgClass + imgTitle
                + " style=\"" + "width:" + img.width + "px; height:" + img.height + "px;" + imgStyle + ";"
                + "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
                + "(src=\'" + img.src + "\', sizingMethod='scale');\"></span>"
                img.outerHTML = strNewHTML
                i = i-1
            }
        }
    }
}

//
function WindowResize(pix) {
    var box        = document.getElementById('postcontent');
    var cur_height = parseInt( box.style.height ) ? parseInt( box.style.height ) : 200;
    var new_height = cur_height + pix;
    if ( new_height > 0 ) {
        box.style.height = new_height + "px";
    }
    return false;
}



//written by Wooya
function SetMousePos(divId, ev) {
    var placeX;
    var placeY;
    var parsedWidth = parseInt(document.getElementById(divId).style.width);

    document.onmousemove = mouseMove;

    function mouseMove(ev) {
        var ev = ev || window.event;
    }

    OP=NS=IE=false;

    if (navigator.userAgent.indexOf("Opera")!=-1) {
        OP=true;
    } else if (navigator.appName=="Netscape") {
        NS=true;
    } else if (navigator.appName=="Microsoft Internet Explorer") {
        IE=true;
    }

    if (NS) {
        coordX=ev.pageX;
        coordY=ev.pageY;
        winWidth=window.innerWidth;
        winOffset=window.pageXOffset;
    } else {
        coordX=ev.clientX+document.body.scrollLeft;
        coordY=ev.clientY+document.body.scrollTop;
        winWidth=document.body.clientWidth;
        winOffset=eval(document.body.scrollLeft);
    }

    placeX = coordX-2-parsedWidth;
    if (placeX < winOffset) placeX = winOffset;
    placeY = coordY-2;

    document.getElementById(divId).style.top = placeY + 'px';
    document.getElementById(divId).style.left = placeX + 'px';
    document.getElementById(divId).style.display = 'none';
}

//based on TinyMce color map plugin - modified by wooya
function showMapColor(color, mapId) {
    document.getElementById("selectedMapColor" + mapId).style.backgroundColor = color;
    document.getElementById("selectedMapColorBox" + mapId).value = color;
}

//based on TinyMce color map plugin - modified by wooya
function ColorMap(elname, formname) {
	var html = "";
	var colors = new Array(
	   "#000000","#000033","#000066","#000099","#0000cc","#0000ff","#330000","#330033",
	   "#330066","#330099","#3300cc","#3300ff","#660000","#660033","#660066","#660099",
	   "#6600cc","#6600ff","#990000","#990033","#990066","#990099","#9900cc","#9900ff",
	   "#cc0000","#cc0033","#cc0066","#cc0099","#cc00cc","#cc00ff","#ff0000","#ff0033",
	   "#ff0066","#ff0099","#ff00cc","#ff00ff","#003300","#003333","#003366","#003399",
	   "#0033cc","#0033ff","#333300","#333333","#333366","#333399","#3333cc","#3333ff",
	   "#663300","#663333","#663366","#663399","#6633cc","#6633ff","#993300","#993333",
	   "#993366","#993399","#9933cc","#9933ff","#cc3300","#cc3333","#cc3366","#cc3399",
	   "#cc33cc","#cc33ff","#ff3300","#ff3333","#ff3366","#ff3399","#ff33cc","#ff33ff",
	   "#006600","#006633","#006666","#006699","#0066cc","#0066ff","#336600","#336633",
	   "#336666","#336699","#3366cc","#3366ff","#666600","#666633","#666666","#666699",
	   "#6666cc","#6666ff","#996600","#996633","#996666","#996699","#9966cc","#9966ff",
	   "#cc6600","#cc6633","#cc6666","#cc6699","#cc66cc","#cc66ff","#ff6600","#ff6633",
	   "#ff6666","#ff6699","#ff66cc","#ff66ff","#009900","#009933","#009966","#009999",
	   "#0099cc","#0099ff","#339900","#339933","#339966","#339999","#3399cc","#3399ff",
	   "#669900","#669933","#669966","#669999","#6699cc","#6699ff","#999900","#999933",
	   "#999966","#999999","#9999cc","#9999ff","#cc9900","#cc9933","#cc9966","#cc9999",
	   "#cc99cc","#cc99ff","#ff9900","#ff9933","#ff9966","#ff9999","#ff99cc","#ff99ff",
	   "#00cc00","#00cc33","#00cc66","#00cc99","#00cccc","#00ccff","#33cc00","#33cc33",
	   "#33cc66","#33cc99","#33cccc","#33ccff","#66cc00","#66cc33","#66cc66","#66cc99",
	   "#66cccc","#66ccff","#99cc00","#99cc33","#99cc66","#99cc99","#99cccc","#99ccff",
	   "#cccc00","#cccc33","#cccc66","#cccc99","#cccccc","#ccccff","#ffcc00","#ffcc33",
	   "#ffcc66","#ffcc99","#ffcccc","#ffccff","#00ff00","#00ff33","#00ff66","#00ff99",
	   "#00ffcc","#00ffff","#33ff00","#33ff33","#33ff66","#33ff99","#33ffcc","#33ffff",
	   "#66ff00","#66ff33","#66ff66","#66ff99","#66ffcc","#66ffff","#99ff00","#99ff33",
	   "#99ff66","#99ff99","#99ffcc","#99ffff","#ccff00","#ccff33","#ccff66","#ccff99",
	   "#ccffcc","#ccffff","#ffff00","#ffff33","#ffff66","#ffff99","#ffffcc","#ffffff"
	);
	
	html += '<table border="0" cellspacing="1" cellpadding="0" class="tbl"><tr>';
	for (var i=0; i<colors.length; i++) {
	   if (formname == undefined) {
			html += "<td class='tbl1' style='width:10px;height:10px;cursor:crosshair;background-color:" + colors[i] + "' onClick=\"addText('" + elname + "', '[color=" + colors[i] + "]', '[/color]');\" onFocus=\"showMapColor('" + colors[i] +  "', '" + elname + "');\" onMouseOver=\"showMapColor('" + colors[i] + "', '" + elname + "');\">"
		} else {
			html += "<td class='tbl1' style='width:10px;height:10px;cursor:crosshair;background-color:" + colors[i] + "' onClick=\"addText('" + elname + "', '[color=" + colors[i] + "]', '[/color]', '" + formname + "');\" onFocus=\"showMapColor('" + colors[i] +  "', '" + elname + "');\" onMouseOver=\"showMapColor('" + colors[i] + "', '" + elname + "');\">"
		}
		html += '</td>';
		if ((i+1) % 18 == 0)	html += '</tr><tr>';
	}
	html += '<tr><td colspan="18">'
	+ '<table width="100%" border="0" cellspacing="0" cellpadding="0">'
	+ '<tr><td id="selectedMapColor' + elname + '" width="50%" height="16">'
	+ '</td><td width="50%">'
	+ '<input id="selectedMapColorBox' + elname + '" name="selectedMapColorBox' + elname + '" type="text" size="7" maxlength="7" style="text-align:center;font-weight:bold;width:100%" class="textbox" value="" />'
	+ '</td></tr>'
	+ '</table>'
	+ '</td></tr>'
	+ '</table>';

	document.write(html);
}

//written by Wooya
NewWindowPopUp = null;
function OpenWindow(src, wdth, hght, wcenter) {

	//close previous popup window
	if (NewWindowPopUp != null) {
	   NewWindowPopUp.close();
	   NewWindowPopUp = null;
	}

	//f center parameter given center opoup window 
	if (wcenter == false) { 
		wtop = 0;
		wleft = 0;
	} else {
	   wtop = (screen.availHeight-hght)/2;
	   wleft = (screen.availWidth-wdth)/2;
	}

	NewWindowPopUp = window.open(src, "","toolbar=no,menubar=no,location=no,personalbar=no,scrollbars=yes,status=no,directories=no,resizable=yes,height="+hght+",width="+wdth+",top="+wtop+",left="+wleft+"");

	NewWindowPopUp.focus();
}

/**********************************************************
 Adapted from the sortable lists example by Tim Taylor
 http://tool-man.org/examples/sorting.html
 Modified by Tom Westcott : http://www.cyberdummy.co.uk 
 **********************************************************/

var DragDrop = {
	firstContainer : null,
	lastContainer : null,
        parent_id : null,
        parent_group : null,
	makeListContainer : function(list, group) {
		// each container becomes a linked list node
		if (this.firstContainer == null) {
			this.firstContainer = this.lastContainer = list;
			list.previousContainer = null;
			list.nextContainer = null;
		} else {
			list.previousContainer = this.lastContainer;
			list.nextContainer = null;
			this.lastContainer.nextContainer = list;
			this.lastContainer = list;
		}
		
		// these functions are called when an item is draged over
		// a container or out of a container bounds.  onDragOut
		// is also called when the drag ends with an item having
		// been added to the container
		list.onDragOver = new Function();
		list.onDragOut = new Function();
                list.onDragDrop = new Function();
                list.group = group;
		
    	//var items = list.getElementsByTagName( "li" );
    	var items = list.getElementsByTagName( "div" );
    	
		for (var i = 0; i < items.length; i++) {
			DragDrop.makeItemDragable(items[i]);
		}
	},
        
        serData : function ( group, theid ) {
                var container = DragDrop.firstContainer;
		var j = 0;
                var string = "";
                
                while (container != null) {
                
                        if(theid != null && container.id != theid)
                        {
                          container = container.nextContainer;
                          continue;
                        }

                        if(group != null && container.group != group)
                        {
                          container = container.nextContainer;
                          continue;
                        }
                
                        j ++;
                        if(j > 1)
                        {
                          string += ":";
                        }
                        string += container.id;
                        
                        //var items = container.getElementsByTagName( "li" );
                        var items = container.getElementsByTagName( "div" );
    	                string += "(";
		        for (var i = 0; i < items.length; i++) {
                            if(i > 0)
                            {
                              string += ",";
                            }
				  //string += items[i].id;            	
			     string += items[i].innerHTML;	  // original: string += items[i].id; xx test: string += items[i].innerHTML; 
		        }
                        string += ")";
                        
			container = container.nextContainer;
		}
                return string;   
        },

	makeItemDragable : function(item) {
		Drag.makeDraggable(item);
		item.setDragThreshold(5);
		
		// tracks if the item is currently outside all containers
		item.isOutside = false;
		
		item.onDragStart = DragDrop.onDragStart;
		item.onDrag = DragDrop.onDrag;
		item.onDragEnd = DragDrop.onDragEnd;
	},

	onDragStart : function(nwPosition, sePosition, nwOffset, seOffset) {
		// update all container bounds, since they may have changed
		// on a previous drag
		//
		// could be more smart about when to do this
		var container = DragDrop.firstContainer;
		while (container != null) {
			container.northwest = Coordinates.northwestOffset( container, true );
			container.southeast = Coordinates.southeastOffset( container, true );
			container = container.nextContainer;
		}
		
		// item starts out over current parent
		this.parentNode.onDragOver();
                parent_id = this.parentNode.id;
                parent_group = this.parentNode.group;
	},

	onDrag : function(nwPosition, sePosition, nwOffset, seOffset) {
		// check if we were nowhere
		if (this.isOutside) {
			// check each container to see if in its bounds
			var container = DragDrop.firstContainer;
			while (container != null) {

				if ((nwOffset.inside( container.northwest, container.southeast ) ||
					seOffset.inside( container.northwest, container.southeast )) && container.group == parent_group) {
					// we're inside this one
					container.onDragOver();
					this.isOutside = false;
					
					// since isOutside was true, the current parent is a
					// temporary clone of some previous container node and
					// it needs to be removed from the document
					var tempParent = this.parentNode;
					tempParent.removeChild( this );
					container.appendChild( this );
					tempParent.parentNode.removeChild( tempParent );
					break;
				}
				container = container.nextContainer;
			}
			// we're still not inside the bounds of any container
			if (this.isOutside)
				return;
		
		// check if we're outside our parent's bounds
		} else if (!(nwOffset.inside( this.parentNode.northwest, this.parentNode.southeast ) ||
			seOffset.inside( this.parentNode.northwest, this.parentNode.southeast ))) {
			
			this.parentNode.onDragOut();
			this.isOutside = true;
			
			// check if we're inside a new container's bounds
			var container = DragDrop.firstContainer;
			while (container != null) {
				if ((nwOffset.inside( container.northwest, container.southeast ) ||
					seOffset.inside( container.northwest, container.southeast )) && container.group == parent_group) {
					// we're inside this one
					container.onDragOver();
					this.isOutside = false;
					this.parentNode.removeChild( this );
					container.appendChild( this );
					break;
				}
				container = container.nextContainer;
			}
			// if we're not in any container now, make a temporary clone of
			// the previous container node and add it to the document
			if (this.isOutside) {
				var tempParent = this.parentNode.cloneNode( false );
				this.parentNode.removeChild( this );
				tempParent.appendChild( this );
				// body puts a border or item at bottom of page if do not have this
                                tempParent.style.border = 0;
				document.getElementsByTagName( "body" ).item(0).appendChild( tempParent );
				return;
			}
		}
		
		// if we get here, we're inside some container bounds, so we do
		// everything the original dragsort script did to swap us into the
		// correct position
		
		var parent = this.parentNode;
				
		var item = this;
		var next = DragUtils.nextItem(item);
		while (next != null && this.offsetTop >= next.offsetTop - 2) {
			var item = next;
			var next = DragUtils.nextItem(item);
		}
		if (this != item) {
			DragUtils.swap(this, next);
			return;
		}

		var item = this;
		var previous = DragUtils.previousItem(item);
		while (previous != null && this.offsetTop <= previous.offsetTop + 2) {
			var item = previous;
			var previous = DragUtils.previousItem(item);
		}
		if (this != item) {
			DragUtils.swap(this, item);
			return;
		}
	},

	onDragEnd : function(nwPosition, sePosition, nwOffset, seOffset) {
		// if the drag ends and we're still outside all containers
		// it's time to remove ourselves from the document or add 
                // to the trash bin
		if (this.isOutside) {
                        var container = DragDrop.firstContainer;
                        while (container != null) {
                           if(container.id == parent_id)
                           {
                             break;
                           }
                           container = container.nextContainer;
                        }
			this.isOutside = false;
			this.parentNode.removeChild( this );
			container.appendChild( this );
                        this.style["top"] = "0px";
		        this.style["left"] = "0px";
                        //var container = DragDrop.firstContainer;
                        //container.appendChild( this );
			return;
		}
		this.parentNode.onDragOut();
                this.parentNode.onDragDrop();
      		this.style["top"] = "0px";
		this.style["left"] = "0px";
	}
};

var DragUtils = {
	swap : function(item1, item2) {
		var parent = item1.parentNode;
		parent.removeChild(item1);
		parent.insertBefore(item1, item2);

		item1.style["top"] = "0px";
		item1.style["left"] = "0px";
	},

	nextItem : function(item) {
		var sibling = item.nextSibling;
		while (sibling != null) {
			if (sibling.nodeName == item.nodeName) return sibling;
			sibling = sibling.nextSibling;
		}
		return null;
	},

	previousItem : function(item) {
		var sibling = item.previousSibling;
		while (sibling != null) {
			if (sibling.nodeName == item.nodeName) return sibling;
			sibling = sibling.previousSibling;
		}
		return null;
	}		
};

/*
 * drag.js - click & drag DOM elements
 *
 * originally based on Youngpup's dom-drag.js, www.youngpup.net
 */

/**********************************************************
 Further modified from the example by Tim Taylor
 http://tool-man.org/examples/sorting.html
 
 Changed onMouseMove where it calls group.onDrag and then
 adjusts the offset for changes to the DOM.  If the item
 being moved changed parents it would be off so changed to
 get the absolute offset (recursive northwestOffset).
 
 **********************************************************/

var Drag = {
	BIG_Z_INDEX : 10000,
	group : null,
	isDragging : false,

	makeDraggable : function(group) {
		group.handle = group;
		group.handle.group = group;

		group.minX = null;
		group.minY = null;
		group.maxX = null;
		group.maxY = null;
		group.threshold = 0;
		group.thresholdY = 0;
		group.thresholdX = 0;

		group.onDragStart = new Function();
		group.onDragEnd = new Function();
		group.onDrag = new Function();
		
		// TODO: use element.prototype.myFunc
		group.setDragHandle = Drag.setDragHandle;
		group.setDragThreshold = Drag.setDragThreshold;
		group.setDragThresholdX = Drag.setDragThresholdX;
		group.setDragThresholdY = Drag.setDragThresholdY;
		group.constrain = Drag.constrain;
		group.constrainVertical = Drag.constrainVertical;
		group.constrainHorizontal = Drag.constrainHorizontal;

		group.onmousedown = Drag.onMouseDown;
	},

	constrainVertical : function() {
		var nwOffset = Coordinates.northwestOffset(this, true);
		this.minX = nwOffset.x;
		this.maxX = nwOffset.x;
	},

	constrainHorizontal : function() {
		var nwOffset = Coordinates.northwestOffset(this, true);
		this.minY = nwOffset.y;
		this.maxY = nwOffset.y;
	},

	constrain : function(nwPosition, sePosition) {
		this.minX = nwPosition.x;
		this.minY = nwPosition.y;
		this.maxX = sePosition.x;
		this.maxY = sePosition.y;
	},

	setDragHandle : function(handle) {
		if (handle && handle != null) 
			this.handle = handle;
		else
			this.handle = this;

		this.handle.group = this;
		this.onmousedown = null;
		this.handle.onmousedown = Drag.onMouseDown;
	},

	setDragThreshold : function(threshold) {
		if (isNaN(parseInt(threshold))) return;

		this.threshold = threshold;
	},

	setDragThresholdX : function(threshold) {
		if (isNaN(parseInt(threshold))) return;

		this.thresholdX = threshold;
	},

	setDragThresholdY : function(threshold) {
		if (isNaN(parseInt(threshold))) return;

		this.thresholdY = threshold;
	},

	onMouseDown : function(event) {
		event = Drag.fixEvent(event);
		Drag.group = this.group;

		var group = this.group;
		var mouse = event.windowCoordinate;
		var nwOffset = Coordinates.northwestOffset(group, true);
		var nwPosition = Coordinates.northwestPosition(group);
		var sePosition = Coordinates.southeastPosition(group);
		var seOffset = Coordinates.southeastOffset(group, true);

		group.originalOpacity = group.style.opacity;
		group.originalZIndex = group.style.zIndex;
		group.initialWindowCoordinate = mouse;
		// TODO: need a better name, but don't yet understand how it
		// participates in the magic while dragging 
		group.dragCoordinate = mouse;

		Drag.showStatus(mouse, nwPosition, sePosition, nwOffset, seOffset);

		group.onDragStart(nwPosition, sePosition, nwOffset, seOffset);

		// TODO: need better constraint API
		if (group.minX != null)
			group.minMouseX = mouse.x - nwPosition.x + 
					group.minX - nwOffset.x;
		if (group.maxX != null) 
			group.maxMouseX = group.minMouseX + group.maxX - group.minX;

		if (group.minY != null)
			group.minMouseY = mouse.y - nwPosition.y + 
					group.minY - nwOffset.y;
		if (group.maxY != null) 
			group.maxMouseY = group.minMouseY + group.maxY - group.minY;

		group.mouseMin = new Coordinate(group.minMouseX, group.minMouseY);
		group.mouseMax = new Coordinate(group.maxMouseX, group.maxMouseY);

		document.onmousemove = Drag.onMouseMove;
		document.onmouseup = Drag.onMouseUp;

		return false;
	},

	showStatus : function(mouse, nwPosition, sePosition, nwOffset, seOffset) {
		window.status = 
				"mouse: " + mouse.toString() + "    " + 
				"NW pos: " + nwPosition.toString() + "    " + 
				"SE pos: " + sePosition.toString() + "    " + 
				"NW offset: " + nwOffset.toString() + "    " +
				"SE offset: " + seOffset.toString();
	},

	onMouseMove : function(event) {
		event = Drag.fixEvent(event);
		var group = Drag.group;
		var mouse = event.windowCoordinate;
		var nwOffset = Coordinates.northwestOffset(group, true);
		var nwPosition = Coordinates.northwestPosition(group);
		var sePosition = Coordinates.southeastPosition(group);
		var seOffset = Coordinates.southeastOffset(group, true);

		Drag.showStatus(mouse, nwPosition, sePosition, nwOffset, seOffset);

		if (!Drag.isDragging) {
			if (group.threshold > 0) {
				var distance = group.initialWindowCoordinate.distance(
						mouse);
				if (distance < group.threshold) return true;
			} else if (group.thresholdY > 0) {
				var deltaY = Math.abs(group.initialWindowCoordinate.y - mouse.y);
				if (deltaY < group.thresholdY) return true;
			} else if (group.thresholdX > 0) {
				var deltaX = Math.abs(group.initialWindowCoordinate.x - mouse.x);
				if (deltaX < group.thresholdX) return true;
			}

			Drag.isDragging = true;
			group.style["zIndex"] = Drag.BIG_Z_INDEX;
			group.style["opacity"] = 0.75;
		}

		// TODO: need better constraint API
		var adjusted = mouse.constrain(group.mouseMin, group.mouseMax);
		nwPosition = nwPosition.plus(adjusted.minus(group.dragCoordinate));
		nwPosition.reposition(group);
		group.dragCoordinate = adjusted;

		// once dragging has started, the position of the group
		// relative to the mouse should stay fixed.  They can get out
		// of sync if the DOM is manipulated while dragging, so we
		// correct the error here
		//
		// TODO: what we really want to do is find the offset from
		// our corner to the mouse coordinate and adjust to keep it
		// the same
		
		// changed to be recursive/use absolute offset for corrections
		var offsetBefore = Coordinates.northwestOffset(group, true);
		group.onDrag(nwPosition, sePosition, nwOffset, seOffset);
		var offsetAfter = Coordinates.northwestOffset(group, true);

		if (!offsetBefore.equals(offsetAfter)) {
			var errorDelta = offsetBefore.minus(offsetAfter);
			nwPosition = Coordinates.northwestPosition(group).plus(errorDelta);
			nwPosition.reposition(group);
		}

		return false;
	},

	onMouseUp : function(event) {
		event = Drag.fixEvent(event);
		var group = Drag.group;

		var mouse = event.windowCoordinate;
		var nwOffset = Coordinates.northwestOffset(group, true);
		var nwPosition = Coordinates.northwestPosition(group);
		var sePosition = Coordinates.southeastPosition(group);
		var seOffset = Coordinates.southeastOffset(group, true);

		document.onmousemove = null;
		document.onmouseup   = null;
		group.onDragEnd(nwPosition, sePosition, nwOffset, seOffset);

		if (Drag.isDragging) {
			// restoring zIndex before opacity avoids visual flicker in Firefox
			group.style["zIndex"] = group.originalZIndex;
			group.style["opacity"] = group.originalOpacity;
		}

		Drag.group = null;
		Drag.isDragging = false;

		return false;
	},

	fixEvent : function(event) {
		if (typeof event == 'undefined') event = window.event;
		Coordinates.fixEvent(event);

		return event;
	}
};

/**********************************************************
 Very minorly modified from the example by Tim Taylor
 http://tool-man.org/examples/sorting.html
 
 Added Coordinate.prototype.inside( northwest, southeast );
 
 **********************************************************/

var Coordinates = {
	ORIGIN : new Coordinate(0, 0),

	northwestPosition : function(element) {
		var x = parseInt(element.style.left);
		var y = parseInt(element.style.top);

		return new Coordinate(isNaN(x) ? 0 : x, isNaN(y) ? 0 : y);
	},

	southeastPosition : function(element) {
		return Coordinates.northwestPosition(element).plus(
				new Coordinate(element.offsetWidth, element.offsetHeight));
	},

	northwestOffset : function(element, isRecursive) {
		var offset = new Coordinate(element.offsetLeft, element.offsetTop);

		if (!isRecursive) return offset;

		var parent = element.offsetParent;
		while (parent) {
			offset = offset.plus(
					new Coordinate(parent.offsetLeft, parent.offsetTop));
			parent = parent.offsetParent;
		}
		return offset;
	},

	southeastOffset : function(element, isRecursive) {
		return Coordinates.northwestOffset(element, isRecursive).plus(
				new Coordinate(element.offsetWidth, element.offsetHeight));
	},

	fixEvent : function(event) {
		event.windowCoordinate = new Coordinate(event.clientX, event.clientY);
	}
};

function Coordinate(x, y) {
	this.x = x;
	this.y = y;
}

Coordinate.prototype.toString = function() {
	return "(" + this.x + "," + this.y + ")";
}

Coordinate.prototype.plus = function(that) {
	return new Coordinate(this.x + that.x, this.y + that.y);
}

Coordinate.prototype.minus = function(that) {
	return new Coordinate(this.x - that.x, this.y - that.y);
}

Coordinate.prototype.distance = function(that) {
	var deltaX = this.x - that.x;
	var deltaY = this.y - that.y;

	return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
}

Coordinate.prototype.max = function(that) {
	var x = Math.max(this.x, that.x);
	var y = Math.max(this.y, that.y);
	return new Coordinate(x, y);
}

Coordinate.prototype.constrain = function(min, max) {
	if (min.x > max.x || min.y > max.y) return this;

	var x = this.x;
	var y = this.y;

	if (min.x != null) x = Math.max(x, min.x);
	if (max.x != null) x = Math.min(x, max.x);
	if (min.y != null) y = Math.max(y, min.y);
	if (max.y != null) y = Math.min(y, max.y);

	return new Coordinate(x, y);
}

Coordinate.prototype.reposition = function(element) {
	element.style["top"] = this.y + "px";
	element.style["left"] = this.x + "px";
}

Coordinate.prototype.equals = function(that) {
	if (this == that) return true;
	if (!that || that == null) return false;

	return this.x == that.x && this.y == that.y;
}

// returns true of this point is inside specified box
Coordinate.prototype.inside = function(northwest, southeast) {
	if ((this.x >= northwest.x) && (this.x <= southeast.x) &&
		(this.y >= northwest.y) && (this.y <= southeast.y)) {
		
		return true;
	}
	return false;
}