jQuery(function($){
// FUNCTIONS
// PANTHER OBJECT
// @description:  methods derived from tplPanther (open source project yet to be released)
// @author : Jeremy Dill
// @package : tplPanther
jQuery.panther = {
	wait:false,
	debug:false,
	debugResp:false,	
	debugTypes:"ALL", // SPECIFY A COMMA SEP LIST LIKE "ERR,WRN,INFO," OR JUST SPECIFY "ALL"
	IEConsole:"#footerLinks", // ALTERNATE PLACE TO OUTPUT ERRORS IF THERE IS NO FIREBUG CONSOLE	
	sess:"",
	store:[],
	notice:function(sel,msg,sticky){	
			jQuery(sel).stop().stop().queue(
			    function(){
			        $(this).html(msg).show().shake()
			        if (!sticky)$(this).fadeLater();
			        $(this).dequeue()
			    });
	},
	// debug functions
	trace:function (msg,sel) {
		if(sel==undefined) sel="body";
		$(sel).append(msg+"<br>");
		return msg;
	},
	console:function (msg,func) {
	    if (!this.debug) return false;
	    if ((window.console && window.console.error)||jQuery(jQuery.panther.IEConsole).length) {
		    var valid=false;
			msg=msg.replace(/^\s+|\s+$/g,"");
			type=msg.toUpperCase().substring(0,msg.indexOf("-"));
	        if(this.debugTypes.toUpperCase().indexOf(type+",")>-1 || this.debugTypes=="ALL") valid=true;
			if (valid){
				if (window.console && window.console.error){
					if (type=="ERR"||type=="WRN") console.error(msg);
					else console.log(msg);
				} else {
					this.trace(msg,jQuery.panther.IEConsole);
				}
			}
		}
		return msg;
	},
	// activateFilter FUNCTION -JDILL
	// @description:  filter rows
	// @ver .1
	activateFilter:function(){
		sel=this.className;
		mode=this.title;
		val=$(this).val().toLowerCase();
		var combine="";
		var tr="";		
		filt=jQuery.panther.store['filtername'];
		if (filt=="undefined") jQuery.panther.store['filtername']="default";
		if (val){
		//	$.trace(val+" "+mode+" "+sel);	
			$('td.'+sel).each(function(){
				var hide=false;
				var unhide=false;
			    var fieldtext=$(this).text().toLowerCase().trim();						
				switch (mode) {
					case "match any":
						if (fieldtext.indexOf(val)<0) hide=true;
					break;
					case "match exact":
						if (fieldtext!=val) hide=true;
					break;
					case "match beginning special":
						if ($(this).find(".xf_match").text().toLowerCase().indexOf(val)!=0) hide=true;
					break;
					case "match any combine":
						thistr=$(this).parents('tr:first').attr('id');
						if (tr!=thistr) combine="";
						combine+=fieldtext;
						if (combine.indexOf(val)<0) hide=true;
							else unhide=true;
						tr=thistr;
					break;															
					default: /* match beginning */
						if (fieldtext.indexOf(val)!=0) hide=true;
					break;
				}
				if (hide) $(this).parents('tr:first').hide();
				if (unhide) $(this).parents('tr:first:hidden').show();				
			});
		}
		jQuery.panther.store[jQuery.panther.store['filtername']+'_filter_'+sel]=val;	
	},
	// restoreFilters FUNCTION -JDILL
	// @description: restore saved filters
	// @ver .1
	   restoreFilters : function(fltrObj){
		filt=jQuery.panther.store['filtername'];
		if (filt=="undefined") jQuery.panther.store['filtername']="default";			
		jQuery(fltrObj).find("input").each(function(){
			name=jQuery.panther.store['filtername']+'_filter_'+jQuery(this).attr("className");
			jQuery(this).val(jQuery.panther.store[name]);
		})
		.each(jQuery.panther.activateFilter);
	},
	// JCALL - AJAX CALL AND RESPONSE HANDLER
	// @author : Jeremy Dill
	// @ver : 1.2
	// @package : tplPanther
	// @param [str] func : php jCall function to execute
	// @param [array] params : array of parameters ( "value1","value2" )  to be passed to the jCall function
	// @param [obj] opt : set of options for the ajax call.  Supported options inlcude:
	// 			[str] url : path to ajax.php, the entry point for ajax call
	//			[bool] setWait (true) : if true, $.panther.wait will be set to true before call, and will be set to false on response.  Simulates synchronous calling if you check $.panther.wait before request.
	//			[bool] jsonly (false) : only return javascript...no xhtml, no target
	//			[bool] scall (false) : pass session $.panther.sess with request 
	//			[bool] noloader (false) : disable ajax loader
	//			[int] timeBeforeGivingUp (10000): ms time to wait for response before giving up and throwing an error.
	//			[func] timeoutAction (alert): function to run on timeout
	//			[func] errorAction (alert): function to run on error	
	//			[obj] loaderOpts : set of options for loader.  Can clone loader object and reuse.   
	//				[int] delay (200) : ms time to wait after request before showing loader.		
	//				[int] transSpeed (10) : ms time for fadin and fadeout of loader.
	//				[selector] sel ("#smallLoader") : ID selector for ajax loader graphic that gets placed next to target anchorpoint on page (don't use a class selector!)
	//				[obj/selector] ap ("body") : specifies the object to place the loaderSel next to.
	//				[str] loc ("top-right") : where to mount loader on ap.  options are based on placer plugin.	 Accepted presently: top-left, top-right, bottom-left, bottom-right, off-left, top-center
	//				[obj] offset ({0,0}) :  x and y offsets for loaders.	
	// @RESPONSE - JSON MULTI DIMENSIONAL ASSOC ARRAY, EACH DIMENSION MAY HAVE 4 PRIMARY KEYS :
	//  'target' - A LOCAL JQUERY OBJECT "target" WHICH IS GOING TO GET THE RETURNED XHTML RESPONSE.  
	//			   TYPICALLY A SINGLE DIV OR BLOCK ELEMENT BUT CAN BE ANY ELEMENT OR JQUERY COLLECTION OF ELEMENTS (EVEN TABLE ROWS!)
	//	'xhtml' - ANY HTML TO BE RENDERED TO EACH RESULT OF "target"
	//	'js' - (REQUIRED) ANY JS TO BE EVAL AFTER XHMTL HAS BEEN RENEDERED. 
	// 	'linkJs' - ARRAY OF JS FILES TO BE LINKED TO THE PAGE (IF NOT ALREADY LINKED).
	//
	//  NOTE: FOR XHTML TO BE USED, YOU MUST RETURN THE 'target' JQUERY OBJECT.
	//		 FOR EXAMPLE, IN PHP - $response['target']="target=jQuery("#mydiv");";
	//		 IF NO TARGET IS INCLUDED IN THE RESPONSE, ONLY THE 'js' WILL EXECUTE.
	//
	// SET $.PANTHER.DEBUG=TRUE FOR DEBUG MESSAGES IN THE CONSOLE.	
	// SET OF DEFAULT OPTIONS FOR LOADER.  I RECOMMEND THAT YOU CUSTOMIZE THIS OBJ IN YOUR OWN SCRIPT. THEN FOR ALL CALLS, CLONE THE OBJECT, EXTEND THE CLONE, THEN PASS TO JCALL
	jcallLoaderOpts : {
		delay:200,
		transSpeed:10,		
		sel:'#smallLoader',
		ap:"#header",
		loc : "top-right",				
		offset:{offsetX:0,offsetY:0}
	},
	// SET OF DEFAULT OPTIONS FOR JCALL.  I RECOMMEND THAT YOU CUSTOMIZE THIS OBJ IN YOUR OWN SCRIPT. THEN FOR ALL CALLS, CLONE THE OBJECT, EXTEND THE CLONE, THEN PASS TO JCALL
	jcallOpts : {
		url:"/handler.aspx",
		setWait:true,
		jsonly:false,
		scall:false,
		noloader: false,
		persistloader: false,						
		timeBeforeGivingUp:10000,
		timeoutAction: function(reqestObj){alert("Sorry, it is taking too long for a response.  Please try again");},
		errorAction: function(reqestObj){alert("Sorry, an error has occurred.  Please contact an administrator.");},	
		loaderOpts:jQuery.extend({},this.jcallLoaderOpts)
	},
	jcallHandleResp:function(resp){
		var jp=jQuery.panther;		
		target=jQuery(resp['target']);
		if( "undefined"!=typeof(target) && "undefined"!=typeof(resp['xhtml']) && resp['xhtml']!=null && target!=null  ) {
			target.each(function(){
				if(this.nodeName=="TR") {
					jQuery(this).trHtml(resp['xhtml']);
				} else {
					if(resp['mode']=="append"){
						jQuery(this).append(resp['xhtml']);
					} else {
						jQuery(this).html(resp['xhtml']);
					}
				}
			});
		}
		if ("undefined"!=typeof(resp['linkJs'])){
			for (var i=0;i<resp['linkJs'].length;i++) {
			 jQuery('head').append("<script type='text/javascript' src='"+resp['linkJs']+"'></script>");
			}
		}
		//todo, linkJsOnce
	    eval(resp['js']);
	},
	jcall:function(func,params,opt){
	var jp=jQuery.panther;
	if("undefined"==typeof(opt)) opt=this.jcallOpts;
	if("undefined"==typeof(params)) params=[];	
	var settings={};
	if(opt.scall) jQuery.extend(settings,{sess:jp.sess});
	if(opt.setWait) jp.wait=true;
		else jQuery.extend(settings,{setWait:false});
	if(opt.jsonly) jQuery.extend(settings,{jsonly:true});	
	if(!opt.noloader){
		var loaderID=Math.floor(Math.random()*999);
		var goLoader=function(){
			if(jQuery(opt.loaderOpts.ap).length<1 && jp.debug) {
				jp.console("WRN-Can't display loader. Anchor point 'ap="+opt.loaderOpts.ap+"' is unselectable for loaderOpts.");
				return false;
			}
			if(jQuery(opt.loaderOpts.sel).length<1 && jp.debug) {
				jp.console("WRN-Can't display loader. Loader image/element selector 'sel="+opt.loaderOpts.sel+"' is unselectable for loaderOpts.","error");
				return false;
			}
			jQuery(opt.loaderOpts.sel).clone().attr("id",loaderID).placer(opt.loaderOpts.ap, { offsetX : opt.loaderOpts.offset.offsetX , offsetY : opt.loaderOpts.offset.offsetY , where : opt.loaderOpts.loc } ).fadeIn(opt.loaderOpts.transSpeed);
		}
		setTimeout(goLoader, opt.loaderOpts.timeout);
	}

	jQuery.ajax({
		type: "POST",
		url: opt.url,
		dataType: "json",
		data: { func: func, parameters: jQuery.compactJSON(params), settings:jQuery.toJSON(settings) },
		timeout: opt.timeBeforeGivingUp,
		success: function(resp){
		if ((!opt.noloader && !opt.persistloader) || resp[0]['kldr']) jQuery("#" + loaderID).fadeOut(opt.loaderOpts.transSpeed, function() {
				while (jQuery("#"+loaderID).length>0) jQuery("#"+loaderID).remove();
			});			
			for ( key in resp ) {
				if (jp.debugResp) {
					jp.console("RESPONSE #"+key+" "+func+" "+params[0]+" "+params[1]);
					jp.console(key+"->XHTML\n"+resp[key]['xhtml']);
					jp.console(key+"->SCRIPT\n"+resp[key]['js']);
				}										
				if(resp[key]) jp.jcallHandleResp(resp[key]) 
				else if (jp.debug) jp.console("INFO-An empty response was ignored");
			}
		},
		error: function(XMLHttpRequest, textStatus, errorThrown) {
				if(opt.setWait) jp.wait=false;
				
		        if (textStatus!=undefined && jp.debug) jp.console("ERR-There was ajax call error:"+textStatus,"error");
		        if (errorThrown!=undefined && jp.debug) jp.console("ERR-There was ajax call exception:"+errorThrown,"error");
				if (!opt.noloader) jQuery("#"+loaderID).fadeOut(opt.loaderOpts.transSpeed, function(){
					while (jQuery("#"+loaderID).length>0) jQuery("#"+loaderID).remove();
				});
				if (textStatus=="timeout") {
					opt.timeoutAction(XMLHttpRequest);	
				} else {
					if (jp.debug) jp.console("RESP-"+XMLHttpRequest.responseText); 
					opt.errorAction(XMLHttpRequest);									
				}	
		}
	 });
	}
}
});