/*
	Studbook system JS
	Common JS functions/code
*/

// use code object collection to register complex JS which needs to be rerun after ajax calls
var coc = new CodeObjectCollection();
var cocStatus = { init: 0, initCommon: 0 };
var windowKey='';
var siteName='';
var prevWindowName='';
var uniqueCheckQueue=0;
var hasFirebug = "console" in window && "firebug" in window.console;

// extend jQuery selectors
//jQuery.extend(
//  jQuery.expr[ ":" ], 
//  { parentsVisible : "(jQuery(a).parents(':hidden').length == 0)" }
//);


// functions/code to be run on every page
$(document).ready(function(){
	$.preloadCssImages();
	
	var cocInitCommonId = setInterval(function(){ 
		if(cocStatus.init) {
			clearInterval(cocInitCommonId);
			// ensures this runs after the script output has run its coc.init function
			cocStatus.initCommon = coc.add('initCommon',"",function(context) {
				// icon image switcher
				//alert('image switcher: '+context);
				$.swapImage('.imageSwitcher');
				
				// alternate colours on list tables
				$('.moduleListData tr:even').addClass('listDataEven');
				$('.moduleListData tr:odd').addClass('listDataOdd');
				$('.moduleActivityListData tr:even').addClass('listDataEven');
				$('.moduleActivityListData tr:odd').addClass('listDataOdd');
				
				// custom function
				if(typeof custom_systemReady_coc == 'function') { custom_systemReady_coc(); }
			});
			
			// opens and closes the list data filters
			$('.moduleFilterToggle').live('click',function() {
				var ff = $(this).data('targetId');
				if($(this).hasClass('filterOpen')) {
					// close the filter
					$(ff).hide('blind',300);
					$(this).removeClass('filterOpen');
					$(this).html('Show Filter');
				}
				else {
					// open filter
					$(ff).show('blind',300);
					$(this).addClass('filterOpen');
					$(this).html('Hide Filter');
					var status = $(ff).data('operatorStatus');
					if(status == 'display')
						toggleFilterOperators(ff,"show",0);
					else
						toggleFilterOperators(ff,"hide",0);
				}
			});
			
			// resets the filter form
			$('.moduleFilterReset').live('click',function() {
				var form = $(this).data('targetFilterId');
				var fa	= form+' input[name="filterAction"]';
				$(fa).val('reset');
				$(form).submit();
			});
			
			// register the list data headers as controls which can rearrange the data order
			$('.moduleListData thead td').live('click',function() {
				//alert('running reorder');
				var sortField	= $(this).data('sortField');
				var form	= $(this).data('targetFilterId');
				var prefix	= $(form).data('prefix');
				var sortB	= '#filter_'+prefix+'LF_sortB';
				var sortD	= '#filter_'+prefix+'LF_sortD';
				var pSortField	= $('#filter_'+prefix+'prevSortB').val();
				var pSortDir	= $(sortD).selectedValues()[0];
				var fa		= form+' input[name="filterAction"]';
				
				$(sortB).selectOptions(sortField);
				if(pSortField == sortField && pSortDir == 'ASC')
					$(sortD).selectOptions('DESC');
				else
					$(sortD).selectOptions('ASC');
				//alert('various field: ('+sortField+') ('+form+') ('+prefix+') ('+sortB+') ('+sortD+') ('+pSortField+') ('+pSortDir+')');
				$(fa).val('apply');
				$(form).submit();
			});
			
			// quick links: rows per page
			$('.recordsPerPageLink').live('click',function() {
				var rowsPerPage	= $(this).html();
				var form	= $(this).data('targetFilterId');
				var prefix	= $(form).data('prefix');
				var rows	= '#filter_'+prefix+'LF_rows';
				var fa		= form+' input[name="filterAction"]';
				$(rows).selectOptions(rowsPerPage);
				$(fa).val('apply');
				$(form).submit();
			});
			
			// quick links: refresh page
			$('.recordsPerPage .refresh').live('click',function() {
				var form = $(this).data('targetFilterId');
				//alert('form: ('+form+')');
				var fa	 = form+' input[name="filterAction"]';
				$(fa).val('refresh');
				$(form).submit();
			});
				
			// quick links: result navigator left
			$('.resultsNavigator .left a').live('click',function() {
				var form	= $(this).data('targetFilterId');
				var prefix	= $(form).data('prefix');
				var page	= '#filter_'+prefix+'LF_page';
				var pageNum	= $(page).selectedValues()[0]-2;
				var fa		= form+' input[name="filterAction"]';
				$(page+' option:eq('+pageNum+')').attr('selected', 'selected');
				$(fa).val('apply');
				$(form).submit();
			});
			
			// quick links: result navigator centre
			$('.resultsNavigator .centre a').live('click',function() {
				var pageNum	= $(this).html();
				var form	= $(this).data('targetFilterId');
				var prefix	= $(form).data('prefix');
				var page	= '#filter_'+prefix+'LF_page';
				var fa		= form+' input[name="filterAction"]';
				$(page).selectOptions(pageNum);
				//alert('running centre link: ('+form+') ('+prefix+') ('+page+')');
				$(fa).val('apply');
				$(form).submit();
			});
			
			// quick links: result navigator right
			$('.resultsNavigator .right a').live('click',function() {
				var form	= $(this).data('targetFilterId');
				var prefix	= $(form).data('prefix');
				var page	= '#filter_'+prefix+'LF_page';
				var pageNum	= $(page).selectedValues()[0];
				var fa		= form+' input[name="filterAction"]';
				$(page+' option:eq('+pageNum+')').attr('selected', 'selected');
				//$(page).selectOptions(newPage);
				$(fa).val('apply');
				$(form).submit();
			});
			
			// quick links: apply favourite search
			$('.favouriteSearch .apply').live('click',function() {
				var form 	= $(this).data('targetFilterId');
				var prefix	= $(form).data('prefix');
				var fsn		= form+' input[name="favouriteSearchId"]';
				var fa		= form+' input[name="filterAction"]';
				var fav	 	= '#'+prefix+'userFilterViewId';
				var id		= $(fav).val();
				//alert('Fav info: ('+form+') ('+prefix+') ('+fsn+') ('+fav+')');
				//alert('Fav ID: '+id);
				$(fsn).val(id);
				$(fa).val('apply');
				$(form).submit();
			});
			
			// export links
			$('.exportResults .export').live('click',function() {
				var form 	= $(this).data('targetFilterId');
				var prefix	= $(form).data('prefix');
				var url		= $(form).attr('action')+$(form+' input[name="action"]').val();
				var sel		= $('#'+prefix+'exportSelection').val();
				//var query	= '?exportMode='+$(this).html()+'&exportSelection='+sel+'&'+windowKey+'='+getWindowName();
				var query	= '?exportMode='+$(this).html()+'&exportSelection='+sel;
				
				//alert('Fav info: ('+form+') ('+prefix+') ('+url+') ('+query+')');
				window.location = url+query;
			});
			
			// reset the AC ID back to zero if the user deletes the input
			$('.autoCompleteContents').live('change',function() {
				var idField	= $(this).attr('id').replace(/_ac$/,'');
				var contents	= $(this).val();
				if(contents.match(/\w/)) {} else { $('#'+idField).val(0).change(); }
			});
			
			// toggles and reorders
			//$('.moduleAjaxLink').live('click',function(e){ performAJAXLinkClick($(this),e); });
			
			$(window).bind('beforeunload',function() {
				//$.cookie(windowKey,null);
				//$.cookie(windowKey+'_prev',null);
				
				// create and pass a temporary cookie with the request
				//var expiry = new Date(2000)
				//$.cookie(windowKey,getWindowName(),{expires: expiry});
				
				$.cookie(windowKey,getWindowName(),{path: '/'});
				if(prevWindowName.match(/\w/)) {
					$.cookie(windowKey+'_prev',prevWindowName,{path: '/'});
				}
			});
			
			// custom function
			if(typeof custom_systemReady == 'function') { custom_systemReady(); }
		}
	},50);
});

