/*******************************************************************************

	Drag-and-Drop Library

	Author: Fred Snyder
	Company: Castwide Technologies
	URL: http://castwide.com
	Date Created: May 14, 2007
	Date Modified: Jul 4, 2008

	Required files:
	* prototype.js (http://prototypejs.org)
	* cfx.js (http://castwide.com)

	This library provides three static objects.  DND enables
	drag-and-drop functionality for HTML elements.
	Sortable utilizes the DND object to allow users to
	change the order of items in lists or rows in tables.
	Popup simplifies the creation of HTML-based popup windows.

	11-21-2007	Case-insensitive tagName checking to resolve discrepancies
				between HTML and XHTML
	1-11-2008	Popup class
	1-13-2008	More popup features
	1-16-2008	Popup.connect() and Popup.contain()
	7-4-2008	Replaced getElementsByClassName() with select()
*******************************************************************************/

var DND = new function() {

	var currentDragElement = null;
	var currentX = -1;
	var currentY = -1;

	var startDrag = function(e) {
		if ( (!currentDragElement) && (Event.element(e).draggee) ) {
			currentDragElement = Event.element(e);
		} else {
			var par = Event.element(e).parentNode;
			while (par) {
				if (par.draggee) {
					currentDragElement = par;
					break;
				}
				par = par.parentNode;
			}
		}
		if ( (currentDragElement) && (currentDragElement.draggee) ) {
			oldPosition = currentDragElement.draggee.style.position;
			currentX = Event.pointerX(e);
			currentY = Event.pointerY(e);
			Event.stop(e);
		}
	}

	var updateDrag = function(e) {
		if (currentDragElement) {
			var d = currentDragElement.draggee;
			if (d) {
				d.position.set(d.position.getX() + (Event.pointerX(e) - currentX), d.position.getY() + (Event.pointerY(e) - currentY));
				currentX = Event.pointerX(e);
				currentY = Event.pointerY(e);
				Event.stop(e);
			}
		}
	}

	var stopDrag = function(e) {
		if (currentDragElement) {
			currentX = -1;
			currentY = -1;
			var thisDragElement = currentDragElement;
			currentDragElement = null;
			if (thisDragElement.onDrop) {
				thisDragElement.onDrop(e);
			}
			Event.stop(e);
		}
	}

	Event.observe(document, 'mousemove', updateDrag.bindAsEventListener(DND));
	Event.observe(document, 'mouseup', stopDrag.bindAsEventListener(DND));

	return {
		enable: function(button, element, params) {
			button = $CFX(button);
			element = $CFX(element);
			button.draggee = element;
			Event.observe(button, 'mousedown', startDrag);
			if (params) {
				if (params.onDrop) {
					button.onDrop = params.onDrop.bind(button);
				}
			}
		},
		disable: function(button) {
			button.draggee = null;
			Event.stopObserving(button, 'mousedown', startDrag);
		}
	};

}

var Sortable = new function() {
	var onDropListItem = function(e) {
		var moved = this.draggee;
		var list = null;
		switch (moved.tagName.toLowerCase()) {
			case 'tr':
				list = moved.parentNode;
				while (list) {
					if (list.tagName.toLowerCase() == 'table') {
						break;
					}
					list = list.parentNode;
				}
				break;
			case 'li':
				list = moved.parentNode;
				while (list) {
					if ( (list.tagName.toLowerCase() == 'ul') || (list.tagName.toLowerCase() == 'ol') ) {
						break;
					}
					list = list.parentNode;
				}
				break;
			default:
				alert('Unsortable item');
		}
		if (!list) {
			alert('Could not find item\'s parent element');
			return;
		}
		var items = list.getElementsByTagName(moved.tagName);
		var before = null;
		for (var i = items.length - 1; i >= 0; i--) {
			if (items[i] != moved) {
				var ie = $CFX(items[i]);
				if (moved.position.getY() <= ie.position.getY()) {
					before = ie;
				}
			}
		}
		var parentNode = moved.parentNode;
		parentNode.removeChild(moved);
		if (before) {
			parentNode.insertBefore(moved, before);
		} else {
			parentNode.appendChild(moved);
		}
		moved.style.position = 'static';
		if (list.submitForm) {
			list.submitForm.submit();
		}
	}
	return {
		enable: function(list, moverClass, submitForm) {
			/*
			Arguments:
				list - The UL, LI, or TABLE element to be made sortable.
				moverClass - The class name of the element that users push to
					move the item.  If moverClass is omitted, users can move
					the item by clicking anywhere inside it.
				submitForm - An optional form to be submitted after an item
					is moved.
			*/
			list = $(list);
			if (submitForm) {
				list.submitForm = $(submitForm);
			}
			var tagName = '';
			switch (list.tagName.toLowerCase()) {
				case 'table':
					tagName = 'tr';
					break;
				case 'ul':
				case 'ol':
					tagName = 'li';
					break;
				default:
					alert('Unsortable element');
			}
			var items = list.getElementsByTagName(tagName);
			for (var i = 0; i < items.length; i++) {
				var mover = items[i];
				if ( (moverClass != null) && (moverClass != '') ) {
					var movers = $(items[i]).select('.' + moverClass);
					if (movers[0]) {
						mover = movers[0];
						if (mover.tagName.toLowerCase() == 'a') {
							mover.onclick = function() {
								return false;
							}
						}
					}
				}
				DND.enable(mover, items[i], {onDrop: onDropListItem});
				Event.observe(mover, 'mousedown', function(e) {
					// If we're dragging a table row, explicitly declare each
					// column's width so it doesn't change size after being
					// absolutely positioned
					if (Event.element(e).draggee.tagName.toLowerCase() == 'tr') {
						var cols = Event.element(e).draggee.getElementsByTagName('td');
						for (var i = 0; i < cols.length; i++) {
							cols[i].style.width = cols[i].clientWidth + 'px';
						}
					}
				});
			}
		}
	};
}

