/**
 * This module deals with navigation, specifically the draggable tab menus.
 */
 
var alertStatusTimer;

// This is the definition of a CSS selector behaviour (see thirdparty/behaviour.js).
var navRules = {
	'a#show_header' : function(element) {
		element.onclick = function() {
			Element.toggle('page_nav_container');
			Element.toggle('header_container');
			if (Element.hasClassName(element, 'header_visible')) {
				Element.removeClassName(element, 'header_visible');
				Element.addClassName(element, 'header_hidden');
				element.title = $F('show_header_title');
			} else {
				Element.removeClassName(element, 'header_hidden');
				Element.addClassName(element, 'header_visible');
				element.title = $F('hide_header_title');
			}
			return false;
		};
	},
	'a.page_action_link' : function(element) {
		innerToTitle(element);
	},
	'span.page_action_image' : function(element) {
		innerToTitle(element);
	},
	'a.action_link' : function(element) {
		innerToTitle(element);
	},
	/** 
	 * When a button has this class, clicking it will refresh the current nav page, so
	 * no matter how far down they have drilled, they'll end up on the main screen for the
	 * tab.
	 */
	'button.refresh_current_page' : function(element) {
		element.onclick = function() {
			var path = buildViewCurrentPageLink() + '?p=' + currentPage;
			window.location.href = path;
			return false;
		};
	},
	/**
	 * When a button has this class, clicking it will just reoad whatever the current page is.
	 */
	'button.refresh' : function(element) {
		element.onclick = function() {
			reloadPage();
			return false;
		};
	},
	/**
	 * When a button has this class, clicking it will go back to the previous page.
	 */
	'button.back' : function(element) {
		element.onclick = function() {
			history.go(-1);
			return false;
		};
	},
	/**
	 * When a button has this class, clicking it will go to the URL in the name parameter
	 */
	'button.anchor' : function(element) {
		element.onclick = function() {
			window.location.href = element.name;
			return false;
		};
	},
	'a.back' : function(element) {
		element.onclick = function() {
			history.go(-1);
			return false;
		};
	},	
	/**
	 * Prevent a click on a tab from following an href.  This is to get around the fact
	 * that in IE, a single click and hold is treated as an onclick.  In Firefox, you have
	 * to click and release in roughly the same spot for it to be an onclick. That's the
	 * desired behavior when someone clicks and drags a tab - we don't want it to change tabs.
	 */
	'li.nav_list_item' : function(element) {
		element.onclick = function() {
			var li = findParent(element, 'li');
			if (! li) return;
			var anchor = li.getElementsByTagName('a')[0];
			if (! anchor) return;
			window.location.href = anchor.href;
			return false;
		};
		element.onmouseover = function() {
			// sometimes get errors when switching pages and mouseover event received
			try {
				if (Element.hasClassName) {	
					if (Element.hasClassName(element, 'current')) {
						Element.addClassName(element, 'current_nav_list_item_hover');
					} else {
						Element.addClassName(element, 'nav_list_item_hover');
					}
				}
			} catch (ex) {}
		};
		element.onmouseout = function() {
			try {
				if (Element.removeClassName) {
					Element.removeClassName(element, 'nav_list_item_hover');
					Element.removeClassName(element, 'current_nav_list_item_hover');
				}
			} catch (ex) {}
		};
	},
	'div.handle' : function(element) {
		/*
		var parent = findParent(element, 'li');
		var pos = Position.cumulativeOffset(parent);
		var dims = Element.getDimensions(parent);
		Element.setStyle(element, {'left':pos[0],'top':pos[1],'width':dims.width+'px'});
		*/
		element.onclick =
			function() {
				return false;
			};
		element.onmouseover = 
			function() {
				if (document.body) {
					document.body.style.cursor = 'move';
				}
				if (Element.hasClassName) {	
					var li = findParent(element, 'li');
					if (Element.hasClassName(li, 'current')) {
						Element.addClassName(li, 'current_nav_list_item_hover');
					} else {
						Element.addClassName(li, 'nav_list_item_hover');
					}
				}
			};
		
		element.onmouseout = 
			function() {
				if (document.body) {
					document.body.style.cursor = 'auto';
				}
				if (Element.removeClassName) {
					var li = findParent(element, 'li');
					Element.removeClassName(li, 'nav_list_item_hover');
					Element.removeClassName(li, 'current_nav_list_item_hover');
				}
			};
	},	
	
	'li.nav_list_item a' : function(element) {
		element.onclick = 
			function() {
				return true;
			};
	},
	'#dashboard_select_list' : function(element) {
		element.onchange = function() {
			$('dashboard_select_form').submit();
		};
	},
	'a.help_link' : function(element) {
		element.onclick = function() {
			var helpId = element.id.replace("_help", "");
			showOnlineHelp(helpId, false);
			return false;
		};
	},
	'#help_button_edit' : function(element) {
		element.onclick = function() {
			var helpId = $('helpId').value;
			showOnlineHelp(helpId, true);
			return false;
		}
	},
	'#help_button_close' : function(element) {
		element.onclick = function() {
			hideOnlineHelp();
			return false;
		};
	},
	'#help_button_save_popup' : function(element) {
		element.onclick = function() {
			submitOnlineHelp(element, true);
			return false;
		};
	},
	'#help_button_save' : function(element) {
		element.onclick = function() {
			submitOnlineHelp(element, false);
			return false;
		};
	},	

	'img.layout_image' : function(element) {
		element.onmouseover = function() {
			element.src = element.src.replace(".png","_hover.png");
		};
		element.onmouseout = function() {
			element.src = element.src.replace("_hover","");
		};
	},
	'#layout_page_action' : function(element) {
		element.onclick = 
			function() {
				var pos = Position.cumulativeOffset(element);
				var top = pos[1] + 32;
				var left = pos[0];
				Element.setStyle('layout_action_container', {'top':top,'left':left,'position':'absolute','display':'block','zIndex':200});
				showIframeBlocker('layout_action_container', true);
				var observer = 
					function(e) { 
						// Handle if they click on a link in the layout box
						var target = Event.element(e);
						if (target.tagName.toLowerCase() == 'a' && Element.hasClassName(target, 'layout_action_link')) {
							// No need to do anything here because they clicked on a layout and we're
							// going to a new page
							return false;
						}
						if (target.tagName.toLowerCase() == 'img' && Element.hasClassName(target.parentNode,'layout_action_link')) {
							return false;
						}
						
						// Any other click should hide everything
						Element.setStyle('layout_action_container', {'display':'none'});
						Event.stopObserving(document, "mousedown", observer, true); 
						hideIframeBlocker('layout_action_container',true);
						return false;
					};
					
				Event.observe(document, "mousedown", observer, true);
				
				registerKeyPress(function() {
					Element.setStyle('layout_action_container', {'display':'none'});
					Event.stopObserving(document, "mousedown", observer, true);
					hideIframeBlocker('layout_action_container',true);
				});
				return false;
			};
	},

	/*
	 * This should not be necessary.  Firefox can do all of this in css, but surprise, surprise, IE has
	 * issues when you try to do hover things with an anchor that has been image replaced.
	 */
	'#alert_indicator' : function(element) {
		element.onmouseover =
			function() {
				var pos = Position.cumulativeOffset(element);
				var tooltip = $('alert_indicator_tooltip');
				var left = pos[0] + 30;
				var top = pos[1] + 5;
				Element.setStyle(tooltip, {'display':'block', 'left':left+'px', 'top':top+'px'});
			};
		element.onmouseout =
			function() {
				if (Element.setStyle) {
					var tooltip = $('alert_indicator_tooltip');
					Element.setStyle(tooltip, {'display':'none'});
				}
			};
	},
	'span.title_only' : function(element) {
		innerToTitle();
	},
	'#hide_welcome' : function(element) {
		element.onclick = 
			function() {
				setUserOption('user.options.hide.welcome.page', element.checked);
				try {
					var welcomeTab = document.getElementsByClassAndTag('welcome','li',$('nav_list'))[0];
					if (welcomeTab) {
						if (element.checked) {
							Element.addClassName(welcomeTab, 'hidden');
						} else {
							Element.removeClassName(welcomeTab, 'hidden');
						}
					}
				} catch (ex) {}
				return true;
			};
	},
	'a.table_row_up' : function(element) {
		element.onclick = function() {
			tableRowUp(element);
			return false;
		};
	},
	'a.table_row_down' : function(element) {
		element.onclick = function() {
			tableRowDown(element);
			return false;
		};
	},
	'#search_link' : function(element) {
		innerToTitle(element);
		element.onclick = function() {
			var query = $F('search');
			if (query && query != '' && query != $F('search_prompt')) {
				var path = element.href + '?q=' + $F('search');
				window.location.href = path;
			} else {
				window.location.href = buildAdvancedSearchLink();
			}
			return false;
		};
	},
	'#search' : function(element) {
		element.onfocus = function() {
			if (element.value && element.value == $F('search_prompt')) {
				element.value = '';
			}
		};
	},
	'span.alerting_span' : function(element) {
		element.onclick = function() {
			alert(element.title);
			return false;
		};
	}
};