// function to uppercase first letter of string
String.prototype.ucfirst = function() {  return this.charAt(0).toUpperCase() + this.substr(1); }


// structure holding standard tooltips
var stdTooltip = {
	'default_no':	'Not Default',
	'default_yes':	'Default'
};

function getToolTip(name) {
	if(stdTooltip[name])
		return stdTooltip[name];
	else {
		var string = name.ucfirst();
		return string.replace(/_/g,' ');
	}
}

function setSiteName(site) { siteName = site; };
function getWindowName() { return window.name; }
function setWindowName(prevName,forceName) {
	var name	= getWindowName();
	var sitePrefix	= 'sbo_';
	if(!name || !name.match(/\w/)) {
		//alert('Window not named');
		if(prevName.match(/\w/)) { prevWindowName=prevName; }
		if(forceName.match(/\w/)){ 
			//alert('Forcing name: '+forceName);
			window.name=forceName;
		}
		else {
			//alert('Generating new window name');
			var d = new Date();
			window.name = sitePrefix+d.getTime();
		}
	}
}
function setWindowNameInActions(key,trackClass) {
	//setGlobalLinkVariable(key,getWindowName(),trackClass);
	setGlobalFormVariable(key,getWindowName(),trackClass);
	
	if(prevWindowName.match(/\w/)) {
		//setGlobalLinkVariable(key+'_prev',prevWindowName,trackClass+'_prev');
		setGlobalFormVariable(key+'_prev',prevWindowName,trackClass+'_prev');
	}
	
	// save the window key in case any URLs are dynamically generated by the JS
	windowKey=key;
}

// session variables are used to hold data which will be unique to the browser tab/window
function setSessionVariable(ns,key,value) {
	var namespace = window.name+'-'+ns+'-';
	$.jStorage.set(namespace+key,value);
}
function getSessionVariable(ns,key) {
	var namespace = window.name+'-'+ns+'-';
	return $.jStorage.get(namespace+key);
}
function deleteSessionVariable(ns,key) {
	var namespace = window.name+'-'+ns+'-';
	$.jStorage.deleteKey(namespace+key);
}
function flushAllSessionVariables() {
	var namespace = window.name+'-';
	flushSessionVariablesWithNS(namespace);
}
function flushSessionVariables(ns) {
	var namespace = window.name+'-'+ns+'-';
	flushSessionVariablesWithNS(namespace);
}
function flushSessionVariablesWithNS(namespace) {
	var key = $.jStorage.index();
	var length = key.length;
	for(var i=0; i<length; i++) {
		if(key[i].match(/^namespace/)) {
			alert('Deleting: '+key[i]);
			$.jStorage.deleteKey(key[i]);
		}
	}
}

// register of events/functions which need to be reexecuted after the DOM changes (eg after an AJAX call)
function CodeObjectCollection() 			{ this.object = new Array(); }
CodeObjectCollection.prototype.add = function(n,c,func) { this.object.push(new CodeObject(n,c,func)); return 1; }
//CodeObjectCollection.prototype.run = function(c) 	{ var l=this.object.length; alert('coc context: '+c); for(var i=0; i<l; i++) { this.object[i].execute(c); } }
CodeObjectCollection.prototype.run = function(c) 	{ var l=this.object.length; for(var i=0; i<l; i++) { this.object[i].execute(c); } }

function CodeObject(name,selector,func) 		{ this.name = name; this.selector = selector; this.func = func; }
CodeObject.prototype.execute = function(context) {
	var run=false;
	if(context == 'ALL')					{run=true;}
	else if(context == 'NEVER')				{run=false;}
	else if(this.selector == "")				{run=true;}
	else if($(context+':has('+this.selector+')').length)	{run=true;}
	
	//alert('Function name: '+this.name);
	if(run) this.func(context);
}


// function performAJAXObserverCheck(data,target,url,arg,loadingHTML,funcSucc) {
// 	if(loadingHTML) { $(targetId).html(loadingHTML); }
// 	var data = arg+'&sourceData='+data;
// 	$.ajax({
// 		url: 		url,
// 		data: 		data,
// 		dataType:	'html',
// 		cache: 		false,
// 		success: function(scriptOutput){
// 			$(targetId).html(scriptOutput);
// 			if(typeof funcSucc == "function") { funcSucc(); }
// 		},
// 		error: function() {
// 			alert("Error communicating with server");
// 		}
// 	});
// }

