/**
*
*  Copyright 2005 Sabre Airline Solutions
*
*  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
*  file except in compliance with the License. You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software distributed under the
*  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
*  either express or implied. See the License for the specific language governing permissions
*  and limitations under the License.
**/


//-------------------- rico.js
var Rico = {
	Version: '1.1.2',
	prototypeVersion: parseFloat(Prototype.Version.split(".")[0] + "." + Prototype.Version.split(".")[1])
}

if((typeof Prototype=='undefined') || Rico.prototypeVersion < 1.3)
throw("Rico requires the Prototype JavaScript framework >= 1.3");

Rico.ArrayExtensions = new Array();

if (Object.prototype.extend) {
	Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
}else{
	Object.prototype.extend = function(object) {
		return Object.extend.apply(this, [this, object]);
	}
	Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
}

if (Array.prototype.push) {
	Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.push;
}

if (!Array.prototype.remove) {
	Array.prototype.remove = function(dx) {
		if( isNaN(dx) || dx > this.length )
		return false;
		for( var i=0,n=0; i<this.length; i++ )
		if( i != dx )
		this[n++]=this[i];
		this.length-=1;
	};
	Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.remove;
}

if (!Array.prototype.removeItem) {
	Array.prototype.removeItem = function(item) {
		for ( var i = 0 ; i < this.length ; i++ )
		if ( this[i] == item ) {
			this.remove(i);
			break;
		}
	};
	Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.removeItem;
}

if (!Array.prototype.indices) {
	Array.prototype.indices = function() {
		var indexArray = new Array();
		for ( index in this ) {
			var ignoreThis = false;
			for ( var i = 0 ; i < Rico.ArrayExtensions.length ; i++ ) {
				if ( this[index] == Rico.ArrayExtensions[i] ) {
					ignoreThis = true;
					break;
				}
			}
			if ( !ignoreThis )
			indexArray[ indexArray.length ] = index;
		}
		return indexArray;
	}
	Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.indices;
}

// Create the loadXML method and xml getter for Mozilla
if ( window.DOMParser &&
window.XMLSerializer &&
window.Node && Node.prototype && Node.prototype.__defineGetter__ ) {

	if (!Document.prototype.loadXML) {
		Document.prototype.loadXML = function (s) {
			var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
			while (this.hasChildNodes())
			this.removeChild(this.lastChild);

			for (var i = 0; i < doc2.childNodes.length; i++) {
				this.appendChild(this.importNode(doc2.childNodes[i], true));
			}
		};
	}

	Document.prototype.__defineGetter__( "xml",
	function () {
		return (new XMLSerializer()).serializeToString(this);
	}
	);
}

document.getElementsByTagAndClassName = function(tagName, className) {
	if ( tagName == null )
	tagName = '*';

	var children = document.getElementsByTagName(tagName) || document.all;
	var elements = new Array();

	if ( className == null )
	return children;

	for (var i = 0; i < children.length; i++) {
		var child = children[i];
		var classNames = child.className.split(' ');
		for (var j = 0; j < classNames.length; j++) {
			if (classNames[j] == className) {
				elements.push(child);
				break;
			}
		}
	}

	return elements;
}






//-------------------- ricoColor.js
Rico.Color = Class.create();

Rico.Color.prototype = {

	initialize: function(red, green, blue) {
		this.rgb = { r: red, g : green, b : blue };
	},

	setRed: function(r) {
		this.rgb.r = r;
	},

	setGreen: function(g) {
		this.rgb.g = g;
	},

	setBlue: function(b) {
		this.rgb.b = b;
	},

	setHue: function(h) {

		// get an HSB model, and set the new hue...
		var hsb = this.asHSB();
		hsb.h = h;

		// convert back to RGB...
		this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
	},

	setSaturation: function(s) {
		// get an HSB model, and set the new hue...
		var hsb = this.asHSB();
		hsb.s = s;

		// convert back to RGB and set values...
		this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
	},

	setBrightness: function(b) {
		// get an HSB model, and set the new hue...
		var hsb = this.asHSB();
		hsb.b = b;

		// convert back to RGB and set values...
		this.rgb = Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
	},

	darken: function(percent) {
		var hsb  = this.asHSB();
		this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
	},

	brighten: function(percent) {
		var hsb  = this.asHSB();
		this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
	},

	blend: function(other) {
		this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
		this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
		this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
	},

	isBright: function() {
		var hsb = this.asHSB();
		return this.asHSB().b > 0.5;
	},

	isDark: function() {
		return ! this.isBright();
	},

	asRGB: function() {
		return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
	},

	asHex: function() {
		return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart();
	},

	asHSB: function() {
		return Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
	},

	toString: function() {
		return this.asHex();
	}

};

Rico.Color.createFromHex = function(hexCode) {
	if(hexCode.length==4) {
		var shortHexCode = hexCode;
		var hexCode = '#';
		for(var i=1;i<4;i++) hexCode += (shortHexCode.charAt(i) +
		shortHexCode.charAt(i));
	}
	if ( hexCode.indexOf('#') == 0 )
	hexCode = hexCode.substring(1);
	var red   = hexCode.substring(0,2);
	var green = hexCode.substring(2,4);
	var blue  = hexCode.substring(4,6);
	return new Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) );
}

