(function($){
	$.fn.cbTip = function(options)
	{
		var defaults = {
			tip : "toolTip", // ID of cbTip
			tipClass : "cbTip", // Class for styling
			inDelay : 0, // Delay before cbTip shows
			outDelay	 : 0, // Delay before cbTip hides
			tipPlace : ["top","center"],
			tipOffset : [0,0],
			tipEffect : "normal",
			showArrows : false,
			CSS3 : {
				tipGradient : false,
				tipRound : false,
				tipShadow : false	
			}
		},
		params = $.extend(true,{},defaults,options),
		tipSelector = "#"+params.tip, _shown;		
		
		function getTipPosition(trigger,tip)
		{
			var top = tip.offset().top - trigger.outerHeight() - params.tipOffset[0],
					left = tip.offset().left + tip.outerWidth() + params.tipOffset[1];
					posY = params.tipPlace[0], posX = params.tipPlace[1],
					totalWidth = trigger.outerWidth() + tip.outerWidth();
					totalHeight = trigger.outerHeight() + tip.outerHeight();
					
					if(posY == 'center') { top += totalHeight / 2 }
					if(posY == 'bottom') { top += totalHeight }
					
					if(posX == 'center') { left -= totalWidth / 2 }
					if(posX == 'left') { left -= totalWidth; }
					
					if(posX == 'none') { left -= tip.outerWidth() }
					
			return {top:top,left:left};		
		}
		
		function showTip(_this, _toolTip, params)
		{
			switch(params.tipEffect)
			{
				default:
				case "normal":
				{
					_toolTip.fadeIn(250);	
				}
				break;
				
				case "slide":
				{
					var extraPadding = 5,
							topPosition = parseInt(_toolTip.css('top'),10);
					if(params.tipPlace[0] == 'top' || params.tipPlace[0] == 'center')
					{
						newPosition = topPosition-extraPadding;
						_toolTip.css({
							top : newPosition+"px"
						});
					}
					
					if(params.tipPlace[0] == 'bottom')
					{
						newPosition = topPosition+extraPadding;
						_toolTip.css({
							top : newPosition+"px"
						});				
					}
					_toolTip.css({
						display : 'block',
						opacity : 0	
					}).stop().animate({
						opacity : 1,
						top : topPosition+"px"	
					},250);
				}
			}
		}
		
		this.each(function(){
			var _this 			= $(this),
				   _title 			= _this.attr('title'),
				   _preTimer 	= 0,
				   _timer			= 0,
				   _customPositions = _this.attr('positions'),
				   _toolTip;
				   
			_this.bind("mouseenter",function(){
				
				clearTimeout(_timer);
				if(_shown === true) 
					return _toolTip;
					
				_toolTip = $("<div />").attr({
					id : params.tip	
				}).addClass(params.tipClass).appendTo(document.body)
				.hide().append(_title);
				
				if(_customPositions != undefined)
				{
					var _customValues = _customPositions.split(":"),
							_defaultPositions = params.tipPlace;
							params.tipPlace = [_customValues[0],_customValues[1]];
				}
				
				var positions = getTipPosition(_toolTip,_this);
																				   
				// adding common CSS3 classes	   
				$.each(params.CSS3,function(name,value){
					if(value === true)	
						_toolTip.addClass(name);
				});
				
				_toolTip.css({position:"absolute",top:positions.top,left:positions.left});
				if(params.showArrows === true)
				{
					$("<span />").attr({
						id : "arrow-"+params.tipPlace[0]+"-"+params.tipPlace[1]+"-"+Math.random(Math.random(Math.random()+2*3)*11)	
					}).addClass("arrow-"+params.tipPlace[0]+"-"+params.tipPlace[1]).html("&nbsp;").appendTo(_toolTip);
				}							   
				if(params.inDelay)
				{
					_preTimer = setTimeout(function(){  showTip(_this,_toolTip,params); _shown = true; },params.inDelay);
				} else {
					showTip(_this,_toolTip,params);
					_shown = true;	
				}	
								
				if(_defaultPositions)
					params.tipPlace = _defaultPositions;
					
			}).bind("mouseleave",function(){
				clearTimeout(_preTimer);
				if(params.outDelay)
				{
					_timer = setTimeout(function(){ _toolTip.remove(); _shown = false; },params.outDelay);	
				} else {
					_toolTip.remove();
					_shown = false;	
				}
			})
			
			_this.removeAttr('title');
			_this.data('title',_title)	;   
		})
	}
})(jQuery);
