

// operate on list items. detach them form the recod set and the <li> parent or just send a signal to detach
function detach(tbl,pair,args)
{
	
	// setup default 
	var arg = {
				kill: '',
				fx: true,
				message: "Are you sure you want to detach " + pair + " from " + tbl + "?"
			}

	if(args) $.extend(arg, args);

	if(arg.kill == '') 
	{	
		alert("Misconfigured detach() call ... this is programers error. Sorry I can't delete your entry");
		return;
	}

	// // DEV ====
	// var mesg = 'deleting ' + id + ' from ' + tbl;
	// log(mesg);
	// // ========
	
	msg = arg.message;
					
	if(confirm(msg))
	{
		var cfg = 'table=' + tbl + '&set=' + pair + '&state=false';
		// alert("Sending -> " +  cfg);

		$.ajax({
			type: "POST",
			url: 'mod_associate.php',
			data: cfg,
			dataType: "json",
			timeout: 30000,
			error: function(arg1,arg2){ 
				alert( 'Error on process cbx_associate(). Error function reports -> args:['+arg1+'],['+arg2+']'); 
			},
			success: function(data){
		
				// extract json vars
				var ret = data.op[0].ret; 
				var msg = data.op[0].msg; 
				
				if(ret) 
				{
					if(arg.fx)
					{ 
						$('#' + arg.kill).hide('slow',function(){
							$('#' + arg.kill).remove();
						}); 
					} // fancy remove the html if requested
					else { $('#' + arg.kill).hide().remove(); } // just remove the trigger
				}	
				else // report the message returned from the server
				{
					report(msg,{cls:'apperr',type:'sticky'}); 
				}
			},
			complete: function(arg1,arg2){
				//alert( 'complete() reports -> args:['+arg1+'],['+arg2+']'); 
			}
		});
		

	} // else do nothing 

}

// this is a client side function that is designed to work hand in hand with get_cbx_group in util.inc
function cbxdel(table,cbx,args)
{
	// an expression to retrieve the text lable for the entry to delete.
	// This scould be passed in in args and evaled; then used to replace a placeholder in the message as passed in through args
	var entry_label = $(cbx).siblings('label').html();  
	
	var label = entry_label.replace(/\s*<[^>]*>\s*/,'').toUpperCase(); // remove tags from the entry_label

	// setup default 
	var arg = {
				//message: "Are you sure you want to delete %1 from %2 ?", // it would be really nice to do it this way and pass in  search and replace perams in teh args
				message: "Are you sure you want to delete the service: \n" + label + "?",
				remove: 'parent'
			};

	if(args) $.extend(arg, args);

	var msg = arg.message;

	// get the id of the element to delete ... this expression should be passed in args!
	var id = real($(cbx).siblings('label').children('input').attr('value'));

	if(confirm(msg))
	{	
		var pargs = 'id=' + id + '&table=' + table;
			
		// request removal of the object -> 	
		// server deletes a row from a table -> reports back
		// do ajax here -> get : status,message,sctipt
		$.ajax({
			type: "POST",
			url: 'mod_entry_del.php',
			data: pargs,
			dataType: "json",
			timeout: 30000,
			error: function(arg1,arg2){ 
				alert( 'Error ocurred in process cbxdel() [core.js]. Please contact findit@learningchange.com to report the error'); 
			},
			success: function(data){
				var ret = data.op[0].ret;
				var msg = data.op[0].msg;
				var scpt = data.op[0].scpt || null;

				if(ret) // server returned sucessful delete
				{
					switch(arg.remove)
					{
						case 'parent':
							$(cbx).parent().hide('slow');
						break;

						case 'self':
							// $('#' + arg.kill).hide('slow'); // leaving this for later if needed!
						break;
					}
				}	
				else // report the message returned from the server
				{
					alert('The delete operation failed beacuse of a server error. The message returned from the server was: ' + msg);
				}
			},
			complete: function(arg1,arg2){
				//alert( 'complete() reports -> args:['+arg1+'],['+arg2+']'); 
			}
		});
	} // else do nothing
}

