/**
 * JPolite V2
 * http://www.trilancer.com/jpolite214
 */
(function(){var c="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split("");Math.uuid=function(f,d){var a=[];d=d||c.length;if(f)for(var b=0;b<f;b++)a[b]=c[0|Math.random()*d];else{var e;a[8]=a[13]=a[18]=a[23]="-";a[14]="4";for(b=0;b<36;b++)if(!a[b]){e=0|Math.random()*16;a[b]=c[b==19?e&3|8:e]}}return a.join("")}})();
(function($){
	
$.fn.extend({
/**
 * Utility functions added to jQuery.fn
 */
	// Shortcut function to for tab / menu item switching
	on: function() {
		if (this.is(".on")) return false;
		this.siblings(".on").andSelf().toggleClass("on");
		return true;
	},
	flash: function() {
/*	if ($(this).is(':visible')) this.delay('slow').pulse({opacity:[0,1]}, 'fast');*/
		return this;
	},
	scroll2: function() {
		if ($(this).is(':visible')) {
			var cOffset = parseInt($('#content').css('padding-top')) + 35; // Hold #Content offset
			//$.scrollTo(this, "normal", {offset:-cOffset});
		}
		return this;
	},
	scroll2flash: function() {
		return this.scroll2().flash();
	},
	stripHtml: function(value) {
		return value.replace(/<.[^<>]*?>/g, ' ').replace(/&nbsp;|&#160;/gi, ' ').trim();	// remove html tags and space chars
	},
	ckeditorDestroy: function() {
		$(".ckeditor",this).each(function(){$(this).ckeditorGet().destroy()});
		return this;
	},
	loading: function() {
		return this.ckeditorDestroy().html("<img src='/img/loading.gif' width='160' height='24' />");
	},
	localLoad: function(u) {
		var x = $(this);
		if (x.data('xhr')) return false; // Prevent Reload multiple times
		if((x.data('module') && !x.data('module').loaded) || x.data('forced') || !x.data('module'))
			this.empty2().loading().slideDown("normal", function(){
				$.ajax({
					url: u,
					beforeSend: function (xhr) {
						if (x.data('xhr')) return false;
						x.data('xhr', xhr);
					},
					success: function(data, textStatus, XMLHttpRequest) {
						if (data) lastAccess = new Date(); 
						else {
							if (XMLHttpRequest.status != 0) {
								$.alert({title:'Error Loading',text:'Module: '+ x['context'].id +'<br/>URL:'+u});
								if (new Date() - lastAccess > 15000) location.reload();
							} else return;
						}
						$.widgetize.apply(x.empty2().html(data));
						
						x.data('xhr', null);
						if (x.data('module')) {
							if (x.data('forced')) x.parents(".module").scroll2flash();
							x.data('module').loaded = true;
							return;
						}
						x.scroll2flash();
					}
				});
			});
		return this;
	},
	empty2: function() {
		return this.ckeditorDestroy().empty();
	},
	remove2: function() {
		return this.ckeditorDestroy().remove();
	},

/**
 * Here you can add your own Advanced Control definitions
 * like Tabs, Accordion, ... as jQuery plugin to apply on
 * target HTML sections
 */
	// Apply on pre-formated <DIV><tabsul><DIVs></DIV> section
	Tabs: function() {
		return this.each(function() {
			var x = $(this);
			/*console.log(x);*/
			var targets = x.children("div").addClass("tabsdiv").hide();
			x.loaded = new Array();
			x.children(".tabsul").children("li").each(function(i) {
				this.target = targets[i];
				x.loaded[i] = false;
				$(this).click(function() {
					var h = $(this).attr("href") || $('a:first', this).attr("href");
					if (h && !x.loaded[i]) {
						$(this.target).localLoad(h);
						x.loaded[i]=true;
					}
					var tgt=$(this.target);
					tgt.siblings("div:visible").hide("fast", function(){ 
						$(this).addClass('hidden');
					});
					tgt.show("normal", function(){
						$(this).removeClass('hidden');
						$(".ckeditor",this).CKEditor();
					});
					if (!$(this).on()) { 
						if (h) $(this.target).localLoad(h);
						return; 
					}
				});
			}).eq(0).click();
		});
	},

	// Apply on pre-formated <DL.accordion> section
	Accordion: function() {
		return this.each(function() {
			$(this).children("dt").click(function(){
				var x = $(this);
				if (!x.on()) return;
				x.siblings("dd:visible").add(x.next()).slideToggle();
			}).eq(0).click();
		});
	},

	// Used on pre-formated <DL.maccordion> section
	MAccordion: function() {
		return this.each(function() {
			var x = $(this);
			x.addClass("accordion");
			x.children("dd").each(function() {
				if ($(this).hasClass("expand"))	$(this).slideDown(function(){$(this).prev("dt")}).prev("dt").toggleClass("on");
				else $(this).slideUp(function(){$(this).prev("dt")});
			});
			x.children("dt").click(function(){
				$(this).toggleClass("on").next().slideToggle(function(){
					if ($(this).is(":visible"))	$(this).prev("dt");
					else $(this).prev("dt");
					if ($(this).attr("href"))
						if ($(this).is(":visible"))	$(this).localLoad($(this).attr("href"));
						else $(this).empty2();
				});
			});
		});
	},
	
	// Used on Textarea for CKEDITOR with CKFINDER
	CKEditor: function() {
		CKFinder.setupCKEditor(null, '/js/ckfinder/');
		return this.each(function() {
			var id = $(this).attr("id");
			// Generate an unique id for duplicate ckeditor instances or textarea with no id
			if (CKEDITOR.instances[id] || !$(this).attr("id")) $(this).attr("id",$(this).attr("id")+'_'+Math.uuid(6)); 
			$(this).ckeditor();
		});
	},
	FormValidate: function() {
		return this.each(function() {
			$(this).validate({
				submitHandler: function(form) {
					var fr = true;
					$(".ckeditor").each(function(){
						CKEDITOR.instances[$(this).attr("id")].updateElement();
					});
				   $(".ckerequired",form).each(function(){
					    var x = $(this).val();
					    if ($.fn.stripHtml($(this).val()).blank()){
							var eLabel = buildHTML("label","This field is required.",{"class":"error"});
							if ($(this).prev().is(".error")) $(this).prev().remove();
							$(eLabel).insertAfter($(this).prev());
							fr = false;
						}else{
							fr = true;
						}
				   });
				   if (fr == false) return fr;
			       $(':submit', form).attr('disabled', 'disabled');
			       form.submit();
				}
			});
		});
	},
	ValidateCkeditor: function() {
		return this.each(function() {
			var fr = true;
			$(this).closest("form").submit(function(){
				$(".ckerequired",this).each(function(){
				    var x = $(this).val();
				    if ($.fn.stripHtml($(this).val()).blank()){
						var eLabel = buildHTML("label","This field is required.",{"class":"error"});
						if ($(this).prev().is(".error")) $(this).prev().remove();
						$(eLabel).insertAfter($(this).prev());
						fr = false;
					}else{
						fr = true;
					}
				});
				return fr;
				});
			});
	},
	DynDateTime: function() {
		this.each(function() {
			var t = $(this);
			var st = t.hasClass('showtime');
			var f = st?"%Y-%m-%d %H:%M":"%Y-%m-%d";
			t.attr('readonly', 'readonly');
			$(this).dynDateTime({
				showsTime: st,
				ifFormat: f,
				weekNumbers: true,
				timeFormat: 12
			});
		});
	},

	//Apply on UL.menu, when clicked, replace the visible module in a column with another 
	SideMenu: function() {
		return this.each(function(){
			$(this).children().click(function(e){
				if ($("a", this).hasClass('resetLayout')) {
					if (confirm('Reset Layout To Default?')){
						$.cookie('jpolite2layout',null); 
						$.cookie('jpolite2tab',null); 
						for (var c in get_cookies_array()) 
							if (/^m_([\.a-zA-Z0-9_-])*_url$/i.test(c))
								$.cookie(c,null);
						location.reload();
						return false;
					} else return false;
				};
				//var m = $("a", this)[0].rel.split(":");
				//$.jpolite.replaceModule('c2', m)
				var a = $("a", this);
				var s = a.attr("rel").split(":");
				var u = a.attr("href");
				var r = (a.attr("refresh") == "true")? true:false;
				if ($(this).parents(".menu").hasClass("replace")) $.jpolite.replaceModule('c2', s, u, r);
				else 
					$.jpolite.addModule({
						id: s[0],
						c:	s[1] || 'c2',	//Add to c2 of current tab by default
						mc: s[2] || '',
						mt:	s[3] || '',
						scroll2: true,
						url: u, 
						refresh: r
					});
			});
		});
	},
	
	SideMenu2: function() {
		return this.each(function(){
			$(this).click(function(e){
				e.preventDefault();
				e.stopPropagation();
				var s = $(this).attr("rel").split(":");
				var u = $(this).attr("href");
				var r = ($(this).attr("refresh")=="true")?true:false;
				if ($(this).hasClass("replace")) $.jpolite.replaceModule('c2', s, u, r);
				else 
					$.jpolite.addModule({
						id: s[0],
						c:	s[1] || 'c2',	//Add to c2 of current tab by default
						mc: s[2] || '',
						mt:	s[3] || '',
						scroll2: true,
						url: u,
						refresh: r
					});
			});
		});
	},
	
	// Used on forms
	Form: function() {
		return this.each(function(){
			$(this).validate({
				invalidHandler: function(form, validator) {
					var errors = validator.numberOfInvalids();
					if (errors) {
						$(this).scroll2();
						return false;
					};
				},
				submitHandler: function(form) {
					var options = { 
						//target:        $(form).attr("rel"),   // target element(s) to be updated with server response 
						success:       showResponse, // post-submit callback 
						resetForm:     true
					}; 
					// post-submit callback 
					function showResponse(responseText, statusText, xhr, $form)  { 
						//$.alert('status: ' + statusText + '\n\nresponseText: \n' + responseText); 
						$.taconite(responseText);
					} 

					jQuery(form).ajaxSubmit(options);
					return false;
				}
			});
		});
	}, // Form:
	
	// Load an URL into an element and apply widgets
	AjaxLoad: function() {
		return this.each(function(){
			var h = $(this).attr("href");
			if (h) $(this).localLoad(h);
		});
	},
	
	// Live Highlighter for text input
	Highlighter: function() {
		return this.each(function(){
			var t = $(this);
			var h = t[0].tagName =="INPUT" && t.attr("type") == "text";
			var o = t.attr("highlight");
			if (h) {
				var s = t.attr("selector")?$(t.attr("selector"), t.parents(".moduleContent")):t.parents(".moduleContent");
				var d = t.attr("delay")?t.attr("delay"):500;
				t.bind("textchange", function(){
					var v = $(this).val().trim();
					clearTimeout(timeout[this]);
					timeout[this] = setTimeout(function () {
						if (!v && v=="") s.removeHighlight();
						else s.removeHighlight().highlight(v);
					}, parseInt(d));
				});
			}
			if (o && o.trim() != "") t.highlight(o.trim());
		});
	},

	// Table Zebra
	TableZebra: function() {
		return this.each(function(){
			$("tr:odd",this).addClass("odd");
			$("tr:even",this).addClass("even");
		});
	}
});

/**
 * Extensions to jQuery to apply widgetization actions on newly DOM nodes,
 * module_content, helper, dynamic content ...
 */
$.extend({
	/**
	 * Handy alert alternative based on Gritter (http://boedesign.com/blog/2009/07/11/growl-for-jquery-gritter/)
	 */
	alert: function(msg) {
		if (msg && msg.title && msg.text) this.gritter.add(msg);
		else this.gritter.add({title:"Message", text:String(msg)});
	},

	//Registry of controls that may appear in modules
	_widgetControls:{},
	/**
	 * Register Controls into the Control registry
	 * @param {Object} ctrls - hash key:value pairs wherein
	 * 		key:   jQuery selector, e.g., ".class"
	 * 		value: jQuery plugin function Array
	 * 				[$.fn.plugin_func] or
	 * 				[$.fn.plugin_func, settings_obj]
	 */
	regControls: function(ctrls) {	//{selector:handler}
		this.extend(this._widgetControls, ctrls);
	},
	/**
	 * Search and initialize controls on a given DOM node
	 */
	widgetize: function() {
		//Make external links open in new window
		$("a[href^=http]", this).attr("target", "_blank");
		for (var c in $._widgetControls) {		//c is the key, a.k.a., selector
			var f = $._widgetControls[c][0],	//Function
				p = $._widgetControls[c][1];	//Settings
			if ($.isArray(p)) f.apply($(c, this), p);
			else f.call($(c, this), p);
		}
	},

	//A message registry and handling system to handle server side messages
	//Can be used for local messaging as well
	_MsgRegistry: {
		//find out what the target: header, tab#id, helper, container#id, module#id
		jpolite: [],
		//update content of a module
		module: [],
		//find out which XDO to handle, name#url
		resource: [],
		//show some alerts to user (after success)
		msg: [
			function(msg) {
				$({title:'System Notification', text:msg});
				return true;
			}
		]
	},
	/**
	 * Register Controls into the Control registry
	 * @param {Object} handlers - hash key:value pairs wherein
	 * 		key:   message name, e.g., "greeting"
	 * 		value: message processing function
	 */
	regMsgHandlers: function(handlers) {
		var mr = this._MsgRegistry;
		for (var x in handlers) {
			if (!mr[x]) mr[x]=[];
			mr[x].push(handlers[x])
		}
	},
	/**
	 * Process a given message
	 * @param {Object} m - message hash key:value pairs wherein
	 * 		key:   message name, e.g., "greeting"
	 * 		value: content of the message, e.g., "hello"
	 */
	handleMessage: function(m) {
		var rv = true;
		for (var k in m) {
			var x = this._MsgRegistry[k];
			if (x) for (var i in x) x[i](m[k])
		};
		return rv;
	},

	//A global custom event processing mechanism
	_DOC: $(document),
	/**
	 * Register custom events onto document
	 * @param {Object} evt - event hash key:value pairs wherein
	 * 		key:   event name, e.g., "moduleLoadedEvent"
	 * 		value: event processing function
	 */
	regEvent: function(evt){
		for (var e in evt) this._DOC.bind(e, evt[e]);
	},
	/**
	 * Trigger a given event
	 * @param {string} e - name of the custom event
	 * @param {object} data - event associated data
	 */
	triggerEvent: function(e, data){
		this._DOC.trigger(e, data);
	}
});


/**
 * JPolite Core Features and Functions
 */
$.jpolite = {
	/**
	 * Main Navigator Object & Methods
	 */
	Nav: {
		its: null,			//A jQuery collection of tab items, set in init() 
		tabs: {},			//Hash for tabs, tabs[tab_x_id] => tab_x DOM node
		ct:	null,			//Current tab id
		cc: $("#content"),	//Content container
		t1: $.fn.fadeOut,	//Content transition out function
		t2: $.fn.fadeIn,	//Content transition in function
		showModules: function(forced) {	//Utility function to show all modules under a certain main nav item
			for (var i in this.modules) {
				var m = this.modules[i];
				$(m).show().removeClass("hidden");
				if (forced) m.loadContent(forced); 
				else m.loadContent();
			};
		},

		/**
		 * Initialization method
		 * @param {String} cts - main nav selector object, "#main_nav" by default
		 * @param {String} its - main nav item selector,   "li" by default
		 * @param {Function} func - optional init method to be applied upon main nav
		 * @param {Object} p - optional parameter for the init method
		 */
		init: function(cts, its, func, p){
			var t = this.tabs;
			func.call($(cts), p);		//Pre-process main nav
			this.its = $(its, cts).each(function(){
				this.modules = {};		//Modules fall logically under this main nav item
				this.showModules = $.jpolite.Nav.showModules;
				t[this.id] = this;		//"this" is a main nav item DOM node 
				$(this).click(function(e){
					if($(e.target).hasClass("logout")) location.href="/users/logout";
					if($(this).attr("id")=="") return true;
					//If click on an active item without submenu, then return
					if (!$(this).on() && !$(".on",this).length) {
						t[this.id].showModules(true);
						return false;
					}
					//If click on a leaf menu item => switch it on, and off others
					if (e.originalEvent || $(".on",this).length == 0) {
						$.jpolite.Nav.switchTab(this.id);
						$(".on", $.jpolite.Nav.its).not(this).not($(this).parents()).removeClass("on");
					}
					$(this.parentNode).click();
					return false;
				});
			});
		},
		/**
		 * Switch to designated main nav item 
		 * @param {String} id - main nav item's ID
		 */
		switchTab: function(id){
			var cc = this.cc,
				x = this.tabs[id],
				t2 = this.t2,
				mv = $(".module:visible"),
				//Call back function to be executed after tab switching
				f = function(){
					mv.addClass('hidden').hide();
					$.jpolite.Content.switchTab(x.id);
					x.showModules();
					t2.call(cc, 500)
				};
			this.ct = id;
			this.t1.apply(cc, [500, f]);
			$.cookie('jpolite2tab', id);
		},
		/**
		 * Retrieve the DOM node
		 * @param {String} id - main nav item ID
		 * 		"tab_id" ==> return tab#tab_id DOM node
		 * 		null	 ==> return current active tab node
		 */
		getTab: function(id) {
			return this.tabs[id || this.ct];
		},
		/**
		 * Link modules statically defined in index.html to designated tab item
		 * @param {DOM node} m - static module DOM node
		 * @param {String} tid - main nav item ID
		 */
		addStaticModule: function(m, tid){
			m.tab = this.tabs[tid];		//Link tab to module
			m.tab.modules[m.id] = m;	//Add module to tab
		},
		/**
		 * Unlink modules from tab item
		 * @param {DOM node} m - static module DOM node
		 */
		removeModule: function(m){
			delete m.tab.modules[m.id];
		}
	},

	/**
	 * Content Area (module container) - Object and Methods
	 */
	Content: {
		_loadLayout: function(){},	//Customizable Method to load layout
		_saveLayout: function(){},	//Customizable Method to save layout
		cc: $(".cc"),				//Containers jQuery object
		MTS: {}, 					//Module Templates
		//Actions to be assigned upon each module
		moduleActions: {
			loadContent: function(url, forced) {
				var x = this;
				if (typeof url === "boolean") {
					forced = url;
					url = x.url;
				} else url = url || $.cookie(x.id+'_url') || x.url;
				var mc = $(".moduleContent", this);
				if (!url || (x.loaded && !forced) ) return;
				mc.data('forced', forced);
				mc.data('module', x);
				mc.localLoad(url);
				$(".actionMax",this).hide();
				$(".actionMin",this).show();
				$(x).removeClass('hidden');
				return this;
			},
			max: function(){
				var x = this;
				$(".actionMax",this).hide();
				$(".moduleContent", this).slideDown("normal");
				$(x).removeClass('hidden');
				$(".actionMin",this).show();
				return this;
			},
			min: function(){
				var x = this;
				$(".actionMin",this).hide();
				$(".moduleContent", this).slideUp("fast");
				$(x).addClass('hidden');
				$(".actionMax",this).show();
				return this;
			},
			refresh: function(){
				return this.loadContent(true);
			},
			reload: function(){
				return this.loadContent(true);
			},
			close: function(){
				$(this).remove2();
				$.jpolite.Nav.removeModule(this);
				$.jpolite.Content.saveLayout();
				return this;
			},
			scrollTo: function(){
				$(this).scroll2();
				return this;
			},
			flash: function(){
				$(this).flash();
				return this;
			}
		},

		/**
		 * Initialization method
		 * @param {Boolean} moduleSortable - if true, enable module drag & drop
		 */
		init: function(moduleSortable) {
			var x = this.cc;
			if (moduleSortable) x.sortable({
				start: function(){
					$.jpolite.Content.cc.addClass("dragging")
				},
				stop:  function(e, u){
					$.jpolite.Content.cc.removeClass("dragging");
					var m = u.item[0]; 
					if (m.c) m.c = m.parentNode.id;	//Change module container ID
					$.jpolite.Content.saveLayout();
				},
				connectWith: '.cc',
				handle: '.moduleHeader',
				opacity: .5,
				placeholder: 'ui-sortable-placeholder',
				tolerance: 'pointer',
				revert: true
			});
			x = x.toArray(); 
			for (var i in x) this[x[i].id] = $(x[i]);	//Now Content has properties c1, c2, c3 ... each is an jQuery object

			//Detach module templates from index.html and put into MTS
			x = $(".module_template").toArray();
			for (i in x){
				var id = x[i].id || 0;	//MTS[0] => default template
				this.MTS[id] = $(x[i]).attr("class","module").remove2();
			};
			this.loadStatic();
			this.loadLayout();
		},
		/**
		 * Content area change (column class) according to tab_id
		 * @param {String} tab_id - new ID of tab
		 */
		switchTab: function (tab_id) {
			var x = $.extend({}, _columnLayout._default, _columnLayout[tab_id]),
				bc = $('body').attr('class') || 'normal';

			if (bc != x.bg) {
				$('body').toggleClass(bc);
				$('body').toggleClass(x.bg);
			}
			delete x.bg;
			for (var c in x) { this[c].attr('class', 'cc ' + x[c]); };
		},
		/**
		 * Add a new module to a given tab
		 * @param {Object} m - module definition, properties include
		 * 			id: unique ID of the module defined in modules.js, e.g., m101
		 *			c:	container ID, e.g., c1, c2 ...
		 *			mc: (optional) module color class, e.g., 'red'
		 *			mt:	(optional) module template name as defined in index.html
		 * @param {DOM node} t - target tab
		 */
		addModule: function(m, t) {
			var c = this[m.c];
			if (!c) return;		//return if invalid column ID given
			//Load module definition
			var y = _modules[m.id];
			var x = this.MTS[m.mt || 0].clone()[0];
			$.extend(x, {mc:'', mt:''}, this.moduleActions, m, {
				loaded: false,
				url: y.url,
				tab: t,
				scroll2: false
			});
			//Check for duplicate module, and refuse
			if (t.modules[m.id]) {
				if (m.refresh) {
					if (m.url) {
						$.cookie(m.id+'_url', m.url);
						t.modules[m.id].loadContent(m.url, true);
					} else t.modules[m.id].loadContent(true);
				} else t.modules[m.id].max().scrollTo().flash();
				return;
			};
			t.modules[m.id] = x;
			$(".moduleTitle", x).text(y.t);
			if (m.mc) $(x).addClass(m.mc);
			c.append(x);
			if (t.id == $.jpolite.Nav.ct) {
				$(x).show();
				if (m.url) {
					$.cookie(m.id+'_url', m.url);
					x.loadContent(m.url, true);
				} else x.loadContent(true);
			} else $(x).addClass('hidden');
			$.jpolite.Content.saveLayout();
			return $(x);
		}, 
		/**
		 * Make DIV.module sections preloaded in index.html active modules
		 */
		loadStatic: function(){
			var ma = this.moduleActions;
			$(".module").each(function(){
				var p = this.id.split(":");	//e.g., m101:t1
				$.extend(this, {
					id: p[0],
					tab: p[1],
					loaded: true
				}, ma);
				$.widgetize.apply(this);
				$.jpolite.Nav.addStaticModule(this, p[1])
			});
		},
		/**
		 * Load layout defined in modules.js
		 */
		loadLayout: function() {
			//Load layout via custom method or _moduleLayout variable defined in modules.js
			var l = this._loadLayout() || _moduleLayout;
			for (var t in l) {
				var tab = $.jpolite.Nav.getTab(t);
				if (tab) for (var i in l[t]) {
					var s = l[t][i].split(":");
					u = ($.cookie('s[0]'+'_url'))?$.cookie('s[0]'+'_url'):_modules[s[0]].url;
					this.addModule({
						id: s[0],
						c:	s[1],
						mc: s[2] || '',
						mt:	s[3] || '',
						url: u
					}, tab);	
				}
			}
		},
		/**
		 * Retrieve current layout and save via customizable method
		 */
		saveLayout: function() {
			var r = "{" + $.jpolite.Nav.its.map(function(){
				var t = [], m = this.modules;
				for (var i in m)
					if (m[i].c)		//Skip static modules
						t.push("'".concat(m[i].id, ":", m[i].c, ":", m[i].mc, ":", m[i].mt, "'"));
				return "'" + this.id + "':[" + t.toString() + "]";
			}).get().join(",") + "}";
			if (this._saveLayout) this._saveLayout(r);
		}
	},

	/**
	 * JPolite initialization method
	 * @param {Object} options - initialization parameters, with default values
	 * 		cts: "#main_nav",				//Navigation Tab container id
	 * 		its: "li",						//Navigation Tab selector
	 * 		t1: $.fn.fadeOut,				//Content transition Out callback
	 * 		t2: $.fn.fadeIn,				//Content transition In callback
	 * 		navInit: TraditionalTabs,		//Navigation Tab Initialization callback
	 * 		navInitArguments: {},			//Navigation Tab Initialization parameters
	 * 		moduleSortable: true			//Whether to allow module drag-n-drop
	 * 		layoutPersistence: []			//Methods to load/save layout of modules
	 */
	init: function(options){
		var s = $.extend({
	 		cts: "#main_nav",
	 		its: "li",
	 		t1: $.fn.fadeOut,
	 		t2: $.fn.fadeIn,
	 		navInit: TraditionalTabs,
	 		navInitArguments: {},
	 		moduleSortable: true
		}, options);

		this.Nav.init(s.cts, s.its, s.navInit, s.navInitArguments);
		this.Nav.t1 = s.t1;
		this.Nav.t2 = s.t2;
		if (s.layoutPersistence) {
			this.Content._loadLayout = s.layoutPersistence[0];
			this.Content._saveLayout = s.layoutPersistence[1];
		}
		this.Content.init(s.moduleSortable);
		delete this.Nav.init;
		delete this.Nav.addStaticModule;
		delete this.Content.init;
		delete this.Content.loadStatic;
		delete $.jpolite.init;
	},
	gotoTab: function(id) {
		$(this.Nav.getTab(id)).click();
	},
	addModule: function(m) {
		this.Content.addModule(m, this.Nav.getTab());
	},
	replaceModule: function(col, ids, href, refr) {
		var x = $(".module:visible", this.Content[col]).get();
		var t = this.Nav.getTab();
		for (var i in x) x[i].close();
		for (i in ids) this.Content.addModule({id: ids[i], c: col, url: href, refresh: refr}, t);
		this.Content.saveLayout();
	}
}
/*
 * Here you can add your own Live Event definitions
 */
function myLiveEvents(){
	$.rt.delegate(".module .maxAll", "mousedown",  function(e){
		e.preventDefault();
		var x = $("#c2 .module:visible").get();
		for (i in x) x[i].max();
	});
	$.rt.delegate(".module .minAll", "mousedown",  function(e){
		e.preventDefault();
		var x = $("#c2 .module:visible").get();
		for (i in x) x[i].min();
	});
	$.rt.delegate(".module .actionRefresh", "mousedown",  function(e){
		e.preventDefault();
		var x = $(this).parents(".module");
		var u = $.cookie(x.attr('id')+'_url');
		if (u) $(this).parents(".module")[0].loadContent(u, true);
		else $(this).parents(".module")[0].loadContent(true);
	});
	$.rt.delegate(".module .actionMin", "mousedown",  function(e){
		e.preventDefault();
		$(this).parents(".module")[0].min();
		$(this).hide().siblings(".actionMax").show();	
	});
	$.rt.delegate(".module .actionMax", "mousedown",  function(e){
		e.preventDefault();
		$(this).parents(".module")[0].max();
		$(this).hide().siblings(".actionMin").show();	
	});
	$.rt.delegate(".module .actionClose", "mousedown",  function(e){
		e.preventDefault();
		var x = $(this).parents(".module");
		$.cookie(x.attr('id')+'_url', null);
		$(this).parents(".module")[0].close();	
	});
	$.rt.delegate(".module .moduleHeader", "dblclick",  function(e){
		e.preventDefault();
		if (e.target.className == "moduleTitle" || e.target.className == "moduleHeader" )
			$(this).parents(".cc").toggleClass("max").siblings(".cc").toggleClass("min");
	});
	$.rt.delegate(".module a.tab", "click",  function(e){
		e.preventDefault();
		$.jpolite.gotoTab(this.rel);
		return false;
	});
	$.rt.delegate(".module a.local", "click",  function(e){
		h = $(this).attr("href");
		if (h) {
			e.preventDefault();
			a = $(this);
			s = a.attr("selector");
			t = a.attr("tab");
			r = a.attr("refresh");
			var x = $(this).parents(".moduleContent");
			if (t) {
				$(t).attr("href", h).click().removeAttr("href");
				return;
			}
			if (s) $(s, x).localLoad(h,r);
			else {
				var x = $(this).parents(".module");
				$.cookie(x.attr('id')+'_url', this.href);
				$(this).parents(".module")[0].loadContent(this.href, true);
			}
		}
		return false;	
	});
	$.rt.delegate(".moduleContent .paging a", "click",  function(e){
		h = $(this).attr("href");
		if (h) {
			e.preventDefault();
			s = $(this).attr("selector");
			var x = $(this).parents(".moduleContent");
			if (s) $(s, x).localLoad(h);
			else $(this).parents(".paging").parent().localLoad(h);
		}
		return false;	
	});
	$.rt.delegate(".moduleContent .input", "click",  function(e){
		$(this).find(':input:not(:disabled):first').focus();
	});
	$.rt.delegate(".moduleContent input, .moduleContent textarea, .moduleContent select", "focus",  function(e){
		$(this).parents('div.input').addClass("focus");
	});
	$.rt.delegate(".moduleContent input, .moduleContent textarea, .moduleContent select", "blur",  function(e){
		$(this).parents('div.input').removeClass("focus");
	});
};

/*
 * Here you can register Custom System Events
 */
function myCustomEvents(){
	$.regEvent({
		"moduleLoadedEvent": function(e, target){
			//$.alert({title:'Module Loaded',text:$(".moduleTitle", target).text()});
		}
	});

	//Ajax Start & Stop event processor registered with jQuery's methods
	$("#logo").ajaxStart(function(){$(this).addClass('loading');}).ajaxStop(function(){$(this).removeClass('loading');});
};

/*
 * Here you can register the message handlers for messages returned from Server side
 */
function myMessageHandlers() {
	$.regMsgHandlers({
		resource: function(res){
			for (var i in res) {
				var o = res[i];
				var p = [o.name];
				if (o.url) p.push(o.url);
				p.push(true);
				$.triggerEvent(o.method == 'destroy' ? "destroyEvent" : "refreshEvent", p);					
			}
			return true;
		},
		//Promot a important notices in a JsonForm
		notice: function(note) {
			var f = $("form:visible");
			if (note.length) {	//Array, Possibly a error / warning message 
				note = $.map(note, function(o, i){
					return o.join(" -- ");
				});
				if (f.size() > 0) $(".notice", f).html(note.join("<br/>")).hide().slideDown();
			}
			return false;
		},
		//Prompt user about errors in a JsonForm
		error: function(err) {
			var f = $("form:visible");
			if (f.size() > 0) $(".error", f).html(err).hide().slideDown();
			return false;
		}
	})
};

/*
 * Here you can define which controls you want in the format of
 * {selector} : [callBackFunction, {one:argument}] or 
 * {selector} : [callBackFunction, [array, of, arguments]]
 * The callBackFunctions will be called upon each module content
 */
function myControls(){
	//Assign Controls handlers to selectors 
	$.regControls({
		//JPolite native controls, zero arguement
		".tabs":		[$.fn.Tabs],
		//".accordion":	[$.fn.Accordion],
		".maccordion":	[$.fn.MAccordion],
		//".menu":		[$.fn.SideMenu],
		//".menu2":		[$.fn.SideMenu2],
		//jqModal controls, One object as arguement
		//".jqmWindow":	[$.fn.jqm, {toTop:true}],
		//CKEditor
		".ckeditor":	[$.fn.CKEditor],
		"form.formvalidate":[$.fn.FormValidate],
		"form .ckerequired":[$.fn.ValidateCkeditor],
		"form .dyndatetime":[$.fn.DynDateTime],
		//".ajaxload":	[$.fn.AjaxLoad],
		"form":			[$.fn.Form]
		//".highlighter": [$.fn.Highlighter],
		//"table":		[$.fn.TableZebra]
	});
};

/*
 * A traditional navigation tabs initializer with tricks from Dragon Interactive:
 * http://labs.dragoninteractive.com/pufferfish_article.php
 */
function TraditionalTabs(){};

/*
 * Initialization Code
 */

var timeout = new Array();
var lastAccess = new Date();
myControls();
$.validator.addMethod("NumbersOnly", function(value, element) {
	return this.optional(element) || /^[0-9\-\+]+$/i.test(value);
	}, "Must contain only numbers, + and -.");
	/**$(function(){
	// http://www.codenothing.com/archives/2010/8-jquery-micro-optimization-tips/
	$.rt = jQuery("body"); 
	//Load Live / Custom Events & Message Handlers
	myLiveEvents();
	myCustomEvents();
	myMessageHandlers();
	myControls();
	//Here you can see how to customize the look & feel of the navigation tabs
	var s, customNav = window.name;	//Read Nav Tab style set in index.html
	switch (customNav) {
	default://3 or else - Traditional
		s = {navInit:TraditionalTabs};
	}

	 * 		Default initialization parameters:
	 * 
	 * 		cts: "#main_nav",				//Navigation Tab container id
	 * 		its: "li",						//Navigation Tab selector
	 * 		t1: $.fn.fadeOut,				//Content transition Out callback
	 * 		t2: $.fn.fadeIn,				//Content transition In callback
	 * 		navInit: TraditionalTabs,		//Navigation Tab Initialization callback
	 * 		navInitArguments: {},			//Navigation Tab Initialization parameters
	 * 		moduleSortable: true			//Whether to allow module drag-n-drop
	 * 		layoutPersistence: []			//Methods to load/save layout of modules
	 
	s.its = "li, dd"
	s.layoutPersistence = [
		function() {
			return window["eval"]("(" + $.cookie('jpolite2layout') + ")");
		},
		function(s) {
			return $.cookie('jpolite2layout', s);
		}
	];
	s.moduleSortable = false;
	$.jpolite.init(s);
	$.jpolite.gotoTab((!$.cookie('jpolite2tab'))?'t_task':$.cookie('jpolite2tab'));	//Activate the first tab by default, or another id of your choice
	$('#firstload').remove();
});*/
})(jQuery);