// This registers the behaviour rule so all elements with class .nav_list_item 
// will have that onclick function
Behaviour.register(navRules, 'NavRules');

// This causes addTabDragBehaviour to be called after the page loads
Behaviour.addLoadEvent(function() { if ($('nav_list')) addTabDragBehaviour(); });
Behaviour.addLoadEvent(
	function() { 
		if ($('alert_indicator') && ! $('alert_list')) {
			alertStatusTimer = setTimeout(monitorAlertNotificationStatus, 1000);
		}
		/*
		document.onkeypress = function(e) {
			log.warn('nav.js addLoadEvent keypress');
			if (!e) e = window.event;
			if (e.keyCode == 27 && isOverlayShowing()) {
				if (functionExists('hideConfigureFieldPopup')) {
					hideConfigureFieldPopup();
				}
				if (functionExists('hideOnlineHelp')) {
					hideOnlineHelp();
				}
			}
		};
		*/
		
		//document.onkeypress = handleKeyPress;
		
		if (showHelpOnLoad) {
			try {
				var element = document.getElementsByClassAndTag('help_link','a')[0]
				var helpId = element.id.replace("_help", "");
				showOnlineHelp(helpId, false);
			} catch (ex) {}
		}
	}
);
			

var navTabResizeTimer;
/**
 * This lets us handle resize events; we may need to adjust the layout of the tabs.
 */