function del(tbl,id,args)
{
	// setup default 

	var arg = {
			// err_into: 'app_err', // this was to be passed into report on delete failure ... but since its not working here you dont need it!
			// err_append: true, // this was to be passed into report on delete failure ... but since its not working here you dont need it!
			kill: '',
			fx: true,
			message: "Are you sure you want to delete " + id + " from " + tbl + "?",
			confirm: true,
			calback: false
		}

	if(args) $.extend(arg, args);

	if(arg.kill == '') 
	{	
		alert("Misconfigured del() call ... this is programers error. Sorry I can't delete your entry");
		return;
	}

	if(arg.confirm)
	{
		msg = arg.message;
						
		if(confirm(msg))
		{
			var pargs = 'id=' + id + '&table=' + tbl;
			
			// request removal of the object -> 	
			// server deletes a row from a table -> reports back
			// do ajax here -> get : status,message,sctipt
			$.ajax({
				type: "POST",
				url: 'mod_entry_del.php',
				data: pargs,
				dataType: "json",
				timeout: 30000,
				error: function(arg1,arg2){ 
					alert( 'Error ocurred in process del() [core.js]. Error function reports -> args:['+arg1+'],['+arg2+']'); 
				},
				success: function(data){
					var ret = data.op[0].ret;
					var msg = data.op[0].msg;
					var scpt = data.op[0].scpt || null;

					if(ret) // server returned sucessful delete
					{
						if(tbl == 'document')
						{
							if(arg.fx){ $('.' + arg.kill).hide('slow'); } // remove the html	
						}
						else
						{
							if(arg.fx){ $('#' + arg.kill).hide('slow'); } // remove the html 
						}
						
						if(arg.callback)
						{
							eval(arg.callback);
						}
					}	
					else // report the message returned from the server
					{
						alert('The delete operation failed beacuse of a server error. The message returned from the server was: ' + msg);
					}
				},
				complete: function(arg1,arg2){
					//alert( 'complete() reports -> args:['+arg1+'],['+arg2+']'); 
				}
			});
		} // else do nothing 
	}
	else
	{
		// request removal of the object -> 	// server deletes a row from a table -> reports back

		// do ajax here -> get : status,message,sctipt

		//if sucessful 
		//{
			if(arg.fx){ $('#' + arg.kill).hide('slow'); } // remove the html if requested
		//else // report the message returned from the server
		//{
			// 	report(msg,{cls:'apperr',type:'sticky'}); 
		//}
	}	


	
}

// function eldel(id,args)
// {
// 	// setup default function config
// 	var arg = {
// 				fx: true,
// 				message: "Are you sure you want to delete?",
// 				confirm: true
//               }
// 
// 	// merge any overrides
// 	if(args) $.extend(arg, args);
// 	
// 	if(arg.confirm) // ask to remove
// 	{
// 		msg = arg.message;
// 						
// 		if(confirm(msg))
// 		{
// 			if(arg.fx){ $('#' + id).hide('slow'); } 
// 			else $('#' + id).hide();		
// 		} 
// 	}
// 	else // just remove it
// 	{
// 		if(arg.fx){ $('#' + id).hide('slow'); } 
// 		else $('#' + id).hide();
// 	}	
// }

/*
operate on a checkbox. send messages to the server to record select value
table: the join table to manage the association in
id: a known id 
el: a html checkbox element; using these elements:
		el.value
		el.checked
ordered: do the arguments as passed in match the db table name like T1_T2 = t1-ID,t2-ID or are they backwards like t2-ID,t1-ID		
*/
function cbx_associate(table,id,el,ordered)
{
	var ordered = arguments[3] == false ? false : true; //define a default boolean value of true

	//create the argument string to pass to mod_associate.php
	var args = 'table=' + table;
	if(ordered) { args += '&set=' + id + ',' + real(el.value); } else { args += '&set=' + real(el.value) + ',' + id; }
	args += '&state=' + el.checked;

	// alert('sending args: ['+args+']');

	// send an ajax request to mod_associate.php
	$.ajax({
		type: "POST",
		url: 'mod_associate.php',
		data: args,
		dataType: "json",
		timeout: 30000,
		error: function(arg1,arg2){ 
			alert( 'Error on process cbx_associate(). Error function reports -> args:['+arg1+'],['+arg2+']'); 
		},
		success: function(data){
			
			// extract json vars
			var ret = data.op[0].ret; 
			var msg = data.op[0].msg; 
			
			// report the error message returned from the server 
			if(!ret) { report(msg,{cls:'apperr',type:'sticky'}); }
			// else // do nothing. the operation was successful
		},
		complete: function(arg1,arg2){
			//alert( 'complete() reports -> args:['+arg1+'],['+arg2+']'); 
		}
	});	
}

/*
create an entry in an assoiative (join) table using mod_associate.php
table: the join table to manage the association in
id1: a known id 
el2: a html checkbox element; using these elements:
		el.value
		el.checked
ordered: do the arguments as passed in match the db table name like T1_T2 = t1-ID,t2-ID or are they backwards like t2-ID,t1-ID		
*/
function associate(table,id1,id2,ordered)
{
	var ordered = arguments[3] == false ? false : true; //define a default boolean value of true

	//create the argument string to pass to mod_associate.php
	var args = 'table=' + table;
	if(ordered) { args += '&set=' + id1 + ',' + id2; } else { args += '&set=' + id2 + ',' + id1; }
	args += '&state=true';

	// alert('sending args: ['+args+']');

	// send an ajax request to mod_associate.php
	$.ajax({
		type: "POST",
		url: 'mod_associate.php',
		data: args,
		dataType: "json",
		timeout: 30000,
		error: function(arg1,arg2){ 
			alert( 'Error on process associate(). Error function reports -> args:['+arg1+'],['+arg2+']'); 
		},
		success: function(data){
			
			// extract json vars
			var ret = data.op[0].ret; 
			var msg = data.op[0].msg; 
			
			// report the error message returned from the server 
			if(!ret) { report(msg,{cls:'apperr',type:'sticky'}); }
			// else // do nothing. the operation was successful
		},
		complete: function(arg1,arg2){
			//alert( 'complete() reports -> args:['+arg1+'],['+arg2+']'); 
		}
	});	
}


