/*
;(C) picturemaxx AG, München, 2007
;------------------------------------------------------------------------
;$RCSfile: gui.js,v $
;$Revision: 1.5 $
;$Author: mzelend $
;$Date: 2010/04/27 07:49:36 $
;$Info: main gui jscripts $
;------------------------------------------------------------------------
*/

/**
 * manager class for tooltips
 */
function class_tooltip_manager() {
	// private
	this.tooltips = new Object();
	this.fades = false;
	this.visible = false;
	this.tooltipcounter = 0;
	this.hidetimeout = false;
	this.showtimeout = false;
	this.mposx = 0;
	this.mposy = 0;
	this.tooltipid = '';
	this.enabled = true;
	/**
	 * adds a tooltip to a html item
	 * @param	htmlid	string	the id of html element
	 * @param	text		string	html to be shown in tooltip, if empty, tooltip will be removed
	 */
	this.add = function(htmlid, text){
		// maybe dom instance with id has changed in background, so allways remove old handler and add new ones
		this.remove(htmlid);
		if(text){
			$('#'+htmlid).mouseover(this.event_over).mouseout(this.event_out).mousemove(this.event_move);
			this.tooltips[htmlid] = text;
		}
	}

	/**
	 * removes a tooltip from a html item
	 * @param	htmlid	string	the id of html element
	 */
	this.remove = function(htmlid){
		if(this.tooltips[htmlid]){
			this.tooltips[htmlid] = '';
			$('#'+htmlid).unbind('mouseover', this.event_over).unbind('mouseout', this.event_out).unbind('mousemove', this.event_move);
		}
	}

	/**
	 * mouseover event handler, filters event bubbling effects and calls real event handler
	 */
	this.event_over = function(event){
		// Check if mouse(over|out) are still within the same parent element
		var p = event.relatedTarget;
		while ( p && p != this ) try { p = p.parentNode; } catch(e) { p = this; };
		// If we actually just moused on to a sub-element, ignore it
		if ( p == this ) return false;
		tooltip_manager.over(event, this);
	}

	/**
	 * mouseover event handler
	 */
	this.over = function(event, domobject){
		if(!this.enabled) return;
		// increase tooltip id, will be used later to check in timer event
		this.tooltipcounter++;
		// store current mouse position
		this.mposx = event.pageX;
		this.mposy = event.pageY;
		this.tooltipid = domobject.id;

		window.setTimeout('tooltip_manager.showtimer(' + this.tooltipcounter + ')', 1000);
	}

	/**
	 * shows tooltip
	 */
	this.show = function(){
		if(!this.enabled) return;
		var tooltip = $('#thetooltipdiv');
		if(tooltip.length==0){
			// there is no tooltip div yet, create one
			tooltip = $('<div id="thetooltipdiv" class="widget_tooltip"><table border="0" cellspacing="0" cellpadding="0"><tr><td class="widget_tooltip_c" id="thetooltipdivcontent"></td><td class="widget_tooltip_r pngtrans"><img width="1" height="1" border="0" src="res/icon_blind.gif"/></td></tr><tr><td class="widget_tooltip_b pngtrans"><img width="1" height="1" border="0" src="res/icon_blind.gif"/></td><td class="widget_tooltip_br pngtrans"><img width="1" height="1" border="0" src="res/icon_blind.gif"/></td></tr></table></div>');
			tooltip.appendTo('body').hide();
		}

		tooltip.find('td.widget_tooltip_c').empty().append(this.tooltips[this.tooltipid]);
		var width = tooltip.width();
		var height = tooltip.height();
		var posy = this.mposy+10;
		var posx = this.mposx+5;
		if(posx + width > window.innerWidth) posx = window.innerWidth - width;
		if(posy + height > window.innerHeight) posy = window.innerHeight - height;
		tooltip.css({top: posy, left: posx});
		tooltip.fadeIn("medium", function(){
			tooltip_manager.fades = false;
			tooltip_manager.visible = true;
		});
	}

	/**
	 * timer event after mouse enter
	 */
	this.showtimer = function(tooltipcounter){
		if(tooltipcounter == this.tooltipcounter && this.enabled){
			this.fades = true;
			this.show();
		}
	}

	/**
	 * mousemove event handler, filters event bubbling effects and calls real event handler
	 */
	this.event_move = function(event){
		tooltip_manager.move(event, this);
	}

	/**
	 * mousemove event handler
	 */
	this.move = function(event, domobject){
		if(!this.visible){
			// store current mouse position
			this.mposx = event.pageX;
			this.mposy = event.pageY;
		}
		if(this.visible && !this.fades && !this.hidetimeout){
			if(Math.abs(this.mposx - event.pageX) + Math.abs(this.mposy - event.pageY) > 10){
				this.hidetimeout = true;
				window.setTimeout('tooltip_manager.hidetimer(' + this.tooltipcounter + ')', 2000);
			}
		}
	}

	/**
	 * mouseout event handler, filters event bubbling effects and calls real event handler
	 */
	this.event_out = function(event){
		// Check if mouse(over|out) are still within the same parent element
		var p = event.relatedTarget;
		while ( p && p != this ) try { p = p.parentNode; } catch(e) { p = this; };
		// If we actually just moused on to a sub-element, ignore it
		if ( p == this ) return false;
		tooltip_manager.out(event, this);
	}

	/**
	 * mouseout event handler
	 */
	this.out = function(event, domobject){
		// increase tooltip id, will be used later to check in timer event
		this.tooltipcounter++;
		this.hide();
	}

	/**
	 * hides tooltip
	 */
	this.hide = function(tooltipcounter){
		$('#thetooltipdiv').hide();
		this.fades = false;
		this.visible = false;
		this.hidetimeout = false;
	}

	/**
	 * timer event after mouse move
	 */
	this.hidetimer = function(tooltipcounter){
		if(tooltipcounter == this.tooltipcounter){
			this.hide();
		}
	}

	/**
	 * jquery plugin function to add tooltips based on tooltip attribute
	 */
	$.fn.add_tooltips = function(){
		$(this).find('[tooltip]').each(function(){
			var elem = $(this);
			tooltip_manager.add(elem.attr('id'), elem.attr('tooltip'));
			elem.removeAttr('tooltip');
		});
	}
}