function performAJAXLinkClick(element,event) {
	event.stopPropagation();
	//event.stopImmediatePropagation();
	//alert('blah');
	event.preventDefault();
	var targ = $(element).data('targetId');
	var href = $(element).attr('href');
	//alert('ajax click param: ('+targ+')('+href+')');
	var hrefPart = href.split('?');
	$(targ).block({ message: '<div class="moduleListLoading">Loading data ...</div>' });
	$.ajax({
		url:		hrefPart[0],
		data:		hrefPart[1]+'&_isAjax=1',
		dataType:	'html',
		cache:		false,
		success:	function(o) { $(targ).html(o); coc.run(targ); },
		error:		function()  { alert('Error occurred while communicating with server - data could not be updated'); },
		complete:	function()  { $(targ).unblock(); }
	});
}
function registerAJAXForm(selector) {
	$(selector).ajaxForm({
		beforeSubmit: 	function(a,f,o) {
			var n = f.data('targetId');
			//alert('AJAX target: '+n);
			$(this).attr('rel',n);
			if($(n+'FilterToggle').hasClass('filterOpen')) {
				$(n+'Filter').hide();
				$(n+'FilterToggle').removeClass('filterOpen');
				$(n+'FilterToggle').html('Show Filter');
			}
			$(n).block({ message: '<div class="moduleListLoading">Loading data ...</div>' });
		},
		data:		{'_isAjax': 1},
		success: 	function(o,s,xhr,f) 	{ var n = f.data('targetId'); $(n).html(o); coc.run(n); },
		error: 		function() 		{ alert('Error occurred while communicating with server - data could not be filtered'); },
		complete: 	function(unk,s) 	{ $($(this).attr('rel')).unblock(); }
	});
}

// misc functions

function hasEvent(element,event) {
	var events = $(element).data('events');
	var hasEvent = false;
	if(events) {
		$.each($(element).data('events'), function(iColl,eColl) {
			$.each(eColl, function(i,e) {
				//alert('Type: '+e.type+' ('+e.namespace+')');
				if(e.type == event) hasEvent = true;
			});
		});
	}
	//alert('hasEvent: '+hasEvent);
	return hasEvent;
}

// usage: $(src).keyup(function(){ limitCharacters('#src',128,'#info'); });
function limitCharacters(src,limit,info) {
	//alert('limit chars: '+src);
	var text = $(src).val();
	var length = text.length;
	if(length > limit) {
		$(info).html('<span class="charLimitError">You cannot write more than '+limit+' characters</span>');
		$(src).val(text.substr(0,limit));
	}
	else {
		//logger('character limit ok');
		$(info).html('<span class="charLimitOK">You have '+(limit-length)+' characters left</span>');
	}
}

function setGlobalLinkVariable(key,value,trackClass) {
	//alert('Tracking class: '+trackClass);
	$('a:not(.'+trackClass+')').each(function(){
		var sep = (this.href.indexOf('?') != -1) ? '&' : '?';
		$(this).attr('href', this.href + sep + key + '=' + value);
		$(this).addClass(trackClass);
	});
}

function setGlobalFormVariable(key,value,trackClass) {
	$('form:not(.'+trackClass+')').each(function(){
		var hField = $('<input />').attr('type', 'hidden').attr('name',key).attr('value',value);
		$(this).append(hField);
		$(this).addClass(trackClass);
	});
}

function actionIfChecked(isEvent,src,onChecked,onUnchecked,onCheck) {
	var checked = $(src).is(':checked');
	if(typeof onCheck == 'function') { checked = onCheck(checked); }
	if(checked) { if(typeof onChecked == 'function') { onChecked(isEvent); } }
	else { if(typeof onUnchecked == 'function') { onUnchecked(isEvent); } }
}

function hideIfChecked(src,targ,inverse,onHide,onShow,onCheck) {
	var hide = $(src).is(':checked');
	if(inverse && hide) { hide = false; } else if (inverse && !hide) { hide = true; }
	if(typeof onCheck == 'function') { hide = onCheck(hide); }
	if(hide && $(targ).is(':visible')) {
		$(targ).hide('blind',300);
		if(typeof onHide == 'function') { onHide(); }
	}
	else if(!hide && $(targ).is(':hidden')) {
		$(targ).show('blind',300);
		if(typeof onShow == 'function') { onShow(); }
	}
}

function actionIfMatched(src,match,onMatch,onUnmatch,onCheck) {
	var state 	= $(src).val();
	var matched	= false;
	if(state == match) { matched = true; }
	if(typeof onCheck == 'function') { matched = onCheck(matched); }
	if(matched) { if(typeof onMatch == 'function') { onMatch(); } }
	else { if(typeof onUnmatch == 'function') { onUnmatch(); } }
}

function hideIfMatched(src,srcType,match,targ,effect,inverse,onHide,onShow,onCheck) {
	var state;
	if(srcType == 'select') { state = $(src).selectedValues()[0];} else { state = $(src).val();}
	
	var hide = false;
	if(state == match)  { hide = true;  }
	if(inverse && hide) { hide = false; } else if (inverse && !hide) { hide = true; }
	if(typeof onCheck == 'function') { hide = onCheck(hide,state); }
	
	//alert('State: '+state+' ('+hide+') ('+$(targ).is(':visible')+') ('+$(targ).is(':hidden')+') ('+$(targ).parents(':hidden').length+')');
	if(hide && ($(targ).is(':visible') || ($(targ).is(':hidden') && $(targ).parents(':hidden').length > 0))) {
		if(effect == 'fade')
			$(targ).fadeOut(300);
		else
			$(targ).hide(effect,300);
		if(typeof onHide == 'function') { onHide(); }
	}
	else if(!hide && $(targ).is(':hidden')) {
		if(effect == 'fade')
			$(targ).fadeIn(300);
		else
			$(targ).show(effect,300);
		if(typeof onShow == 'function') { onShow(); }
	}
}