/**
* Factory method for creating a color from the background of
* an HTML element.
*/
Rico.Color.createColorFromBackground = function(elem) {

	var actualColor = RicoUtil.getElementsComputedStyle($(elem), "backgroundColor", "background-color");

	if ( actualColor == "transparent" && elem.parentNode )
	return Rico.Color.createColorFromBackground(elem.parentNode);

	if ( actualColor == null )
	return new Rico.Color(255,255,255);

	if ( actualColor.indexOf("rgb(") == 0 ) {
		var colors = actualColor.substring(4, actualColor.length - 1 );
		var colorArray = colors.split(",");
		return new Rico.Color( parseInt( colorArray[0] ),
		parseInt( colorArray[1] ),
		parseInt( colorArray[2] )  );

	}
	else if ( actualColor.indexOf("#") == 0 ) {
		return Rico.Color.createFromHex(actualColor);
	}
	else
	return new Rico.Color(255,255,255);
}

Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {

	var red   = 0;
	var green = 0;
	var blue  = 0;

	if (saturation == 0) {
		red = parseInt(brightness * 255.0 + 0.5);
		green = red;
		blue = red;
	}
	else {
		var h = (hue - Math.floor(hue)) * 6.0;
		var f = h - Math.floor(h);
		var p = brightness * (1.0 - saturation);
		var q = brightness * (1.0 - saturation * f);
		var t = brightness * (1.0 - (saturation * (1.0 - f)));

		switch (parseInt(h)) {
			case 0:
			red   = (brightness * 255.0 + 0.5);
			green = (t * 255.0 + 0.5);
			blue  = (p * 255.0 + 0.5);
			break;
			case 1:
			red   = (q * 255.0 + 0.5);
			green = (brightness * 255.0 + 0.5);
			blue  = (p * 255.0 + 0.5);
			break;
			case 2:
			red   = (p * 255.0 + 0.5);
			green = (brightness * 255.0 + 0.5);
			blue  = (t * 255.0 + 0.5);
			break;
			case 3:
			red   = (p * 255.0 + 0.5);
			green = (q * 255.0 + 0.5);
			blue  = (brightness * 255.0 + 0.5);
			break;
			case 4:
			red   = (t * 255.0 + 0.5);
			green = (p * 255.0 + 0.5);
			blue  = (brightness * 255.0 + 0.5);
			break;
			case 5:
			red   = (brightness * 255.0 + 0.5);
			green = (p * 255.0 + 0.5);
			blue  = (q * 255.0 + 0.5);
			break;
		}
	}

	return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) };
}

Rico.Color.RGBtoHSB = function(r, g, b) {

	var hue;
	var saturation;
	var brightness;

	var cmax = (r > g) ? r : g;
	if (b > cmax)
	cmax = b;

	var cmin = (r < g) ? r : g;
	if (b < cmin)
	cmin = b;

	brightness = cmax / 255.0;
	if (cmax != 0)
	saturation = (cmax - cmin)/cmax;
	else
	saturation = 0;

	if (saturation == 0)
	hue = 0;
	else {
		var redc   = (cmax - r)/(cmax - cmin);
		var greenc = (cmax - g)/(cmax - cmin);
		var bluec  = (cmax - b)/(cmax - cmin);

		if (r == cmax)
		hue = bluec - greenc;
		else if (g == cmax)
		hue = 2.0 + redc - bluec;
		else
		hue = 4.0 + greenc - redc;

		hue = hue / 6.0;
		if (hue < 0)
		hue = hue + 1.0;
	}

	return { h : hue, s : saturation, b : brightness };
}













//-------------------- ricoDragAndDrop.js
Rico.DragAndDrop = Class.create();