function onResizeNavTab() {
	if (navTabResizeTimer) {
		clearTimeout(navTabResizeTimer);
	}
	navTabResizeTimer = setTimeout('navTabResize()', 500);
}

function navTabResize() {
}

function monitorAlertNotificationStatus() {
	if (alertStatusTimer) {
		clearTimeout(alertStatusTimer);
	}
	var completeFunc = 
		function(xml) { 
			try {
				/*  false if no new alerts; true if new alerts
					<status>false|true</status>
				*/
				var status = getFirstXmlElement(xml, 'status');
				if (status == 'true') {
					flashAlertNotification();
				} else {
					var alertIndicator = $('alert_indicator');
					if (alertIndicator) {
						if (! Element.hasClassName(alertIndicator, 'invisible')) {
							Element.addClassName(alertIndicator, 'invisible');
						}
					}
				}	
			
			} catch (ex) { 
				processAjaxError(ERROR_HANDLING_LOG, 'warn', 'ajax.monitor.alert.notification', new Array(ex.description), null);
			} finally {
				// Sometimes this causes an error when switching pages.  It's like the function goes away but the timer
				// is still trying to call it.  I've tried killing the timer in onunload but it didn't help.
				try {
					if (monitorAlertNotificationStatus) {
						alertStatusTimer = setTimeout(monitorAlertNotificationStatus, 60000);
					}
				} catch (ex) {}
			}
		};
	
	var path = buildGetAlertNotificationStatusLink();
	asyncAjaxCall('ajax.monitor.alert.notification', path, null, 'post', completeFunc, null, ERROR_HANDLING_LOG);
}