function hideIfBlank(src,srcType,targ,effect,inverse,onHide,onShow,onCheck) {
	var state;
	if(srcType == 'select') { state = $(src).selectedValues()[0];} else { state = $(src).val();}
	
	var hide = false;
	if(!state || !state.match(/\w/))	{ hide = true;  }
	if(inverse && hide)			{ hide = false; } else if (inverse && !hide) { hide = true; }
	if(typeof onCheck == 'function') { hide = onCheck(hide); }
	
	//alert('State: '+state+' ('+hide+') ('+$(targ).is(':visible')+') ('+$(targ).is(':hidden')+') ('+$(targ).parents(':hidden').length+')');
	if(hide && ($(targ).is(':visible') || ($(targ).is(':hidden') && $(targ).parents(':hidden').length > 0))) {
		if(effect == 'fade')
			$(targ).fadeOut(300);
		else
			$(targ).hide(effect,300);
		if(typeof onHide == 'function') { onHide(); }
	}
	else if(!hide && $(targ).is(':hidden')) {
		if(effect == 'fade')
			$(targ).fadeIn(300);
		else
			$(targ).show(effect,300);
		if(typeof onShow == 'function') { onShow(); }
	}
}

function handleContextMenuAction(site,action,element,prefix,systemURL,extraArg) {
	var htmlId 	= $(element).attr('id');
	var id 		= htmlId.replace(prefix,'');
	if(id && id.match(/^\d+$/)) {
		var idField 	= prefix+prefix.replace(/_/,'Id');
		//var url 	= '/'+site+'/'+action+'?'+idField+'='+id+'&'+windowKey+'='+getWindowName()+'&'+windowKey+'_prev='+prevWindowName;
		var url 	= '/'+site+'/'+action+'?'+idField+'='+id;
		if(extraArg && extraArg.match(/\w/)) { url += '&'+extraArg; }
		window.location = url;
	}
	else alert('Could not find record ID ('+htmlId+')');
}

function handleListDataMenuAction(action,actionId,element,cmenu,listdata) {
	var htmlId 	= $(element).attr('id');
	var htmlIdLink	= '#'+htmlId+'_'+action;
	var url		= $(htmlIdLink).attr('href');
	var isAJAX	= $(htmlIdLink).hasClass('moduleAjaxLink');
	//alert('various: ('+htmlId+') ('+htmlIdLink+') ('+action+') ('+url+') ('+element+') ('+isAJAX+') ('+cmenu+')');
	
	if(!url) {
		var id = htmlId.replace(/\D/g,'');
		if(action.match(/^filter_/)) {
			var form	= $('#'+cmenu).data('targetFilterId');
			var prefix	= $('#'+cmenu).data('prefix');
			var fa		= form+' input[name="filterAction"]';
			var target	= form+' #'+action.replace(/_/,'_'+prefix);
			var field	= action.replace(/^filter_/,'');
			//alert('various: ('+form+') ('+prefix+') ('+fa+') ('+target+') ('+field+')');
			$(fa).val('apply');
			$(target).val(listdata[id][field]);
			$(form).submit();
			return true;
		}
		else if (action == "email") {
			var email  = listdata[id]['email'];
			if(email && email.match(/\w+\@\w+/))
				window.location = 'mailto:'+email;
			else
				alert('Invalid email address - cannot generate email');
			return false;
		}
		else {
			// try to get the url from the context menu; note that this makes an ajax call impossible
			isAJAX=false;
			var newWindow=true;
			var aTarget = $('#'+actionId).attr('target');
			if(aTarget && aTarget.match(/^_self$/)) { newWindow=false; }
			
			//var href = $('#'+actionId).attr('href')+id+'&forceNewWindowName=1'+'&'+windowKey+'_prev='+getWindowName();
			var href = $('#'+actionId).attr('href')+id+'&forceNewWindowName=1';
			if(!id || !href || !href.match(/\w/)) {
				alert("You can't perform this action ("+action+") on this item");
				return false;
			}
			
			//alert('HREF: '+href);
			
			if(newWindow)
				window.open(href);
			else
				window.location = href;
			
			return true;
		}
	}
	
	
	// only trigger the click handler on the AJAX call; although it might look like this would work
	// for all calls, the 'single click' handler intercepts the call and reroutes the command to the view function
	if(isAJAX)
		$(htmlIdLink).trigger('click');
	else
		window.location = url;
}

function highlightRow(element) 	 { $(element).addClass('rowHighlight'); }
function deHighlightRow(element) { $(element).removeClass('rowHighlight'); }

function prepareContextMenu(menu,mask,element,disable,listdata,filterField,prefix,checkField,toggleField,coreField) {
	var htmlId 	= $(element).attr('id');
	var id		= htmlId.replace(/\D/g,'');
	//alert('various: ('+htmlId+') ('+menu+') ('+id+') ('+mask[id]+')');
	
	$('#'+menu).enableContextMenuItems();
	if(disable.match(/\w/)) { $('#'+menu).disableContextMenuItems(disable);}
	
	// masks are used by the system to turn off options for certain records
	if(mask[id]) {
		var string='';
		for(var option in mask[id]) {
			if(string.match(/\w/)) { string += ','; }
			string += '#'+option;
		}
		//alert('disabling: '+string);
		$('#'+menu).disableContextMenuItems(string);
	}
	
	// loop through the filter fields and update the menu descriptions
	for(var field in filterField) {
		var data = $('#'+htmlId+' .'+prefix+field).html();
		$('#'+menu+'_filter_'+field).html('Filter on <i>'+filterField[field]+'='+data+'</i>');
		if(!data || !data.match(/\w/))
			$('#'+menu).disableContextMenuItems('#filter_'+field);
	}
	
	// check fields are used to disable menuitems if a check field isn't set
	for(var i=0; i<checkField.length; i++) {
		var field = checkField[i];
		var data = listdata[id][field];
		//alert('Checking field: '+field+' ('+data+')');
		if(!data || !data.match(/\w/)) {
			$('#'+menu).disableContextMenuItems('#'+field);
		}
	}
	
	// toggle field options must be disabled if the toggled field is not displayed in the list
	for(var i=0; i<toggleField.length; i++) {
		var data = $('#'+htmlId+' .'+prefix+toggleField[i]).html();
		//alert('Checking toggle field: '+toggleField[i]+' ('+data+')');
		if(!data || !data.match(/\w/)) { $('#'+menu).disableContextMenuItems('#toggle_'+toggleField[i]); }
	}
	
	// core fields should only be enabled if they appear on the row line as an option
	for(var i=0; i<coreField.length; i++) {
		var htmlIdLink	= '#'+htmlId+'_'+coreField[i];
		var url		= $(htmlIdLink).attr('href');
		if(!url) { $('#'+menu).disableContextMenuItems('#'+coreField[i]); }
	}
}