Rico.DragAndDrop.prototype = {

	initialize: function() {
		this.dropZones                = new Array();
		this.draggables               = new Array();
		this.currentDragObjects       = new Array();
		this.dragElement              = null;
		this.lastSelectedDraggable    = null;
		this.currentDragObjectVisible = false;
		this.interestedInMotionEvents = false;
		this._mouseDown = this._mouseDownHandler.bindAsEventListener(this);
		this._mouseMove = this._mouseMoveHandler.bindAsEventListener(this);
		this._mouseUp = this._mouseUpHandler.bindAsEventListener(this);

		this.draggablebox = null;
		
		this.workzone = null;

	},

	registerDropZone: function(aDropZone) {
		this.dropZones[ this.dropZones.length ] = aDropZone;
	},

	deregisterDropZone: function(aDropZone) {
		var newDropZones = new Array();
		var j = 0;
		for ( var i = 0 ; i < this.dropZones.length ; i++ ) {
			if ( this.dropZones[i] != aDropZone )
			newDropZones[j++] = this.dropZones[i];
		}

		this.dropZones = newDropZones;
	},

	clearDropZones: function() {
		this.dropZones = new Array();
	},

	registerDraggable: function( aDraggable ) {
		this.draggables[ this.draggables.length ] = aDraggable;
		this._addMouseDownHandler( aDraggable );
	},

	clearSelection: function() {
		for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
		this.currentDragObjects[i].deselect();
		this.currentDragObjects = new Array();
		this.lastSelectedDraggable = null;
	},

	hasSelection: function() {
		return this.currentDragObjects.length > 0;
	},

	setStartDragFromElement: function( e, mouseDownElement ) {
		this.origPos = RicoUtil.toDocumentPosition(mouseDownElement);
		this.startx = e.screenX - this.origPos.x
		this.starty = e.screenY - this.origPos.y
		//this.startComponentX = e.layerX ? e.layerX : e.offsetX;
		//this.startComponentY = e.layerY ? e.layerY : e.offsetY;
		//this.adjustedForDraggableSize = false;

		this.interestedInMotionEvents = this.hasSelection();

		this._terminateEvent(e);
	},

	updateSelection: function( draggable, extendSelection ) {
		if ( ! extendSelection )
		this.clearSelection();

		if ( draggable.isSelected() ) {
			this.currentDragObjects.removeItem(draggable);
			draggable.deselect();
			if ( draggable == this.lastSelectedDraggable )
			this.lastSelectedDraggable = null;
		}
		else {
			this.currentDragObjects[ this.currentDragObjects.length ] = draggable;
			draggable.select();
			this.lastSelectedDraggable = draggable;
		}
	},

	_mouseDownHandler: function(e) {
		if ( arguments.length == 0 )
		e = event;

		// if not button 1 ignore it...
		var nsEvent = e.which != undefined;
		if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
		return;

		var eventTarget      = e.target ? e.target : e.srcElement;
		var draggableObject  = eventTarget.draggable;

		var candidate = eventTarget;
		while (draggableObject == null && candidate.parentNode) {
			candidate = candidate.parentNode;
			draggableObject = candidate.draggable;
		}

		if ( draggableObject == null )
		return;

		this.updateSelection( draggableObject, e.ctrlKey );

		// clear the drop zones postion cache...
		if ( this.hasSelection() )
		for ( var i = 0 ; i < this.dropZones.length ; i++ )
		this.dropZones[i].clearPositionCache();

		this.setStartDragFromElement( e, draggableObject.getMouseDownHTMLElement() );
	},


	_mouseMoveHandler: function(e) {
		var nsEvent = e.which != undefined;
		if ( !this.interestedInMotionEvents ) {
			//this._terminateEvent(e);
			return;
		}

		if ( ! this.hasSelection() )
		return;

		if ( ! this.currentDragObjectVisible )
		this._startDrag(e);

		if ( !this.activatedDropZones )
		this._activateRegisteredDropZones();

		//if ( !this.adjustedForDraggableSize )
		//   this._adjustForDraggableSize(e);

		this._updateDraggableLocation(e);
		this._updateDropZonesHover(e);

		this._terminateEvent(e);
	},

	_makeDraggableObjectVisible: function(e)
	{
		if ( !this.hasSelection() )
		return;

		var dragElementO;
		if ( this.currentDragObjects.length > 1 )
		dragElementO = this.currentDragObjects[0].getMultiObjectDragGUI(this.currentDragObjects);
		else
		dragElementO = this.currentDragObjects[0].getSingleObjectDragGUI();

		var dragElement = document.createElement( 'div' );


		document.body.appendChild( dragElement );

		//		dragElement.style.display = 'inline';
		//dragElement.style.visibility = 'visible';

		//	document.getElementById( 'debugbox' ).innerHTML += "<br>" + dragElement.style.visibility;


		var s = dragElement.style;

		s.cursor = "move";
		s.border = "2px solid #aaa";
		s.zIndex = 999;



		dragElementO.style.opacity = .1;
		dragElementO.style.filter = "alpha(opacity=10)";

		dragElement.style.width = dragElementO.offsetWidth + "px";
		dragElement.style.height = dragElementO.offsetHeight + "px";

		dragElement.innerHTML = dragElementO.innerHTML;
		dragElement.className = dragElementO.className;
		dragElement.style.color = dragElementO.style.color;
		dragElement.style.backgroundColor = dragElementO.style.backgroundColor;


		// go ahead and absolute position it...
		if ( RicoUtil.getElementsComputedStyle(dragElement, "position")  != "absolute" )
		dragElement.style.position = "absolute";

		// need to parent him into the document...
		if ( dragElement.parentNode == null || dragElement.parentNode.nodeType == 11 )
		document.body.appendChild(dragElement);

		this.dragElement = dragElement;
		this._updateDraggableLocation(e);

		this.currentDragObjectVisible = true;
	},

	/**
	_adjustForDraggableSize: function(e) {
	var dragElementWidth  = this.dragElement.offsetWidth;
	var dragElementHeight = this.dragElement.offsetHeight;
	if ( this.startComponentX > dragElementWidth )
	this.startx -= this.startComponentX - dragElementWidth + 2;
	if ( e.offsetY ) {
	if ( this.startComponentY > dragElementHeight )
	this.starty -= this.startComponentY - dragElementHeight + 2;
	}
	this.adjustedForDraggableSize = true;
	},
	**/

	_leftOffset: function(e) {
		return e.offsetX ? document.body.scrollLeft : 0
	},

	_topOffset: function(e) {
		return e.offsetY ? document.body.scrollTop:0
	},


	_updateDraggableLocation: function(e) {
		var dragObjectStyle = this.dragElement.style;
		dragObjectStyle.left = (e.screenX + this._leftOffset(e) - this.startx) + "px"
		dragObjectStyle.top  = (e.screenY + this._topOffset(e) - this.starty) + "px";

		//   	document.getElementById( 'debugbox' ).innerHTML += "<br>" + this.dragElement.style.visibility;

	},

	_updateDropZonesHover: function(e) {
		var n = this.dropZones.length;
		//	document.getElementById( 'debugbox' ).innerHTML += "<br>zones: " + n;

		var divider = document.getElementById( 'dragdivider' );
		for ( var i = 0 ; i < n ; i++ ) {
			if ( ! this._mousePointInDropZone( e, this.dropZones[i] ) )
			{
				this.dropZones[i].hideHover();
				if ( divider != null )
				{
					divider.style.display = "none";
				}

			}
		}

		for ( var i = 0 ; i < n ; i++ ) {
			if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
				if ( this.dropZones[i].canAccept( e, this.currentDragObjects) )
				this.dropZones[i].showHover();
			}

			//		document.getElementById( 'debugbox' ).innerHTML += "<br>zone: " + this.dropZones[i].getHTMLElement().id;

		}
	},

	_startDrag: function(e) {
		for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
		this.currentDragObjects[i].startDrag();

		this._makeDraggableObjectVisible(e);
	},

	_mouseUpHandler: function(e) {
		if ( ! this.hasSelection() )
		return;

		var nsEvent = e.which != undefined;
		if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
		return;

		this.interestedInMotionEvents = false;

		if ( this.dragElement == null ) {
			this._terminateEvent(e);
			return;
		}


		var divider = document.getElementById( 'dragdivider' );
		if ( divider != null )
		{
			divider.style.display = "none";
		}

		if ( this._placeDraggableInDropZone(e) )
		this._completeDropOperation(e);
		else {
			this._terminateEvent(e);
			new Rico.Effect.Position( this.dragElement,
			this.origPos.x,
			this.origPos.y,
			200,
			20,
			{ complete : this._doCancelDragProcessing.bind(this) } );
		}

		Event.stopObserving( this.workzone, "mousemove", this._mouseMove);
		Event.stopObserving( this.workzone, "mouseup",  this._mouseUp);

	},

	_retTrue: function () {
		return true;
	},

	_completeDropOperation: function(e) {
		if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
			if ( this.dragElement.parentNode != null )
			this.dragElement.parentNode.removeChild(this.dragElement);
		}

		this._deactivateRegisteredDropZones();
		this._endDrag();
		this.clearSelection();
		this.dragElement = null;
		this.currentDragObjectVisible = false;
		this._terminateEvent(e);
	},

	_doCancelDragProcessing: function() {

		var dragElementO;
		if ( this.currentDragObjects.length > 1 )
		dragElementO = this.currentDragObjects[0].getMultiObjectDragGUI(this.currentDragObjects);
		else
		dragElementO = this.currentDragObjects[0].getSingleObjectDragGUI();

		dragElementO.style.opacity = 1;
		dragElementO.style.filter = "alpha(opacity=100)";


		this._cancelDrag();

		if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() && this.dragElement)
		if ( this.dragElement.parentNode != null )
		this.dragElement.parentNode.removeChild(this.dragElement);


		this._deactivateRegisteredDropZones();
		this.dragElement = null;
		this.currentDragObjectVisible = false;
	},

	_placeDraggableInDropZone: function(e) {
		var foundDropZone = false;
		var n = this.dropZones.length;
		for ( var i = 0 ; i < n ; i++ ) {
			if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
				if ( this.dropZones[i].canAccept( e, this.currentDragObjects) ) {
					this.dropZones[i].hideHover();
					this.dropZones[i].accept( e, this.currentDragObjects);
					foundDropZone = true;
					break;
				}
			}
		}

		return foundDropZone;
	},

	_cancelDrag: function() {
		for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
		this.currentDragObjects[i].cancelDrag();
	},

	_endDrag: function() {
		for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
		this.currentDragObjects[i].endDrag();
	},

	_mousePointInDropZone: function( e, dropZone ) {

		var absoluteRect = dropZone.getAbsoluteRect();

		return e.clientX  > absoluteRect.left + this._leftOffset(e) &&
		e.clientX  < absoluteRect.right + this._leftOffset(e) &&
		e.clientY  > absoluteRect.top + this._topOffset(e)   &&
		e.clientY  < absoluteRect.bottom + this._topOffset(e);
	},

	_addMouseDownHandler: function( aDraggable )
	{
		htmlElement  = aDraggable.getHandle();//  getMouseDownHTMLElement();
		if ( htmlElement  != null ) {
			htmlElement.draggable = aDraggable;
			Event.observe(htmlElement, "mousedown", this._onmousedown.bindAsEventListener(this));
			Event.observe(htmlElement, "mousedown", this._mouseDown);
		}
	},

	_activateRegisteredDropZones: function() {
		var n = this.dropZones.length;
		for ( var i = 0 ; i < n ; i++ ) {
			var dropZone = this.dropZones[i];
			if ( dropZone.canAccept( null, this.currentDragObjects) )
			dropZone.activate();
		}

		this.activatedDropZones = true;
	},

	_deactivateRegisteredDropZones: function() {
		var n = this.dropZones.length;
		for ( var i = 0 ; i < n ; i++ )
		this.dropZones[i].deactivate();
		this.activatedDropZones = false;
	},

	_onmousedown: function () {
		Event.observe( this.workzone, "mousemove", this._mouseMove);
		Event.observe( this.workzone, "mouseup",  this._mouseUp);
	},

	_terminateEvent: function(e) {
		if ( e.stopPropagation != undefined )
		e.stopPropagation();
		else if ( e.cancelBubble != undefined )
		e.cancelBubble = true;

		if ( e.preventDefault != undefined )
		e.preventDefault();
		else
		e.returnValue = false;
	},


	initializeEventHandlers: function() {
		if ( typeof document.implementation != "undefined" &&
		document.implementation.hasFeature("HTML",   "1.0") &&
		document.implementation.hasFeature("Events", "2.0") &&
		document.implementation.hasFeature("CSS",    "2.0") ) {
			document.addEventListener("mouseup",   this._mouseUpHandler.bindAsEventListener(this),  false);
			document.addEventListener("mousemove", this._mouseMoveHandler.bindAsEventListener(this), false);
		}
		else {
			document.attachEvent( "onmouseup",   this._mouseUpHandler.bindAsEventListener(this) );
			document.attachEvent( "onmousemove", this._mouseMoveHandler.bindAsEventListener(this) );
		}
	}
}

