/******************************************************/
/* Name: Hints
/* Info: Hints class
/* Version: 0.7.8 b20060928 beta [with Aculo's prototype & effects]
/* Author: Adam Kusmierz vel Raistlin Majere
/* E-mail: adam@kusmierz.be / kusmierz@o2.pl
/* WWW: kusmierz.be
/* GG.no: 1294390
/******************************************************/

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
/* !!! do NOT edit anything here !!! */
/* !!!     see documentation     !!! */
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */

function hints(hint_name, hint_options) {
	//creating general object obj
	var obj = new Object();
	//setting hint_name
	obj.now = new Date();
	if(hint_name == undefined) hint_name = obj.now.getTime();
	obj.hint_name = 'hint_' + hint_name;
	
	obj.posx = 0;
	obj.posy = 0;
	obj.dimension = new Object();
	obj.visible = false;
	obj.node = null;
	obj.node_position = new Array(0, 0);
	obj.myhint = null;
	obj.fading = null;
	obj.apearing = null;
	obj.time_show = 0;
	obj.time_hover = 0;
	obj.time_hide = 0;
	obj.time_out = 0;
	obj.ajax_cache = new Array();
	obj.hid = null;
	obj.sid = null;
	obj.pid = null
	
	//settings
	obj.config = new Array();
	//obj.config.parameter = value;
	//ie. obj.config.parameter = new array(value);
	with(obj) {
		//default options
		config['alpha'] = 1; //hint with alpha (0..1)
		config['animation'] = false; //for appear and fade
		config['animation-delay_cancel'] = 0; //do not animate appear, if hint was dissapearded x sec. ago
		config['animation-time_in'] = .3; //appear time (works only if animation is true)
		config['animation-time_out'] = .3; //fade time (works only if animation is true)
		config['class'] = 'hint'; //hint's class
		config['content-ajax_cache'] = true;
		config['content-default_ajaxerr'] = 'Error while trying to load url [[$$$]]';
		config['content-default_ajax404'] = 'Error 404: location "[$$$]" was not found.';
		config['content-default_ajaxloading'] = 'Loading...';
		config['content-default'] = 'Default content';
		config['content-escape_html'] = false; //do not use both together
		config['content-strip_tags'] = false; //do not use both together
		config['content-template'] = '[$$$]'; //template of hint, ie "My hint content: [$$$]. End of my hint content."
		config['hide-event'] = new Array('mouseout', 'click'); //node [mouseout, click, blur]
		config['hide-on_document_click'] = true //hide hint after click anywhere on document
		config['hide-on_hint_click'] = false; //hide hint after click anywhere on this hint
		config['hide-on_hint_mouseout'] = true; //keep hint, if mouse pointer is over hint
		config['hide-delay'] = 0; //hide hint after x sec. after hide-event
		config['move'] = true; //hint follows mouse
		config['move-on_hide'] = false; //follow mouse when hint is fading/hiding (works only if 'move' is true and 'animation' false)
		config['show-delay'] = 0; //show after x second after show action (ie. onmouseover)
		config['show-delay_cancel'] = 0; //show immeditialy if last hint was hide x sec ago. Works only if show-delay > 0.
		//delay_show_mousemove
		config['show-over_screen'] = 1; //[0 - stop move hint if it's out of screen, 1 -  show on other side mouse pointer]
		config['show-position'] = 'mouse_pointer'; //works only if 'move' false ['mouse_pointer' - under mouse pointer, 'top/bottom_left/right-body/node/window' - position of top left hint's corner in realtion with body/node/window, ie bottom_right-node, 'center-body/node/window']

		//jeśli jest myszka nad A i przechodzi nad B, to animuj przejscie (opcja)
		//jesli ruszono myszka, to nie pokazuj (opcja) [resetuj timer]
		//opcja wylaczenia chwilowego hintow (np. w konfiguracji)
		//show_on (?!) copy func...
		//do hinta - jeśli jest na nim mycha, to nie wykonuj/zatrzymaj chowanie dymka... jeśli już się chowa, to olej to. osobne delay? inne eventy?
		//w show i hide .title. jeśli usunie, to pamiętaj o uzupelnieniu z powrotem przy hide()
		//daj hint_dimension jako wlasciwosc globalna
		//sprawdz onclicka w ie
		//przejrzyj kod od poczatku do konca jeszcze raz!!!
	}
	
	//setting up options from second function's parameter
	for(a in hint_options)
		obj.config[a] = hint_options[a];
	//check settings
	if(obj.config['move-on_hide'] && (!obj.config['animation'] || !obj.config['move']))
		obj.config['move-on_hide'] = false;
	if(obj.config['content-template'].search('\\[\\$\\$\\$\\]') == -1)
		obj.config['content-template'] = '[$$$]';
	if(obj.config['move'] && obj.config['show-position'] != 'mouse_pointer')
		obj.config['show-position'] = 'mouse_pointer';
	obj.config['animation-delay_cancel'] *= 1000;
	obj.config['show-delay'] *= 1000;
	if(obj.config['show-delay'])
		obj.config['show-delay_cancel'] *= 1000;
	else
		obj.config['show-delay_cancel'] = 0;
	obj.config['hide-delay'] *= 1000;
	if(obj.config['content-strip_tags'] && obj.config['content-escape_html']) {
		obj.config['content-strip_tags'] = false;
		obj.config['content-escape_html'] = false;
	}
	obj.config['hide-event'] = obj.config['hide-event'].findAll(function(element) {
		return (['mouseout', 'click', 'blur'].indexOf(element) + 1);
	});
	
	//lets start!
	//preparing div-block function
	function creatediv(hname, hclass) {
		if(!$(hint_name)) {
			obj.myhint = document.createElement('div');
			obj.myhint.id = hname;
			obj.myhint.className = hclass;
			obj.myhint.style.display = 'none';
			document.body.appendChild(obj.myhint);
		} else if(!obj.myhint)
			obj.myhint = $(hint_name);
		obj.myhint.innerHTML = '';
	}
	
	function move(ignore) {
		if(obj.visible || ignore)
			correct_position([obj.posx, obj.posy], [15, 15]);
	}
	
	function hide_cancel() {
		if(obj.hid) {
			window.clearInterval(obj.hid);
			obj.hid = null;
		}
		obj.time_out = 0;
		Event.stopObserving(obj.myhint, 'mouseover', hide_cancel, false);
		Event.observe(obj.myhint, 'mouseout', obj.hide, false);
	}
	
	function hide(hide_hint) {
		var now = new Date();
		
		//ie fix (click)
		if(now.getTime() - obj.time_show <= 10)
			return false;
		
		if(obj.hid) {
			window.clearInterval(obj.hid);
			obj.hid = null;
		}
		
		if(obj.pid) {
			window.clearInterval(obj.pid);
			obj.pid = null;
		}
		
		obj.time_out = 0;
		obj.dimension.width = obj.dimension.height = 0;
		//cancel appearing...
		if(obj.appearing) {
			obj.appearing.cancel();
			obj.appearing = null;
		}
		
//		if(obj.config['hide-on_hint_mouseout'])
//			Event.stopObserving(obj.myhint, 'mouseout', obj.hide, false);
		
		obj.time_hover = 0;
		obj.time_show = 0;
		obj.node_position.clear();
		
		if(obj.config['move'])
			Event.stopObserving(obj.node, 'mousemove', move, false);
		obj.config['hide-event'].each(function(value, index) {
			Event.stopObserving(obj.node, value, obj.hide, false);
		});
		if(obj.config['hide-on_document_click'])
			Event.stopObserving(document, 'click', hide, false);
		
		if(obj.config['hide-on_hint_click'])
			Event.stopObserving(obj.myhint, 'click', hide, false);
			
		if(obj.config['animation'] && hide_hint) {
			obj.fading = Effect.Fade(obj.myhint, {duration: obj.config['animation-time_out'], afterFinish: hide_animated});
		} else if(hide_hint) {
			obj.myhint.style.display = 'none';
			obj.visible = false;
			obj.node = null;
		}
		now = new Date();
		obj.time_hide = now.getTime();
		return true;
	}
	
	obj.hide = function() {
		if(obj.visible) {
			var now = new Date();
			//delay hiding
			if(obj.config['hide-delay']) {
				if(!obj.time_out)
					obj.time_out = now.getTime();
				if(( (now.getTime() - obj.time_out) < obj.config['hide-delay'])) {
					if(!obj.hid)
						obj.hid = window.setInterval(function() {
							obj.hide(true);
						}, obj.config['hide-delay']/10);
					return false;
				}
			}
			hide(true);
		} else return false;
	}
	
	function set_hintcontent(content, template){
		if(obj.config['content-strip_tags'])
			content = content.stripTags();
		if(obj.config['content-escape_html'])
			content = content.escapeHTML();
		if(template == '[$$$]')
			return content;
		else
			return template.replace('\[\$\$\$\]', content);
	}
	
	function hide_animated() {
		if(obj.visible) {
			if(obj.config['move-on_hide'])
				Event.stopObserving(document, 'mousemove', move, false);
			obj.node = null;
			obj.myhint.style.display = 'none';
			obj.visible = false;
			obj.fading = null;
			obj.time_hide = (new Date).getTime();
			return true;
		} else return false;
	}
	
	function delayshow_mouseout() {
		obj.config['hide-event'].each(function(value, index) {
			Event.stopObserving(obj.node, value, delayshow_mouseout, false);
		});
		window.clearInterval(obj.sid);
		obj.node = null;
		obj.sid = null;
		obj.time_hover = 0;
	}
	
	obj.show = function(node, hint_content, url) {
		var now = new Date();
		obj.node = node;
		obj.time_out = 0;
		if(obj.config['show-delay'] && !obj.visible && ( (now.getTime() - obj.time_hide) > (obj.config['show-delay_cancel']) )) {
			if(!obj.time_hover) {
				obj.time_hover = now.getTime();
				window.clearInterval(obj.sid);
				obj.sid = null;
			}
			if(( (now.getTime() - obj.time_hover) < obj.config['show-delay'])) {
				if(!obj.sid) {
					obj.sid = window.setInterval(function() {
						obj.show(node, hint_content, url);
					}, obj.config['show-delay']/10);
					obj.config['hide-event'].each(function(value, index) {
						Event.observe(node, value, delayshow_mouseout, false);
					});
				}
				return false;
			}
		}
		
		if(obj.sid)
			delayshow_mouseout();
		
		//back to the life!
		if(obj.visible && obj.fading){
			obj.fading.cancel();
			obj.fading = null;
			hide(false);
		}
		
		obj.node = node;
		
		if(!obj.myhint)
			creatediv(obj.hint_name, obj.config['class']);
		
		obj.time_show = now.getTime();
		obj.config['hide-event'].each(function(value, index) {
			Event.observe(node, value, obj.hide, false);
		});
		
		//animation
		if(obj.config['move-on_hide'] && !obj.visible)
			Event.observe(document, 'mousemove', move, false);
		
		if(obj.config['hide-on_document_click'])
			Event.observe(document, 'click', hide, false);
		
		if(obj.config['hide-on_hint_click'])
			Event.observe(obj.myhint, 'click', hide, false);
		
//		if(obj.config['hide-on_hint_mouseout'])
//			Event.observe(obj.myhint, 'mouseover', hide_cancel, false);
		
		//content
		if(url) {
			if(!hint_content || hint_content == undefined)
				hint_content = obj.config['content-default_ajaxloading'];
			obj.myhint.innerHTML = set_hintcontent(hint_content, obj.config['content-template']);
			var opt = {
				method: 'get',
				// Handle successful response
				onSuccess: function(t) {
					obj.myhint.innerHTML = set_hintcontent(t.responseText, obj.config['content-template']);
					if(obj.config['content-ajax_cache']) obj.ajax_cache[escape(url)] = t.responseText;
					obj.myhint.style.top = '0px';
					obj.myhint.style.left = '0px';
					obj.dimension = Element.getDimensions(obj.myhint);
					if(obj.config['move'])
						move();
					else {
						set_position();
						correct_position([0, 0], [0, 0]);
					}
				},
				// Handle 404
				on404: function(t) {
					obj.myhint.innerHTML = set_hintcontent(t.statusText, obj.config['content-default_ajax404']);
					obj.myhint.style.top = '0px';
					obj.myhint.style.left = '0px';
					obj.dimension = Element.getDimensions(obj.myhint);
					if(obj.config['move'])
						move();
					else {
						set_position();
						correct_position([0, 0], [0, 0]);
					}
				},
				// Handle other errors
				onFailure: function(t) {
					obj.myhint.innerHTML = set_hintcontent(t.status + ' - ' + t.statusText, obj.config['content-default_ajaxerr']);
					obj.myhint.style.top = '0px';
					obj.myhint.style.left = '0px';
					obj.dimension = Element.getDimensions(obj.myhint);
					if(obj.config['move'])
						move();
					else {
						set_position();
						correct_position([0, 0], [0, 0]);
					}
				},
				asynchronous: true,
				contentType: 'text/html'
			};

			if(!obj.config['content-ajax_cache']) {
				opt['requestHeaders'] = ['cache-request-directive', 'no-cache', 'Pragma', 'no-cache', 'cache-response-directive', 'no-cache'];
				opt['parameters'] = 'uniq_id=' + now.getTime();
			}
			
			if(obj.ajax_cache[escape(url)] && obj.config['content-ajax_cache'])
				obj.myhint.innerHTML = set_hintcontent(obj.ajax_cache[escape(url)], obj.config['content-template']);
			else
				new Ajax.Request(url, opt);
		} else if(!hint_content) {
			if(obj.node.alt) hint_content = obj.node.alt;
			else if(obj.node.title) hint_content = obj.node.title;
			else hint_content = obj.config['content-default'];
			obj.myhint.innerHTML = set_hintcontent(hint_content, obj.config['content-template']);
		} else
			obj.myhint.innerHTML = set_hintcontent(hint_content, obj.config['content-template']);
		
		if(obj.node.title)
			obj.node.title = '';
		var prev_display = Element.getStyle(obj.myhint, 'display');
		obj.myhint.style.display = 'block';
		obj.myhint.style.top = '0px';
		obj.myhint.style.left = '0px';
		obj.dimension = Element.getDimensions(obj.myhint);
		//start position
		if(obj.config['move']) {
			Event.observe(obj.node, 'mousemove', move, false);
			move(true);
		} else {
			set_position();
			correct_position([0, 0], [0, 0]);
		}
		obj.myhint.style.display = prev_display;
		
		now = new Date();
		//show hint
		if(obj.config['animation'] && now.getTime() - obj.time_hide > obj.config['animation-delay_cancel'])
			obj.appearing = Effect.Appear(obj.myhint, {to: obj.config['alpha'], duration: obj.config['animation-time_in']});
		else {
			obj.myhint.style.display = 'block';
			if(obj.config['alpha'] < 1)
				new Effect.Opacity(obj.myhint, {duration: 0, to: obj.config['alpha']});
		}
		
		if(!obj.config['move'] && obj.config['show-position'] != 'mouse_pointer' && !obj.pid)
			obj.pid = window.setInterval(function() {
				//set_position();
				//correct_position([0, 0], [0, 0]);
			}, 500);
			//zmien na onscroll, czy cos... wywal setinterval!
		
		obj.time_hide = 0;
		obj.visible = true;
	}
	
	function set_position() {
		//get absolute node position
		obj.node_position = Position.positionedOffset(obj.node);
		var element_relative = new Object();
		switch(obj.config['show-position'].split('-')[1]) {
			default: //node
				element_relative.top = obj.node_position[1];
				element_relative.left = obj.node_position[0];
				element_relative.width = obj.node.offsetWidth;
				element_relative.height = obj.node.offsetHeight;
			break;
			case 'body':
				element_relative.top = 0;
				element_relative.left = 0;
				element_relative.width = Element.getDimensions(document.body).width - obj.dimension['width'];
				element_relative.height = Element.getDimensions(document.body).height - obj.dimension['height'];
			break
			case 'window':
				var docsize = getDocSize();
				docsize.width += getScrollXY().x;
				docsize.height += getScrollXY().y;
				element_relative.top = getScrollXY().y;
				element_relative.left = getScrollXY().x;
				element_relative.width = docsize.width - obj.dimension['width'];
				element_relative.height = docsize.height - obj.dimension['height'];
			break
		}
		//set position
		switch (obj.config['show-position'].split('-')[0]) {
			default: //under mouse pointer
				obj.myhint.style.top = obj.posy + 5 + 'px';
				obj.myhint.style.left = obj.posx+ 5 + 'px';
				break;
			case 'top_left':
				obj.myhint.style.top = element_relative.top + 'px';
				obj.myhint.style.left = element_relative.left + 'px';
				break;
			case 'top_right':
				obj.myhint.style.top = element_relative.top + 'px';
				obj.myhint.style.left = element_relative.left + element_relative.width + 'px';
				break;
			case 'bottom_left':
				obj.myhint.style.top = element_relative.top + element_relative.height + 'px';
				obj.myhint.style.left = element_relative.left + 'px';
				break;
			case 'bottom_right':
				obj.myhint.style.top = element_relative.top + element_relative.height + 'px';
				obj.myhint.style.left = element_relative.left + element_relative.width + 'px';
				break;
			case 'center':
				obj.myhint.style.top = element_relative.top + (element_relative.height/2) + 'px';
				obj.myhint.style.left = element_relative.left + (element_relative.width/2) + 'px';
				break;
		}
	}
	
	function getScrollXY() {
		//from http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
		var scrOfX = 0, scrOfY = 0;
		if(typeof(window.pageYOffset) == 'number') {
			scrOfY = window.pageYOffset;
			scrOfX = window.pageXOffset;
		} else if(document.body && (document.body.scrollLeft || document.body.scrollTop)) {
			scrOfY = document.body.scrollTop;
			scrOfX = document.body.scrollLeft;
		} else if(document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
			scrOfY = document.documentElement.scrollTop;
			scrOfX = document.documentElement.scrollLeft;
		}
		return new Object({x: scrOfX, y: scrOfY});
	}
	
	function getDocSize() {
		//from http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
		//changed for Opera 9
		var doc_width = 0, doc_height = 0;
		if(document.documentElement && document.documentElement.clientWidth)
			doc_width = document.documentElement.clientWidth;
		else if(document.body && document.body.clientWidth)
			doc_width = document.body.clientWidth;
		else if(typeof(window.innerWidth) == 'number')
			doc_width = window.innerWidth;
		
		if(typeof(window.innerWidth) == 'number')
			doc_height = window.innerHeight;
		else if(document.documentElement && document.documentElement.clientHeight)
			doc_height = document.documentElement.clientHeight;
		else if(document.body && document.body.clientHeight)
			doc_height = document.body.clientHeight;
		
		return new Object({width: doc_width, height: doc_height});
	}
	
	function correct_position(hint_pos, space) {
		//hint_pos = [x, y]
		//space = [x, y]
		
		var docsize = getDocSize();
		docsize.width += getScrollXY().x;
		docsize.height += getScrollXY().y;
		
		if(hint_pos[0] == 0 && hint_pos[1] == 0)
			hint_pos = Position.positionedOffset(obj.myhint);
		
		if(obj.config['show-over_screen']) {
			if(hint_pos[0] + space[0] + obj.dimension.width > docsize.width)
				obj.myhint.style.left = hint_pos[0] - obj.dimension.width + 'px';
			else
				obj.myhint.style.left = hint_pos[0] + space[0] + 'px';
			
			if(hint_pos[1] + space[1] + obj.dimension.height > docsize.height)
				obj.myhint.style.top = hint_pos[1] - obj.dimension.height + 'px';
			else
				obj.myhint.style.top = hint_pos[1] + space[1] + 'px';
			//what if top or/and left corner is out of screen?
		} else {
			if(hint_pos[0] + space[0] + obj.dimension.width > docsize.width)
				obj.myhint.style.left = docsize.width - obj.dimension.width + 'px';
			else
				obj.myhint.style.left = hint_pos[0] + space[0] + 'px';
			
			if(hint_pos[1] + space[1] + obj.dimension.height > docsize.height)
				obj.myhint.style.top = docsize.height - obj.dimension.height + 'px';
			else
				obj.myhint.style.top = hint_pos[1] + space[1] + 'px';
		}
	}
	
	function showPosition(e) {
		obj.posx = Event.pointerX(e);
		obj.posy = Event.pointerY(e);
	}
	
	Event.observe(document, 'mousemove', showPosition, false);
	return obj;
}