var mooTips = new Class({

	Implements: [Options], 

	options: {
		onShow: function(tip){
			tip.fade('in');
		},
		onHide: function(tip){
			tip.fade('out');
		},
		showOnClick: false,
		showOnMouseEnter: true,
		showDelay: 200,
		hideDelay: 200,
		offsets: {'x': 16, 'y': 16},
		className: 'tool',
		fixed: false
	},

	initialize: function(elements, options){
		this.setOptions(options);
		$$(elements).each(this.build, this);
		
		if (this.options.initialize) this.options.initialize.call(this);
	},
	build: function(el){

		if (el.title){

			if (el.title.test('^DOM:', 'i')) {
				id_string = el.title.split(':')[1].trim();

				//if it is relative reference (if it got "this")
				if (id_string.contains('this'))
					id_string = eval(id_string.replace(/this/, "el"));

				el.domObject = $(id_string);

				el.domObject.setStyles({
					'display': '',
					position: 'absolute',
					top: '0',
					left: '0',
					opacity: '0'
				});
				
				el.domObject.addClass(this.options.className+'-text').inject(document.body);
				
			} else {
				el.$tmp.myTitle = (el.href && el.getTag() == 'a') ? el.href.replace('http://', '') : (el.rel || false);
				//building element.domObject (div)
				internalDiv = new Element('div', {
					'class': this.options.className + '-tip',
					'styles': {
						'position': 'absolute',
						'top': '0',
						'left': '0',
						opacity: '0'
					}
				}).inject(document.body);
				
				//think this wrapper is unnecessary
				wrapper = new Element('div').inject(internalDiv);
				
				el.domObject = internalDiv;
				
				var dual = el.title.split('::');
				if (dual.length > 1){
					el.$tmp.myTitle = dual[0].trim();
					el.$tmp.myText = dual[1].trim();
				} else {
					el.$tmp.myText = el.title;
				}
				if (el.$tmp.myTitle && el.$tmp.myTitle.length > this.options.maxTitleChars) el.$tmp.myTitle = el.$tmp.myTitle.substr(0, this.options.maxTitleChars - 1) + "&hellip;";

				if (el.$tmp.myTitle){
					this.title = new Element('span').inject(new Element('div', {'class': this.options.className + '-title'}).inject(wrapper)).setHTML(el.$tmp.myTitle);
				}
				if (el.$tmp.myText){
					this.text = new Element('span').inject(new Element('div', {'class': this.options.className + '-text'}).inject(wrapper)).setHTML(el.$tmp.myText);
				}

			}
			//this ones makes hide tip only when mouseleave it
			//IF fixed=true
			el.domObject.addEvents({
				'mouseenter': function(event){
					el.state = 'mouseenter';
				}.bind(this),
				
				'mouseleave': function(event){
					el.state = 'mouseleave';
					this.end(el);
				}.bind(this)
			});
			
			this.domObject = el.domObject;
			el.removeAttribute('title');
		}
		
		if (el.domObject) {

			if (this.options.showOnClick) {
				el.addEvent('click', function(event){
					this.start(el);
					if (!this.options.fixed) this.locate(event,el);
					else this.position(el);
				}.bindWithEvent(this));
			}
	
			if (this.options.showOnMouseEnter) {
				el.addEvent('mouseenter', function(event){
					this.start(el);
					if (!this.options.fixed) this.locate(event,el);
					else this.position(el);
				}.bind(this));
			}
			
			if (!this.options.fixed) el.addEvent('mousemove', this.locate.create({
													'arguments': [el],
													'bind': this,
													'event': Event
													}));
			
//			var end = this.end.bind(this);
			el.addEvent('mouseleave', this.end.create({
										'arguments': [el],
										'bind': this
										}));
			el.addEvent('trash', this.end.create({
										'arguments': [el],
										'bind': this
										}));
		}
	},

	start: function(el){
		if (el.domObject) {
			//pick up saved domObject element
			this.domObject = el.domObject;

			$clear(el.timer);
			
			//settting initial state of tip
				el.state = 'mouseleave';
			
			el.timer = this.show.delay(this.options.showDelay, this, el);
		}
	},
	
	end: function(el){
		$clear(el.timer);
		el.timer = this.hide.delay(this.options.hideDelay, this, el);
	},

	position: function(element){
		var pos = element.getPosition();

		element.domObject.setStyles({
			'left': pos.x + this.options.offsets.x+'px',
			'top': pos.y + this.options.offsets.y+'px'
		});
	},

	locate: function(event,el){
		var win = {'x': window.getWidth(), 'y': window.getHeight()};
		var scroll = {'x': window.getScrollLeft(), 'y': window.getScrollTop()};
		var tip = {'x': el.domObject.offsetWidth, 'y': el.domObject.offsetHeight};
		var prop = {'x': 'left', 'y': 'top'};
		for (var z in prop){
			var pos = event.page[z] + this.options.offsets[z];
			if ((pos + tip[z] - scroll[z]) > win[z]) pos = event.page[z] - this.options.offsets[z] - tip[z];
			el.domObject.setStyle(prop[z], pos);
		};
	},

	show: function(el){
		if (this.options.timeout) el.timer = this.hide.delay(this.options.timeout, this);
		this.fireEvent('onShow', [el.domObject]);
	},

	hide: function(el){
		//if fixed, then it only hide when mouse leave toolTip (the tip itself)
		if ((el.state == 'mouseleave') || (!this.options.fixed))
			this.fireEvent('onHide', [el.domObject]);
	}
});

mooTips.implement(new Events, new Options);