/*
add an entry to the database see mod_entry_add.php for the server side code
table: the name of a table
f: a list of fields to use in an insert statement like: "f1,f2,f3,f4" -> server executes: insert into table (f1,f2,f3,f4) ...
fval: a list of values to insert into the "table" like: "'f1val','f2val','f3val','f4val'" -> server executes: insert into table (f1,f2,f3,f4) values ('f1val','f2val','f3val','f4val');
owner: the column name and the id of the owner (who owns the new data :-/ ) like: "id,1" ... see mod_entry_add.php
retobj: a javascript object passed back form the server that contains the row you just inserted or null if it failed		
*/
function addentry(table,f,fval,owner,retobj)
{	
	//create the argument string to pass to mod_associate.php
	var args = 'table=' + table + "&f=" + f + '&fval=' + fval + "&o=" + owner;

	// send an ajax request to mod_associate.php
	$.ajax({
		async: false, // this is so we can get the values from sucess: and pass them into the ret_obj
		type: "POST",
		url: 'mod_entry_add.php',
		data: args,
		dataType: "json",
		timeout: 30000,
		error: function(arg1,arg2){ 
			alert( 'error() on process addentry(). Error function reports -> args:['+arg1+'],['+arg2+']'); 
		},
		success: function(data){
			
			// extract json vars and pass them back to the caller
			retobj.ret = data.op[0].ret; 
			retobj.msg = data.op[0].msg; 
			retobj.dat = data.op[0].dat;
		},
		complete: function(arg1,arg2){
			//alert( 'complete() reports -> args:['+arg1+'],['+arg2+']'); 
		}
	});	
}

/**
 * add an entry into the database and retrieve the results threough a return object
 * NOTE: This is a rewrite of addentry() which was written before the db.inc function get_last_insert() existed. 
 *
 * @return void
 * @author Dan Bryant <db@leadingtone.org>
 * @copyright LearningChange LLC - Dan Bryant (Shared Source Initiave/Dual Ownership),  4 May, 2007
 * @package core.js
 * @version: 1.0
 * @perams:
 *	table: the name of a table
 * 	fields: a list of fields to use in an insert statement like: "f1,f2,f3,f4" -> server executes: insert into table (f1,f2,f3,f4) ...
 * 	fvals: a list of values to insert into the "table" like: "'f1val','f2val','f3val','f4val'" -> server executes: insert into table (f1,f2,f3,f4) values ('f1val','f2val','f3val','f4val');
 * 	keyf: the name of the primary key field in the table you are inserting into
 * 	retobj: a javascript object passed back form the server that contains the row you just inserted or null if it failed

	sample call to db_addentry()
	
	obj = new Object(); // the object that will be stuffed by mod_db_addentry.php .. holds the newly inserted data
	retobj = {ret:'', msg:'', dat:obj}; // the return object will be stuffed by mod_entry_add.php 
	db_addentry('category','name',"'"+cname+"'",'id',retobj);

	if(retobj.ret)
	{
		eval(retobj.dat) // create the 'data' var to pull out the returned values
		log(jdump(data));
	}
	else //error occured
	{
		alert(retobj.msg);
	}

 **/
function db_addentry(table,fields,fvals,keyf,retobj)
{
	//create the argument string to pass to mod_associate.php
	var args = 'table=' + table + "&fields=" + fields + '&fvals=' + fvals + "&keyf=" + keyf;

	// send an ajax request to mod_associate.php
	$.ajax({
		async: false, // this is so we can get the values from sucess: and pass them into the retobj
		type: "POST",
		url: 'mod_db_addentry.php',
		data: args,
		dataType: "json",
		timeout: 30000,
		error: function(arg1,arg2){ 
			alert('error() on process db_addentry(). Your entry could not be added.'); 
		},
		success: function(data){
			// extract json vars and pass them back to the caller
			retobj.ret = data.op[0].ret; 
			retobj.msg = data.op[0].msg; 
			retobj.dat = data.op[0].dat;
		},
		complete: function(arg1,arg2){
			//alert( 'complete() reports -> args:['+arg1+'],['+arg2+']'); 
		}
	});
}


// wrapper fnuction for jQuery $.ajax
function load_content(page,args,target,fx)
{	
	/*
	$.ajax(prop)
	Load a remote page using an HTTP request. This function is the primary means of making AJAX requests using jQuery. $.ajax() takes one property, an object of key/value pairs, that're are used to initalize the request.

	These are all the key/values that can be passed in to 'prop':
		(String) type - The type of request to make (e.g. "POST" or "GET").
		(String) url - The URL of the page to request.
		(String) data - A string of data to be sent to the server (POST only).
		(String) dataType - The type of data that you're expecting back from the server (e.g. "xml", "html", "script", or "json").
		(Boolean) ifModified - Allow the request to be successful only if the response has changed since the last request, default is false, ignoring the Last-Modified header
		(Number) timeout - Local timeout to override global timeout, eg. to give a single request a longer timeout while all others timeout after 1 seconds, see $.ajaxTimeout
		(Boolean) global - Wheather to trigger global AJAX event handlers for this request, default is true. Set to true to prevent that global handlers like ajaxStart or ajaxStop are triggered.
		(Function) error - A function to be called if the request fails. 
						The function gets passed two arguments: The XMLHttpRequest object and a string describing the type of error that occurred.
		(Function) success - A function to be called if the request succeeds. 
						The function gets passed one argument: The data returned from the server, formatted according to the 'dataType' parameter.
		(Function) complete - A function to be called when the request finishes. 
						The function gets passed two arguments: The XMLHttpRequest object and a string describing the type the success of the request.
	
	example:
	$.ajax({ 
		type: "POST", 
		url: "some.php", 
		data: "name=John&location=Boston", 
		success: function(msg){ 
			alert( "Data Saved: " + msg ); 
			} 
		});
	
	*/
	
	$.ajax({
		type: "POST",
		url: page,
		data: args,
		dataType: "json",
		timeout: 30000,
		error: function(arg1,arg2){ 
			alert( 'error() on process ' + target + '. Error function reports -> args:['+arg1+'],['+arg2+']'); 
		},
		success: function(data){
			process_return(data,target,fx);
		},
		complete: function(arg1,arg2){
			//alert( 'complete() reports -> args:['+arg1+'],['+arg2+']'); 
		}
	});	
}

