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:"#footer", // ALTERNATE PLACE TO OUTPUT ERRORS IF THERE IS NO FIREBUG CONSOLE	
	sess:"",
	store:[],
	notice:function(sel,msg,sticky){
		while ($(sel).is(":animated")) {
            $(sel).queue("fx", []);
            $(sel).stop();
        }	
		jQuery(sel).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;
			if(typeof msg != "string") msg="Invalid console param.  Not a string.";
			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);
	},
	// tableToCsv 
	// @author : Jeremy Dill
	// @param [selector] tableSel : table to export
	// @param [str] headings : csv list of headings.
	// @notes: add class of "noex" to td to not inlclude in csv
	// @package : tplPanther
	tableToCsv : function (tableSel,headings) {
		var table=[]
		var i=1;
		table[0]=headings;
		//do all visble rows.
		jQuery(tableSel+" tbody tr:visible")
			.each(function(){

				jQuery(this).find('td').not(".noex")
					.each(function(){
						if(typeof(table[i])=="undefined") table[i]=jQuery(this).text();
						 else table[i]+=","+jQuery(this).text();
					});	
				i++;		
			});	
	
		var url="/_common_php/export.php";
				
		$("body").append("<form name='redir' action='"+url+"' method='POST'><input type='hidden' name='parameters' value='"+jQuery.compactJSON(table)+"'></form>");
		document.redir.submit();
		$("form[name='redir']").remove();
	},	
	// JCALL - AJAX CALL AND RESPONSE HANDLER
	// @author : Jeremy Dill
	// @ver : 1.4
	// @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
	//			[bool] persistLoader (false) :  keep loader after returning response.
	//			[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).
	// 	'mode' - OPTIONAL FUNCTION CALL INSTEAD OF ASSIGNING NEW CONTENT TO TARGET, YOU CAN 'append','prepend,'after','before' OR 'replaceWith' ON THE TARGET SELECTOR
	//  'kldr' - USE ALONG WITH 'persistLoader' OPTION TO CONTROL ON/OFF LOADER.  SET $resp['kldr']=1 IN FIRST RESPONSE TO KILL PERSISTANT LOADER 
	//
	//  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:"body",
		loc : "top-right",				
		offset:{offsetX:5,offsetY:5}
	},
	// 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:"/jq-ajax/ajax.php",
		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){if(!jQuery.panther.debug) alert("Sorry, an error has occurred.  Please contact an administrator.");},	
		loaderOpts:jQuery.extend({},this.jcallLoaderOpts)
	},
	// SET UP ANCHOR POINT JCALL LOADER OPTIONS
	apLoader:function(apsel,o) {
		o = jQuery.extend({
			delay:$.panther.jcallLoaderOpts.delay,
			transSpeed:$.panther.jcallLoaderOpts.transSpeed,		
			sel:$.panther.jcallLoaderOpts.sel,
			loc:$.panther.jcallLoaderOpts.loc,				
			offset:{offsetX:($(apsel).width()*.2),offsetY:($(apsel).height()/2)-8}
		}, o);
        aLoad = $($.panther.jcallLoaderOpts).cloneObj({ offset: o.offset, loc: o.loc, ap: apsel, sel: o.sel, transSpeed:o.transSpeed , delay: o.delay });
        return $($.panther.jcallOpts).cloneObj({ loaderOpts: aLoad });
    },
	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 {
					switch(resp['mode']){
						case "append":
							jQuery(this).append(resp['xhtml']);
						break;
						case "prepend":
							jQuery(this).prepend(resp['xhtml']);
						break;
						case "before":
							jQuery(this).before(resp['xhtml']);
						break;						
						case "after":
							jQuery(this).after(resp['xhtml']);
						break;
						case "replaceWith":
							jQuery(this).replaceWith(resp['xhtml']);
						break;																							
						default:
							jQuery(this).html(resp['xhtml']);
						break;
					}
				}
			});
		}
		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);									
				}	
		}
	 });
	}
}
});