var flashCount = 0;
function flashAlertNotification() {
	var alertIndicator = $('alert_indicator');
	if (! alertIndicator) {
		return;
	}
	if (! Element.hasClassName(alertIndicator, 'invisible')) {
		return;
	}
	Element.removeClassName(alertIndicator, 'invisible');
	flashCount = 11;
	setTimeout(flashAlertIndicator, 1000);
}

function flashAlertIndicator() {
	var alertIndicator = $('alert_indicator');
	if (! alertIndicator) {
		return;
	}
	if (Element.hasClassName(alertIndicator, 'invisible')) {
		Element.removeClassName(alertIndicator, 'invisible');
	} else {
		Element.addClassName(alertIndicator, 'invisible');
	}
	flashCount--;
	if (flashCount > 0) {
		setTimeout(function() { flashAlertIndicator(); }, 1000);
	} else {
		Element.removeClassName(alertIndicator, 'invisible');
	}
}

function dashboard_select_list_onselect(element, data) {
	var id = data['id'];
	$(id).value = data['key'];
	$('dashboard_select_form').submit();
}


var tabMap = null;
var tabList = null;
var TabWrapper = Class.create();
TabWrapper.prototype = {
	initialize : function(li, left, top) {
		if(isNaN(parseInt(li.style.left))) {
			li.style.left="0px";
		}
		if(isNaN(parseInt(li.style.top))) {
			li.style.top="0px";
		}
		var pos = Position.cumulativeOffset(li);
		this.left = pos[0];
		this.top = pos[1];
		this.li = li;
	}
};

function addTabDragBehaviour() {
	var container = $('nav_list');
	if (! Element.hasClassName(container, 'nav_list_draggable')) return;
	
	var tabs = document.getElementsByClassAndTag('nav_list_item','li',container);
	for (var i=0; i < tabs.length; ++i) {
		addTabDrag(tabs[i]);
	}
	
}

function addTabDrag(tab) {
	if (Element.hasClassName(tab, 'dummy')) return;
	var handle = document.getElementsByClassAndTag('handle','div',tab)[0];
	Drag.init(handle, tab);
 	tab.onDragStart = function(x, y) { tabDragStart(tab, x, y); };
 	tab.onDrag = function(x, y) { tabDrag(tab, x, y); };
 	tab.onDragEnd = function(x, y) { tabDragEnd(tab, x, y); };
 	
}

var tabHolder = null;
var lastTabX = null;
var lastTabY = null;
var previousTabOrder = null;

function tabDragStart(tab, x, y) {
	previousTabOrder = getTabOrder();
	
	var size = Element.getDimensions(tab);
	var pos = Position.cumulativeOffset(tab);
	Element.setStyle(tab, {
		'position':'absolute',
		'width':size.width+'px',
		'zIndex':100,
		'left':pos[0]+'px',
		'top':pos[1]+'px'
	});
	
	tabHolder = document.createElement('li');
	tabHolder.innerHTML = '&nbsp;';
	tabHolder.id = 'nav_drop_holder';
	Element.addClassName(tabHolder, 'nav_placeholder');
	Element.setStyle(tabHolder, {
		'border':'2px dashed #ccc',
		'height':size.height-1+'px',
		'width':size.width-1+'px'
	});
	tab.parentNode.insertBefore(tabHolder, tab.nextSibling);

	tabMap = new Array();
	tabList = new Array();
	var tabs = document.getElementsByClassAndTag('nav_list_item','li',$('nav_list'));
	for (var i=0; i < tabs.length; ++i) {
		var wrapper = new TabWrapper(tabs[i]);
		tabList[i] = wrapper;
		tabMap[tabs[i].id] = wrapper;
	}
	lastTabX = null; lastTabY = null;
}


