;
/**
 * author: Simon Au-Yong
 * @module ajax_fw A core set of tools as part of the WebMart MVC framework
 * @namespace jQuery
 */

(function(){

		/**
		 * dependency checks
		 * @requires jQuery and JSON.org parser
		 */
		if(typeof jQuery==='undefined'){
			throw new Error('The base jQuery library needs to be included prior to loading the framework.');
		}
		if(typeof JSON==='undefined'){
			throw new Error('The JSON.org library needs to be included prior to loading the framework.');
		}

		/**
		 * Some ajax_fw calls do not require selectors, so here's an alternative API
		 * @method ajax_fw
		 * @param fn function Returns the object with the necessary params
		 * @namespace jQuery
		 * @return jQuery|string|number|boolean|function|array|object|null|NaN|undefined
		 * @static
		 */
		jQuery.ajax_fw = function(fn){
			return jQuery(document).ajax_fw(fn);
		};

		/**
		 * Persistent JS storage objects for the datatable, do not use!
		 * @private
		 */
		jQuery.ajax_fw.rowclicked_callback={};
		jQuery.ajax_fw.cellclicked_callback={};
		jQuery.ajax_fw.classclicked_callback={};
		jQuery.ajax_fw.datatable_callback={};
		jQuery.ajax_fw.classlist={};

		jQuery.ajax_fw.maskcount=0;
		jQuery.ajax_fw.get_mask_dimension = function() {
	    	var theBody = document.getElementsByTagName("BODY")[0];

			var fullHeight;
			if (window.innerHeight!=window.undefined){
				fullHeight = window.innerHeight;
			}else if (document.compatMode=='CSS1Compat'){
				fullHeight = document.documentElement.clientHeight;
			}else if (document.body){
				fullHeight = document.body.clientHeight;
			}

			var fullWidth;
			if (window.innerWidth!=window.undefined){
				fullWidth = window.innerWidth;
			}else if (document.compatMode=='CSS1Compat'){
				fullWidth = document.documentElement.clientWidth;
			}else if (document.body){
				fullWidth = document.body.clientWidth;
			}

			// Determine what's bigger, scrollHeight or fullHeight / width
			if (fullHeight > theBody.scrollHeight) {
				maskHeight = fullHeight;
			} else {
				maskHeight = theBody.scrollHeight;
			}

			if (fullWidth > theBody.scrollWidth) {
				maskWidth = fullWidth;
			} else {
				maskWidth = theBody.scrollWidth;
			}
			return [maskHeight,maskWidth];
		}
		window.onresize = function(event) {
		    if (jQuery('#loading_mask').length!=0){
		    	var dimensions = jQuery.ajax_fw.get_mask_dimension();
				jQuery('#loading_mask').height(dimensions[0]);
				jQuery('#loading_mask').width(dimensions[1]);
			}
		}

		/**
		 * @method ajax_fw
		 * @namespace jQuery()
		 * @return jQuery|string|number|boolean|function|array|object|null|NaN|undefined
		 * @static
		 */
		jQuery.fn.ajax_fw  = function(fn){
			var settings;
			var config;
			var pagename;
			var evalstring;
			var returnval;
			/**
			 * An internal supercontainer
			 * @private
			 */
			config = {

				/**
				 * 'Class members'
				 * @private
				 * @param xhr_tracker object An object to keep track of xhrs
				 * @param json_payload object Temp location for JSON messages
				 */
				mask_count: 0,
				xhr_tracker: {},
				json_payload: undefined,

				/**
				 * @private
				 * @method get_querystring Returns key value pairs from a GET-based URL (or an empty string if unsuccessful)
				 * @param seek
				 * @param url
				 * @return string | object
				 */
				get_querystring: function(seek,url){
					var myvars ='{';
					var tempvars;
					var queryfragments;
					var counterr=0;
					(typeof url==='undefined') ? queryfragments = window.location.href.split(/[\\?&\#]/) : queryfragments = url.split(/[\\?&\#]/);
					if(typeof queryfragments[1]!=='undefined'){
						queryfragments.shift();
						if(typeof seek==='object' || seek==='all'){
							jQuery(queryfragments).each(function(){
									tempvars = this.split(/=/);
									if (tempvars.length == 2){
										if(seek==='all'){
											if(counterr!==0 && counterr!==queryfragments.length){
												myvars+=',';
											}
											myvars+= '"'+tempvars[0]+'":"'+tempvars[1].replace(/[&#]/g,'')+'"';
										} else if(typeof seek==='object') {
											jQuery(seek).each(function(){
													if(this==tempvars[0]){
														if(counterr!==0 && counterr!==queryfragments.length){
															myvars+=',';
														}
														myvars+= '"'+tempvars[0]+'":"'+tempvars[1].replace(/[&#]/g,'')+'"';
													}
											});
										}
										counterr++;
									}
							});
							myvars+='}';
							myvars=this.json_string_to_jsobj(myvars);
						} else {
							if (tempvars.length == 2){
								tempvars = queryfragments[0].split(/=/);
								myvars= tempvars[1].replace(/[&#]/g,'');
							}
						}
					} else {
						myvars = '';
					}
					return myvars;
				},

				/**
				 * @private
				 * @method show_modal Displays a custom modal
				 * @return void
				 */
				show_modal: function(context){
					if (jQuery.ajax_fw.maskcount===0){
						if (jQuery('#loading_mask').length!==0){
							jQuery('#loading_mask').show();
						}else{
							jQuery('body').append('<div id="loading_mask"><div id="fw_working"></div></div>');
						}
				    	var dimensions = jQuery.ajax_fw.get_mask_dimension();
						jQuery('#loading_mask').height(dimensions[0]);
						jQuery('#loading_mask').width(dimensions[1]);
					}
					jQuery.ajax_fw.maskcount++;
				},

				/**
				 * @private
				 * @method show_modal Hides the custom modal; must be called after show_modal
				 * @return void
				 */
				hide_modal: function(context){
					if(jQuery.ajax_fw.maskcount==1){
						jQuery('#loading_mask').hide();
					}
					jQuery.ajax_fw.maskcount--;
				},

				/**
				 * @private
				 * @method json_string_to_jsobj Convert an xhr response (JSON string) into a JS object *without* eval()
				 * @param inputstring string The JSON string
				 * @param flagg boolean If set to true the object will be wrapped in framework methods otherwise the raw xhr response will be returned
				 * @return object
				 */
				json_string_to_jsobj: function(inputstring,flagg){
					var xhr_response;
					var returnobject;
					xhr_response = 'return (' + inputstring + ')';
					xhr_response = Function(xhr_response);
					xhr_response = xhr_response();
					//return the object with methods, if it's not generic
					if(flagg){
						returnobject = {
							get_status: function() {
								return xhr_response.status;
							},
							get_message:  function() {
								return xhr_response.message;
							},
							data: xhr_response.data
						};
					} else {
						returnobject = xhr_response;
					}
					return returnobject;
				},

				/**
				 * @private
				 * @method get_string_check A flexible string checker
				 * @param thestring string Your input
				 * @param theflag boolean true enables it to bypass the string check if thestring isn't set
				 * @return boolean | string
				 */
				get_string_check: function(thestring,theflag){
					var theresult =false;
					if(theflag){//undefined goes through; only for non-compulsory strings
						(typeof thestring==='undefined')
						? theresult = true
						: (typeof thestring==='string')
						? theresult = true
						: '';
					}
					(typeof thestring==='string') ? theresult = true : '';
					return theresult;
				},

				/**
				 * @private
				 * @method get_params_check Parameter checking
				 * @param theparams array Parameters to be checked
				 * @param theflag string Currently with a value of 'compulsory-string' only
				 * @param callerfunc string The caller's name
				 * @return boolean
				 */
				get_params_check: function(theparams,theflag,callerfunc){
					if(!jQuery.isArray(theparams)) {
						throw new Error("get_params_check() params are incorrect;"
							+ "check your "
							+ callerfunc
							+ " function [Error code: 1]");
					}
					if(theflag==='compulsory-string'){
						var o_parent = this;
						var counterr = theparams.length;
						var memberr;
						var theresult = false;
						var recursive_array_iteration = function(a_input) {
							if(counterr === 0){
								theresult = true;
							} else {
								memberr = theparams.shift();
								--counterr;
								if(!o_parent.get_string_check(memberr)){
									return false;
								}
								arguments.callee(theparams);
							}
						}
						recursive_array_iteration(theparams);
						return theresult;
					}
				},

				/**
				 * @private
				 * @method get_array_from_object Returns an array of either the keys or the values of an object
				 * @param inputt object Your native JS object
				 * @param flagg boolean if true then you get the keys
				 * @return array
				 */
				get_array_from_object:function(inputt,flagg) {
					if(typeof inputt!=='object'
						|| typeof inputt==='undefined'
					|| typeof inputt==='object' && inputt===null) {
					throw new Error("An application error has occurred. [Error code: 2]");
					}
					var return_array = [];
					var countt = 0;
					var s_member = '';
					for(var s_member in inputt){
						(flagg)
						? return_array[countt] = inputt[s_member]
						: return_array[countt] = s_member;
						countt++;
					}
					return return_array;
				},
				
				/**
				 * @private
				 * @method upload hidden iframe-based file upload
				 * @see http://valums.com/ajax-upload/
				 * @param class_name string Class to be called
				 * @param function_name string Method to be called
				 * @param selectfile_anchorid string The id of the anchor (it *has* to be an <a>) to trigger the filesystem dialogue
				 * @param displayfilename_divid string The id of the div to display the filename in (you can use other elements like <span> though)
				 * @param uploadfile_anchorid string The id of the anchor (it *has* to be an <a>) for the user to click to fire the upload event
				 * @param file_extensions string Single or multiple regex atoms, e.g. gif|png|jpg|jpeg
				 * @param callback function Lambda
				 * @param message object|string Messaging payload
				 * @return void
				 */
				 upload: function(class_name, function_name, selectfile_anchorid, displayfilename_divid, uploadfile_anchorid, file_extensions, callback, message) {
					var this_context;
					var session_id;
					var options_obj;
					var s_name;
					var upload_obj;
					if(typeof AjaxUpload==='undefined'){
						throw new Error('AjaxUpload library needs to be included prior to loading the framework.');
					}
					this_context = this;
					session_id = this_context.get_querystring('all').sess_id;
					(typeof message==='object' && typeof message.filename=='string') ? s_name = message.filename : s_name=displayfilename_divid;
					options_obj = {
						action: 'main.php?c='
						+ class_name
						+ '&f='
						+ function_name
						+ '&s='
						+ session_id
						+ '&n='
						+ window.name,
						name: s_name,
						id:	selectfile_anchorid,
						message: {},
						autoSubmit: false,
						responseType: false,
						onChange: function(s_filename, s_file_extension) {
							(jQuery('#'+displayfilename_divid)[0].tagName==='INPUT') ? jQuery('#'+displayfilename_divid).val(s_filename) : jQuery('#'+displayfilename_divid).html(s_filename);
						},
						onSubmit: function(s_filename,s_uploaded_file_ext){
							var given_fileextensions;
							var resulting_regexp;
							var b_flag;
							var multiple_fileextensions  = '';
							var display_string;
							given_fileextensions = "^(" + file_extensions + ")$";
							resulting_regexp = new RegExp(given_fileextensions);
							if(typeof s_uploaded_file_ext==='undefined'){
								s_uploaded_file_ext = '';
							}
							if (!resulting_regexp.test(s_uploaded_file_ext)){
								/**
								 * Instead of calling this_context.show_modal()
								 * 	we have to use the public method 
								 *	due to lexical scoping constraints
								 */
								jQuery.ajax_fw(function(){
										return {
											run:'show_modal'
										};
								});
								b_flag = /\|/.test(file_extensions);
								if(b_flag){//recursively parse the multiple args
									(function(a){
											if(a.length===2){
												multiple_fileextensions += a.pop() + ' and ' + a.toString();
												display_string = multiple_fileextensions;
												return false;
											} else {
												multiple_fileextensions += a.pop() + ', ';
												arguments.callee(a);
											}
									})(file_extensions.split('|'));
								} else {
									display_string = file_extensions;
								}
								alert('Error: The file type you tried to upload was not valid. Please only upload ' + display_string + ' files');
								jQuery.ajax_fw(function(){
										return {
											run:'hide_modal'
										};
								});
								return false;
							}
							jQuery.ajax_fw(function(){
									return {
										run:'show_modal'
									};
							});
						},
						onComplete: function(s_filename, o_response) {
							var _o_return;
							_o_return = jQuery.ajax_fw(function(){
									return {
										run:'objectise',
										params:{
											myjson:o_response,
											fw_it:true
										}
									};
							});
							if(typeof callback==='function'){
								callback.call(this_context,s_filename,_o_return);
							}
							jQuery.ajax_fw(function(){
									return {
										run:'hide_modal'
									};
							});
						}
					};
					upload_obj = new AjaxUpload('#'+selectfile_anchorid, options_obj);
					jQuery('#'+uploadfile_anchorid).click(function () {
							if(typeof message==='object'){
								upload_obj.setData(message);
							}
							upload_obj.submit();
					});
					return upload_obj;
				 },

				/**
				 * Ajax
				 */

				/**
				 * @private
				 * @method send_message Ajax messaging
				 * @param class_name string Class to be called
				 * @param function_name string Method to be called
				 * @param message object|string Messaging payload
				 * @param show_modal boolean true forces the modal to show
				 * @param callback function Lambda
				 * @return void
				 */
				send_message: function (class_name, function_name, message, show_modal, callback) {
					var
					passed_callback,
					payload = {
						message: ''
					};
					if((!this.get_string_check(message) && typeof message!=='object')
						|| (typeof message==='object' && message===null)) {
						throw new Error("Framework 'send_message' params are incorrect [Error code: 3]");
					}
					if(typeof callback!=='function') {
						if(typeof callback==='undefined') {
							passed_callback = function(){};
						} else {
							throw new Error("Framework 'send_message' params are incorrect [Error code: 4]");
						}
					} else {
						passed_callback = callback;
					}
					if(typeof message==='object'){
						message = JSON.stringify(message);
					} else if(typeof message==='string') {
						message = message;
					}
					payload.message = message;
					this.json_payload = payload;
					this.send_form(class_name,function_name,show_modal,'',passed_callback,'send_message');
				},

				/**
				 * @private
				 * @method send_form Core ajax engine (framework wrapper around $.ajax())
				 * @param class_name string Class to be called
				 * @param function_name string Method to be called
				 * @param show_modal boolean true forces the modal to show
				 * @param form_selector string jQuery selector
				 * @param callback function Lambda
				 * @param calling_function string|undefined Either 2 values: send_message or undefined; it needs to know whether send_message called it
				 * @return void
				 */
				send_form: function (class_name,function_name,show_modal,form_selector,callback,calling_function) {
					var
					session_id,
					o_parent = this,
					wn = window.name,
					jq_form,
					targeturl,
					iframer,
					xhr_settings,
					native_form_selector,
					my_params = [];
					session_id = this.get_querystring('all').sess_id;
					targeturl='main.php?c='+class_name+ '&f='+function_name+'&s='+session_id+'&n='+ wn;
					my_params[0] = class_name;
					my_params[1] = function_name;
					my_params[2] = session_id;
					my_params[3] = wn;
					my_params[4] = form_selector;
					native_form_selector = form_selector.split(' ')[0].split(':')[0].split('[')[0];
					(/:+/.test(form_selector)) ? jq_form = form_selector : jq_form = form_selector + ' :input';
					if((typeof callback!=='function')||(!this.get_string_check(calling_function,true))) {
						throw new Error("Framework 'send_form' params are incorrect [Error code: 5]");
					}
					if(calling_function!=='send_message' && typeof calling_function!=='undefined'){
						throw new Error("Framework 'send_form' params are incorrect [Error code: 6]");
					}
					this.xhr_tracker.s_class_name = class_name;
					this.xhr_tracker.s_function_name = function_name;
					if(calling_function==='send_message'){
						this.xhr_tracker.o_data = this.json_payload;
					} else {
						this.xhr_tracker.o_data = jQuery(jq_form).serialize();
					}

					xhr_settings = {
						async:true,
						//don't cache server response
						cache:false,
						//other jQuery local Ajax params
						data:o_parent.xhr_tracker.o_data,
						datafilter: function(s_raw_xhr_response,s_datatype) {
							o_parent.xhr_tracker.s_raw_xhr_response = s_raw_xhr_response;
							o_parent.xhr_tracker.s_datatype = s_datatype;
						},
						type:'POST',
						url:targeturl,
						// jQuery local Ajax Events
						success: function(the_xhr_response,text_status) {
							var callback_flag = false;
							if(typeof jQuery.ajax_fw.global_error==='function'){
								callback_flag = true;
							}
							//store the xhr response
							o_parent.xhr_tracker.o_xhr_response=the_xhr_response;
							//store the jquery success message
							o_parent.xhr_tracker.xhr_success_description = text_status;
							var my_return = o_parent.json_string_to_jsobj(the_xhr_response,true);
							if(typeof my_return.get_status()==='number') {
								if(my_return.get_status()===-1){
									jQuery('html').html('');
									if(!callback_flag){
										//alert(my_return.get_message());
										window.location.replace('login.php?access_denied=true');
									} else {
										jQuery.ajax_framework.global_error();
									}
									if(show_modal){
										o_parent.hide_modal();
									}
								} else {
									callback.call(o_parent,my_return);
									if(show_modal){
										o_parent.hide_modal();
									}
								}
							} else {
								alert('An application error has occurred [Error code: 7]');
								if(show_modal){
									o_parent.hide_modal();
								}
							}
						},
						error: function(the_xhr_response,
							error_text_status,
							the_error) {
							o_parent.xhr_tracker.o_xhr_response=the_xhr_response;
							o_parent.xhr_tracker.xhr_error_text_status = error_text_status;
							o_parent.xhr_tracker.xhr_error = the_error;
							window.status='An application error has occurred [Error code: 8]';
							if(show_modal){
								o_parent.hide_modal();
							}
						}
					};
					jQuery('html').ajaxError(function(event,o_xhr,o_ajaxoptions,error){
						//alert('Error: '+o_xhr.responseText+'; '+error);
					});
					if(show_modal){
						o_parent.show_modal();
					}
					jQuery.ajax(xhr_settings);
				},

				/**
				 * @private
				 * @method load_form Form data populator
				 * @param formselector string jQuery selector string
				 * @param ajax_data object The returned framework object
				 * @param callback function Lambda
				 * @return void
				 */
				load_form: function(formselector,ajax_data,callback) {
					//params' check
					if(!this.get_string_check(formselector)
						|| typeof ajax_data==='undefined'
					&& typeof ajax_data!=='object') {
					throw new Error("Framework 'load_form_ajax' params are incorrect [Error code: 9]");
					}
					var
					o_parent = this,
					the_flag,
					//the "keys" of the xhr response
					ajax_data_keys = this.get_array_from_object(ajax_data),
					//the values of the xhr response
					ajax_data_values = this.get_array_from_object(ajax_data,true),
					my_flag = false,
					inputname,
					_n1 = 0,
					_n2 = 0;
					inputname = formselector;
					(/:+/.test(formselector)) ? my_flag = true : inputname += ' :input';
					var recurse_ajax_data = function(){
						if(_n1===ajax_data_keys.length){
							return true;
						} else {
							jQuery(inputname).each(function(){
									if((jQuery(this).attr('type') === 'checkbox' || jQuery(this).attr('type') === 'radio') && (jQuery(this).val()===ajax_data_values[_n1])){
										jQuery(this).attr('checked',true);_n2++;
									} else if(jQuery(this).attr('name')===ajax_data_keys[_n1]){
										if(jQuery(this).attr('type') === 'image'){
											jQuery(this).attr('src',ajax_data_values[_n1]);
										} else {
											jQuery(this).val(ajax_data_values[_n1]);
										}
									}
							});
							_n1++;
							arguments.callee();
						}
					};
					recurse_ajax_data();
					the_flag = !!_n2;//websearch 'double exclamation js'
					(typeof callback!=='undefined') ? callback.call(o_parent,the_flag) : '';
				},

				/**
				 * @private
				 * @method datatable Messages the server and draws an interactive datatable
				 * @param o_settings object A supercontainer of config settings; please see cheat sheet for more info
				 * @return void
				 */
				datatable: function(o_settings){
					var _fn_error;
					var s_htmlelementselector;
					var o_parent = this;
					var payload;
					var recs_per_page;
					if(typeof o_settings.direction==='undefined'){
						o_settings.direction='down'
					};
					if(typeof o_settings.orderedby==='undefined'){
						o_settings.orderedby=0
					};
					if(typeof o_settings.beginatpage==='undefined'){
						o_settings.beginatpage=1
					};
					if(typeof o_settings.recordsperpage_count==='undefined'){
						o_settings.recordsperpage_count=10
					};
					if(typeof o_settings.recordsperpage_count === 'object'){
						recs_per_page = o_settings.recordsperpage_count[o_settings.initialrecordsperpage_index];
					}else{
						recs_per_page = o_settings.recordsperpage_count;
					}
					if(typeof o_settings.searchin==='undefined'){
						o_settings.searchin='';
					}
					if(typeof o_settings.searchfor==='undefined'){
						o_settings.searchfor='';
					}
					if(typeof o_settings.message==='undefined'){
						o_settings.message='';
					}

					_fn_error = function(b_flag){
						if(b_flag){
							throw new Error('The jquery.ajax_datatable component needs to be included first.');
						}
					};
					(typeof jQuery.fn.ajax_fw_datatable==='undefined')?_fn_error(true):'';
					s_htmlelementselector = o_settings.elementselector;
					o_settings.strippedelementselector=o_settings.elementselector.replace(/^#/,'');
					o_settings.strippedelementselector=o_settings.strippedelementselector.replace(/^\./,'');

					if(typeof o_settings!== 'object'){
						throw new Error('An application error has occurred [Error code: 10]');
					}

					payload = {
						d:o_settings.direction,
						o:o_settings.orderedby,
						p:o_settings.beginatpage,
						r:recs_per_page,
						si:o_settings.searchin,
						sf:o_settings.searchfor,
						m:o_settings.message
					};
					this.send_message(o_settings.class_name,
						o_settings.function_name,
						payload,
						true,
						function(o_data){
							var datatable;
							var rowcounter=0;
							var cellcounter=0;
							var classcounter=0;
							var rowcellcounter=0;
							var totalrows=0;
							var totalcells=0;
							var totalcols=0;
							var indivrow;
							o_settings.headings_array = o_data.data.headings;
							o_settings.row_count = o_data.data.no_of_rows;
							o_settings.ajaxdata = o_data.data.data;
							o_settings.rowdata = o_data.data.row_data;
							datatable = jQuery(s_htmlelementselector).ajax_fw_datatable(o_settings);
							//precalculate -- and give classclicked a free ride =D
							jQuery(o_settings.elementselector + ' .dt_row').each(function(){
									indivrow = this;
									var myrowdata = o_settings.rowdata[totalrows];
									//classclicked
									if(typeof o_settings.classclicked_callback==='function' || typeof jQuery.ajax_fw.classclicked_callback[o_settings.elementselector]==='function'){
										if(jQuery.isArray(jQuery.ajax_fw.classlist[o_settings.elementselector])){
											jQuery(jQuery.ajax_fw.classlist[o_settings.elementselector]).each(function(){
													var classselector = this;
													jQuery(indivrow).find('.'+classselector).each(function(){
															jQuery(this).bind('click',function(e){
																	jQuery.ajax_fw.classclicked_callback[o_settings.elementselector].call(o_parent,e,this,classselector,myrowdata);
															})
													})
											});
										}
									}
									totalrows++
							});
							jQuery(o_settings.elementselector + ' .dt_cell').each(function(){
									totalcells++
							});
							totalcols = totalcells/totalrows;
							//rowclicked_callback
							if(typeof o_settings.rowclicked_callback==='function' || typeof jQuery.ajax_fw.rowclicked_callback[o_settings.elementselector]==='function'){
								jQuery(o_settings.elementselector + ' .dt_row').each(function(){
										var myrowdata = o_settings.rowdata[rowcounter];
										jQuery(this).unbind();
										jQuery(this).bind('click',function(e){
												jQuery.ajax_fw.rowclicked_callback[o_settings.elementselector].call(o_parent,e,this,myrowdata);
												return false;
										});
										rowcounter++
								});
							}
							//cellclicked_callback
							if(typeof o_settings.cellclicked_callback==='function' || typeof jQuery.ajax_fw.cellclicked_callback[o_settings.elementselector]==='function'){
								jQuery(o_settings.elementselector + ' .dt_cell').each(function(){
										var classselector = jQuery(this).attr('class');
										var colnumber;
										var myrowdata;
										var myselector;
										cellcounter++;
										if(cellcounter%totalcols==1){
											rowcellcounter++;
										}
										classselector = classselector.replace(/^dt_cell\s/,'');
										colnumber = classselector.replace(/^.+_([0-9]+)$/,'$1');
										myrowdata = o_settings.rowdata[rowcellcounter-1];
										myselector = o_settings.elementselector;
										jQuery(this).unbind();
										jQuery(this).bind('click',function(e){
												jQuery.ajax_fw.cellclicked_callback[myselector].call(o_parent,e,this,classselector,colnumber,myrowdata);
												return false;
										});
								});
							}
							//datatable_callback
							if(typeof o_settings.datatable_callback==='function' || typeof jQuery.ajax_fw.datatable_callback[o_settings.elementselector]==='function'){
								jQuery.ajax_fw.datatable_callback[o_settings.elementselector].call(o_parent,o_data,datatable);
							}
						});
					}
			};
			/**
			 * This is the returned config object after calling ajax_fw
			 * @private
			 */
			settings = fn.apply(this,arguments);

			/**
			 * Parameter checks - see cheat sheet
			 */
			if(settings.run!=='init'
				&& settings.run!=='init_globalerror'
				&& settings.run!=='show_modal'
				&& settings.run!=='hide_modal'
				&& settings.run!=='get'
				&& settings.run!=='objectise'
				&& settings.run!=='stringify'
				&& settings.run!=='eval'){
				settings.params.elementselector = jQuery(this).selector;
				if(typeof settings.params.initialrecordsperpage_index==='undefined'){
					settings.params.initialrecordsperpage_index = 0;
				}
			}
			if(settings.run!=='' && typeof settings.run!=='undefined'){
				if (typeof settings.params ==='undefined'
					|| typeof settings.params.class_name === 'undefined'
					|| typeof settings.params.function_name === 'undefined'
					|| settings.params.class_name.length===0
					|| settings.params.function_name.length===0) {
					if(settings.run!=='init'
						&& settings.run!=='init_globalerror'
						&& settings.run!=='show_modal'
						&& settings.run!=='hide_modal'
						&& settings.run!=='get'
						&& settings.run!=='objectise'
						&& settings.run!=='stringify'
						&& settings.run!=='eval'
						&& settings.run!=='load_form'){
						throw new Error('An application error has occurred [Error code: 11]');
					}
				}

				/**
				 * Public methods; please see cheat sheet for more detail
				 */

				/**
				 * 'init' - Access control for interface elements
				 */
				if(settings.run=='init'){
					pagename = window.location.pathname.substring(window.location.pathname.lastIndexOf('/') + 1);
					config.send_message('common_page', 'init', {
							page:pagename
					},
					true,
					function(o_this){
						(function(){
								var s_build = '';
								self.WM_EXEC = [];
								for(var x=0;x<o_this.data.length;x++){
									s_build = "WM_EXEC[" + x + "] = function(){jQuery('" + o_this.data[x]['identifier'] + "')." + o_this.data[x]['command'] + "};WM_EXEC[" + x + "]();";
									Function(s_build)();
								}
								self.WM_EXEC = null;
						})();
					});
				}

				/**
				 * @method init_globalerror Convenient wrapper for an application-wide global error callback
				 */
				else if(settings.run=='init_globalerror'){
					if(typeof settings.params==='undefined'){
						throw new Error('An application error has occurred [Error code: 12]');
					}
					if(typeof settings.params.callback!=='function'){
						throw new Error('An application error has occurred [Error code: 12]');
					}
					jQuery.ajax_fw.global_error = settings.params.callback;
				}

				/**
				 * @method show_modal/hide_modal - Activates/deactivates modal
				 * A public method to config.show_modal / config.hide_modal (see source)
				 */
				else if(settings.run=='show_modal'){
					config.show_modal(this);
				} else if(settings.run=='hide_modal'){
					config.hide_modal(this);
				}

				/**
				 * @method get Retrieve the GET variables of the query string
				 * A public method to config.get_querystring (see source)
				 */
				else if(settings.run=='get'){
					if(typeof settings.params==='undefined'){
						settings.params = {
							myvar:'all'
						};
					}
					(typeof settings.params.myurl==='undefined')
					? returnval = config.get_querystring(settings.params.myvar)
					: returnval = config.get_querystring(settings.params.myvar,settings.params.myurl);
				}

				/**
				 * @method objectise Converts JSON string to a native JS object
				 * A public method to config.json_string_to_jsobj (see source)
				 */
				else if(settings.run=='objectise'){
					if(typeof settings.params==='undefined'){
						throw new Error('An application error has occurred [Error code: 13]');
					}
					if(typeof settings.params.myjson==='undefined' || typeof settings.params.myjson!=='string'){
						throw new Error('An application error has occurred [Error code: 13]');
					}
					(typeof settings.params.fw_it==='undefined' || !!settings.params.fw_it!==true)
					? returnval = config.json_string_to_jsobj(settings.params.myjson)
					: returnval = config.json_string_to_jsobj(settings.params.myjson, true);
				}

				/**
				 * @method stringify Reveses objectise
				 * A wrapper for JSON.stringify
				 */
				else if(settings.run=='stringify'){
					if(typeof settings.params==='undefined'){
						throw new Error('An application error has occurred [Error code: 14]');
					}
					if(typeof settings.params.myobject==='undefined' || typeof settings.params.myobject!=='object'){
						throw new Error('An application error has occurred [Error code: 14]');
					}
					returnval = JSON.stringify(settings.params.myobject);
				}

				/**
				 * @method eval Parses a string of Javascript without native eval()
				 */
				else if(settings.run=='eval'){
					if(typeof settings.params==='undefined'){
						throw new Error('An application error has occurred [Error code: 15]');
					}
					if(typeof settings.params.mystring!=='string'){
						throw new Error('An application error has occurred [Error code: 15]');
					}
					evalstring = 'return (' + settings.params.mystring + ');';
					evalstring = Function(evalstring);
					returnval = evalstring();
				}

				/**
				 * @method send_message Ajax messaging
				 * A public method to config.send_message (see source)
				 */
				else if(settings.run=='send_message'){
					if(typeof settings.params.message==='undefined'){
						settings.params.message = '';
					}
					if(typeof settings.params.show_modal==='undefined'){
						settings.params.show_modal = true;
					}
					if(typeof settings.params.sendmessage_callback!=='undefined'){
						config.send_message(settings.params.class_name,settings.params.function_name,settings.params.message,settings.params.show_modal,settings.params.sendmessage_callback);
					} else {
						config.send_message(settings.params.class_name,settings.params.function_name,settings.params.message,settings.params.show_modal);
					}
				}

				/**
				 * @method upload file utility
				 * A public method which acts as a thin 
				 * 	wrapper for Andrew Valums' AjaxUpload plugin (see source)
				 */
				else if(settings.run=='upload'){
					returnval = config.upload(settings.params.class_name,
						settings.params.function_name,
						settings.params.selectfile,
						settings.params.displayfilename,
						settings.params.uploadfile,
						settings.params.file_extensions,
						settings.params.callback,
						settings.params.message);
				}

				/**
				 * @method send_form Core ajax engine (framework wrapper around $.ajax())
				 * A public method to config.send_form (see source)
				 */
				else if(settings.run=='send_form'){
					if(typeof settings.params.show_modal==='undefined'){
						settings.params.show_modal = true;
					}
					if(typeof settings.params.sendform_callback!=='undefined'){
						config.send_form(settings.params.class_name,settings.params.function_name, settings.params.show_modal, settings.params.elementselector, settings.params.sendform_callback);
					} else {
						config.send_form(settings.params.class_name,settings.params.function_name, settings.params.show_modal, settings.params.elementselector,function(){});
					}
				}

				/**
				 * @method load_form Form data populator
				 * A public method to config.load_form (see source)
				 */
				else if(settings.run=='load_form'){
					if(typeof settings.params.loadform_callback!=='undefined'){
						config.load_form(settings.params.elementselector, settings.params.data, settings.params.loadform_callback);
					} else {
						config.load_form(settings.params.elementselector, settings.params.data);
					}
				}

				/**
				 * @method datatable Messages the server and draws an interactive datatable
				 * A public method to config.datatable (see source)
				 */
				else if(settings.run=='datatable'){
					//initialise callbacks
					if(typeof settings.params.datatable_callback==='function'){
						jQuery.ajax_fw.datatable_callback[settings.params.elementselector] = settings.params.datatable_callback;
					}
					if(typeof settings.params.rowclicked_callback==='function'){
						jQuery.ajax_fw.rowclicked_callback[settings.params.elementselector] = settings.params.rowclicked_callback;
					}
					if(typeof settings.params.cellclicked_callback==='function'){
						jQuery.ajax_fw.cellclicked_callback[settings.params.elementselector] = settings.params.cellclicked_callback;
					}
					if(typeof settings.params.classclicked_callback==='function'){
						jQuery.ajax_fw.classclicked_callback[settings.params.elementselector] = settings.params.classclicked_callback;
					}
					if(typeof settings.params.classlist!=='undefined'){
						jQuery.ajax_fw.classlist[settings.params.elementselector] = settings.params.classlist;
					}
					settings.params.recordsperpage_count = jQuery.makeArray(settings.params.recordsperpage_count);
					settings.params.eventjs_prepend = 'jQuery(\''
					+settings.params.elementselector
					+'\').ajax_fw(function(){return {run:\'datatable\',params:{class_name:\''
					+settings.params.class_name
					+'\',function_name:\''+settings.params.function_name
					+'\',recordsperpage_count:['+settings.params.recordsperpage_count.toString()
					+'],';
					settings.params.eventjs_prepend2 = 'jQuery(\''
					+settings.params.elementselector
					+'\').ajax_fw(function(){return {run:\'datatable\',params:{class_name:\''
					+settings.params.class_name
					+'\',function_name:\'' + settings.params.function_name + '\',';//arbitrary records per page input
					config.datatable(settings.params);
				}
			}
			(typeof returnval==='undefined') ? returnval = this : '';
			return returnval;
		};
})();