var dndMgr = new Rico.DragAndDrop();
dndMgr.initializeEventHandlers();


//-------------------- ricoDraggable.js
Rico.Draggable = Class.create();

Rico.Draggable.prototype = {

	initialize: function( type, htmlElement, handleElement ) {
		this.type          = type;
		this.htmlElement   = $(htmlElement);
		this.selected      = false;
		this.handle		 = document.getElementById( handleElement );
	},

	/**
	*   Returns the HTML element that should have a mouse down event
	*   added to it in order to initiate a drag operation
	*
	**/
	getMouseDownHTMLElement: function() {
		return this.htmlElement;
	},

	getHandle: function() {
		return this.handle;
	},

	select: function() {
		this.selected = true;

		if ( this.showingSelected )
		return;

		var htmlElement = this.getMouseDownHTMLElement();

		var color = Rico.Color.createColorFromBackground(htmlElement);
		color.isBright() ? color.darken(0.033) : color.brighten(0.033);

		this.saveBackground = RicoUtil.getElementsComputedStyle(htmlElement, "backgroundColor", "background-color");
		htmlElement.style.backgroundColor = color.asHex();
		this.showingSelected = true;
	},

	deselect: function() {
		this.selected = false;
		if ( !this.showingSelected )
		return;

		var htmlElement = this.getMouseDownHTMLElement();

		htmlElement.style.backgroundColor = this.saveBackground;
		this.showingSelected = false;
	},

	isSelected: function() {
		return this.selected;
	},

	startDrag: function() {
	},

	cancelDrag: function() {
	},

	endDrag: function() {
	},

	getSingleObjectDragGUI: function() {
		return this.htmlElement;
	},

	getMultiObjectDragGUI: function( draggables ) {
		return this.htmlElement;
	},

	getDroppedGUI: function() {
		return this.htmlElement;
	},

	toString: function() {
		return this.type + ":" + this.htmlElement + ":";
	}

}