var Popup = new function() {
	var _nextId = 0;
	var _idTemplate = "popup-";
	var _popupClass = "popup";
	var _menubarClass = "popup-menubar";
	var _titleClass = "popup-title";
	var _contentClass = "popup-content";
	var _staticPopups = new Object();
	var _ajaxPopups = new Object();

	var _initialize = function(showCloser) {
		var popup = document.createElement('div');
		popup.id = _idTemplate + _nextId;
		popup.className = _popupClass;
		var menubar = document.createElement('div');
		menubar.className = _menubarClass;
		var title = document.createElement('div');
		title.className = _titleClass;
		menubar.appendChild(title);
		if (showCloser) {
			var closer = document.createElement('a');
			closer.className = 'popup-close';
			closer.href = '#';
			closer.innerHTML = 'Close';
			Event.observe(closer, 'click', function(e) {
				var par = Event.element(e).up('.' + _popupClass);
				if (par) {
					if (par.onClose) {
						par.onClose();
					}
					Popup.close(par);
					Event.stop(e);
				}
			});
			menubar.appendChild(closer);			
		}
		popup.appendChild(menubar);
		var content = document.createElement('div');
		content.className = _contentClass;
		popup.appendChild(content);
		DND.enable(menubar, popup);
		_nextId++;
		popup.hide();
		return $(popup);
	}

	this.contain = function(id, titleText, opener, params) {
		var elem = $(id);
		var showCloser = true;
		if ( (params) && (params.closer) ) {
			showCloser = params.closer;
		}
		var popup = _initialize(showCloser);
		if (titleText) {
			var title = popup.select('.' + _titleClass)[0];
			title.innerHTML = titleText;
		}
		var content = popup.select('.' + _contentClass)[0];
		content.appendChild(elem);
		if (params) {
			if (params.onClose) {
				popup.onClose = params.onClose.bind(popup);
			}
		}
		_staticPopups[id] = popup;
		if (opener) {
			Event.observe(opener, 'click', function(e) {
				Popup.show(id);
				$CFX(popup).position.set(Event.pointerX(e), Event.pointerY(e));
				Event.stop(e);
			});
		}
	}

	this.show = function(id) {
		if (_staticPopups[id]) {
			var popup = _staticPopups[id];
			document.body.appendChild(popup);
			_staticPopups[id].show();
			popup.opacity.fade(0, 100, 200);
			return popup;
		}
	}

	this.open = function(url, titleText, params) {
		for (p in _ajaxPopups) {
			if (_ajaxPopups[p] == url) {
				var popup = $CFX(p);
				//popup.position.set( (document.body.clientWidth / 2) - (popup.clientWidth / 2), document.body.scrollTop + 100 );
				return popup;
			}
		}
		var showCloser = true;
		if (params) {
			if (params.closer != undefined) {
				showCloser = params.closer;
			}
		}
		var popup = _initialize(showCloser);
		if (titleText) {
			var title = popup.select('.' + _titleClass)[0];
			title.innerHTML = titleText;
		}
		var content = popup.select('.' + _contentClass)[0];
		new Ajax.Updater(content, url, {
			evalScripts: true,
			onComplete: function() {
				document.body.appendChild(popup);
				popup.show();
				popup.opacity.fade(0, 100, 200);
				//$CFX(popup).position.set( (document.body.clientWidth / 2) - (popup.clientWidth / 2), document.body.scrollTop + 100 );
			}
		});
		if (params) {
			if (params.onClose) {
				popup.onClose = params.onClose.bind(popup);
			}
		}
		_ajaxPopups[popup.id] = url;
		return popup;
	}

	this.connect = function(url, titleText, opener, params) {
		Event.observe(opener, 'click', function(e) {
			var popup = Popup.open(url, titleText, params);
			$CFX(popup).position.set(Event.pointerX(e), Event.pointerY(e));
			Event.stop(e);
		});
	}

	this.close = function(elem) {
		if (elem.className != _popupClass) {
			elem = elem.up('.' + _popupClass);
		}
		if (elem) {
			elem.opacity.fade(100, 50, 200, {
				onComplete: function() {
					document.body.removeChild(elem);
				}
			});
			if (_ajaxPopups[elem.id]) {
				delete _ajaxPopups[elem.id];
			}
		}
	}

}
