(function($){
/*----------------------------------------------------------------------------------
Class: FloatObject
-------------------------------------------------------------------------------------*/
	function FloatObject(jqObj, params) {
		this.jqObj = jqObj;

		switch(params.speed)
		{
			case 'fast': this.steps = 5; break;
			case 'normal': this.steps = 10; break;
			case 'slow': this.steps = 20; break;
			default: this.steps = 10;
		};

		var offset = this.jqObj.offset();
		this.width = this.jqObj.width();
		this.height = this.jqObj.height();
		this.currentX = offset.left;
		this.currentY = offset.top;

		if (params.bottom) {
			if (typeof(params.bottom) == "string") {
				this.origY = this.currentY;
				this.bottom = $(window).scrollTop() + $(window).height() - this.height - this.currentY;
			} else {
				this.origY = $(window).scrollTop() + $(window).height() - this.height - params.bottom;
				this.bottom = params.bottom;
			}
		} else {
			this.origY = typeof(params.top) == "string" ?  this.currentY : params.top;
		}
		if (params.right) {
			if (typeof(params.right) == "string") {
				this.origX = this.currentX;
				this.right = $(window).scrollLeft() + $(window).width() - this.width - this.currentX;
			} else {
				 this.origX = $(window).scrollLeft() + $(window).width() - this.width - params.right;
				 this.right = params.right;
			}
		} else {
			this.origX = typeof(params.left) == "string" ?  this.currentX : params.left;
		}

		if (params.minTop) {
			this.minTop = params.minTop;
			if (this.origY < this.minTop) {
				this.origY = this.minTop;
			}
		}

		this.jqObj.css({'position': 'absolute' , 'top': this.origY, 'left': this.origX});
	}

	FloatObject.prototype.updateLocation = function() {

		if (this.right) {
			this.updatedX = $(window).scrollLeft() + $(window).width() - this.width - this.right;
		} else {
			this.updatedX = $(window).scrollLeft() + this.origX;
		}

		if (this.bottom) {
			this.updatedY = $(window).scrollTop() + $(window).height() - this.height - this.bottom;
		} else {
			this.updatedY = $(window).scrollTop() + this.origY;
		}

		if (this.minTop) {
			if (this.updatedY < this.minTop) {
				this.updatedY = this.minTop;
			}
		}

		this.dx = Math.abs(this.updatedX - this.currentX);
		this.dy = Math.abs(this.updatedY - this.currentY);

		return this.dx || this.dy;
	}

	FloatObject.prototype.windowHeight = function()
	{
		var de = document.documentElement;

		return self.innerHeight ||
			(de && de.clientHeight) ||
			document.body.clientHeight;
	}

	FloatObject.prototype.windowWidth = function()
	{
		var de = document.documentElement;

		return self.innerWidth ||
			(de && de.clientWidth) ||
			document.body.clientWidth;
	}


	FloatObject.prototype.move = function()
	{
		if (this.jqObj.css("position") != "absolute") return;
		var cx = 0;
		var cy = 0;

		if (this.dx > 0) {
			if( this.dx < this.steps / 2 )
				cx = (this.dx >= 1) ? 1 : 0;
			else
				cx = Math.round(this.dx/this.steps);

			if (this.currentX < this.updatedX)
					this.currentX += cx;
			else
				this.currentX -= cx;
		}

		if (this.dy > 0) {
			if (this.dy < this.steps / 2)
				cy = (this.dy >= 1) ? 1 : 0;
			else
				cy = Math.round(this.dy/this.steps);

			if (this.currentY < this.updatedY)
				this.currentY += cy;
			else
				this.currentY -= cy;

		}

		this.jqObj.css({'left': this.currentX, 'top': this.currentY });
	}



/*----------------------------------------------------------------------------------
Object: floatMgr
-------------------------------------------------------------------------------------*/
	$.floatMgr = {

		FOArray: new Array() ,

		timer: null,

		initializeFO: function(jqObj, params) {
			var settings =  $.extend({
				left: 0,
				top: 0,
				speed: 'normal',
				alwaysVisible: false,
				alwaysTop: false}, params||{});
			var newFO = new FloatObject(jqObj,settings);

			$.floatMgr.FOArray.push(newFO);

			if (!$.floatMgr.timer) $.floatMgr.adjustFO();

			//now making sure we are registered to all required window events
			if (!$.floatMgr.registeredEvents) {
				$(window).bind("resize", $.floatMgr.onChange);
				$(window).bind("scroll", $.floatMgr.onChange);
				$.floatMgr.registeredEvents = true;
			}
		},

		adjustFO: function() {
			$.floatMgr.timer = null;

			var moveFO = false;

			for (var i = 0 ; i < $.floatMgr.FOArray.length ; i++) {
				 FO = $.floatMgr.FOArray[i];
				 if( FO.updateLocation() )  moveFO = true;
			}

			if (moveFO) {
				for (var i = 0 ; i < $.floatMgr.FOArray.length; i++) {
					FO = $.floatMgr.FOArray[i];
					FO.move();
				}

				if (!$.floatMgr.timer) $.floatMgr.timer = setTimeout($.floatMgr.adjustFO,50);
			}
		},

		stopFloatChk: false,

		onChange: function() {
			if (!$.floatMgr.timer && !$.floatMgr.stopFloatChk) $.floatMgr.adjustFO();
		}
	};

/*----------------------------------------------------------------------------------
Function: makeFloat
-------------------------------------------------------------------------------------*/
	$.fn.makeFloat = function(params) {
		var obj = this.eq(0); //we only operate on the first selected object;
		$.floatMgr.initializeFO(obj, params);
		if($.floatMgr.timer == null) $.floatMgr.adjustFO();
		return obj;
	};
	$.fn.stopFloat = function(params) {
		$.floatMgr.stopFloatChk = true;
	};

	$.fn.restartFloat = function(params) {
		$.floatMgr.stopFloatChk = false;
	};
})(jQuery);