function process_return(data,target,fx)
{
	var ret = data.op[0].ret;
	var msg = data.op[0].msg;
	var scpt = data.op[0].scpt || null; // is any javascript'n returned from the server?
	 
	var fx = fx || false; // no visual cool by default

	// log('doing process return; ret:' + ret + ', msg:' + msg+ ', scpt:' + scpt);

	if(ret)
	{	
		//report(msg,{cls:'appmsg',type:'fade'}); // dont need message reporting for normal content loads
		
		if(!fx) // just show the content
		{ 
			$(target).html(msg); 
			
			// if there is scripting returned from the server then execute it
			if(scpt != null){ eval(scpt); }
		} 
		else // do the process return with a cool size animation and fade 
		{
			
			$(target).hide('fast',function() {$(target).html(msg);}); 
			$(target).fadeIn('slow');
			
			// if there is scripting returned from the server then execute it
			if(scpt != null) { eval(scpt); }
			
			// or all in one line!
			//$(target).hide('fast',function() {$(target).html(msg);}).fadeIn('slow'); 
		}
	}
	else
	{
		report(msg,{cls:'apperr',type:'sticky'}); // report the message returned from the server 
	
		if(!fx) { $(target).html(msg); } // just show the content
		else // do the process return with a cool size animation and fade 
		{
			$(target).hide('fast',function() {$(target).html(msg);}); 
			$(target).fadeIn('slow');
		
			// if there is scripting returned from the server then execute it
			if(scpt != null) { eval(scpt); }
		
			// or all in one line!
			//$(target).hide('fast',function() {$(target).html(msg);}).fadeIn('slow'); 
		}
	}	
}

 
/* Author: Dan Bryant <db@leadingtone.org>
 * description: a general message reporting function for jquery bassed web apps. 
 *   adds a error message to a <span id="app_msg">. The error message fades out after 5 seconds or on click if it is an error *
 * perams: 
 * 		msg: the error message                                                                                   
 * 		cfgin: aconfig object                                                                                    
 * 	 		inject: 'app_msg' :: where do you want to put the output?                                                
 * 	 		append: true :: append the output inside the inject or prepend it if false                               
 * 	 		cls:'apperr' :: set the class of the div ...                                                           
 * 	 		fade_length: a time to fade out in miliseconds; 1000 = 1 second; defaults to 10 seconds                  
 * 			type: ( sticky || fade ) :: sticky *cough* sticks until you click on it, fade automagicly fades out. defaults to fade 
 */
//function report(msg,cls,type,fade_length) 
function report(msg,cfgin) 
{	
	// define default values needed by this function	
	var cfg = {
		inject: 'app_msg',
		append: true,
		cls:'apperr',
		fade_length: 10000,
		type: 'fade'
	}

	if(cfgin) $.extend(cfg, cfgin);

	// log(msg);
	// log(jdump(cfg));

	// create the empty element and get the handle
	var dv = document.createElement("div");

	// add the requested class to the new div 
	if(document.all) { var ie = 'retarded'; dv.className = cfg.cls; } // ie specific code
	else { dv.setAttribute("class", cfg.cls); } // real browsers

	// add the div into the target
	if(cfg.append) { $('#' + cfg.inject).append(dv); }
	else $('#' + cfg.inject).prepend(dv);



	// set the error type and inject the content in to the new div
	switch(cfg.type)
	{
		case 'sticky':
			// show the message 
			close_msg = '<span class="sticky-message-button">close</span>';
			$(dv).html(close_msg + msg);
			$(dv).bind( "click", function() { $(dv).fadeOut("slow"); } )
		break;
		
		case 'fade':
			$(dv).html(msg);
			$(dv).fadeOut(cfg.fade_length);
		break;	
	}
}


/**
 * check if a value already exists in a db table
 *
 * @return void; returned by reference through ro (return object): a return object value (ro.ret) and a return object message (ro.msg)
 * @author Dan Bryant <db@leadingtone.org>
 * @copyright LearningChange LLC - Dan Bryant (Shared Source Initiave/Dual Ownership), 24 May, 2007
 * @package core.js
 * @version: 1.0
 * @perams:
 *	tbl = the table to check in
 *	key = the table key name to check for (like name, user_mail, etc...) a column that has a unique value
 *	value = the value to check and see if it already exists as a value for 'key'
 *	ro = values returned through this return object (ro.val & ro.msg)
 **/