//-------------------- ricoDropzone.js
Rico.Dropzone = Class.create();

Rico.Dropzone.prototype = {

	initialize: function( htmlElement, callBack ) {
		this.htmlElement  = $(htmlElement);
		this.callback = callBack;
		this.absoluteRect = null;
		this.showingHover = false;
	},

	getHTMLElement: function() {
		return this.htmlElement;
	},

	clearPositionCache: function() {
		this.absoluteRect = null;
	},

	getAbsoluteRect: function() {
		if ( this.absoluteRect == null ) {
			var htmlElement = this.getHTMLElement();
			var pos = RicoUtil.toViewportPosition(htmlElement);

			this.absoluteRect = {
				top:    pos.y,
				left:   pos.x,
				bottom: pos.y + htmlElement.offsetHeight,
				right:  pos.x + htmlElement.offsetWidth
			};
		}
		return this.absoluteRect;
	},

	activate: function() {
		var htmlElement = this.getHTMLElement();
		if (htmlElement == null  || this.showingActive)
		return;

		this.showingActive = true;
		this.saveBackgroundColor = htmlElement.style.backgroundColor;

		var fallbackColor = "#ffea84";
		var currentColor = Rico.Color.createColorFromBackground(htmlElement);
		if ( currentColor == null )
		htmlElement.style.backgroundColor = fallbackColor;
		else {
			currentColor.isBright() ? currentColor.darken(0.2) : currentColor.brighten(0.2);
			htmlElement.style.backgroundColor = currentColor.asHex();
		}
	},

	deactivate: function() {
		var htmlElement = this.getHTMLElement();
		if (htmlElement == null || !this.showingActive)
		return;

		htmlElement.style.backgroundColor = this.saveBackgroundColor;
		this.showingActive = false;

		this.saveBackgroundColor = null;
	},

	showHover: function() {
		var htmlElement = this.getHTMLElement();
		if ( htmlElement == null || this.showingHover )
		return;

		this.saveBorderWidth = htmlElement.style.borderWidth;
		this.saveBorderStyle = htmlElement.style.borderStyle;
		this.saveBorderColor = htmlElement.style.borderColor;


		//      document.getElementById( 'debugbox' ).innerHTML += "show: " + htmlElement.id + " " + this.saveBorderWidth + " " + this.showingHover + "<br>";
		this.showingHover = true;
		//      document.getElementById( 'debugbox' ).innerHTML += "show2: " + htmlElement.id + " " + this.saveBorderWidth + " " + this.showingHover + "<br>";

		htmlElement.style.borderWidth = "1px";
		htmlElement.style.borderStyle = "solid";
		//htmlElement.style.borderColor = "#ff9900";
		htmlElement.style.borderColor = "#ffff00";


	},

	hideHover: function() {
		var htmlElement = this.getHTMLElement();
		if ( htmlElement == null || !this.showingHover )
		return;

		//      document.getElementById( 'debugbox' ).innerHTML += "hide: " + htmlElement.id + " " +  this.showingHover + "<br>";


		htmlElement.style.borderWidth = this.saveBorderWidth;
		htmlElement.style.borderStyle = this.saveBorderStyle;
		htmlElement.style.borderColor = this.saveBorderColor;
		this.showingHover = false;
	},

	canAccept: function( e, draggableObjects) {
		var htmlElement = this.getHTMLElement();
		if ( htmlElement == null || e == null )
		return true;


		var el = this.findPreviousObject( e, htmlElement );
		var divider = document.getElementById( 'dragdivider' );

		if ( divider != null )
		{
			divider.style.display = "block";

			var obj = draggableObjects[0].getDroppedGUI();
			divider.style.height = obj.offsetHeight + "px";
			//	document.getElementById( 'debugbox' ).innerHTML += "<br>" + draggableObjects[0].getDroppedGUI();
			if ( el != null )
			{
				htmlElement.insertBefore( divider , el );
			}
			else
			{
				htmlElement.appendChild( divider );
			}
		}

		return true;
	},


	findPreviousObject: function( e, htmlElement ) {

		var el;
		var prevEl = null;
		var found = false;
		for ( var i = htmlElement.childNodes.length - 1; i >= 0 ; i-- )
		{
			el = htmlElement.childNodes[ i ];
			var dd = el.getAttribute( "draggable" );

			if ( dd != null && dd.toUpperCase() == 'YES' )
			{
				var pos = RicoUtil.toViewportPosition( el );
				var topy = pos.y
				var midy = pos.y  + parseInt( el.offsetHeight / 2 );
				var bottomy = pos.y  + el.offsetHeight;

				// check half top portion of div
				found = e.clientY  > topy &&
				e.clientY  < midy;


				if ( found )
				{
					break;
				}

				// check half bottom portion of div
				found = e.clientY  > midy &&
				e.clientY  < bottomy;

				if ( found )
				{
					el = prevEl;
					break;
				}
				prevEl = el;


			}

		}

		if ( found )
		{
			return el;
		}
		else
		{
			return null;
		}

	},



	accept: function( e, draggableObjects) {
		var htmlElement = this.getHTMLElement();
		if ( htmlElement == null )
		return;

		n = draggableObjects.length;

		var el = this.findPreviousObject( e, htmlElement );


		for ( var i = 0 ; i < n ; i++ )
		{
			var theGUI = draggableObjects[i].getDroppedGUI();
			if ( RicoUtil.getElementsComputedStyle( theGUI, "position" ) == "absolute" )
			{
				theGUI.style.position = "static";
				theGUI.style.top = "";
				theGUI.style.top = "";
			}

			theGUI.style.opacity = 1;
			theGUI.style.filter = "alpha(opacity=100)";

			if ( el != null )
			{
				htmlElement.insertBefore( theGUI, el );
			}
			else
			{
				htmlElement.appendChild(theGUI);
			}
		}

		if ( this.callback != null )
		{
			if ( el != null )
			{
				var cmd = this.callback + '( htmlElement.id, theGUI.id, el.id );';
			}
			else
			{
				var cmd = this.callback  + '( htmlElement.id, theGUI.id, null );';

			}
			eval( cmd );

		}


		var divider = document.getElementById( 'dragdivider' );
		if ( divider != null )
		{
			divider.style.display = "none";
		}
	}
}