function checkListDataMenuAction(ar,element,menu) {
	var htmlId = $(element).attr('id');
	for(var i=0; i<ar.length; i++) {
		var action = ar[i];
		var htmlIdLink = '#'+htmlId+'_'+action;
		if(!$(htmlIdLink).attr('href')) {
			// disable menu option
			$(menu).disableContextMenuItems('#'+action);
		}
		else {
			// enable menu option
			$(menu).enableContextMenuItems('#'+action);
		}
	}
}

function toggleDiv(targetId,linkId,baseLinkText) {
	if($('#'+targetId).hasClass('hide')) {
		$('#'+targetId).removeClass('hide');
		$('#'+linkId).html('Hide '+baseLinkText);
	}
	else {
		$('#'+targetId).addClass('hide');
		$('#'+linkId).html('Show '+baseLinkText);
	}
	return false;
}

function toggleFilterOperators(ff,action,duration) {
	if(!action) {
		var status = $(ff).data('operatorStatus');
		if(status == 'display') action = 'hide';
	}
	if(!duration && duration != 0) duration=400;
	
	if(action == 'hide') {
		$(ff+' .operator').fadeOut(duration);
		$(ff).data('operatorStatus','hidden');
		$(ff+' .hideOperator').hide(0);
		$(ff+' .showOperator').show(0);
	}
	else {
		$(ff+' .operator').fadeIn(0);
		$(ff).data('operatorStatus','display');
		$(ff+' .showOperator').hide(0);
		$(ff+' .hideOperator').show(0);
	}
}

function autocompleteSource(req,res,prefix,url,data,srcDataField,idField,makeFormDirty) {
	var recordsField = idField+'_ac_records';
	data.term	= req.term;
	
	for(var i=0; i<srcDataField.length; i++) {
		data[srcDataField[i]] = $('#'+prefix+srcDataField[i]).val();
	}
	
	data['_isAjax']	= 1;
	$.ajax({
		url:		url,
		data:		data,
		dataType:	"json",
		cache: 		false,
		beforeSend:	function (jqXHR, s) { $(recordsField).html('Searching ...'); if(makeFormDirty) { $('.moduleRecordForm').make_dirty(); } },
		success:	
			function(output) {
				if(output.numRecord == 0) {
					$(recordsField).html('No match found');
				}
				else if(output.numRecord == 1)
					$(recordsField).html('1 record found');
				else 
					$(recordsField).html(output.totalRecord+' records found - showing first '+output.numRecord+' records');
				
				res($.map(output.result,function(item) {
					return {
						label:	item.label,
						value:	item.value,
						id:	item.id,
						update:	item._update
					}
				}));
			}
	});
}

function displayACPicker(modalId,field,prefix,fieldList,url,data,srcDataField,makeFormDirty,uPrefix,uField,uVField,dMask,dtMask) {
	var modalResultsId	= modalId+'Results';
	var modalActionId	= modalId+' .search';
	var searchStatus	= modalId+' .searchStatus';
	var searchNav		= modalId+' .searchNavigator';
	var searchField		= modalId+' input[name="searchName"]';
	var targetFieldId	= prefix+field;
	var targetFieldStr	= prefix+field+'_ac';
	
	//alert('various: ('+modalId+') ('+field+') ('+modalResultsId+') ('+modalActionId+') ('+targetFieldId+')');
	
	// display filter
	$('#'+modalId).overlay({ 
		mask:		{ color: '#333', loadSpeed: 200, opacity: 0.9 },
		onClose: 	
			function() { 
				$('#'+modalId).unbind();
				$('#'+modalActionId).unbind();
				$('#'+modalResultsId+' tr').unbind();
				$('#'+searchField).unbind();
			}
	});
	$('#'+modalActionId).click(function(e) {
		// get search field + validate it contains something
		var searchData = $('#'+searchField).val();
		if(!searchData || !searchData.match(/\w/)) {
			alert('Please enter search data');
			return false;
		}
		
		for(var i=0; i<srcDataField.length; i++) {
			data[srcDataField[i]] = $('#'+prefix+srcDataField[i]).val();
		}
		
		// submit search data via AJAX/JSON
		data.term	= searchData;
		data['_isAjax']	= 1;
		$('#'+modalId).data('ACinfo',{url: url, data: data, fieldList: fieldList, srcDataField: srcDataField, prefix: prefix, field: field, uPrefix: uPrefix, uField: uField, uVField: uVField, dMask: dMask, dtMask: dtMask});
		$.ajax({
			url:		url,
			data:		data,
			cache: 		false,
			dataType:	"json",
			beforeSend:	
				function (jqXHR, s) {
					$('#'+searchStatus).html('Searching ...');
					if(makeFormDirty) { $('.moduleRecordForm').make_dirty(); }
					$('#'+modalId+' .modalSelect').unbind();
			},
			success:	function(output) { renderACPickerResults(modalId,output); }
		});
	});
	
	// enter key - intercept and submit modal lookup, not form submission
	$('#'+searchField).keydown(function(e){
		if(e.keyCode == 13) { $('#'+modalActionId).click(); e.preventDefault(); }
	});
	$('#'+modalId).overlay().load();
	return false;
}