function value_exists(tbl,key,val,ro)
{
	// send an ajax request to mod_exists.php
	var args = "table=" + encode(tbl) + '&key=' + encode(key) + '&value=' + encode(val);
	
	// log(args);
	
	$.ajax({
		async: false, // this is so we can get the values from sucess: and pass them into the ro
		type: "POST",
		url: 'mod_exists.php',
		data: args,
		dataType: "json",
		timeout: 30000,
		error: function(arg1,arg2){ 
			alert( 'error() on process value_exists().' ); 
		},
		success: function(data){
			
			// extract json vars
			var ret = data.op[0].ret; 
			var msg = data.op[0].msg; 
			
			ro.msg = msg;
			ro.ret = ret;
			
			// if(ret) is backwards from normal ... an error has occurred if the value exists
			//if(ret) { report(msg,'apperr','sticky'); } // report the error message returned from the server
			//else report(msg,'appmsg','fade');
		},
		complete: function(arg1,arg2){
			//alert( 'complete() reports -> args:['+arg1+'],['+arg2+']'); 
		}
	});
}

// ajax check to see if a key,value pair exists in the table and return the data back to the caller
function lookup_data(table,kv,ret_obj)
{
	// send an ajax request to mod_exists.php
	var args = "table=" + table + '&kv=' + kv;
	
	$.ajax({
		async: false, // this is so we can get the values from sucess: and pass them into the ret_obj
		type: "POST",
		url: 'mod_lookup.php',
		data: args,
		dataType: "json",
		timeout: 30000,
		error: function(arg1,arg2){ 
			alert( 'error() on process value_exists(). Error function reports -> args:['+arg1+'],['+arg2+']'); 
		},
		success: function(data){
			
			// extract json vars
			var ret = data.op[0].ret; 
			var msg = data.op[0].msg; 
			var dat = data.op[0].dat || null;
			
			ret_obj.msg = msg;
			ret_obj.ret = ret;
			ret_obj.dat = dat;
			
			// if(ret) is backwards from normal ... an error has occurred if the value exists
			//if(ret) { report(msg,'apperr','sticky'); } // report the error message returned from the server
			//else report(msg,'appmsg','fade');
		},
		complete: function(arg1,arg2){
			//alert( 'complete() reports -> args:['+arg1+'],['+arg2+']'); 
		}
	});
}



// this function signals mod_setpub.php to set is_published value of key id in the "tbl" to the value of the "cbx" as passed in "this"
// tbl = a database table 
// id = the id of the entry to set is_published in
// cbx = the actual checkbox as passed by "this"
function set_publish(tbl,id,cbx)
{
	// alert("doing set_publish for " + tbl + " with an id of " + id + ", using " + cbx.checked);	
	// alert("Doing set_publish for " + tbl);	

	args = "table="+tbl+"&id="+id+"&state=" + cbx.checked;
	
	$.ajax({
		type: "POST",
		url: 'mod_set_publish.php',
		data: args,
		dataType: "json",
		timeout: 30000,
		error: function(arg1,arg2){ 
			alert( 'A fatal error occured. Could not set the publishing perameter of id:' + id + ' in table: ' + tbl); 
		},
		success: function(data){
			
			// extract json vars
			var ret = data.op[0].ret; 
			var msg = data.op[0].msg; 

			if(!ret) { alert( 'A fatal error occured.\nCould not set the publishing perameter of id:' + id + ' in table: ' + tbl + '.\nThe server reports: ' + msg); } // report the error 
			else { /* nothing! */ }
		},
		complete: function(arg1,arg2){
			//alert( 'complete() reports -> args:['+arg1+'],['+arg2+']'); 
		}
	});	
}

/**
 * validate a field against arguments passed in through args
 *
 * @return bool
 * @author Dan Bryant <db@leadingtone.org>
 * @copyright LearningChange LLC - Dan Bryant (Shared Source Initiave/Dual Ownership),  1 May, 2007
 * @package core.js
 * @version: 1.0
 * @perams:
 *	field = a html input element
 *  prev_error = has an error already occured (take from previous return to validate) ... track previous errors
 *	args = a hash 
 *  	possible values:
 *			message: '',
 *  		preg: '',
 *  		match: null,
 *  		special: '',
 *  		remote: '',
 *  		rargs: '',
 *  		show_valid: false
 **/