//-------------------- ricoEffects.js

Rico.Effect = {};

Rico.Effect.SizeAndPosition = Class.create();
Rico.Effect.SizeAndPosition.prototype = {

	initialize: function(element, x, y, w, h, duration, steps, options) {
		this.element = $(element);
		this.x = x;
		this.y = y;
		this.w = w;
		this.h = h;
		this.duration = duration;
		this.steps    = steps;
		this.options  = arguments[7] || {};

		this.sizeAndPosition();
	},

	sizeAndPosition: function() {
		if (this.isFinished()) {
			if(this.options.complete) this.options.complete(this);
			return;
		}

		if (this.timer)
		clearTimeout(this.timer);

		var stepDuration = Math.round(this.duration/this.steps) ;

		// Get original values: x,y = top left corner;  w,h = width height
		var currentX = this.element.offsetLeft;
		var currentY = this.element.offsetTop;
		var currentW = this.element.offsetWidth;
		var currentH = this.element.offsetHeight;

		// If values not set, or zero, we do not modify them, and take original as final as well
		this.x = (this.x) ? this.x : currentX;
		this.y = (this.y) ? this.y : currentY;
		this.w = (this.w) ? this.w : currentW;
		this.h = (this.h) ? this.h : currentH;

		// how much do we need to modify our values for each step?
		var difX = this.steps >  0 ? (this.x - currentX)/this.steps : 0;
		var difY = this.steps >  0 ? (this.y - currentY)/this.steps : 0;
		var difW = this.steps >  0 ? (this.w - currentW)/this.steps : 0;
		var difH = this.steps >  0 ? (this.h - currentH)/this.steps : 0;

		this.moveBy(difX, difY);
		this.resizeBy(difW, difH);

		this.duration -= stepDuration;
		this.steps--;

		this.timer = setTimeout(this.sizeAndPosition.bind(this), stepDuration);
	},

	isFinished: function() {
		return this.steps <= 0;
	},

	moveBy: function( difX, difY ) {
		var currentLeft = this.element.offsetLeft;
		var currentTop  = this.element.offsetTop;
		var intDifX     = parseInt(difX);
		var intDifY     = parseInt(difY);

		var style = this.element.style;
		if ( intDifX != 0 )
		style.left = (currentLeft + intDifX) + "px";
		if ( intDifY != 0 )
		style.top  = (currentTop + intDifY) + "px";
	},

	resizeBy: function( difW, difH ) {
		var currentWidth  = this.element.offsetWidth;
		var currentHeight = this.element.offsetHeight;
		var intDifW       = parseInt(difW);
		var intDifH       = parseInt(difH);

		var style = this.element.style;
		if ( intDifW != 0 )
		style.width   = (currentWidth  + intDifW) + "px";
		if ( intDifH != 0 )
		style.height  = (currentHeight + intDifH) + "px";
	}
}