function navigateACPicker(modalId,page) {
	var url			= $('#'+modalId).data('ACinfo').url;
	var data		= $('#'+modalId).data('ACinfo').data;
	var srcDataField	= $('#'+modalId).data('ACinfo').srcDataField;
		
	for(var i=0; i<srcDataField.length; i++) {
			data[srcDataField[i]] = $('#'+prefix+srcDataField[i]).val();
		}
	
	data.page = page;
	$.ajax({
		url:		url,
		data:		data,
		cache: 		false,
		dataType:	"json",
		success:	function(output) { renderACPickerResults(modalId,output); }
	});
	
}

function renderACPickerResults(modalId,output) {
	var url			= $('#'+modalId).data('ACinfo').url;
	var data		= $('#'+modalId).data('ACinfo').data;
	var fieldList		= $('#'+modalId).data('ACinfo').fieldList;
	var prefix		= $('#'+modalId).data('ACinfo').prefix;
	var field		= $('#'+modalId).data('ACinfo').field;
	var modalResultsId	= modalId+'Results';
	var searchStatus	= modalId+' .searchStatus';
	var searchNav		= modalId+' .searchNavigator';
	var searchField		= modalId+' input[name="searchName"]';
	var targetFieldId	= prefix+field;
	var targetFieldStr	= prefix+field+'_ac';
	
	$('#'+modalId+' .modalSelect').unbind();
	$('#'+modalId).data('ACloaded',output);
	$('#'+modalResultsId+' tr').unbind();
	$('#'+modalResultsId).unbind();
	$('#'+modalResultsId+' tbody').empty();
	
	if(output.numRecord == 0)
		$('#'+searchStatus).html('No match found');
	else if(output.numRecord == 1 && output.totalRecord == 1)
		$('#'+searchStatus).html('1 record found');
	else {
		var highWM = output.page * output.rows;
		var lowWM  = highWM - output.rows + 1;
		$('#'+searchStatus).html(output.totalRecord+' records found - showing records '+lowWM+' to '+highWM);
	}
	
	var flLength = fieldList.length;
	if(output.numRecord > 0) {
		var rLength = output.result.length;
		var tbody='';
		for(var i=0; i<rLength; i++) {
			var r = output.result[i];
			var dataRow = '<tr id="'+prefix+field+'modalSel_'+i+'">';
			for(var j=0; j<flLength; j++) {
				var f = fieldList[j];
				var d = r[f];
				if(!d) { d = ''; }
				dataRow += '<td class="field '+f+'">'+d+'</td>';
			}
			dataRow += '<td class="field noClick options"><a href="#" class="modalSelect noSavePrompt">Select</a></td></tr>';
			tbody += dataRow;
		}
		$('#'+modalResultsId+' tbody').append(tbody);
		$('#'+modalResultsId+' tbody tr:even').addClass('listDataEven');
		$('#'+modalResultsId+' tbody tr:odd').addClass('listDataOdd');
		$('#'+modalResultsId).tableHover({rowClass: 'rowHover'});
		$('#'+modalResultsId+' tr td:not(.noClick)').click(function(e) {
			var selector = $(this).closest('tr').attr('id');
			$('#'+selector+' .modalSelect').click();
		});
		
		output.totalRecord	= parseInt(output.totalRecord);
		output.page		= parseInt(output.page);
		
		if(output.totalRecord > output.numRecord) {
			// not all of the records where shown - enable the navigator
			$('#'+searchNav).removeClass('hide');
			if(output.page > 1)
				$('#'+searchNav+' .left').html('<a href="#" onClick="navigateACPicker(\''+modalId+'\','+parseInt(output.page-1)+')">&lt;&lt; Prev</a>');
			else
				$('#'+searchNav+' .left').html('');
			
			if(output.page < output.totalPage)
				$('#'+searchNav+' .right').html('<a href="#" onClick="navigateACPicker(\''+modalId+'\','+parseInt(output.page+1)+')">Next &gt;&gt;</a>');
			else
				$('#'+searchNav+' .right').html('');
			
			var lowLink	= output.page - 5;
			var highLink	= output.page + 5;
			if(lowLink < 1) { lowLink=1;}
			if(highLink > output.totalPage) { highLink = output.totalPage; }
			var centreHTML = '';
			var count=0;
			for(var i=lowLink; i<=highLink; i++) {
				if(count > 0) { centreHTML += ' | '; }
				if(i == parseInt(output.page))
					centreHTML += '<span class="selected">'+i+'</span>';
				else
					centreHTML += '<a href="#" onClick="navigateACPicker(\''+modalId+'\','+i+')">'+i+'</a>';
				count++;
			}
			$('#'+searchNav+' .centre').html(centreHTML);
		}
		else {
			$('#'+searchNav).addClass('hide');
			$('#'+searchNav+' .left').html('');
			$('#'+searchNav+' .centre').html('');
			$('#'+searchNav+' .right').html('');
		}
	}
	else {
		var dataRow = '<tr><td class="field noResults" colspan="'+flLength+1+'">No records were found</td></tr>';
		$('#'+modalResultsId+' tbody').append(dataRow);
	}
	
	$('#'+modalId+' .modalSelect').click(function(e) {
		var myId = $(this).closest('tr').attr('id').replace(/\D/g,'');
		var loadedData = $('#'+modalId).data('ACloaded');
		$('#'+targetFieldId).val(loadedData.update[myId].id).change();
		$('#'+targetFieldStr).val(loadedData.update[myId].value).change();
		
		// update any other fields required by the AC selection
		var acInfo = $('#'+modalId).data('ACinfo');
		updateFields(acInfo.uPrefix,acInfo.uField,acInfo.uVField,loadedData.result[myId],acInfo.dMask,acInfo.dtMask);
		
		$('#'+modalId).data('overlay').close();
		return false;
	});
}

function resetACTerm(field) {
	if($(field+'_ac').data('autocomplete'))
		$(field+'_ac').data('autocomplete').term='';
}