function validate(field,no_error,args) 
{
	var arg = {
		errmsg: '',
		preg: '',
		match: null,
		special: '',
		remote: '',
		rargs: '',
		input_elm: false,
		show_valid: false
	}

	if(args) $.extend(arg, args);

	// get hte value of the field to check
	var check_val = (arg.input_elm) ? field : field.value;

	// Assume true
	retval = true;

	// Do we have a remote page to check?
	if(arg.remote)
	{
		// Do the ajax call using the remote for the page and the rargs. pass the json.return and json.message back to through this
	}
	else // do all the other checks
	{
		// If we have a preg see if value matches
		if(arg.preg)
		{
			if(!check_val.match(arg.preg)) retval = false; 
		}

		// If we have have a value match field check the two fields values
		if(arg.match)
		{
			if(check_val != arg.match.value) retval = false; 
		}

		// Do we have a special check to do?
		if(arg.special)
		{
			switch(arg.special)
			{
				case '!blank':
					if(check_val.replace(/\s+/,'').length == 0){ retval = false; }
				break;

				default: alert("Cannot handle special validation: " + arg.specal);
			}
		}		
	}

	// does a span class="vmesg" exist? remove it clearing the way for a new one for this field
	affect = (!arg.input_elm) ? field : arg.input_elm;
	
	$(affect).siblings(".vmesg").remove();

	// show the proper message for the set return value
	if(retval) 
	{
		if(arg.show_valid)
		{	
			// figure out the parent of this field and append the validation message to it

			$(affect).parent().append('<span class="vmesg"><img src="../codebase/jQuery_js/img/accept.gif" alt="good data" /></span>');
			
			// do we have a class spec for this? apply it to the parent
		}
		rval = (no_error) ? true : false; // dont return true if there was a previous error
		return rval;		
	}
	else
	{	
		var formatted_message = (arg.errmsg) ? '<span class="verror">' + arg.errmsg + '</span>' : '';
		
		// figure out the parent of this field and append the validation message to it
				
		// prepend or apend to the parent?
		
		$(affect).parent().append('<span class="vmesg"><img src="../codebase/jQuery_js/img/error.gif" alt="error in data" />' + formatted_message + '</span>');
		
		return false;
	}
}

/**
 * validate a field against arguments passed in through args
 *
 * @return bool
 * @author Dan Bryant <db@leadingtone.org>
 * @copyright LearningChange LLC - Dan Bryant (Shared Source Initiave/Dual Ownership),  1 May, 2007
 * @package core.js
 * @version: 1.0
 * @perams:
 *	field = a html input element
 *  prev_error = has an error already occured (take from previous return to validate) ... track previous errors
 *	args = a hash 
 *  	possible values:
 *			message: '',
 *  		preg: '',
 *  		match: null,
 *  		special: '',
 *  		remote: '',
 *  		rargs: '',
 *  		show_valid: false
 **/
function validate2(field,no_error,args) 
{
	var arg = {
		imagepath:'/codebase/jQuery_js/img/',
		image: 'error.gif',
		msgclass: 'verror',
		vmsg: '',
		preg: '',
		match: null,
		special: '',
		remote: '',
		rargs: '',
		input_elm: false,
		show_valid: false
	}

	if(args) $.extend(arg, args);

	// get hte value of the field to check
	var check_val = (arg.input_elm) ? field : field.value;

	// Assume true
	retval = true;

	// Do we have a remote page to check?
	if(arg.remote)
	{
		// Do the ajax call using the remote for the page and the rargs. pass the json.return and json.message back to through this
	}
	else // do all the other checks
	{
		// If we have a preg see if value matches
		if(arg.preg)
		{
			if(!check_val.match(arg.preg)) retval = false; 
		}

		// If we have have a value match field check the two fields values
		if(arg.match)
		{
			// match against a single value if check_val is not an array ... if it is then loob through the array breaking and true when found
			if(check_val != arg.match.value) retval = false; 
		}

		// Do we have a special check to do?
		if(arg.special)
		{
			switch(arg.special)
			{
				case '!blank':
					if(check_val.replace(/\s+/,'').length == 0){ retval = false; }
				break;

				case '!url':
				 	if(!check_val.match(/^((ht|f)tp(s?)\:\/\/|~\/|\/)?([\w]+:\w+@)?([a-zA-Z]{1}([\w\-]+\.)+([\w]{2,5}))(:[\d]{1,5})?((\/?\w+\/)+|\/?)(\w+\.[\w]{3,4})?((\?\w+=\w+)?(&\w+=\w+)*)?/)){ retval = false; }
				break;

				case '!email':
					if(!echeck(check_val)){ retval = false; }
				break;


				default: alert("Cannot handle special validation: " + arg.specal);
			}
		}		
	}

	// does a span class="vmesg" exist? remove it clearing the way for a new one for this field
	affect = (!arg.input_elm) ? field : arg.input_elm;
	$(affect).siblings(".vmesg").remove();

	// show the proper message for the set return value
	if(retval) 
	{
		if(arg.show_valid)
		{	
			// figure out the parent of this field and append the validation message to it

			$(affect).parent().append('<span class="vmesg"><img src="'+arg.imagepath+'accept.gif" alt="good data" /></span>');
			
			// do we have a class spec for this? apply it to the parent
		}
		rval = (no_error) ? true : false; // dont return true if there was a previous error
		return rval;		
	}
	else
	{	
		var formatted_message = (arg.errmsg) ? '<span class="'+arg.msgclass+'">' + arg.vmsg + '</span>' : '';
		
		// figure out the parent of this field and append the validation message to it
				
		// prepend or apend to the parent?
		
		$(affect).parent().append('<span class="vmesg"><img src="'+arg.imagepath+''+arg.image+'" alt="error in data" />' + formatted_message + '</span>');
		
		return false;
	}
}