function tabDrag(tab, x, y) {
	if (x == lastTabX && y == lastTabY) {
		return;
	}
	lastTabX = x;
	lastTabY = y;
	
	var pos = Position.cumulativeOffset(tab);
	var thisTab = tabMap[tab.id];
	var minDistance = 999999999;
	var holderDistance = 0;
	var closestTab = null;
	for (var i=0; i < tabList.length; ++i) {
		var checkTab = tabList[i];
		if (checkTab == thisTab) continue;
		var distance = Math.sqrt(Math.pow(checkTab.left - x, 2) + Math.pow(checkTab.top - y, 2));
		//log.debug('Tab: ' + pos[0] + '  ' + checkTab.li.innerHTML + ' Check: ' + checkTab.left + ' = ' + distance);
		if (isNaN(distance)) continue;
		if (distance < minDistance) { 	
			minDistance = distance;
			closestTab = checkTab;
		}
	}
	
	if (closestTab) {
		if (closestTab.top > tabList[0].top) {
			closestTab.li.parentNode.insertBefore(tabHolder, closestTab.li.nextSibling);
		} else {
			if (tabHolder.nextSibling != closestTab.li) {
				closestTab.li.parentNode.insertBefore(tabHolder, closestTab.li);
			}
		}
	}
}

function tabDragEnd(tab, x, y) {
	Element.setStyle(tab, {
		'position':'',
		'width':'',
		'height':'',
		'zIndex':'',
		'top':'0px',
		'left':'0px'
	});
	
	tab.parentNode.insertBefore(tab, tabHolder.nextSibling);
	tabHolder.parentNode.removeChild(tabHolder);
	tabHolder = null;
	moveTab(tab);
}

/**
 * This function is called when a tab is moved. It makes an Ajax call
 * to the server to update the position in the database.
 */
function moveTab(tab) {
	var order = getTabOrder();
	if (previousTabOrder && order == previousTabOrder) return;
	
	asyncAjaxCall('ajax.reorder.pages', buildSetNavigationLayoutLink(), 
		order, 'get', null, null, ERROR_HANDLING_SHOW);	
}

function getTabOrder() {
	var list = $('nav_list');
	var tabs = list.getElementsByTagName('li');
	var order = 'order=';
	for (var i=0; i < tabs.length; ++i) {
		var tab = tabs[i];
		if (Element.hasClassName(tab, 'nav_list_draggable')) {
			if (i > 0) {
				order += ',';
			}
			order += tabs[i].id.replace(/nav_list_/,"");
		}
	}
	return order;
}

function page_rename_onsubmit(req, link, map) {
	var tab_anchor = $('nav_list_' + map['entityKey'] + '_anchor');
	var span = tab_anchor.getElementsByTagName('span')[0];
	span.innerHTML = unescape(map['display']);
	if (map['configuration'].indexOf('|') > 0) {
		span.title = map['configuration'].split('|')[1];
		if (map['displayElement']) {
			$(map['displayElement']).title = span.title;
		}
	}
	return true;
}

var currentHelp = null;
var helpShowing = false;

function showOnlineHelp(helpId, edit) {
	// TODO: this is a hack because we're not calling showOverlay unil 
	// the async which means this method can run twice on a double-click
	// which would cause problems without this check
	if (helpShowing && ! edit) {
		return;
	}
	helpShowing = true;
	
	/* Create the help div */
	if (currentHelp == null) {
		help = document.createElement('div');
		Element.setStyle(help, {'display':'block', 'visibility':'visible'});
		Element.addClassName(help, 'help');
		document.body.appendChild(help);
		help.id = 'online_help';
	} else {
		help = currentHelp;
	}
	currentHelp = help;
	var path = buildGetOnlineHelpLink();
	var parameters = "h=" + helpId;
	if (edit) {
		parameters += '&e=true';
	}
	try {
		var h1 = document.getElementsByTagName('h1')[0];
		var text = findText(h1);
		if (h1) {
			parameters += '&title=' + text;
		}
		var h2 = document.getElementsByTagName('h2')[0];
		text = findText(h2);
		if (h2) {
			parameters += '&subtitle=' + escape(escapeHTML(text));
		}
	} catch (ex) {}
	parameters += randomizeURL(false);
	
	// This particular call cannot go through the utility function because it's going to 
	// display the response as-is - we can't guarantee that Online Help will contain
	// valid xml so better to let the browser deal with it.
	var failureFunc = function(req) { 
		hideOnlineHelp(); 
		processAjaxError(LOG_HANDLING_SHOW, 'error', 'ajax.online.help', new Array('ajax.failure'), dumpAjaxResponse(req));
	};
	
	var exceptionFunc = function(req, exception) { 
		hideOnlineHelp(); 
		processAjaxError(LOG_HANDLING_SHOW, 'error', 'ajax.online.help', new Array('ajax.exception'), dumpAjaxResponse(req.transport, exception));
	};
	
	var completeFunc = function(req) { 
		try {
			var xml = convertAjaxResponseToXml(req.responseText);
			if (xml) {
				if (processXmlErrors(ERROR_HANDLING_SHOW, xml, '', req)) {
					hideConfigureFieldPopup(); 
					hideInProgress();
					return;
				}
			}
		} catch (ex) {}
		help.innerHTML = req.responseText; 
		displayOnlineHelp(help); 
	};
	
	var myAjax = new Ajax.Request(path,
		{
			method: 'post',
			asynchronous: true,		
			parameters: parameters,
			onComplete: completeFunc,
			onFailure: failureFunc,
			onException: exceptionFunc
		});
			
}