function resetFields(prefix,fieldList,vfieldList) {
	//alert('resetting fields');
	for(var field in fieldList) {
		var type = fieldList[field];
		if(type == 'id')
			$('#'+prefix+field).val(0);
		else
			$('#'+prefix+field).val('');
	}
	for(var field in vfieldList) {
		var type = vfieldList[field];
		if(type == 'id') {
			$('#'+prefix+field).val(0);
			$('#row_'+prefix+field+' .field').html('-');
		}
		else {
			$('#'+prefix+field).val('-');
			$('#row_'+prefix+field+' .field').html('-');
		}
	}
}

function updateFields(prefix,fieldList,vfieldList,data,dMask,dtMask) {
	//alert("updating fields: "+prefix);
	for(var field in fieldList) {
		var type = fieldList[field];
		$('#'+prefix+field).val(formatUserData(type,data[field],dMask,dtMask,''));
	}
	for(var field in vfieldList) {
		var type = vfieldList[field];
		$('#'+prefix+field).val(formatUserData(type,data[field],dMask,dtMask,'-'));
		$('#row_'+prefix+field+' .field').html(formatUserData(type,data[field],dMask,dtMask,'-'));
	}
}

function formatUserData(type,data,dMask,dtMask,def) {
	if(!data || !data.match(/\w/)) { return def; }
	if(type == 'date') {
		if(data.match(/^[1-2][0-9]{3}/)) { data = convertDateTime(data,'YYYY-MM-DD',dMask); }
		else if(data.match(/^0000/)) { data = ''; }
	}
	else if(type == 'datetime') {
		if(data.match(/^[1-2][0-9]{3}/)) { data = convertDateTime(data,'YYYY-MM-DD HH:MM:SS',dtMask); }
		else if(data.match(/^0000/)) { data = ''; }
	}
	else if(type == 'unixtime') {
		if(data.match(/^\d+$/) && data>0) { data = convertDateTime(data,'S',dtMask); }
	}
	return data;
}

function convertDateTime(data,from,to) {
	var date = {};
	if(from == 'YYYY-MM-DD HH:MM:SS') {
		var temp = data.split(' ');
		var datePart = temp[0].split('-');
		var timePart = temp[1].split(':');
		date = {
			year:	datePart[0],
			month:	datePart[1],
			day:	datePart[2],
			hour:	timePart[0],
			minute:	timePart[1],
			second:	timePart[2]
		};
	}
	else if(from == 'YYYY-MM-DD') {
		var datePart = data.split('-');
		date = {
			year:	datePart[0],
			month:	datePart[1],
			day:	datePart[2],
			hour:	'00',
			minute:	'00',
			second:	'00'
		};
	}
	else {
		var dObj = Date(data*1000);
		date = {
			year:	dObj.getFullYear(),
			month:	dObj.getMonth()+1,
			day:	dObj.getDate(),
			hour:	dObj.getHours(),
			minute:	dObj.getMinutes(),
			second:	dObj.getSeconds()
		};
		if(date.month < 10) 	{ date.month = '0'+date.month; }
		if(date.day < 10) 	{ date.day = '0'+date.day; }
		if(date.hour < 10) 	{ date.hour = '0'+date.hour; }
		if(date.minute < 10) 	{ date.minute = '0'+date.minute; }
		if(date.second < 10) 	{ date.second = '0'+date.second; }
	}
	
	var sep = '/';
	if(to.match(/-/)) { sep='-'; }
	
	var rDate;
	if(to.match(/^YYYY[-\/]MM[-\/]DD$/))		{ rDate = date.year+sep+date.month+sep+date.day; }
	else if(to.match(/^DD[-\/]MM[-\/]YYYY$/))	{ rDate = date.day+sep+date.month+sep+date.year; }
	else if(to.match(/^MM[-\/]DD[-\/]YYYY$/))	{ rDate = date.month+sep+date.day+sep+date.year; }
	else if(to.match(/^YYYY[-\/]MM[-\/]DD HH:MM:SS$/))	{ rDate = date.year+sep+date.month+sep+date.day+' '+date.hour+':'+date.minute+':'+date.second; }
	else if(to.match(/^HH:MM:SS DD[-\/]MM[-\/]YYYY$/))	{ rDate = date.hour+':'+date.minute+':'+date.second+' '+date.day+sep+date.month+sep+date.year; }
	else {
		// funky date time formats not supported in JS rendering at this time - default is YYYY-MM-DD HH:MM:SS
		rDate = date.year+sep+date.month+sep+date.day+' '+date.hour+':'+date.minute+':'+date.second;
	}
	return rDate;
}

function checkUniqueConstraint(myId,url,idField,prefix,constraint,arField,delay) {
	var currData = $('#'+myId).val();
	var length = arField.length;
	var data = {_excludeId: $(idField).val(), constraint: constraint};
	for(var i=0; i<length; i++) {
		data[arField[i]] = $('#'+prefix+arField[i]).val();
	}
	
	if(currData.match(/\w/)) {
		if(uniqueCheckQueue == 0) {
			uniqueCheckQueue=1;
			data['_isAjax']	= 1;
			setTimeout(function() {
				$.ajax({
					url:		url,
					data:		data,
					cache: 		false,
					dataType:	"json",
					beforeSend:	
						function (jqXHR, s) {
							for(var i=0; i<length; i++) { $('#'+prefix+arField[i]+'_notice').removeClass('warning'); $('#'+prefix+arField[i]+'_notice').html('Checking to see if unique ...'); }
						},
					error:	function(jqXHR, textStatus, errorThrown) {
							for(var i=0; i<length; i++) { $('#'+prefix+arField[i]+'_notice').html('Check failed due to an unknown error'); $('#'+prefix+arField[i]+'_notice').addClass('warning'); }
						},
					success:	
						function(output) {
							if(output.isUnique)
								for(var i=0; i<length; i++) { $('#'+prefix+arField[i]+'_notice').html('Validated - record is unique'); }
							else if(output.isUnique == 0)
								for(var i=0; i<length; i++) { $('#'+prefix+arField[i]+'_notice').html('Warning - record is not unique'); $('#'+prefix+arField[i]+'_notice').addClass('warning'); }
							else
								for(var i=0; i<length; i++) { $('#'+prefix+arField[i]+'_notice').html('Error: '+output.error); $('#'+prefix+arField[i]+'_notice').addClass('warning'); }
						},
					complete: function() { uniqueCheckQueue=0; }
				});
			},delay);
		}
	}
	else {
		$('#'+myId+'_notice').html('Invalid data entered');
	}
}