// visit a "page" with the "args"
function go(url)
{
	window.location = url;
}

// analog of php function
/**
 * check if a varialble 'v' is empty null or undefined
 *
 * @return void
 * @author Dan Bryant <db@leadingtone.org>
 * @copyright LearningChange LLC - Dan Bryant (Shared Source Initiave/Dual Ownership),  1 May, 2007
 * @package core.js
 * @version: 1.0
 * @perams:
 *	v = a variable
 **/
function empty(v) // I want my, I want my empty v!
{
	switch(v)
	{
		case "": return true; break;
		case null: return true; break;
		case undefined: return true; break;
	}
	return false;
}

// fucking thickbox
function tb_latch(anchor) // in the form of '#anchor_id'
{
	$(anchor).click(function(event){
		// stop default behaviour
		event.preventDefault();
		// remove click border
		this.blur();
	
		// get caption: either title or name attribute
		var caption = this.title || this.name || "";
		
		// get rel attribute for image groups
		var group = this.rel || false;
		
		// display the box for the elements href
		TB_show(caption, this.href, group);
	});
}

/**
 * see if a string is made entirely of spaces or blank
 *
 * @return void
 * @author Dan Bryant <db@leadingtone.org>
 * @copyright LearningChange LLC - Dan Bryant (Shared Source Initiave/Dual Ownership),  7 May, 2007
 * @package core.js
 * @version: 1.0
 * @perams:
 *	look = sring to look at
 **/
function blank(look)
{
	if(look.match(/^\s+$/)) return true;
	return false; // else 
}


// // hide the input_info spans in all pages ... show_info() will show them ... if you formatted them properly! see example in frm_documents_attached.php
// $(document).ready(function() { 
// 	$('.input_info').hide(); 
// });

/**
 * get the value in a radio button group 
 *
 * @return selected index value or null
 * @author Dan Bryant <db@leadingtone.org>
 * @copyright LearningChange LLC - Dan Bryant (Shared Source Initiave/Dual Ownership), 12 April, 2007
 * @package core.js
 * @version: 1.0
 * @perams: 
 * 	radio = the actual radio element (!!NOT!! its id/name)
 **/
function get_radio_value(radio)
{
	for (var c = 0; c < radio.length; c++)
	{
		// alert(radio[c].value);		
		// alert(radio[c].checked);
		
		if (radio[c].checked)
		{
		 	return radio[c].value; // a checked value found ... return it
		}	
	}
	return ''; // no checked value found ... returning '' instead of null so that the output of this function can more easily be used in validate()
	// return null; // no checked value found ... 
}

/**
 * // this is a wrapper to allow iframes to add elemts back into the parent window
 *
 * @return void
 * @author Dan Bryant <db@leadingtone.org>
 * @copyright LearningChange LLC - Dan Bryant (Shared Source Initiave/Dual Ownership), 24 May, 2007
 * @package core.js
 * @version: 1.0
 * @perams:
 *	content = the contet to add into the target
 *	target = the target to add the content into
 * 	after = set to false if you want to prepend into the target
 **/
function add_html(content,target,after)
{
	after = after || true;
	
	if(after)
	{
		$(target).append(content);		
	}
	else
	{
		$(target).prepend(content);				
	}
}

// shows the .input_info element contained in "el"
function show_info(el)
{
	// hide any present validation messages set by validate() :: core.js
	$('.vmesg').remove();

	// show the info message
	$(el).parent().children('.input_info').toggle('slow');
}

// if el has value of val then clear it ... use this on text input elements
function clearme(el,val) { if(el.value == val) el.value = ""; }

// ez timstamp!
function timestamp() { return new Date().getTime(); }

// ez microtime!
function microtime() { return new Date().getUTCMilliseconds(); }

// look in a needle property in a object (obj) haystack
function has(property,obj) { if(obj.hasOwnProperty(property)) return true; return false; }

// javascript *cough* javascript ticks! see util.inc for an analogus function ( this ones ancestor ... don't ask )
function jjsticks(string) { return string.replace("'",'&#39;');	}

// fix any characters that could choke html or javascript
// see util.inc for an analogus function ( this ones ancestor ... don't ask )
function jjstring(string)
{
	string = string.replace('/"/g','&rdquo;'); // encode any '"' 
	string = string.replace('/\\/g',"&#92;"); // encode any "\"
	string = string.replace("/'/g",'&rsquo;'); // encode any "'"
	return string;
}

// get a real id from a fake id ... cause html is stupid! not allowing an id to start with a number ... <valleyGirl>I mean C'mon, like get real!</valleyGirl>
function real(id) { return id.substr(1,id.length) }

// cause javascript counterpart for bool2chk() -> see: util.php
function jbool2chk(val) { if(val) return 'checked="checked"'; }

// force the whole app to refresh itself .. after a child window updates a detail in the parent
function reboot_view()
{
	// window.location.reload(); // this is a problem if there is data on the post...
	// dont include post data when rebooting the view!
	window.location = window.location; 
}

function fakesave()
{
	alert('Your work has been saved!');
	reboot_view();
}