tooltip_manager = new class_tooltip_manager();

/**
 * manager class for ajax requests
 *
 * the class will take care of response content type and page context for result (dependent on result headers)
 */
function class_request_manager() {
	/**
	 * request queue (FIFO)
	 */
	this.queue = new Array();
	/**
	 * starts a ajax call
	 */
	this.post = function(url, parameters, asynccall){
		if((typeof asynccall) == 'undefined') asynccall = false;

		if(asynccall){
			request_manager.start({url: url, parameters: parameters, asynccall: asynccall});
		} else {
			request_manager.queue.unshift({url: url, parameters: parameters, asynccall: asynccall});
			if(request_manager.queue.length == 1){
				// no request pending, start
				request_manager.start(this.queue[this.queue.length-1]);
			}
		}
	}

	/**
	 * starts request
	 */
	this.start = function(request){
		var url = request.url;
		var parameters = request.parameters;
		var asynccall = request.asynccall;

		tooltip_manager.enabled = false;
		if(url.indexOf('?') > 0){
			url += '&AJAX=1';
		} else {
			url += '?AJAX=1';
		}
		$('#theajaxdiv').html('');
		$('#theajaxloader').show();
		window.setTimeout(function(){
			jQuery.ajax({
				type: "POST",
				url: url,
				data: parameters,
				success: request_manager.callback,
				beforeSend: request_manager.precallback,
				error: request_manager.errorcallback,
				complete: asynccall ? request_manager.completecallback_async : request_manager.completecallback,
				dataType: ''
			});
		}, 1);
	}

	/**
	 * modal window stack
	 */
	this.modal_stack = new Array();

	/**
	 * module layer stack
	 */
	this.layer_stack = new Array();

	/**
	 * submits a form
	 */
	this.submit = function(form){
		// save all data in tiny mces
		if(typeof tinyMCE !== 'undefined') tinyMCE.triggerSave();
		// select all items in a input_select_list widget
		$(form).find('select.input_select_list').each(function(){
			for(i = 0; i < this.length; i++) this.options[i].selected = true;
		});
		var series = $(form).find('select.input_series_list');
		series.each(function(){
			series.cursel = 0;
			series.attr("multiple", "1");
			for(i = 0; i < this.length; i++){
				if(this.options[i].selected) series.cursel = i;
				this.options[i].selected = true;
			}
		});
		var data = $(form).serializeArray();
		this.post(form.action, data);
		series.each(function(){
			series.attr("multiple", "");
			if(series.get(0).options.length) series.get(0).options[series.cursel].selected = true;
		});
	}

	/**
	 * callback before request is sent
	 */
	this.precallback = function(r){
		this.request = r;
	}

	/**
	 * callback when request failed
	 */
	this.errorcallback = function(r){
		$('#theajaxloader').hide();

		// remove last request and start next
		request_manager.queue.pop();
		if(request_manager.queue.length > 0){
			request_manager.start(request_manager.queue[request_manager.queue.length-1]);
		}
		// TODO make error handling or retry
	}

	/**
	 * callback when request is finished
	 */
	this.callback = function(data){
		if(!$) return;
		$('#theajaxloader').hide();
		// response format handling
		var close = this.request.getResponseHeader('rh-close-modal');
		if(close){
			// close all modal layers up to given layer id
			var modalid = this.request.getResponseHeader('rh-close-modalid');
			var stop = false;
			while(request_manager.modal_stack.length > 0 && !stop){
				var nummod = request_manager.modal_stack.length;
				var lastid = request_manager.modal_stack.pop();
				if(modalid == lastid) stop = true;
				$.modal.close();
				$.modal.remove_layer();
				var remelem = $('#themodaldiv'+nummod);
				request_manager.unload(remelem);
				remelem.remove();

				// no modal layer is left, enable hotkeys again
				if(request_manager.modal_stack.length == 0) $('#maincontents').attr('blockhotkeys', '0');
			}
		}
		close = this.request.getResponseHeader('rh-close-layer');
		if(close){
			// close all module layers up to given layer id
			var modalid = this.request.getResponseHeader('rh-close-layerid');
			var stop = false;
			while(request_manager.layer_stack.length > 0 && !stop){
				var dellayer = $('#themodule' + request_manager.modal_stack.length);
				request_manager.unload(dellayer);
				dellayer.remove();

				var lastid = request_manager.layer_stack.pop();
				if(modalid == lastid[0]) stop = true;
			}
			var layersel = '#themodule';
			if(request_manager.modal_stack.length > 0) layersel += request_manager.modal_stack.length;
			var showlayer = $(layersel);
			showlayer.show();
			showlayer.find('div.restore_scroll_position').each(function(){
				$(this).scrollTop($(this).data('scrollPosOrg'));
			});
		}

		var action = this.request.getResponseHeader('rh-action');
		switch(action){
			case 'rh/exec_script':
				// we got javascript, evaluate
				$('#theajaxdiv').html('<pre>' + data.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;") + '</pre>');
				jQuery.globalEval(data);
				break;
			case 'rh/replace':
				// we got html, replace div contents
				var divid = this.request.getResponseHeader('rh-html-id');
				var div = $('#'+divid);
				if(divid == 'themodule' && request_manager.layer_stack.length > 0){
					// layers are visible, close them
					for(i = 0; i < request_manager.layer_stack.length; i++){
						var remelem = $('#themodule'+i);
						request_manager.unload(remelem);
						remelem.remove();
					}
					request_manager.layer_stack = new Array();
					div.empty().show();
				}
				// check if there are unload functions for current html id
				request_manager.unload(div);

				if($('#main_debugarea').css('display') != 'none'){
					$('#theajaxdiv').html('<pre>' + data.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;") + '</pre>');
				}

				// now replace contents
				var measure = '<br>size ' + data.length + ' ';
				var dt = new Date();
				div.html(data);
				if(div.parent().is('.jScrollPaneContainer')) div.jScrollPane();
				var ndt = new Date(); measure += ' insert ' + (ndt.getTime() - dt.getTime()) / 1000.0; dt = ndt;
				if($('#main_debugarea').css('display') != 'none'){
					$('#theajaxdiv').append(measure);
				}
				break;
			case 'rh/layer':
				var layerid = this.request.getResponseHeader('rh-layerid');
				var layernum = request_manager.modal_stack.length;
				if(request_manager.modal_stack.length == 0 || request_manager.modal_stack[request_manager.modal_stack.length-1] != layerid){
					var layersel = '#themodule';
					if(request_manager.modal_stack.length > 0) layersel += request_manager.modal_stack.length;
					var hidelayer = $(layersel);
					// store scroll position to restore it when layer will be visible again
					hidelayer.find('div.restore_scroll_position').each(function(){
						$(this).data('scrollPosOrg', $(this).scrollTop());
					});
					hidelayer.hide();
					request_manager.layer_stack.push(layerid);
				}
				var layersel = '#themodule' + request_manager.modal_stack.length;
				var layer = $(layersel);
				if(layer.length == 0){
					layer = $('<div id="themodule' + layernum + '"/>');
					layer.insertAfter('#themodule');
				} else {
					// check if there are unload functions for current html id
					request_manager.unload(layer);
				}
				layer.html(data);
				break;
			case 'rh/modal':
				var modalid = this.request.getResponseHeader('rh-modalid');
				var nummod = request_manager.modal_stack.length;
				if(nummod == 0 || request_manager.modal_stack[nummod-1] != modalid){
					// we got a new modal id, so new modal layer has to be created
					$.modal.new_layer();
					request_manager.modal_stack.push(modalid);
					nummod++;
				}

				// block hotkeys in main page when modal windows are visible
				$('#maincontents').attr('blockhotkeys', '1');
				// open contents as modal window
				// check if already modal window exists
				var modal = $('#themodaldiv'+nummod);
				if(modal.length > 0){
					modal.empty().append(data);
					modal.modal({close: false, overlayId: 'modal_overlay' + nummod, containerId: 'modal_container' + nummod, overlayCss: {zIndex: 100 + 2*nummod}, containerCss: {zIndex: 101 + 2*nummod}});
				} else {
					modal = $('<div id="themodaldiv'+nummod+'"></div>');
					$('body').append(modal);
					modal.append(data);
					modal.modal({close: false, overlayId: 'modal_overlay' + nummod, containerId: 'modal_container' + nummod, overlayCss: {zIndex: 100 + 2*nummod}, containerCss: {zIndex: 101 + 2*nummod}});
				}
				$('#theajaxdiv').html('<pre>' + data.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;") + '</pre>');
				break;
			case 'rh/redirect':
				document.location = this.request.getResponseHeader('rh-location');
				break;
			case 'rh/ignore':
				// ignore response
				break;
			default:
				// append contents
				$('body').after(data);
				break;
		}
		tooltip_manager.enabled = true;
		tooltip_manager.hide();

		// ajax history handling
      // has to be at end of function, execution stops in safari after historySet
      /*
      TODO history
		var history = this.request.getResponseHeader('rh-history');
		if(history){
			$.historySet(history);
		}
		*/
	}

	/**
	 * final callback if request is finished
	 */
	this.completecallback = function(){
		// remove last request and start next
		request_manager.queue.pop();
		if(request_manager.queue.length > 0){
			request_manager.start(request_manager.queue[request_manager.queue.length-1]);
		}
	}

	/**
	 * final callback if request is finished - async requests
	 */
	this.completecallback_async = function(){
	}

	/**
	 * checks for registered unload handlers for given jquery object and removes dom from html
	 * @see widget_page::begin_script and widget_page::script_block
	 */
	this.unload = function(element){
		placeholder = element.find('div.bsunloadmarker').each(function(){
			if(this.bsunload) this.bsunload();
		});
	}
}

request_manager = new class_request_manager();

// helper function for smaller javascript links in cms menu
function request_post(url, parameters){
	if((typeof parameters) == 'undefined') parameters = [];
	request_manager.post(url, parameters);
}

/**
 * help system
 */
function class_help_manager(){
	/**
	 * current help id
	 */
	this.current_id = '';
	/**
	 * url of ajax help script
	 */
	this.url = '';
	/**
	 * visible flag
	 */
	this.visible = false;
	/**
	 * set new help id
	 */
	this.helpid = function(id){
		if(this.current_id != id){
			this.current_id = id;
			if(this.url && this.visible){
				request_manager.post(this.url, { HELPID: this.current_id });
			}
		}
	}
	this.show = function(){
		if(this.url && this.current_id){
			request_manager.post(this.url, { HELPID: this.current_id });
		}
		this.visible = true;
	}
	this.hide = function(){
		this.visible = false;
	}
}

help_manager = new class_help_manager();

/**
 * This function is called when:
 * 1. after calling $.historyInit();
 * 2. after calling $.historyLoad();
 * 3. after pushing "Go Back" button of a browser
 */
ajax_history = function(hash) {
	// only load history if hash is history item
	// TODO reactivate me
	// if(hash.substr(0, 2) == 'HI') request_manager.post(location.href.split('#')[0], {EVENT: 'HISTORY', HISTORY: hash});
}

/*
TODO history
$(document).ready(function(){
	// initialize history plugin.
	$.historyInit(ajax_history);
});
*/

// collection of vars for backstage in global namespace
$.bsvars = new Object();

// helper object and function for java based uploader, needs global function as callback
$.bsvars.uploader = new Object();
function uploaderStatusChanged(uploader){
	if(uploader.getStatus() == 0){
		request_manager.post($.bsvars.uploader.action, $.bsvars.uploader.parameters);
	}
}