function loadNewFormElement(type,targetId,url,prefix,srcField,allowBlank,delay) {
	var data = {};
	for(var i=0; i<srcField.length; i++) {
		data[srcField[i]] = $('#'+prefix+srcField[i]).val();
	}
	data['_fieldList']	= srcField.join();
	data['_isAjax']		= 1;
	
	setTimeout(function() {
		$.ajax({
			url:		url,
			data:		data,
			cache: 		false,
			dataType:	"json",
			beforeSend:	
				function (jqXHR, s) {
					$('#'+prefix+targetId+'_notice').removeClass('warning');
					$('#'+prefix+targetId+'_notice').html('Looking up new data ...');
					if(type.match(/SELECT/)) {
						$('#'+prefix+targetId).removeOption(/.*/);
						$('#'+prefix+targetId).addOption('__LOAD', 'Loading ...');
					}
					else if(type.match(/TINYMCE/)) {
						$('#'+prefix+targetId).tinymce().setProgressState(1);
					}
					else if(type.match(/FORM/)) {
						$('#'+prefix+targetId).prop('disabled',true);
						$('#'+prefix+targetId).val('Loading ...');
					}
					else {
						$('#'+prefix+targetId).html('Loading ...');
					}
				},
			error:	function(jqXHR, textStatus, errorThrown) {
					$('#'+prefix+targetId+'_notice').addClass('warning');
					$('#'+prefix+targetId+'_notice').html('Data could not be retrieved due to an unknown error');
				},
			success:	
				function(output) {
					var length=output.result.length;
					if(type.match(/SELECT/)) {
						$('#'+prefix+targetId).removeOption(/.*/);
						if(output.numRecord == 0 && !allowBlank)
							$('#'+prefix+targetId).addOption('', '');
						else {
							for(var i=0; i<length; i++) { $('#'+prefix+targetId).addOption(output.result[i].label, output.result[i].name); }
							$('#'+prefix+targetId).val('');
							
						}
					}
					else if(type.match(/TINYMCE/)) {
						$('#'+prefix+targetId).tinymce().setProgressState(0);
						$('#'+prefix+targetId).tinymce().setContent(output.result[0].html);
					}
					else if(type.match(/FORM/)) {
						$('#'+prefix+targetId).prop('disabled',false);
						$('#'+prefix+targetId).val(output.result[0].value);
					}
					else {
						$('#'+prefix+targetId).html(output.result[0].value);
					}
					
					if(output.numRecord == 0) {
						if(!allowBlank) {
							$('#'+prefix+targetId+'_notice').addClass('warning');
							$('#'+prefix+targetId+'_notice').html('No data was found');
						}
						else
							$('#'+prefix+targetId+'_notice').html('');
					}
					else
						$('#'+prefix+targetId+'_notice').html('');
				}
		});
	},delay);
}

function checkListFieldSelector(e,ui) {
	var senderId	= ui.sender.attr('id');
	var itemId	= ui.item.attr('id');
	var allow	= true;
	//alert('various: ('+senderId+') ('+itemId+')');
	
	if(senderId.match(/_src$/) && itemId.match(/__gb/)) {
		// only one group by field is allowed in the field list - check that this new one is the only one
		var items 	= $(this).sortable('toArray');
		var matched 	= 0;
		for(var i=0; i<items.length; i++) { if(items[i].match(/__gb/)) matched++; }
		if(matched>1) { allow=false; }
	}
	
	if(!allow) {
		$(ui.sender).sortable('cancel');
		$.jGrowl('Error: You are not allowed to have more than one "number" or "group by" fields in the list',{life: 8000 });
	}
	else {
		// update flag field, if defined
		var hasChangedId='';
		if(senderId.match(/_src$/))
			hasChangedId = senderId.replace(/_src$/,'_hasChanged');
		else if(senderId.match(/_targ$/))
			hasChangedId = senderId.replace(/_targ$/,'_hasChanged');
		
		if(hasChangedId.match(/\w/))
			$('#'+hasChangedId).val(1);
	}
}

function parseFieldSelector(src,prefix,setHidden) {
	var field = $(src).sortable('toArray');
	var length = field.length;
	var string='';
	for(var i=0; i<length; i++) {
		var fieldName = field[i].replace(prefix,'');
		string += fieldName+':';
	}
	
	if(setHidden) {
		var target = src.replace(/_targ$/,'');
		$(target).val(string);
	}
	
	//alert('field selector string: '+string);
	return string;
}

function registerSideMenu(src,location) {
	if(location == 'R') {
		$(src+' a').stop().animate({'marginLeft':'85px'},1000);
		$(src+' > li').hover(
			function () { $('a',$(this)).stop().animate({'marginLeft':'5px'},200);  },
			function () { $('a',$(this)).stop().animate({'marginLeft':'85px'},200); }
		);
	}
}

function calcTaxExclusive(targ,amountId,taxId,modalId) {
	var amount	= $(amountId).val();
	var tax		= $(taxId).val();
	var amountEx	= amount / ((parseFloat(tax) + 100)/100);
	//alert('various: ('+amountId+') ('+taxId+') ('+amount+') ('+tax+') ('+amountEx+')');
	$(targ).val(amountEx.toFixed(2));
	$(modalId).data('overlay').close();
}

// convenience functions
function copyFormField(src,targ) 	{ $(targ).val($(src).val()); }
function copyFormSelect(src,targ) 	{ $(targ).selectOptions($(src).selectedValues()[0]); }
function copyFormFieldObj(obj,prefix) 	{ for(var field in obj){ copyFormField(prefix+field,prefix+obj[field]);  }  }
function copyFormSelectObj(obj,prefix) 	{ for(var field in obj){ copyFormSelect(prefix+field,prefix+obj[field]); }  }
function logger(msg)			{ if(hasFirebug) { console.log(msg); } }