function displayOnlineHelp(help) {
	/* Prevent user from clicking on other stuff */
	Element.setStyle(help, {'zIndex':'200', 
							'position':'absolute',
							'top':'0',
							'left':'0'
							});	
							
	Element.setStyle(help, {'display':'block', 'visibility':'hidden'});
	
	// Figure out some boundaries based on the window area
	var scrollTop = document.body.scrollTop;
	var scrollLeft = document.body.scrollLeft;
	var windowHeight = getWindowHeight();
	var windowWidth = getWindowWidth();
	
	var helpDims = Element.getDimensions(help);
	var helpHeight = helpDims.height;
	var helpWidth = helpDims.width;
	
	var helpX = (windowWidth/2) - (helpWidth/2);
	var helpY = (windowHeight/2) - (helpHeight/2);
	
	Element.setStyle(help, {'top':helpY, 'left':helpX});
	showPopup(help);
	Behaviour.apply();	
}

function hideOnlineHelp() {
	if (currentHelp) {
		hidePopup(currentHelp);
	}
	helpShowing = false;
}

function submitOnlineHelp(element, popup) {
	if (! currentHelp && popup) {
		return;
	}
	var form = findParent(element, 'form');
	var helpId = $('help_id').value;
	var path = form.action;
	var parms = 'h=' + helpId + '&' + Form.serialize(form);
	var xml = syncAjaxCall('ajax.save.help', path, parms, 'post', ERROR_HANDLING_SHOW);
	if (xml) {
		if (popup) {
			showOnlineHelp(helpId, false);
		} else {
			window.location.href = buildViewGenerateUserGuideLink(); 
		}
	}
}

function tableRowUp(element) {
	var row = findParent(element, 'tr');
	var previousSibling = row.previousSibling;
	while (previousSibling && previousSibling.nodeType == 3) {
		previousSibling = previousSibling.previousSibling;
	}
	if (! previousSibling) return;
	row.parentNode.insertBefore(row, previousSibling);
	var table = findParent(row, 'table');
	renumberRows(table.tBodies[0]);
}

function tableRowDown(element) {
	var row = findParent(element, 'tr');
	var nextSibling = row.nextSibling;
	while (nextSibling && nextSibling.nodeType == 3) {
		nextSibling = nextSibling.nextSibling;
	}
	if (! nextSibling) return;
	row.parentNode.insertBefore(nextSibling, row);
	var table = findParent(row, 'table');
	renumberRows(table.tBodies[0]);
	alert(table.tBodies[0].innerHTML);
}

var keyPressStack = new Array();


function registerKeyPress(func) {
	return;
	keyPressStack.push(func);
}

function handleKeyPress(e) {
	if (!e) e = window.event;
	if (e.keyCode == 27) {
		var pop = keyPressStack.pop();
		if (pop) {
			setTimeout(pop, 10);
		}
	}
}

function displayKeyPressStack() {
	for (var i=0; i < keyPressStack.length; ++i) {
		if (! confirm(keyPressStack[i])) {
			break;
		}
	}
}

function endSession() {
	syncAjaxCall('endSession',buildEndSession(), null, 'GET', ERROR_HANDLING_SHOW)
}