Rico.Effect.Size = Class.create();
Rico.Effect.Size.prototype = {

	initialize: function(element, w, h, duration, steps, options) {
		new Rico.Effect.SizeAndPosition(element, null, null, w, h, duration, steps, options);
	}
}

Rico.Effect.Position = Class.create();
Rico.Effect.Position.prototype = {

	initialize: function(element, x, y, duration, steps, options) {
		new Rico.Effect.SizeAndPosition(element, x, y, null, null, duration, steps, options);
	}
}

Rico.Effect.Round = Class.create();
Rico.Effect.Round.prototype = {

	initialize: function(tagName, className, options) {
		var elements = document.getElementsByTagAndClassName(tagName,className);
		for ( var i = 0 ; i < elements.length ; i++ )
		Rico.Corner.round( elements[i], options );
	}
};

Rico.Effect.FadeTo = Class.create();
Rico.Effect.FadeTo.prototype = {

	initialize: function( element, opacity, duration, steps, options) {
		this.element  = $(element);
		this.opacity  = opacity;
		this.duration = duration;
		this.steps    = steps;
		this.options  = arguments[4] || {};
		this.fadeTo();
	},

	fadeTo: function() {
		if (this.isFinished()) {
			if(this.options.complete) this.options.complete(this);
			return;
		}

		if (this.timer)
		clearTimeout(this.timer);

		var stepDuration = Math.round(this.duration/this.steps) ;
		var currentOpacity = this.getElementOpacity();
		var delta = this.steps > 0 ? (this.opacity - currentOpacity)/this.steps : 0;

		this.changeOpacityBy(delta);
		this.duration -= stepDuration;
		this.steps--;

		this.timer = setTimeout(this.fadeTo.bind(this), stepDuration);
	},

	changeOpacityBy: function(v) {
		var currentOpacity = this.getElementOpacity();
		var newOpacity = Math.max(0, Math.min(currentOpacity+v, 1));
		this.element.ricoOpacity = newOpacity;

		this.element.style.filter = "alpha(opacity:"+Math.round(newOpacity*100)+")";
		this.element.style.opacity = newOpacity; /*//*/;
	},

	isFinished: function() {
		return this.steps <= 0;
	},

	getElementOpacity: function() {
		if ( this.element.ricoOpacity == undefined ) {
			var opacity = RicoUtil.getElementsComputedStyle(this.element, 'opacity');
			this.element.ricoOpacity = opacity != undefined ? opacity : 1.0;
		}
		return parseFloat(this.element.ricoOpacity);
	}
}

Rico.Effect.AccordionSize = Class.create();

Rico.Effect.AccordionSize.prototype = {

	initialize: function(e1, e2, start, end, duration, steps, options) {
		this.e1       = $(e1);
		this.e2       = $(e2);
		this.start    = start;
		this.end      = end;
		this.duration = duration;
		this.steps    = steps;
		this.options  = arguments[6] || {};

		this.accordionSize();
	},

	accordionSize: function() {

		if (this.isFinished()) {
			// just in case there are round errors or such...
			this.e1.style.height = this.start + "px";
			this.e2.style.height = this.end + "px";

			if(this.options.complete)
			this.options.complete(this);
			return;
		}

		if (this.timer)
		clearTimeout(this.timer);

		var stepDuration = Math.round(this.duration/this.steps) ;

		var diff = this.steps > 0 ? (parseInt(this.e1.offsetHeight) - this.start)/this.steps : 0;
		this.resizeBy(diff);

		this.duration -= stepDuration;
		this.steps--;

		this.timer = setTimeout(this.accordionSize.bind(this), stepDuration);
	},

	isFinished: function() {
		return this.steps <= 0;
	},

	resizeBy: function(diff) {
		var h1Height = this.e1.offsetHeight;
		var h2Height = this.e2.offsetHeight;
		var intDiff = parseInt(diff);
		if ( diff != 0 ) {
			this.e1.style.height = (h1Height - intDiff) + "px";
			this.e2.style.height = (h2Height + intDiff) + "px";
		}
	}

};