// wrapper!
function encode(str)
{
	var str = encodeURIComponent(str);
	if(!str) return false;
	return str;
}

// wrapper!
function decode(str)
{
	var str = decodeURIComponent(str);
	if(!str) return false;
	return str;
}

/**
 * Prints a formatted string (like PHP printf())
 *
 * @return string|false
 * @author Matt Bower <matt@webbower.com>
 * @copyright 
 * @package 
 * @version: 1.0
 * @perams:
 *	
 **/
function printf(formattedString) {
    var s = formattedString;
    if(s.match(/%s/g).length != (arguments.length-1)) {
        alert('Warning. Number of placeholders does not match number of arguments');
        return false;
    }
    for (var ctr = 1 ; ctr < arguments.length ; ctr++) {
        if(s.indexOf('%s') == -1) break;
        s = s.replace(/%s/, arguments[ctr]);
    }
    return s;
}

// neat function found here: http://ajaxcookbook.org/javascript-debug-log/
/*
for (var i = 0; i < 10; i++) {
    log("This is log message #" + i);
}
*/
function log(message) {
    if (!log.window_ || log.window_.closed) {
        var win = window.open("", null, "width=400,height=200," +
                              "scrollbars=yes,resizable=yes,status=no," +
                              "location=no,menubar=no,toolbar=no");
        if (!win) return;
        var doc = win.document;
        doc.write("<html><head><title>Debug Log</title></head>" +
                  "<body></body></html>");
        doc.close();
        log.window_ = win;
    }
    var logLine = log.window_.document.createElement("pre");
    logLine.appendChild(log.window_.document.createTextNode(message));
    log.window_.document.body.appendChild(logLine);
}
/**
* Function : dump()
* Arguments: The data - array,hash(associative array),object
*    The level - OPTIONAL
* Returns  : The textual representation of the array.
* This function was inspired by the print_r function of PHP.
* This will accept some data as the argument and return a
* text that will be a more readable version of the
* array/hash/object that is given.
*/
function jdump(arr,level) 
{
	var dumped_text = "";
	if(!level) level = 0;

	//The padding given at the beginning of the line.
	var level_padding = "";
	for(var j=0;j<level+1;j++) level_padding += "    ";

	if(typeof(arr) == 'object') 
	{ //Array/Hashes/Objects
 		for(var item in arr) 
		{
  			var value = arr[item];

			if(typeof(value) == 'object') 
			{ //If it is an array,
				dumped_text += level_padding + "'" + item + "' ...\n";
	   			dumped_text += dump(value,level+1);
	  		} 
			else 
			{
	   			dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
	  		}
		}
	} 
	else 
	{ //Stings/Chars/Numbers etc.
	 	dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
	}
	return dumped_text;
}

//http://www.bigbold.com/snippets/posts/show/759
function vdump(obj) 
{
   	if(typeof obj == "object") 
	{
      	return "Type: "+typeof(obj)+((obj.constructor) ? "\nConstructor: "+obj.constructor : "")+"\nValue: " + obj;
   	}
 	else 
	{
      	return "Type: "+typeof(obj)+"\nValue: "+obj;
   	}
}


// http://blog.firetree.net/2005/07/04/javascript-find-position/
function findPosX(obj)
{
  var curleft = 0;
  if(obj.offsetParent)
      while(1) 
      {
        curleft += obj.offsetLeft;
        if(!obj.offsetParent)
          break;
        obj = obj.offsetParent;
      }
  else if(obj.x)
      curleft += obj.x;
  return curleft;
}
// http://blog.firetree.net/2005/07/04/javascript-find-position/
function findPosY(obj)
{
  var curtop = 0;
  if(obj.offsetParent)
      while(1)
      {
        curtop += obj.offsetTop;
        if(!obj.offsetParent)
          break;
        obj = obj.offsetParent;
      }
  else if(obj.y)
      curtop += obj.y;
  return curtop;
}

/**
 * DHTML email validation script. Courtesy of SmartWebby.com (http://www.smartwebby.com/dhtml/)
 */
function echeck(str) {

	var at="@";
	var dot=".";
	var lat=str.indexOf(at);
	var lstr=str.length;
	var ldot=str.indexOf(dot);
	if (str.indexOf(at)==-1){
	   // alert("Invalid E-mail ID")
	   return false;
	}

	if (str.indexOf(at)==-1 || str.indexOf(at)==0 || str.indexOf(at)==lstr){
	   // alert("Invalid E-mail ID")
	   return false;
	}

	if (str.indexOf(dot)==-1 || str.indexOf(dot)==0 || str.indexOf(dot)==lstr){
	    // alert("Invalid E-mail ID")
	    return false;
	}

	 if (str.indexOf(at,(lat+1))!=-1){
	    // alert("Invalid E-mail ID")
	    return false;
	 }

	 if (str.substring(lat-1,lat)==dot || str.substring(lat+1,lat+2)==dot){
	    // alert("Invalid E-mail ID")
	    return false;
	 }

	 if (str.indexOf(dot,(lat+2))==-1){
	    // alert("Invalid E-mail ID")
	    return false;
	 }
	
	if (str.indexOf(" ")!=-1){
		// alert("Invalid E-mail ID")
		return false;
	}

	return true;					
}


