var jo_tooltip = Class.create({
	initialize: function(_useclass,options) {
		this.options = Object.extend({
			openDelay:8,
			skinID: 'jo_tooltipCont',
			tipContentID: 'jo_tooltipDynamicContent',
			stemID: 'jo_tooltip_stem',
			tipTopID: 'jo_tooltipTop',
			tipInnerID: 'jo_tooltipInnerContainer',
			tipBottomID: 'jo_tooltipBottom',
			onOpen: Prototype.emptyFunction,
			effect:false,
			onEvent:'mouseover',
			offEvent:'mouseout',
			useStem:false,
			stemHeight: 0,
			stemBuffer: 0,
			offset:{x:0,y:0},
			hook:{tipPosition:'middleRight'},
			stemClasses: ['tl','tr','br','bl']
		}, options || {});
		this.hook = this.options.hook.tipPosition;
		this.timer = null;
		this.tipIDExtended = null;
		this._stemID = null
		this._top = null;
		this._left = null;
		this._dynamicContentID = null;
		this._viewportDimensions = null;
		this._elementViewport = null;
		this._viewportScroll = null;
		this.isOpen = false;
		this.buildTip();
		var tooltip = $$('.' + _useclass);
		tooltip.each(function(elem){
			elem.observe(this.options.onEvent,this.handleOpenEvent.bind(this));
			elem.observe(this.options.offEvent,this.handleCloseEvent.bind(this));
		}.bind(this));
	},
	buildTip: function(){
		var lw = document.createElement('div');
		var bodyElement = document.getElementsByTagName('body')[0];
		var skin = 
			'<div id="' + this.options.skinID + '">'
				+	'<div id="' + this.options.tipInnerID + '">'
					+	'<div id="' + this.options.tipTopID + '">&nbsp;</div>'
					+ 	'<div id="' + this.options.tipContentID + '">&nbsp;</div>'
					+	'<div id="' + this.options.tipBottomID + '">&nbsp;</div>';
		if(this.options.useStem == true){
			skin += '<div id="' + this.options.stemID + '" class="' + this.options.stemClasses[3] + '">&nbsp;</div>';
		}
		skin += 	'</div>'	
			+'</div>';
		lw.innerHTML = skin;
		bodyElement.appendChild(lw);
		this.tipIDExtended = $(this.options.skinID);
		this._dynamicContentID = $(this.options.tipContentID);
		if(this.options.useStem == true){
			this._stemID = $(this.options.stemID);
		}
		try{
			bodyElement.observe('click',this.handleCloseEvent.bind(this));
			bodyElement.observe('mouseover',this.handleCloseEvent.bind(this));
		}catch(e){
			document.body.onclick = function(e){
				this.handleCloseEvent(e);
			}.bind(this);
			document.body.mouseover = function(e){
				this.handleCloseEvent(e);
			}.bind(this);
		}
	},
	makeCalculations: function(tip,target){
		var _max_y = this._viewportDimensions.height + this._viewportScroll.top;
		var _max_x = this._viewportDimensions.width + this._viewportScroll.left;
		this.stemClassReset();
		var bumpup = false;
		var bumpside = false;
		var oldheight = null;
		var stemTop = null;
		switch(this.hook){
			case 'topLeft': 
				this._top = this.options.offset.y + ( ( -1 * ( tip.height - target.height ) ) + this._elementViewport.top + this._viewportScroll.top );
				this._left = this.options.offset.x + (-1 * tip.width) + this._elementViewport.left + this._viewportScroll.left;
				if( this._left < 0){
					this._left = this.options.offset.x + (target.width) + this._elementViewport.left + this._viewportScroll.left;
				}
				break;
			case 'topRight':
				this._top = this.options.offset.y + ( ( -1 * ( tip.height - target.height ) ) + this._elementViewport.top + this._viewportScroll.top );
				this._left = this.options.offset.x + target.width + this._elementViewport.left + this._viewportScroll.left;
				if( ( this._left + tip.width ) > _max_x){
					this._left = this._elementViewport.left + this._viewportScroll.left + ( -1 * tip.width ) - this.options.offset.x;
				}
				break;
			case 'bottomLeft':
				this._top = this.options.offset.y + target.height + this._elementViewport.top + this._viewportScroll.top;
				this._left = this.options.offset.x + (-1 * tip.width) + this._elementViewport.left + this._viewportScroll.left;
				if( this._left < 0){
					this._left = this.options.offset.x + (target.width) + this._elementViewport.left + this._viewportScroll.left;
				}
				if( ( this._top + tip.height ) > _max_y){
					this._top = _max_y - tip.height;
				}
				break;
			case 'bottomRight':
				this._top = this.options.offset.y + (-1 * target.height) + this._elementViewport.top + this._viewportScroll.top;
				this._left = this.options.offset.x + target.width + this._elementViewport.left + this._viewportScroll.left;
				if( ( this._left + tip.width ) > _max_x){
					this._left = this._elementViewport.left + this._viewportScroll.left + ( -1 * tip.width ) - this.options.offset.x;
				}
				if( ( this._top + tip.height ) > _max_y){
					this._top = _max_y - tip.height;
				}
				break;
			case 'middleRight':
				this._top = this.options.offset.y + ( target.height + ( -1 * ( tip.height / 2 ) ) + this._elementViewport.top + this._viewportScroll.top );
				this._left = this.options.offset.x + target.width + this._elementViewport.left + this._viewportScroll.left;
				if( ( this._top + tip.height ) > _max_y){
					oldheight = this._top;
					this._top = _max_y - tip.height;
					bumpup = true;
				}
				if( ( this._left + tip.width ) > _max_x){
					this._left = this._elementViewport.left + this._viewportScroll.left + ( -1 * tip.width ) - this.options.offset.x + 14;
					bumpside = true;
				}
				if(this.options.useStem == true){
					if(bumpup == true && bumpside == false){
						stemTop = (tip.height / 2) + (oldheight - this._top) - (this.options.stemHeight / 2);
						if(stemTop > tip.height - this.options.stemBuffer - (this.options.stemHeight / 2)){
							stemTop = tip.height - this.options.stemBuffer - (this.options.stemHeight / 2);
						}
						this.positionStem( stemTop , 3);
					}else if(bumpup == false && bumpside == true){
						this.positionStem((tip.height / 2) - (this.options.stemHeight / 2) , 2);
					}else if(bumpup ==true && bumpside == true){
						stemTop = (tip.height / 2) + (oldheight - this._top) - (this.options.stemHeight / 2);
						if(stemTop > tip.height - this.options.stemBuffer - (this.options.stemHeight / 2)){
							stemTop = tip.height - this.options.stemBuffer - (this.options.stemHeight / 2);
						}
						this.positionStem(stemTop , 2);
					}else{
						this.positionStem((tip.height / 2) - (this.options.stemHeight / 2) , 3);
					}
				}
				break;
			case 'middleLeft':
				this._top = this.options.offset.y + ( target.height + ( -1 * ( tip.height / 2 ) ) + this._elementViewport.top + this._viewportScroll.top );
				this._left = this.options.offset.x + (-1 * tip.width) + this._elementViewport.left + this._viewportScroll.left;
				if( ( this._top + tip.height ) > _max_y){
					this._top = _max_y - tip.height;
				}
				if( this._left < 0){
					this._left = this.options.offset.x + (target.width) + this._elementViewport.left + this._viewportScroll.left;
				}
				break;
		}
	},
	stemClassReset: function(){
		if(this.options.useStem == true){
			this.options.stemClasses.each(function(elem){
				this._stemID.removeClassName(elem);
			}.bind(this));
		}
		return;
	},
	positionStem: function(theY,theclass){
		this._stemID.addClassName(this.options.stemClasses[theclass]);
		this._stemID.setStyle({
			top: theY + 'px'
		});
		return;
	},
	getWindow: function(element){
		this._viewportDimensions = document.viewport.getDimensions();
		this._elementViewport = element.viewportOffset();
		this._viewportScroll = document.viewport.getScrollOffsets();		
	},
	handleOpenEvent: function(e){
		var elem = Event.element(e);
		if(this.options.onEvent == 'click'){
			Event.stop(e);
		}
		if(this.timer != null){
			clearTimeout(this.timer);
			this.timer = null;
		}
		this.timer = setTimeout(function(){
			this.timer = null;
			if(this.isOpen == false){
				this.isOpen = true;
				var tipDim = this.tipIDExtended.getDimensions();
				var triggerDim = elem.getDimensions();			
				this.getWindow(elem);		
				this.makeCalculations(tipDim,triggerDim);
				this.tipIDExtended.setStyle({
					top:this._top + 'px',
					left:this._left + 'px',
					display:'block'
				});
				this.options.onOpen(elem,this._dynamicContentID);		
			}
		}.bind(this),800);
	},
	handleCloseEvent: function(e){
		if(this.options.offEvent == 'click'){
			Event.stop(e);
		}
		if(this.isOpen == true || this.tipIDExtended.visible()){
			this.isOpen = false;
			this.tipIDExtended.hide();
		}
	}
});