//-------------------- ricoUtil.js
var RicoUtil = {

	getElementsComputedStyle: function ( htmlElement, cssProperty, mozillaEquivalentCSS) {
		if ( arguments.length == 2 )
		mozillaEquivalentCSS = cssProperty;

		var el = $(htmlElement);
		if ( el.currentStyle )
		return el.currentStyle[cssProperty];
		else
		return document.defaultView.getComputedStyle(el, null).getPropertyValue(mozillaEquivalentCSS);
	},

	createXmlDocument : function() {
		if (document.implementation && document.implementation.createDocument) {
			var doc = document.implementation.createDocument("", "", null);

			if (doc.readyState == null) {
				doc.readyState = 1;
				doc.addEventListener("load", function () {
					doc.readyState = 4;
					if (typeof doc.onreadystatechange == "function")
					doc.onreadystatechange();
				}, false);
			}

			return doc;
		}

		if (window.ActiveXObject)
		return Try.these(
		function() { return new ActiveXObject('MSXML2.DomDocument')   },
		function() { return new ActiveXObject('Microsoft.DomDocument')},
		function() { return new ActiveXObject('MSXML.DomDocument')    },
		function() { return new ActiveXObject('MSXML3.DomDocument')   }
		) || false;

		return null;
	},

	getContentAsString: function( parentNode ) {
		return parentNode.xml != undefined ?
		this._getContentAsStringIE(parentNode) :
		this._getContentAsStringMozilla(parentNode);
	},

	_getContentAsStringIE: function(parentNode) {
		var contentStr = "";
		for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
			var n = parentNode.childNodes[i];
			if (n.nodeType == 4) {
				contentStr += n.nodeValue;
			}
			else {
				contentStr += n.xml;
			}
		}
		return contentStr;
	},

	_getContentAsStringMozilla: function(parentNode) {
		var xmlSerializer = new XMLSerializer();
		var contentStr = "";
		for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
			var n = parentNode.childNodes[i];
			if (n.nodeType == 4) { // CDATA node
				contentStr += n.nodeValue;
			}
			else {
				contentStr += xmlSerializer.serializeToString(n);
			}
		}
		return contentStr;
	},

	toViewportPosition: function(element) {
		return this._toAbsolute(element,true);
	},

	toDocumentPosition: function(element) {
		return this._toAbsolute(element,false);
	},

	/**
	*  Compute the elements position in terms of the window viewport
	*  so that it can be compared to the position of the mouse (dnd)
	*  This is additions of all the offsetTop,offsetLeft values up the
	*  offsetParent hierarchy, ...taking into account any scrollTop,
	*  scrollLeft values along the way...
	*
	* IE has a bug reporting a correct offsetLeft of elements within a
	* a relatively positioned parent!!!
	**/
	_toAbsolute: function(element,accountForDocScroll) {

		if ( navigator.userAgent.toLowerCase().indexOf("msie") == -1 )
		return this._toAbsoluteMozilla(element,accountForDocScroll);

		var x = 0;
		var y = 0;
		var parent = element;
		while ( parent ) {

			var borderXOffset = 0;
			var borderYOffset = 0;
			if ( parent != element ) {
				var borderXOffset = parseInt(this.getElementsComputedStyle(parent, "borderLeftWidth" ));
				var borderYOffset = parseInt(this.getElementsComputedStyle(parent, "borderTopWidth" ));
				borderXOffset = isNaN(borderXOffset) ? 0 : borderXOffset;
				borderYOffset = isNaN(borderYOffset) ? 0 : borderYOffset;
			}

			x += parent.offsetLeft - parent.scrollLeft + borderXOffset;
			y += parent.offsetTop - parent.scrollTop + borderYOffset;
			parent = parent.offsetParent;
		}

		if ( accountForDocScroll ) {
			x -= this.docScrollLeft();
			y -= this.docScrollTop();
		}

		return { x:x, y:y };
	},

	/**
	*  Mozilla did not report all of the parents up the hierarchy via the
	*  offsetParent property that IE did.  So for the calculation of the
	*  offsets we use the offsetParent property, but for the calculation of
	*  the scrollTop/scrollLeft adjustments we navigate up via the parentNode
	*  property instead so as to get the scroll offsets...
	*
	**/
	_toAbsoluteMozilla: function(element,accountForDocScroll) {
		var x = 0;
		var y = 0;
		var parent = element;
		while ( parent ) {
			x += parent.offsetLeft;
			y += parent.offsetTop;
			parent = parent.offsetParent;
		}

		parent = element;
		while ( parent &&
		parent != document.body &&
		parent != document.documentElement ) {
			if ( parent.scrollLeft  )
			x -= parent.scrollLeft;
			if ( parent.scrollTop )
			y -= parent.scrollTop;
			parent = parent.parentNode;
		}

		if ( accountForDocScroll ) {
			x -= this.docScrollLeft();
			y -= this.docScrollTop();
		}

		return { x:x, y:y };
	},

	docScrollLeft: function() {
		if ( window.pageXOffset )
		return window.pageXOffset;
		else if ( document.documentElement && document.documentElement.scrollLeft )
		return document.documentElement.scrollLeft;
		else if ( document.body )
		return document.body.scrollLeft;
		else
		return 0;
	},

	docScrollTop: function() {
		if ( window.pageYOffset )
		return window.pageYOffset;
		else if ( document.documentElement && document.documentElement.scrollTop )
		return document.documentElement.scrollTop;
		else if ( document.body )
		return document.body.scrollTop;
		else
		return 0;
	}

};
