/*---------------------------------------
	BRIEF DOCUMENT STRUCTURE OVERVIEW
-----------------------------------------*/
/*
1. prototypes
2. object initializers
3. homemade jquery plugins
4. attach events to elements when dom loads	

CHORDC CONSTANTS - are set in the head, see js.php
1. CHORDC_LOAD_SECTIONS_VIA_AJAX
2. CHORDC_LOAD_LISTS_VIA_AJAX
*/

/*-----------------------------------------
	EXTENDING NATIVE JAVASCRIPT OBJECTS
-------------------------------------------*/
// String
String.prototype.trim  = function() { return this.replace(/^\s+|\s+$/g,""); };
String.prototype.ltrim = function() { return this.replace(/^\s+/,""); };
String.prototype.rtrim = function() { return this.replace(/\s+$/,""); };

// Date
Date.prototype.daysInMonth = function(month, year) {
	return 32 - new Date(year, month, 32).getDate();
};

/*--------------------------------------------------------------------------
	CHORDC'S TOP LEVEL OBJECT INITIALIZER NAMES (alphabetically ordered)
----------------------------------------------------------------------------*/
var Callback,				 // Object used in the submitForm jquery plugin
	ChordC,					 // Various methods, acting as an encapsulator to avoid naming collisions
	Cookie,					 // Helper methods for working with cookies
	AjaxEventsRouter, 		 // Attaching events after various ajax calls other then ListModuleEventsRouter or BodySectionEventsRouter		
	BodySectionEventsRouter, // Attach events after a body section ajax call - see $.fn.bodySectionComponent
	ListModuleEventsRouter,	 //	Attach events after a list module ajax call
	OnloadEventsRouter;		 // Attach events onload	

/*---------------------
	CHORDC NAMESPACE
-----------------------*/
ChordC = {
	"_filter": {}, /* dedicated to the filter menu */
	
	"doAjax":function(me, form, callback, method) {
		method 			= method 				|| "POST";
		var json 		= me.getJsonAttr(),
			controller 	= json.controller 		|| "",
			dataArray 	= form.serializeArray() || json;
		$.ajax({
			type:    method,
			url:     controller,
			cache:   false,
			data:    dataArray,
			error:   function(){ /*TODO*/ },
			success: function(data){
				callback(data);
			}
		});
	},
	"init":function() {
		if (!CHORDC_LOAD_SECTIONS_VIA_AJAX) { Cookie.erase("uriCookiePG"); }
		if (!CHORDC_LOAD_LISTS_VIA_AJAX)    { Cookie.erase("uriCookieLM"); }
		OnloadEventsRouter.run(); // attach the events
	},
	"editPersonalInfo":function(me) {
		Validation.removeErrorMessages();
		
		var btn 	   = $(me),
			frm		   = btn.parents("form:eq(0)"),
			jsonMe 	   = btn.getJsonAttr(),
			controller = btn.attr("href");
		
		btn.ajaxPreloader();
		
		$("#"+jsonMe.loadId).load(controller, function() {
			Validation.create();
			Callback.editProfile();
		});
	},
	"savePersonalInfo":function(me) {
		if (Validation.flag) { return false; }

		var btn 	   = $(me),
			frm		   = btn.parents("form:eq(0)"),
			jsonMe 	   = btn.getJsonAttr(),
			controller = btn.attr("href"),
			frmVals    = frm.serialize();

		btn.ajaxPreloader();

		$.post(controller, frmVals, function(jData) {
			if (jData.success) {
				if (jData.redirect) { // happens when member changes their username from their profile
					window.location = '/profile/'+jData.username+'/info/';
				} else {
					Callback.savedProfile(btn);
				}
			} else {
				Validation.fromServer(jData);
			}
		}, "json");
	},
	"signIn":function(me) {
		if (Validation.flag) { return false; }
		
		var frm        = $(me),
			btn        = frm.find("button[type='submit']"),
			controller = frm.attr("action"),
			frmVals    = frm.serializeArray();
		
		btn.ajaxPreloader();

		$.post(controller, frmVals, function(jData){
			if (jData.success) {
				btn.popupMsg({'msgText':jData.message,
				                'yPos':127,
				                'xPos':-25,
							    'timeout':800,
				                'msg':'msgConfirm txtCenter',
				                'callbackEnd':function() { window.location = '/profile/'; }
				              });
				//btn.disableBtn({"cssClass":"small"});
			} else {
				Validation.fromServer(jData);
			}
		},"json");
	},
	"signUp":function(me) {
		if (Validation.flag) { return false; }
		
		var frm        = $(me),
			btn        = frm.find("button[type='submit']"),
			controller = frm.attr("action"),
			frmVals    = frm.serializeArray();
					
		btn.ajaxPreloader();
		
		$.post(controller, frmVals, function(jData){
			if (jData.success) {
				frm.attr('onsubmit','return false;');
				btn.popupMsg({'msgText':jData.message,
				                'yPos':2,
				                'xPos':-6,
							    'timeout':1000,
				                'msg':'msgConfirm txtCenter',
				                'callbackEnd':function() { window.location = jData.successUrl; }
				              });
				//btn.disableBtn();
			} else {
				Validation.fromServer(jData);
			}
		},"json");
	},
	"resetPassword":function(me) {
		if (Validation.flag) { return false; }
		
		var frm        = $(me),
			btn        = frm.find("button[type='submit']"),
			controller = frm.attr("action"),
			frmVals    = frm.serializeArray();
					
		btn.ajaxPreloader();
		
		$.post(controller, frmVals, function(jData){
			if (jData.success) {
				btn.popupMsg({'msgText':jData.message,
				                'yPos':127,
				                'xPos':-20,
				                'msg':'msgConfirm txtCenter',
								'doNotRemove':true
				              });
				//btn.disableBtn();
			} else {
				Validation.fromServer(jData);
			}
		},"json");
	},
	"selectImage":function(obj) {
		var me 		 	= $(obj),
		 	fileName 	= me.attr('rel') || '',
			defaultPic 	= (fileName === '')? 'default.jpg' : fileName,
			picSrc	 	= $("#profilePic img.profile").attr('src'),
			picSrcNew	= picSrc.split("/src/")[0] + "/src/" + defaultPic,
			controller = me.attr("href");
		me.ajaxPreloader();
		$.post(controller, {avatar:fileName} , function() {
			$("#profileImages a").removeClass('sel');
			me.addClass('sel');
			$("#profilePic img.profile").attr('src',picSrcNew);
		});
	},
	"timeoutMsg":function(callback, time){
		if (!callback) { return false; }
			time 	= time || 500;
		var timeout = setTimeout(callback, time);
	},
	"toggleWith":function(obj, whatId, hideShow){
		whatId   = whatId   || obj;
		hideShow = hideShow || false;
		
		if (whatId === obj) {
			if (obj.is(':visible')){
				if (hideShow) {
					obj.hide();
				} else {
					obj.slideUp("fast");
				}
			} else {
				if (hideShow) {
					obj.show();
				} else {
					obj.slideDown("fast");
				}
			}
		} else {
			if (obj.is(':visible')){
				obj.hide();
				if (hideShow) {
					whatId.show("fast");
				} else {
					whatId.slideDown("fast");
				}
			} else {
				if (hideShow) {
					whatId.hide();
					obj.show();
				} else {
					whatId.slideUp("fast", function() {
						obj.show();
					});
				}
			}
		}
	},
	"rotateChordFinderApp": function() {
		// Rotate chord finder pics
		var pics = $("#screens img"),
			i    = 0;
		pics.eq(i).fadeIn();
		rotateImages = function(){
			pics.eq(i).fadeOut();
			if (i < pics.length - 1) {
				pics.eq(i+1).fadeIn();
				i++;
			} else {
				i = 0;
				pics.eq(i).fadeIn();
			}
		}
		setInterval("rotateImages()", 3000);
	},
	"removePopupMsgs":function() {
		$("p.msgPopup").fadeOut("slow", function() {
			$(this).remove();
		});
	},
	"closeModo":function() {
		Validation.removeErrorMessages();
		$("#modoCase").remove();
		$("#coverMe").fadeOut(function(){$(this).remove();});
		return false;
	},
	"extractBgUrl":function(bgImgString) {
		// remove quotes and wrapping url(), see $.fn.thumbnailAction
		return bgImgString.replace(/"/g,"").replace(/url\(|\)$/ig, "");
	},
	"runListModule":function(me) {
		Validation.removeErrorMessages();
		me.addClass("sel");
		
		var vw 			    = me.parents(".viewWrap:eq(0)"), // vw = View Wrap
		    jsonVW 	  	    = vw.getJsonAttr(),
		    listModuleRoute = jsonVW.listModuleRoute || false,
		    toggleMode 	    = vw.find("div.toggleModeButton a.sel"),
		    jsonToggleMode  = {},
		    controller,
		    json;
		
		// toggle mode
		if (toggleMode && toggleMode.length) {
			jsonToggleMode.toggleMode = (toggleMode.hasClass("edit")) ? "edit": "display";
		}
		
		json = $.extend(jsonVW, jsonToggleMode);
		
		// if you need to post additional stuff put it in the data object
		if (typeof json.data !== "undefined") {
			json = $.extend(json, json.data);
		}
		
		// if it's a form submit then set the preloader to the go button.
		me = (me.hasClass("listModuleFrm")) ? me.find("a.listModuleSearchBtn") : me;
		
		// NEW URI CONTROLLER
		controller = me.attr("href");
		
		var uriCookieLM,
		    uriLM  = {},
			action = controller.indexOf("/list")+5,       // ex: 38
			args   = controller.substr(action); 	      // ex: /page/1/from/0/limit/50/order-by/artist/order/desc/	
		
		action 		  = controller.substr(0, action)+"/"; // ex: /profile/jfyounce/song-collection/list			
		uriLM[action] = args;
		
		if (!Cookie.read("uriCookieLM")) {
			Cookie.create("uriCookieLM", JSON.stringify(uriLM), 360);
		} else {
			uriCookieLM = JSON.parse(Cookie.read("uriCookieLM"));
			$.extend(uriCookieLM, uriLM);
			Cookie.create("uriCookieLM", JSON.stringify(uriCookieLM), 360);
		}
					
		$.ajax({
			type:    "POST",
			url:     controller,
			data:    json,
			error:   function() { /*TODO*/ },
			success: function(data) {
				vw.empty();
				vw.html(data);
				ListModuleEventsRouter.run(listModuleRoute);
			}
		});
		
		me.ajaxPreloader();
		return false;
	},
	"Numbers": {
		"isEven":function(number) {
			return (number%2 == 0) ? true : false;
		},
		"random":function() {
			return Math.floor(Math.random()*11);
		},
		"sortNumber":function(a,b) {
			return a - b; // Fix array not sorting numbers right. EXAMPLE USE: arr.sort(sortNumber);
		}
	}
};

/*----------------------------
	CUSTOM CALLBACK METHODS
------------------------------*/
Callback = {
	"main": function(me, frm, jsonMe, json, jData, regData) {
		this.me  	 = me;
		this.frm 	 = frm;
		this.jsonMe  = jsonMe;
		this.json	 = json;
		this.jData 	 = jData;
		this.regData = regData;
		eval(jsonMe.callback);
	},
	"_removeRowUpdateNumbers": function(o) { // I don't think we need the o argument.
			o 	  	 = o || {};
		var Callback = this,
			row   	 = o.row || "dd:eq(0)",
			dd 	  	 = this.me.parents(row),
			dl	  	 = this.frm.parents("form:eq(0)").find("dl.contentDL"),
			meDD;
			
		dl = (dl.length) ? dl : this.frm.find("dl.contentDL");
					
		dd.slideUp(function() {
			meDD = $(this);
			if (meDD.hasClass("first")) {
				meDD.next().addClass("first");
			}
			meDD.remove();
			Callback.noMoreRecs(dl, Callback.jsonMe.noRecordsRoute);
			Callback.updateMyNumbers(Callback.jData);
		});
	},
	"_successMsgAfterServerCall": function(msg) {
		msg = msg || this.jsonMe.successMsgAfterServerCall;
		this.me.popupMsg({msgText:msg});
	},
	"noMoreRecs": function(dl, noRecordsRoute) {
		noRecordsRoute = noRecordsRoute || false;
		var dd = dl.find("> dd"),
			next,
			prev;
		
		if (!dd.length) {
			next = dl.parents("div.viewWrap:eq(0)").find("div.pagi:eq(0) a.nextIndicator");
			prev = dl.parents("div.viewWrap:eq(0)").find("div.pagi:eq(0) a.prevIndicator");
			
			if (prev.length) {
				prev.click();
			} else if (next.length && !prev.length) {
				//next.attr("json", "{page:1}").click();
				next.click();
			} else {
				if (!noRecordsRoute) { return false; }
				setTimeout(function() {
					$.get(noRecordsRoute, function(data) {
						dl.append(data).find("dd.noRecs").hide().slideDown("slow");
						AjaxEventsRouter.run();
					});
				}, 500);
			}
		}
	},
	"updateMyNumbers": function(jData) { // update them numbers
		var plus;
		if (typeof jData === "object") {
			$.each(jData, function(i) {
				$.each(jData[i].cssClasses, function(j, val) {
					if ($(val).length) {
						plus = (jData[i].plusOrMinus === "-") ? false : "+";
						if (!plus) {
							$(val).html(parseInt($.trim(($(val).html())), 10) - jData[i].cntRecs);
						} else {
							$(val).html(parseInt($.trim(($(val).html())), 10) + jData[i].cntRecs);
						}
					}
				});
			});
		} else {
			return false;
		}
	},
	"albumUpdate": function(){
		this._successMsgAfterServerCall();
		var wrap    = this.frm.parents(".include:eq(0)"),
		    albumId = Callback.jsonMe.albumId;
		this.frm.slideUp(function() {
			wrap.load("/profile/"+Callback.jsonMe.username+"/photo-album/"+albumId+"/info/", function() {
				AjaxEventsRouter.run("photoAlbumCreated");
			});
		});
	},
	"albumAndPhotoUpdate": function(){
		this._successMsgAfterServerCall();
		setTimeout(function() {
			window.location.href = $("a.action.toggleMode.display").attr("href");
		}, 1000);
	},
	"photoDelete": function(){
		this._successMsgAfterServerCall();
		var sel     = $("div.viewWrap.photoThumbsWrap:eq(0) a.sel"),
			next    = sel.parent().next().not(".viewAll").find("a"),
			prev    = sel.parent().prev().find("a"),
			albumId = $("#pContentHeader input[name='albumId']").val(),
			fntUrl 	= function(photoId) { window.location = '/profile/'+Callback.jsonMe.username+'/photo-album/'+albumId+'/photo/'+photoId+'/'; };
		
		setTimeout(function() {
			if (next.length) {
				fntUrl(next.getJsonAttr().photoId);
			} else if (prev.length) {
				fntUrl(prev.getJsonAttr().photoId);
			} else {
				window.location = '/profile/'+Callback.jsonMe.username+'/photo-album/'+albumId+'/empty/';
			}
		}, 1000);
	},
	"communitySongAction": function() {
		var wrap = $("div.addRemoveSongWrap");
		wrap.fadeOut(function() {
			wrap.html("&nbsp;");
			setTimeout(function() {
				$.ajaxSetup({cache:false});
				wrap.load("/profile/"+Callback.jsonMe.username+"/add-or-remove/song/"+Callback.jsonMe.songId+"/", function() {
					wrap.fadeIn("fast", function() {
						AjaxEventsRouter.run();
					});
				});
			}, 1200);
		});
	},
	"editProfile": function() {
		$("#frmBasicInfo input[name='username']").verifyUsername();
		$("#frmLocationInfo select[name='country']").stateSwitcher();
	},
	"savedProfile": function(me) {
		ChordC.editPersonalInfo(me.next());
	},
	"feedbackSent": function(){
		var frm   = this.frm,
			jData = this.jData;
			
		var showDisplayMessage = function() {
			frm.find('div:first-child').fadeOut("slow", function() {
				$(this).remove();
				frm.html('<p class="successDisplayMsg hide">'+jData.displayMsg+'</p>');
				frm.find('p.successDisplayMsg').fadeIn("slow");
			});
		}
			
		if (jData.success) {
			this._successMsgAfterServerCall();
			showDisplayMessage();
		} else if (jData.emailFailed) {
			this._successMsgAfterServerCall(jData.emailFailedMsg);
			showDisplayMessage();
		} else {
			Validation.fromServer(jData);
		}
		
	},
	"feedDelete": function() {
		this._removeRowUpdateNumbers();
	},
	"feedHide": function() {
		this._removeRowUpdateNumbers();
	},
	"friendAdd": function() {
		$("#profilePic").after('<div class="friendRequested">'+this.jsonMe.displayMsg+' <img src="/img/share/common/blank.gif" class="iFriends iconS" /></div>');
		var me = this.me;
		me.fadeOut(function() {
			me.remove();
		});
	},
	"friendConfirm": function(){
		this._removeRowUpdateNumbers();
	},
	"friendIgnore": function(){
		this._removeRowUpdateNumbers();
	},
	"messageSent": function(){
		this.frm.slideUp(function() {
			var sndMsgBtn = $(this).parents(".dhtmlFrmAndBtns:eq(0)").find(".toggleBtns .sendMsg"),
				json	  = sndMsgBtn.getJsonAttr();
				
			$(this).clearForm({'selectIndex':0});
			sndMsgBtn.replaceWith('<small class="txtSubColor3">'+json.message+'</small>');
		});
	},
	"messageDeleted": function() {
		jsonMe = this.jsonMe;
		this.me.disableBtn();
		setTimeout(function() {
			window.location = "/profile/"+jsonMe.myUsername+"/inbox/";
		}, 2000);
	},
	"songCreated": function(){
		if (!this.jData.serverErrorFldsAndMsgs) {
			this.frm.slideUp();
			this._successMsgAfterServerCall();
			setTimeout(function() {
				window.location = '/profile/'+Callback.jsonMe.username+'/song/'+Callback.jData.songId+'/edit/';
			}, 1000);
		} else {
			Validation.fromServer(this.jData);
			return false;
		}
	},
	"songUpdated": function(){
		if (!this.jData.serverErrorFldsAndMsgs) {
			this._successMsgAfterServerCall();
			setTimeout(function() {
				window.location = '/profile/'+Callback.jsonMe.username+'/song/'+Callback.jData.songId+'/';
			}, 500);
		} else {
			Validation.fromServer(this.jData);
			return false;
		}
	},
	"songDeleted": function(){
		this._successMsgAfterServerCall();
		setTimeout(function() {
			window.location = '/profile/'+Callback.jsonMe.username+'/song-collection/';
		}, 500);
	},
	"songRatingAction": function() {
		$("#songRatingMine").fadeOut(function() {
			$(this).empty();
			$(this).html(Callback.regData);
			$(this).fadeIn();
		});
		$("#songRatingCommunity").fadeOut(function() {
			$(this).load("/song/"+Callback.jsonMe.songId+"/rating/", function(){
				$(this).fadeIn();
			});
		});
	},
	"commentDelete": function() {
		this._removeRowUpdateNumbers();
	},
	"commentSave": function() {
		var me 		  	= this.me,
			jsonMe 	  	= this.jsonMe,
			msgWrap   	= me.parents("div.msgWrap:eq(0)"),
			msg		  	= msgWrap.find("div.msg"),
			p		  	= msg.find("p"),
			commentEdit	= msg.find("div.commentEdit"),
			editBtn		= msgWrap.find("a.editComment");
			
		$.extend(jsonMe.data, {'editComment':true});
	
		commentEdit.slideUp(function() {
			msg.load('/comment/'+jsonMe.data.feedId+'/list/', jsonMe.data, function() {
				editBtn.attr("href", "/profile/"+Callback.jsonMe.username+"/comment/"+jsonMe.data.feedId+"/edit/");
				p = msg.find("p.hide");
				p.fadeIn("fast", function() {
					$(this).removeClass("hide");
				});
			});
		});
	},
	"videoUpdate": function() { 
		var dd     = this.frm.parents("dd:eq(0)"),
			frm    = this.frm,
			json   = this.json,
			jsonMe = this.jsonMe,
			url    = "/profile/"+jsonMe.username+"/video/"+jsonMe.videoId+"/list/";
		
		this._successMsgAfterServerCall(); // TODO move to after ajax call
		
		$.ajax({
			type:    "POST",
			url:     url,
			cache:   false,
			data:    json,
			error:   function() { /*TODO*/ },
			success: function(data) {
				dd.replaceWith(data);
				AjaxEventsRouter.run("videos");
			}
		});
	},
	
	// next 5 create methods happen in this.createRecordThenAddToList()
	"createAlbum": function() { 
		return {"listModule":$('#lmPhotoAlbums'), "uri":"/profile/"+Callback.jsonMe.username+"/photo-album/", "ajaxEventsRoute":"photoAlbumCreated"};
	},
	"createFeed": function() { 
		return {"listModule":$('#lmFeeds'), "uri":"/feed/"};
	},
	"createPhotoComment": function() { 
		return {"listModule":$('#lmPhotoComments'), "uri":"/comment/"};
	},
	"createSongComment": function() { 
		return {"listModule":$('#lmSongComments'), "uri":"/comment/"};
	},
	"createVideo": function() { 
		return {"listModule":$('#lmMyVideos'), "uri":"/profile/"+Callback.jsonMe.username+"/video/", "ajaxEventsRoute":"videos"};
	},
	
	"createRecordThenAddToList": function(action) { 
		this.updateMyNumbers(this.jData);
		this._successMsgAfterServerCall();
		
		var o 			 	= this[action](),
			lm 		     	= o.listModule,
			ajaxEventsRoute = o.ajaxEventsRoute || null,
			dd 		     	= lm.find('dl.contentDL:eq(0) dd:eq(0)'),
			ddNoRecs     	= lm.find("dl.contentDL:eq(0) > dd.noRecs"),
			lmComponents 	= lm.find('div.pagi, div.actions, dt.header, div.toggleModeButton'),
			newRecId     	= this.jData[0].newRecId,
			json		 	= this.jsonMe.data || {},
			noFormSlideUp   = this.jsonMe.noFormSlideUp || false,
			frm		     	= this.frm,
			me;
		
		$.ajax({
			type:    "POST",
			url:     o.uri+newRecId+"/list/",
			cache:   false,
			data:    json,
			error:   function() { }, // TODO
			success: function(data) {
				if (noFormSlideUp) { frm[0].reset(); }
				
				if (ddNoRecs.length) { // no records so insert one and remove the no recs message
					ddNoRecs.fadeOut(function() {
						me = $(this);
						me.before(data).prev().hide().fadeIn(function() {
							me.remove();
							AjaxEventsRouter.run(ajaxEventsRoute);
							setTimeout(function() {
								lmComponents.slideDown();
								if (!noFormSlideUp) {
									setTimeout(function() {
										frm.slideUp(function() {
											$(this)[0].reset();
											$(this).find("[hint]").addClass("hintHelper");
										});
									}, 600);
								}
							}, 250);
						});
					});
				} else { // insert another record
					dd.before(data).prev().hide().slideDown(function() {
						AjaxEventsRouter.run(ajaxEventsRoute);
						if (!noFormSlideUp) {
							setTimeout(function() {
								frm.slideUp(function() {
									$(this)[0].reset();
									$(this).find("[hint]").addClass("hintHelper");
								});
							}, 250);
						}
					});
				}
			}
		});
	}
};

/*--------------------
	COOKIE MONSTER
----------------------*/
Cookie = {
	"create": function(name,value,days) {
		var expires, date;
		if (days) {
			date 	= new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			expires = "; expires="+date.toGMTString();
		} else {
			expires = "";
		}
		document.cookie = name+"="+value+expires+"; path=/";
	},
	"read": function(name) {
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0; i < ca.length; i++) {
			var c = ca[i];
			while (c.charAt(0)===' ') {
				c = c.substring(1,c.length);
			}
			if (c.indexOf(nameEQ) === 0) {
				return c.substring(nameEQ.length,c.length);
			}
		}
		return false;
	},
	"erase": function(name) {
		this.create(name,"",-1);
	},
	"eraseAll": function() {
		var cookieString = document.cookie;
		var cookies = cookieString.split(";");
		for (i=0; i < cookies.length; i++) {
			var cookie = unescape(cookies[i].split("=")[0]);
			var date = new Date();
			date.setTime(date.getTime()-1*24*60*60*1000);
			document.cookie = cookie += "=; expires=" + date.toGMTString() +"; path=/";
		}
	}
};	

/*-------------------
	EVENTS ROUTERS
---------------------*/
OnloadEventsRouter = {
	"run": function() {
		var	firewall = $("body").attr("firewall"), // will be public or private
		 	area 	 = $("body").attr("id"),
			page 	 = $("body").attr("page");	
		
		this.init();
		
		if (typeof this[firewall] == "function") {
			this[firewall]();
		}
		if (typeof this[area] == "function") {
			this[area]();
		}
		if (typeof this[page] == "function") {
			this[page]();
		}
	},
	"init": function() {
		Validation.create();
		$("a.openUp").openUp();
		$("a.actionBtn, button.actionBtn").submitForm();
		$("ul.mainMenu .more").dropDownMenu();
		$("#languageSelect").languageSwitcher();
		$("iframe.ad").setIframeAdDimensions();
	},
	
	// FIREWALL
	"public": function() {
		$("a.btnSignUp").signUpModal();
		$("div.logInForm a.lnkForgotPass, div.logInForm a.lnkLogin").toggleSections({toggleBetween:"form.signInForm, form.resetPasswordForm"});
		$(".logInForm input:not(:checkbox)").inputTextReplace({includeLabel:true});
		$("a.addtoanyShareSave").shareItButton();
		//$("form.signInForm button[type='submit']").signUpIndicator();
	},
	"private": function() {
		$("a.singleActionBtn").singleAction(); // look into this
	},
	
	// AREAS
	"Admin": function() {
		$("div.areaMenu a").bodySectionComponent();
		$("a.sectionSwitchBtn").bodySectionSwitchers();
		ListModuleEventsRouter.run();
	},
	"Chords": function() {
		$("a.matchedImg").showMatchedImage();
		$("a.matchedButton").showMatchedDiagram();
		$("#types").setScrollTop();
	},
	"ChordFinderApp": function() {
		ChordC.rotateChordFinderApp();
	},
	"Community": function() {
		$("div.areaMenu a").bodySectionComponent();
		$("a.sectionSwitchBtn").bodySectionSwitchers();
		ListModuleEventsRouter.run();
		$("#twitter_div").load("/twitter/2/");
		$("textarea.hintHelper").hintHelper();
	},
	"Help": function() {
		$("#Help .helpMap .icon a").clickHelp();
	},
	"Home": function() {
		$("#Home .action .btnTab").switchSections({ tabViewId:"homeTabContent",fadeSpeed:500 });
		$("#home_search").inputTextReplace({includeLabel:false});
		$("#twitter_div").load("/twitter/5/");
	},
	"Profile": function() {
		$("div.areaMenu a").bodySectionComponent();
		$("a.sectionSwitchBtn").bodySectionSwitchers();
		ListModuleEventsRouter.run();
		$("a.popupBtn").listPopup();
		$("textarea.hintHelper").hintHelper();
		$("div.frmAlbumPhoto").populateDateFieldFromDropDowns("dateTakenPhoto");
		$("div.frmAlbumPhoto a.submitButton").albumPhotoUpload();
		$(".frmVideo").populateDateFieldFromDropDowns("dateTakenVideo");
		$("#frmBasicInfo input[name='username']").verifyUsername();
	},
	
	// PAGES
	"photoAlbum": function() {
		$("div.viewWrap.photoThumbsWrap:eq(0) a").thumbnailAction();
	},
	"profile": function() {
		$("#statusQuote .btnStatus").statusUpdate();
		$("#frmLocationInfo select[name='country']").stateSwitcher();
	},
	"message": function() {
		
	},
	"signup": function() {
		$("form.signUpForm input[name='username']").verifyUsername();
		$("form.signUpForm select[name='country']").stateSwitcher();
	},
	"song": function() {
		$("body.pgSong #pContentHeader div.toggleModeButton a").toggleSongMode();
		$("#songTabControls div.controls a").insertTabTemplate();
		$("#addChordsModule").addChordsToSong();
		$("body.pgSong #diagrams a.action").addChordsToSongAction();
		$("body.pgSong #songChords.edit h4 a.remove").addChordsToSongAction();
		$("body.pgSong #songChords.edit h4 a.locateChord").addChordsSetScrollPosition();
		$("body.pgSong #songChords a.matchedImg").showMatchedImage();
		$("body.pgSong #songChords a.action.songChordPic").showMatchedImageTrigger();
		$("#frmSongRating a").ratingStars();
	}
};

BodySectionEventsRouter = {
	"run": function(route) {
		this.init();
		if (typeof this[route] == "function") {
			this[route]();
		}
	},
	"init": function() {
		Validation.create();
		$("a.openUp").openUp();
		$("a.actionBtn, button.actionBtn").submitForm();
		$("a.sectionSwitchBtn").bodySectionSwitchers();
		ListModuleEventsRouter.run();
	},
	"feeds": function() {
		$("textarea.hintHelper").hintHelper();
	},
	"friendRequests": function() {
		
	},
	"inbox": function() {
		
	},
	"myInformation": function() {
		$("#frmBasicInfo input[name='username']").verifyUsername();
		$("#frmLocationInfo select[name='country']").stateSwitcher();
	},
	"photoAlbums": function() {
		$("div.frmAlbumPhoto").populateDateFieldFromDropDowns("dateTakenPhoto");
		$("div.frmAlbumPhoto a.submitButton").albumPhotoUpload();
	},
	"songCollection": function() {
		$("a.popupBtn").listPopup();
	},
	"videos": function() {
		$(".frmVideo").populateDateFieldFromDropDowns("dateTakenVideo");
	}
};

ListModuleEventsRouter = {
	"run": function(route) {
		this.init();
		if (typeof this[route] == "function") {
			this[route]();
		}
	},
	"init": function() {
		Validation.create();
		$("a.btnSignUp").signUpModal();
		$("a.openUp").openUp();
		$("a.actionBtn, button.actionBtn").submitForm();
		$("div.viewWrap div.pagi div.nav a").listModuleComponent();
		$("div.viewWrap div.content dt a").listModuleComponent();
		$("div.viewWrap div.filterTitle a.showAll").listModuleComponent();
		$("div.viewWrap div.filter dl.menu a").listModuleComponent();
		$("div.viewWrap form.listModuleFrm").listModuleComponent();
		$("div.viewWrap a.listModuleSearchBtn").listModuleSafeSearch();
		$("div.viewWrap div.toggleModeButton a").listModuleToggleEditMode();
		$("div.filter dd.selector h6 a").listModuleFilter();
		$("div.listModule").listCheckboxes();
		$("a.actionBtnLM").listModuleBtn();
		$("a.listModuleViewAllItems").listModuleViewAllItems();
	},
	"bandLand": function() {
	},
	"comments": function() {
	},
	"feeds": function() {
	},
	"friendRequests": function() {
	},
	"inbox": function() {
	},
	"photoAlbumThumbnails": function() {
		$("div.viewWrap.photoThumbsWrap:eq(0) a").thumbnailAction(); // look into this.
	},
	"photoAlbums": function() {
		$("div.frmAlbumPhoto a.submitButton").albumPhotoUpload();
	},
	"videos": function() {
		$(".frmVideo").populateDateFieldFromDropDowns("dateTakenVideo");
	}
};

AjaxEventsRouter = {
	"run": function(route) {
		this.init();
		if (typeof this[route] == "function") {
			this[route]();
		}
	},
	"init": function() {
		Validation.create();
		$("a.btnSignUp").signUpModal();
		$("a.openUp").openUp();
		$("a.sectionSwitchBtn").bodySectionSwitchers();
		$("a.actionBtn, button.actionBtn").submitForm();
		$("a.popupBtn").listPopup();
		$("textarea.hintHelper").hintHelper();
		$("a.singleActionBtn").singleAction(); // look into this
	},
	"photoAlbum": function() { // used on stand alone photo.
		$("#bigPhoto div.frmAlbumPhoto").populateDateFieldFromDropDowns("dateTakenPhoto");
	},
	"photoAlbumCreated": function() { // used on list module after creating an album
		$("div.frmAlbumPhoto").populateDateFieldFromDropDowns("dateTakenPhoto");
		$("div.frmAlbumPhoto a.submitButton").albumPhotoUpload();
	},
	"photoAlbumThumbnails": function() {
		$("div.viewWrap.photoThumbsWrap:eq(0) a").thumbnailAction(); // look into this.
	},
	"song": function() {
		$("body.pgSong #pContentHeader div.toggleModeButton a").toggleSongMode();
		$("#songTabControls div.controls a").insertTabTemplate();
		$("#addChordsModule").addChordsToSong();
		$("body.pgSong #diagrams a.action").addChordsToSongAction();
		$("body.pgSong #songChords.edit h4 a.remove").addChordsToSongAction();
		$("body.pgSong #songChords.edit h4 a.locateChord").addChordsSetScrollPosition();
		$("body.pgSong #songChords a.matchedImg").showMatchedImage();
		$("body.pgSong #songChords a.action.songChordPic").showMatchedImageTrigger();
		$("#frmSongRating a").ratingStars();
	},
	"ratingStarsAndSubmitForm": function() { // see rating.php
		$("#frmSongRating a").ratingStars();
	},
	"videos": function() {
		$(".frmVideo").populateDateFieldFromDropDowns("dateTakenVideo");
	}
};

/*-----------------------------
	HOMEMADE JQUERY PLUGINS
-------------------------------*/
(function($){
	/*---------------
		UTILITIES
	-----------------*/
	/* Intended to provide the functionality of the $.extend function for the object array returned from the serializeArray()
	   function. e.g., var json = frm.serializeArray(); $.extendForm(json, jsonMe.data); */
	$.extendForm = function(arr,o) {
		if(!arr || !$.isArray(arr)) { return false; }
		if(!o) { return arr; }
		
		$.each(o,function(i,val){
			var p = {};
			eval("$.extend(p,{name: '"+i+"', value: '"+val+"'})");
			arr.push(p);
		});
	};
	$.coverMe = function(o,callback) { 		// modal tool
			o 			 = o 			|| {};
			callback	 = callback		|| function(){};
		var opacity 	 = o.opacity 	|| 0.5,
			filter	 	 = opacity * 100,
			bg			 = o.background || "#000",
			zIndex		 = o.zindex 	|| 1000,
			wHeight 	 = window.innerHeight || document.documentElement.clientWidth || document.body.clientWidth,
			windowHeight = (document.height > wHeight ) ? document.height : wHeight;
		
		var css = {
			'height' 	 : windowHeight,
			'z-index'  	 : zIndex,
			'background' : bg,
			'opacity' 	 : opacity,
			'filter' 	 : "alpha(opacity="+filter+") !important"
		};
		
		if (!$("#coverMe").length) {
			$('<div id="coverMe"></div>').appendTo('body');
			$("#coverMe").css(css);
			$('#coverMe').click(function(){ callback(); });
		}
	};
	$.modoMe = function(me, o, callback) { 	// modal tool
		Validation.removeErrorMessages();
		o = o || {};
		if (!me) { console('Please define an object'); return false; }
		if (!o.controller) { console.log('Please define a controller'); return false; }
		if (!$("#modoCase").length) {
			$.coverMe(o, callback);
			$('<div id="modoCase"></div>').appendTo('body');
			$('#modoCase').load(o.controller,o,function() {
				$('#modoCase').centerOnScreen();
				if (callback){ callback(); }
			});
		}
		return false;
	};
	
	$.fn.getJsonAttr = function(o) {
		if (!this[0] || !this[0]){return false;}
		var jsonAttr = $(this).attr("json");
		return (Boolean(jsonAttr)) ? eval('(' + jsonAttr + ')') : false;
	};	
	$.fn.unwrap = function() { 				// oposite of native jquery wrap method
		this.parent(':not(body)').each(function(){
			$(this).replaceWith( this.childNodes );
		});
		return this;
	};
	$.fn.centerOnScreen = function() { 		// modal tool
		var me 			 = $(this),
			yScroll 	 = self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop,
			windowHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight,
			windowWidth  = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
			top 		 = yScroll+((windowHeight - me.height())/2),
			left 		 = (windowWidth/2) - (me.width()/2);
			top 		 = (top  < 1) ? 10 : top;
			left 		 = (left < 1) ? 10 : left;
		me.css({'top': top  + "px", 'left': left + "px"});
		return this;
	};
	$.fn.inputTextReplace = function(o) { // remove placeholder form text
		if (!this[0] || !this[0]){return false;}
		o = o || {};
		$(this).each(function(){
			var me			= $(this),
				placeholder = me.attr('temptext');
			if (me.val() !== "" || me.val() !== placeholder) { me.val(''); }
			me.focus(function(){
				if(me.val() !== "" || me.val() !== placeholder){
					if (o.includeLabel) {
						me.prev().hide();
					} else {
						me.val(placeholder);
					}
				}
			});
			me.blur(function(){
				if(me.val() === "" || me.val() === placeholder){
					if (o.includeLabel) {
						me.prev().show();
					} else {
						me.val(placeholder);
					}
				}
			});
		});
		
		return this;
	};
	$.fn.disableBtn = function(o) { 		// disable a ctrElements button
		if (!this[0] || !this[0]){return false;}
		o = o || {};
		var cssClass   = o.cssClass || "",
		    btn 	   = $(this),
		    json       = btn.getJsonAttr(),
		    loadingMsg = json.loadingMsg || "";
		
		btn.replaceWith('<span class="btnDisabled '+cssClass+'">'+loadingMsg+'</span>');
		
		return this;
	};
	$.fn.setScrollTop = function() { // set the scrolltop of the selected link in a list
		if(!this[0]){ return false; }
		this[0].scrollTop	= 0;
		var aSel			= $(this).find('a.sel');
		var top 			= aSel.offset().top;
		this[0].scrollTop 	= top - this[0].offsetHeight;
		return this;
	};
	$.fn.populateDateFieldFromDropDowns = function(dateFldName) { // date stuff
		if(!this ||!this[0]) { return false; }
		
		$(this).each(function() {
			var frm 		= $(this),
				monthSel 	= frm.find("select[name='month']"),
				daySel 		= frm.find("select[name='day']"),
				yearSel 	= frm.find("select[name='year']"),
			 	dateSelects = $([monthSel[0], daySel[0], yearSel[0]]),
				dateFld 	= frm.find("input[name='" + dateFldName + "']");

			function createDate() {
				var day   = daySel.find("option:selected").val(),
					month = monthSel.find("option:selected").val(),
					year  = yearSel.find("option:selected").val();
				dateFld.val(year + "-" + month + "-" + day);
			}
		
			var createMonthDays = function() {
				var month = monthSel.find("option:selected").val(),
					year  = (yearSel.find("option:selected").val().length) ? yearSel.find("option:selected").val() : (new Date()).getFullYear(),
					day   = (new Date()).daysInMonth(month - 1, year);
			
				for(var i = daySel.find("option").length; i <= day; i++) {
					daySel.append('<option value="'+i+'">'+i+'</option>');
				}
			
				if(daySel.find("option").filter(":gt(" + day + ")").is(":selected")) {
					daySel.find("option:eq(" + day + ")").attr("selected", "selected");
				}
			
				daySel.find("option").filter(":gt(" + day + ")").remove();
			};
		
			dateSelects.bind("change.populateDate", function() {
				if(!$(this).is(daySel.selector)) {
					createMonthDays();
				}
				createDate(); 
			});
		});
	};
	$.fn.clearForm = function(o) {
		if (!this[0] || !this[0]){return false;}
		
		o = o || {};
		var selectIndex = (typeof o.selectIndex != "undefined") ? o.selectIndex : -1;
		
		$(this).find(':text, :password, textarea, :file').
				attr('value', '').end().
			find(':checkbox, :radio').
				attr('checked', false).end().
			find('select').
				attr('selectedIndex', selectIndex);
	
		return this;
	};
	$.fn.setIframeAdDimensions = function() {
		if (!this[0] || !this[0]){return false;}
		
		$(this).load(function() {
			var ad = $(this).contents().find('iframe:eq(0)'),
				w  = parseInt(ad.attr('width')),
				h  = parseInt(ad.attr('height'));
			$(this).css({'height':h, 'width':w});
		});
		
		return this;
	};
	
	/*--------------------
		AUTHENTICATION
	----------------------*/
	$.fn.signUpIndicator = function() {
		if (!this[0] || !this[0]){return false;}
		var me 			 = $(this),
			signUpBubble = $("#signupBubble"),
			offset 		 = me.offset(),
			Css 		 = { left:(offset.left - 345), top:(offset.top + 31) };
			
		signUpBubble.css(Css);
		
		me.bind('mouseenter',function() {
			signUpBubble.fadeIn();
		}).bind('mouseleave',function(){
			ChordC.signUpIndicatorTO = setTimeout(function() {
				signUpBubble.fadeOut();
			}, 200);
		});
		
		signUpBubble.bind('mouseenter',function() {
			clearTimeout(ChordC.signUpIndicatorTO);
			$(this).show();
		}).bind('mouseleave',function() {
			$(this).fadeOut();
		});
	}
	$.fn.signUpModal = function() {
		if (!this[0] || !this[0]){return false;}
		
		var me = $(this);
		
		me.unbind("click.signUpModal");
		me.bind  ("click.signUpModal", function() {
			$.modoMe($(this), {controller:'/modal/sign-up/', opacity:0.6}, function() {
				Validation.create();
				$("form.signUpForm input[name='username']").verifyUsername().focus();
				$("form.signUpForm select[name='country']").stateSwitcher();
			});
			return false;
		});
	};
	$.fn.verifyUsername = function() {
		if (!this[0] || !this[0]){return false;}
		
		$(this).unbind("keyup.verifyUsername");
		$(this).bind("keyup.verifyUsername", function() {
			var me	        = $(this),
				meVal 	    = me[0].value,
				frm   	    = me.parents("form.form:eq(0)"),
				msgUsername = frm.find("b.msgUsername"),
				msgVerify   = frm.find("small.msgVerify");
				
			$.post("/authenticate/verify-username/", {"username":meVal}, function(jData) {
				if (meVal !== "") {
					if (jData.success) {
						msgVerify.html('| <b style="color:#33cc00;">'+jData.usernameAvailable+'</b>');
					} else {
						msgVerify.html('| <b style="color:#ee4923;">'+jData.serverErrorFldsAndMsgs.username+'</b>');
					}
					msgUsername.html(meVal.toLowerCase());
				} else {
					msgVerify.html('');
					msgUsername.html('???');
				}
			}, "json");
		});
		
		return this;
	};
	
	$.fn.stateSwitcher = function() {
		if (!this[0] || !this[0]){return false;}
		
		$(this).unbind("change.stateSwitcher");
		$(this).bind("change.stateSwitcher", function() {
			var me	          = $(this),
				meVal 	      = me[0].value.trim().toLowerCase(),
				frm   	      = me.parents("form.form:eq(0)")
				stateLbl      = frm.find("label.stateLbl"),
				id            = stateLbl.attr('for'),
				stateFld      = frm.find('[name="state"]'),
				isStateSelect = (stateFld[0].tagName.toLowerCase() == 'select') ? true : false,
				stateSelect   = (isStateSelect) ? stateFld : stateFld.prev();
				stateInput    = (!isStateSelect) ? stateFld : stateFld.next();
			
			if (meVal == "united states") {
				stateInput.hide().attr('name','').attr('id','');
				stateSelect.show().attr('name','state').attr('id',id);
			} else {
				stateSelect.hide().attr('name','').attr('id','');
				stateInput.show().attr('name','state').attr('id',id);
			}
		});
		
		return this;
	};
	
	/*-------------
		ACTIONS
	---------------*/
	$.fn.languageSwitcher = function() {
		var langMenu = $(this), 	// langMenu = $("#languageSelect")
			langsA   = langMenu.find("ul li a"),
			langBtn  = $("#languageButton"),
			popupTO;
		
		// language list
		langsA.unbind("click.languageSwitcher");
	   	langsA.bind  ("click.languageSwitcher", function(e) {
			e.preventDefault();
			Cookie.create("userPreferredLanguage", $(this).attr("lang"), 360);
			window.location.reload();
		});
		
		// language switcher button
		langBtn.toggle(function(e) {
			e.preventDefault();
			langMenu.removeClass("hide");
		}, function(e) {
			e.preventDefault();
			langMenu.addClass("hide");
		});
		
		langBtn.hover(
			function () { window.clearTimeout(popupTO); }, 
			function () { popupTO = setTimeout( function() { langBtn.click(); }, 300); }
		);
		
		langMenu.hover(
			function () { window.clearTimeout(popupTO); }, 
			function () { popupTO = setTimeout( function() { langBtn.click(); }, 300); }
		);
	}
	$.fn.switchSections = function(o) { // example: tabs on the home page, the chords, the community, and you 
		if (!this[0] || !this[0]){return false;}
		var me = this;
		me.whichTabContent 	= o.tabViewId;
		me.fadeSpeed 		= o.fadeSpeed || "slow";
		$("#"+me.whichTabContent+" .tabView:eq(0)").fadeIn();
		$("#"+me.whichTabContent+" .btnTab:eq(0)").addClass("selected");
		me.click(function(){
			var thisID = $(this).attr("href");
			$("#"+me.whichTabContent+" .tabView").fadeOut(me.fadeSpeed);
			$("#"+me.whichTabContent+" .btnTab").removeClass("selected");
			$(this).addClass("selected");
			$(thisID).fadeIn(me.fadeSpeed);
			return false;
		});
	};
	$.fn.toggleSections = function(o) {
		if (!this[0] || !this[0]){return false;}
			o 				= o 				|| {};
		var toggleBetween 	= o.toggleBetween 	|| false;
		if (!toggleBetween) { return false; }
			toggleBetween 	= toggleBetween.split(",");
		var	toggleItem1		= $(toggleBetween[0]),
			toggleItem2		= $(toggleBetween[1]);
		
		$(this).unbind("click.toggleSections");
		$(this).bind("click.toggleSections", function() {
			Validation.removeErrorMessages();
			ChordC.removePopupMsgs();
			if (toggleItem1.is(":hidden")) {
				toggleItem1.show();
			} else {
				toggleItem1.hide();
			}
			if (toggleItem2.is(":hidden")) {
				toggleItem2.show();
			} else {
				toggleItem2.hide();
			}
			return false;
		});
		
		return this;
	};
	$.fn.openUp = function(o) { // mainly for the flyout forms
		if (!this[0] || !this[0]){return false;}
		
		$(this).unbind("click.openUp");
		$(this).bind  ("click.openUp", function(o) {
			var me     = $(this),
				json   = me.getJsonAttr(),
				target = json.target;
			target = (target.indexOf("$")) ? $(target) : eval(target);
			
			if(target.is(":hidden")) {
				target.slideDown("fast");
			} else {
				Validation.removeErrorMessages();
				target.slideUp("fast");
			}
		});
		
		return this;
	};
	$.fn.hintHelper = function() {
		if (!this[0] || !this[0]){return false;}
		
		$(this).unbind("focus.hintHelper");
		$(this).bind  ("focus.hintHelper", function() {
			var me = $(this);
			if (me.val().trim() === me.attr('hint').trim()) {
				me.removeClass('hintHelper').val('');
			}
		});
		
		$(this).unbind("blur.hintHelper");
		$(this).bind  ("blur.hintHelper", function() {
			var me = $(this);
			if (me.val().trim() === '') {
				me.addClass('hintHelper').val(me.attr('hint').trim());
			}
		});
		
		return this;
	};
	$.fn.ratingStars = function() {
		if (!this[0] || !this[0]){return false;}
		var star   = $(this),
			frm    = star.parents("form:eq(0)"),
			rating = frm.find("input[name='feed']");	
		
		function ratingStarsHover(me, rating) {
			var form = me.parent();
			for (var i=0; i<=5; i++) {
				form.removeClass("iRating"+i);
			}
			form.addClass("iRating"+rating);
		}
		
		star.mouseover(function() {
			var me = $(this);
			ratingStarsHover(me, me.text());
			rating.val(me.text());
		});
		
		star.mouseout(function()  {
			var me   = $(this),
				json = me.parent().getJsonAttr(); 
			ratingStarsHover(me, json.originalRating);
			rating.val(json.originalRating);
		});
		
		return this;
	};
	$.fn.listPopup = function(o) {
		if (!this[0] || !this[0]){return false;}
		
			o 			= o || {};
		var btn			= $(this),
			jsonMe 		= btn.getJsonAttr(),
			target  	= jsonMe.target 	|| false,
			xPosAdjust	= jsonMe.xPosAdjust || 0,
			yPosAdjust	= jsonMe.yPosAdjust || 0,
			side		= jsonMe.side		|| "left",
			popupTO, x, y, me;
		
		btn.unbind("click.listPopup");
		btn.bind("click.listPopup", function(){
			me = $(this);
			if (target.is(':visible')) {
				target.hide();
				return false;
			}
			
			$("div.listPopup").hide(); // hide other listPopup(s)
			$("body").append(target);
			target.show();
			
			x = (side === "left") ? me.offset().left - me.width() + 5 - target.width() - xPosAdjust : me.offset().left + me.width() + me.width() + xPosAdjust;
			y = me.offset().top - 20 - yPosAdjust;
			
			target.css({top:y, left:x});
			
			// Cap it off so the ol will scroll
			var cssObj = {
				height: 	"340px",
				overflow: 	"auto",
		        overflowX: 	"hidden",
		        overflowY: 	"scroll"
		    };
			if (target.height() > 335) {
				target.find("> dl").css(cssObj);
			}
			target.hover(
				function () { window.clearTimeout(popupTO); }, 
				function () { popupTO = setTimeout( function() { target.hide(); }, 300); }
			);
		});
		
		return this;
	};
	$.fn.dropDownMenu = function(o) { // main navigation drop down menu
		if (!this[0] || !this[0]){return false;}
		
		var slideSpeed = "fast";
		
		$(this).each(function(i, val) {
			var me 	   	 = $(this),
				li		 = me.parent(),
				jsonMe 	 = me.getJsonAttr(),
				dropDown = jsonMe.dropDown;
			dropDown = eval(dropDown);
			
			var idDD 	 = dropDown.attr("id"),
				widthDD  = dropDown.innerWidth(),
				offsetLI = li.offset(),
				heightLI = li.innerHeight(),
				widthLI	 = li.innerWidth();
				
			var css = {
						'left' : offsetLI.left,
						'top'  : offsetLI.top + heightLI
					  };
			
			// subroutine
			function hideMe(dropDown) {
				clearTimeout(TO2);
				ChordC.dropDownMenu = false;
				TO = setTimeout(function() {
					if (!ChordC.dropDownMenu) {
						dropDown.slideUp(slideSpeed);
					}
				}, 300);
			}
			
			me.hover(
				function () {
					TO2 = setTimeout(function() { // pressure sensitivity
						ChordC.dropDownMenu = true;
						if (!$("body > #"+idDD).length) { // only append to body once
							$("body").append(dropDown);
						}
						if (idDD !== ChordC.dropDownMenuId) { // make sure all menus disappear besides the one that is suppose to be open
							$("ul.menuDD:visible").slideUp(slideSpeed);
						}
						dropDown.css(css).slideDown(slideSpeed);
						ChordC.dropDownMenuId = idDD;
					}, 200);
				},
				function () {
					hideMe(dropDown);
				}
			);
			
			dropDown.hover(
				function () { 
					ChordC.dropDownMenu = true;
				}, 
				function () {
					hideMe(dropDown);
				}
			);
		});
		
		return this;
	};
	$.fn.insertTabTemplate = function() {
		if (!this[0] || !this[0]){return false;}
		
		$(this).each(function(i, val) {
			var me = $(this),
				strBlankTab = "";
				
			switch ($(this).attr("id")) {
				case "tabBlankGuitar":
					strBlankTab = "E|----------------------------------------------------------------------------|\nA|----------------------------------------------------------------------------|\nD|----------------------------------------------------------------------------|\nG|----------------------------------------------------------------------------|\nB|----------------------------------------------------------------------------|\ne|----------------------------------------------------------------------------|\n\n";
				 	break;
				case "tabBlankBass": 
				 	strBlankTab = "E|----------------------------------------------------------------------------|\nA|----------------------------------------------------------------------------|\nD|----------------------------------------------------------------------------|\nG|----------------------------------------------------------------------------|\n\n";
				 	break;
				case "tabLegend":
					strBlankTab = "/ = slide up      \\ = slide down\nh = hammer on     p = pull off\nb = bend          r = release\n~ = vibrato       + = harmonic\nx = mute note     t = tap (with finger or pick)\n\n";
				 	break;
			}
			
			me.unbind("click.insertTablature");
			me.bind  ("click.insertTablature", function() {
				$("#tablature").val(strBlankTab + $("#tablature").val());
			});
		});
		
		return this;
	};
	$.fn.shareItButton = function(){
		if(!this || !this[0]){return false};

		$(this).unbind("click.shareItButton");
		$(this).bind("click.shareItButton", function() {
			if (typeof ChordC.shareCnt == "undefined") {
				ChordC.shareCnt = 0;
			}
			ChordC.shareCnt++;
			if (ChordC.Numbers.isEven(ChordC.shareCnt)) {
				$(this).mouseover();
			}
			return false;
		});

		return this;
	}
	
	
	/*------------------
		AJAX ACTIONS
	--------------------*/
	$.fn.clickHelp = function(o){ // example the help page
		if (!this[0] || !this[0]){return false;}
		var me = $(this);
			o = o || {};
		
		me.unbind("click.clickHelp");
		me.bind("click.clickHelp",function(){
			$(".helpMap ol li.iCheckApprove").addClass("iCheckmark");
			$(".helpMap ol li.iCheckApprove").removeClass("iCheckApprove");
			$(this).each(function(){
				var helpPage = this.href;
				var section = helpPage;
				if (section.indexOf("help/") !== -1) {
					section = section.split("help/")[1].split("/")[1];
				}
				$('<p class="iLoading">Loding...</p>').appendTo("#loadHelpPage");
				$("#loadHelpPage").load(helpPage,{ajax:true},function(){
					$("#loadHelpPage .helpArticles").hide();
					$("#loadHelpPage p.iLoading").remove();
					$("#"+section).show();
				});
			});
			$(this).parent().addClass("iCheckApprove");
			return false;
		});
		
		return this;
	};
	$.fn.statusUpdate = function(){
		if (!this[0] || !this[0]){return false;}
		var btn   	    = $(this),
			statusQuote = $("#statusQuote"),
			displayWrap = statusQuote.find("div.displayWrap"),
			blockquote  = displayWrap.find("blockquote"),
			form		= statusQuote.find("form"),
			cancel		= form.find(".cancelBtn"),
			save		= form.find(".saveBtn"),
			textarea    = form.find("textarea"),
			text 	    = textarea.attr("text"),
			quote, data;
		
		if (textarea.val() === "" || textarea.val() === text) {
			textarea.addClass("question").val(text);
		}
		
		btn.click(function() {
			quote = blockquote.html();
			ChordC.toggleWith(displayWrap, form);
			ChordC.memberStatus = blockquote.text();
			textarea.addClass("question").val(text);
		});
		
		cancel.click(function(){
			data = textarea.val();
			ChordC.toggleWith(displayWrap, form);
			
			if (data === text || data === ""){
				blockquote.html(ChordC.memberStatus);
				return false;
			}
			
			textarea.val('');
		});
		
		save.click(function(){
			data = textarea.val();
			if (data === text){
				data = '';
			}
			
			var controller = $(this).attr("href");
			
			$.post(controller, {caption:data}, function(){
				if (data === ""){
					blockquote.html('...');
				} else {
					blockquote.html(data);
				}
				ChordC.toggleWith(displayWrap, form);
			});
			
			btn.ajaxPreloader();
		});
		
		textarea.focus(function(){
			data = textarea.removeClass("question").val();
			if (data === text){
				textarea.val('');
				return false;
			}
		});
		
		textarea.blur(function(){
			data = textarea.val();
			if (data === ''){
				textarea.addClass("question").val(text);
				return false;
			}
		});
		
		return this;
	};
	$.fn.editComment = function(o) {
		if (!this[0] || !this[0]){return false;}
		
		var me 		  	= $(this),
			jsonMe 	  	= me.getJsonAttr(),
			controller  = me.attr("href"),
			msgWrap   	= me.parents("div.msgWrap:eq(0)"),
			msg		  	= msgWrap.find("div.msg"),
			p		  	= msg.find("p"),
			commentEdit	= msg.find("div.commentEdit"),
			editBtn		= msgWrap.find("a.editComment");
		
		if (p.length) { // edit - remove message and slideDown the edit form
			p.fadeOut("fast", function() {
				msg.load(controller, jsonMe.data, function() {
					me.attr("href", "/comment/"+jsonMe.feedId+"/list/");
					msg.find("div.commentEdit").slideDown();
					AjaxEventsRouter.run();
				});
			});
		} else { // cancel - remove edit form and fadeIn the feed
			Validation.removeErrorMessages();
			commentEdit.slideUp(function() {
				msg.load(controller, jsonMe.data, function() {
					editBtn.attr("href", "/profile/"+jsonMe.username+"/comment/"+jsonMe.feedId+"/edit/");
					p = msg.find("p.hide");
					p.fadeIn("fast", function() {
						$(this).removeClass("hide");
					});
				});
			});
		}
		
		return this;
	};
	$.fn.toggleSongMode = function(o) {
		if (!this[0] || !this[0]){return false;}
			o 	   	   = o || {};
		var wrap   	   = $("div.bodyContent #songWrap"),
			comments   = $("#commentAreaSong"),
			me 	   	   = $(this),
			jsonMe 	   = me.getJsonAttr(),
			controller = me.attr("href");
		
		me.unbind("click.toggleSongMode");
		me.bind  ("click.toggleSongMode", function(o) {
			if ($(this).hasClass("actionBtn")) { return false; } // example song add and remove song
			
			$.ajaxSetup({cache:false});
			wrap.load(controller, function() {
				if (comments.is(":visible")) {
					comments.hide();
				} else {
					comments.show();
				}
				AjaxEventsRouter.run("song");
			});
			$(this).ajaxPreloader();
		});
		
		return this;
	};
	
	/*------------
		PHOTOS
	--------------*/
	$.fn.albumPhotoUpload = function() {
		if(!this ||!this[0]) { return false; }
	   	
		$(this).each(function(i, val) {
			
			$(this).parents("div.form:eq(0)").populateDateFieldFromDropDowns("dateTakenPhoto");
			
		   	$(this).unbind("click.albumPhotoUpload");
		   	$(this).bind  ("click.albumPhotoUpload", function(e) {
				e.stopPropagation();
				
				var me   			= $(this),
					json    		= me.getJsonAttr(),
					formAction      = me.attr("href"),
					reload  		= json.reloadPage || false,
			   	   	frm  			= me.parents("div.form:eq(0)"),
					wrap 			= me.parents(".include:eq(0)"),
					albumId 		= frm.find("input[name='albumId']").val(),
					emptyPhotoAlbum = ($("body").hasClass("pgEmptyPhotoAlbum")) ? true : false,
					baseUrl			= "/profile/"+json.username+"/photo-album/"+albumId+"/";
				
				wrap = (wrap.length) ? wrap : $('#uploadPhoto'); 					// true then on list page, not then on standalone page
				var standAlone = (wrap.attr("id") == "uploadPhoto") ? true : false; // true then on standalone page else on list page
				
				if (Validation.flag) { return false; }
				
				if (!$("#binarySubmit").length) {
		   			$("body").append('<iframe class="hiddenIframe" id="binarySubmit" name="binarySubmit" frameborder="0" scrolling="no"></iframe>');
				}
			   	
			   	if (frm.parent()[0].tagName.toLowerCase() != "form") {
					frm.wrap('<form target="binarySubmit" enctype="multipart/form-data" method="post" action="'+formAction+'"></form>');
				}
								
				frm.parent()[0].submit(function() { return false; });
				
				$("iframe#binarySubmit").load(function() {
					var results = $.trim($(this).contents().text()),
						jData   = eval('(' + results + ')'),
						editUrl = "";
					
					if (jData.success) {
						me.popupMsg({msgText:json.successMsgAfterServerCall, yPos:-260});
						
						if (standAlone) { // not totally sure about this?
							if (emptyPhotoAlbum) {
								window.location = baseUrl+"/photo/"+jData.photoId+"/";
							} else if (reload) {
								window.location.reload();
								return false;
							}
							editUrl = ($("#frmAlbumEdit").length) ? "edit/" : ""; // ensure thumbnail has edit url
						}
						
						frm.slideUp(function() {
							frm.clearForm({'selectIndex':0});
							
							if (!standAlone) {
								wrap.load(baseUrl+"info/", function(){
									AjaxEventsRouter.run("photoAlbumCreated");
								});
							}
							
							$.post(baseUrl+"thumbnail/"+jData.photoId+"/list/"+editUrl, function(data) {
								var thumbsWrap = wrap.next().find("dl.contentDL");
									thumbsWrap = (thumbsWrap.length) ? thumbsWrap : $('div.photoThumbsWrap').find("dl.contentDL"); // true then on list page, not then on standalone page
								
								var viewAll	   = thumbsWrap.find("dd.viewAll"),
									switcher   = viewAll.find("a"),
									noRecs	   = thumbsWrap.find(".noRecs");
									
								if (noRecs.length) {
									noRecs.fadeOut(function() { $(this).remove(); });
								}
								if (switcher.hasClass("listModuleViewAllItems")) {
									viewAll.prev().remove();
								}
								thumbsWrap.prepend(data);
								if (standAlone) {
									AjaxEventsRouter.run("photoAlbumThumbnails");
									$("span.totAlbumPhotos").html(parseInt($.trim(($('span.totAlbumPhotos').html())), 10) + 1); // TODO if error don't update
								}
							});
						});
						
					} else {
						me.popupMsg({ msg:"msgError", msgText:jData.error, 'timeout':4000 }); 
					}
					setTimeout(function() {
						$("#binarySubmit").remove();
					}, 1);
				});
				
				me.ajaxPreloader();
			});
		});
	};
	$.fn.thumbnailAction = function() {
		if (!this[0] || !this[0]){return false;}

		var photoWrap 	 = $("#bigPhoto"),
			commentsWrap = $("#commentsWrap"),
			a         	 = $(this);
		
		$(this).each(function(i, val) {
			if ($(this).parent().hasClass("viewAll")) { return false; }
			
			var me         = $(this),
				jsonMe     = me.getJsonAttr(),
				controller = me.attr("href");
					
			me.unbind("click.thumbnailAction");
			me.bind  ("click.thumbnailAction", function() {
				a.removeClass("sel");
				me.addClass("sel");
				
				var toggleMode = $("body.pgPhotoAlbum a.toggleMode"),
					mode 	   = (toggleMode.length && toggleMode.hasClass("display")) ? "edit" : "display",
					postVals   = {"albumId":jsonMe.albumId, "photoId":jsonMe.photoId, "photoMemId":jsonMe.photoMemId, "mode":mode};
				
				photoWrap.addClass("loaderMedium");
				
				if (mode == "edit") {
					toggleMode.attr("href", me.attr("href").replace("edit/", ""));
				} else {
					toggleMode.attr("href", me.attr("href")+"edit/");
				}
				
				$.get(controller+"info/", function(data) {
					photoWrap.html(data);
					var bigPhoto     = photoWrap.find("img.bigPhoto"),
						bigPhotoPath = ChordC.extractBgUrl(bigPhoto.css("background-image")),
						imageObj     = new Image();
					
					$(imageObj).attr("src", bigPhotoPath).load(function(){ 
						photoWrap.removeClass("loaderMedium");
					});
					
					AjaxEventsRouter.run("photoAlbum");
				});
									
				commentsWrap.load(controller+"comments/", postVals, function() {
					AjaxEventsRouter.run();
					ListModuleEventsRouter.run();
				});
				
				me.ajaxPreloader();
				return false;
			});

		});
		
		return this;
	};
	
	/*--------------------------------------
		ALERTS, MESSAGES, AND INDICATORS
	----------------------------------------*/
	$.fn.ajaxPreloader = function(o) {
		if (!this[0] || !this[0]){return false;}
			o = o || {};
		var target     = $(this),
			xPos       = o.xPos 	  || 0,
			yPos 	   = ($.browser.msie && o.yPosIE) ? o.yPosIE || -1 : o.yPos || -1,
			visibility = o.visibility || "hidden",
			hide       = o.hide 	  || false,
			preLoader  = o.preLoader  || "loader", // options: loaderMedium
			zIndex 	   = o.zIndex 	  || false;
		
		$("body").append('<p class="'+preLoader+'">...</p>');
		
		var cssObj = {
	        position: "absolute",
	        left: 	  (target.offset().left) + xPos,
			top:  	  (target.offset().top)  + yPos
	    };
		
		if (zIndex) {
			$.extend(cssObj, {"zIndex":zIndex});
		}
		
		$("."+preLoader).css(cssObj);
		
		if (hide === true) {
			target.hide();
		} else {
			target.css("visibility",visibility);
		}
		
		$("."+preLoader).ajaxStop(function() {
			$(this).remove();
			if (hide === true) {
				target.show();
			} else {
				target.css("visibility","visible");
			}
		});
		
		return this;
	};
	$.fn.popupMsg = function(o) {
		if (!this[0] || !this[0]){return false;}
		o = o || {};
		var me 		      = $(this),
			target        = o.target        || me,
			xPos          = o.xPos          || 0,
			yPos 	      = ($.browser.msie && o.yPosIE) ? o.yPosIE || -1 : o.yPos || -1,
			msg   	      = o.msg 	        || "msgConfirm", // options: loaderMedium
			zIndex 	      = o.zIndex        || false,
			msgText       = o.msgText 	    || "Rock n Roll",
			timeout    	  = o.timeout       || 2500,
			callbackBegin = o.callbackBegin || false,
			callbackEnd   = o.callbackEnd   || false,
			doNotRemove   = o.doNotRemove   || false;
		
		$("body").append('<p class="msgPopup '+msg+'">'+msgText+'</p>');
		msg = $("p.msgPopup"); // turn msg into object
		
		var meWidth    	= me.outerWidth(),
			meHeight   	= me.outerHeight(),
			msgWidth	= msg.outerWidth(),
			msgHeight   = msg.outerHeight(),
			msgX		= (meWidth + msgWidth) / 6,
			msgY		= meHeight + msgHeight;
		
		var css = {
	        left: (target.offset().left) + (xPos - msgX),
			top:  (target.offset().top)  + (yPos - msgY)
	    };
		
		if (zIndex) {
			$.extend(css, {"zIndex":zIndex});
		}
		
		msg.css(css);
		msg.fadeIn("fast", function() {
			if (callbackBegin) { callbackBegin(); }
			if (doNotRemove) { return false; }
			setTimeout(function() {
				msg.fadeOut(function() {
					if (callbackEnd) { callbackEnd(); }
					$(this).remove();
				});
			}, timeout);
		});
		
		return this;
	};
	
	/*------------------------
		BODY SECTION TOOLS
	--------------------------*/
	$.fn.bodySectionSwitchers = function() {
		if (!this[0] || !this[0]){return false;}
		if (!CHORDC_LOAD_SECTIONS_VIA_AJAX) { return this; }
		
		$(this).unbind("click.bodySectionSwitchers");
		$(this).bind  ("click.bodySectionSwitchers", function() {
			var a         = $(this),
				targetBtn = a.attr('targetBtn');
				
			if (a.hasClass('btnSignUp')) { return false; }
			
			ChordC.noMainNavPreloader = true;
			$('#'+targetBtn).triggerHandler('click.bodySectionComponent');
			a.ajaxPreloader();
			
			return false;
		});
		
		return this;
	};
	$.fn.bodySectionComponent = function() { // use to effect the hash
		if (!this[0] || !this[0]){return false;}
		if (!CHORDC_LOAD_SECTIONS_VIA_AJAX) { return this; }
		
		var me 				  = $(this), // me = $("div.areaMenu a")
			bodySection   	  = $("div.bodySection"),
			breadcrumb 		  = $("#breadcrumbSel"),
			a, json,
			controller, bodySectionRoute,
			switchA, aSwitchId;
		
		me.unbind("click.bodySectionComponent");
		me.bind  ("click.bodySectionComponent", function(e, o) {
			o = o || {};
			Validation.removeErrorMessages();
			
			a = $(this);
			if (a.hasClass('notSectionLink') || a.hasClass('btnSignUp')) { return false; }
			
			a.parents().find("a").removeClass("sel"); // todo, shouldn't remove section switch .sel class
			a.addClass("sel");
			
			json 	   		 = a.getJsonAttr(),
			controller 		 = a.attr("href"),
			switchA    		 = json.switchMe || false,
			bodySectionRoute = json.bodySectionRoute || false;
			
			if (switchA) {
				aSwitchId = a.attr("id");
				a.removeClass("sel");
				a = eval(switchA);
				a.addClass("sel");
			}
			
			Cookie.create("uriCookiePG", controller, 1);
			
			$.ajax({
				type:    "POST",
				url:     controller,
				cache:   false,
				data:    json,
				error:   function() { /*TODO*/ },
				success: function(data) {
					bodySection.html(data);
					BodySectionEventsRouter.run(bodySectionRoute);
					breadcrumb.text(json.breadcrumb);
				}
			});
			
			if (!ChordC.noMainNavPreloader) {
				a.ajaxPreloader();
			} else {
				delete ChordC.noMainNavPreloader;
			}
			
			return false;
		});
		
		return this;
	};
	
	/*-----------------------
		LIST MODULE TOOLS
	-------------------------*/
	$.fn.listModuleSafeSearch = function(o) {
		if (!this[0] || !this[0]){return false;}
		
		$(this).unbind("click.listModuleSafeSearch");
		$(this).bind  ("click.listModuleSafeSearch", function(o) {
			var a	          = $(this),
			    me	     	  = a.prev(),
				meVal         = me[0].value.trim(),
				href          = a.attr("href");
				hrefComments  = href.indexOf("#comments"),
				srchUri       = "search-for",
				hrefSrchIndex = href.indexOf(srchUri),
				hrefSrch      = (hrefSrchIndex != -1) ? href.substr(hrefSrchIndex) : false,
				hrefLC        = href.charAt(href.length-1);
							
			if (meVal !== "") {
				if (hrefLC != "/") {
					href = href+"/";
				}

				if (meVal == "") {
					href = a.attr("href").replace(hrefSrch,"");
					a.attr("href", href);
				} else {
					if (hrefSrch) {
						href = a.attr("href").replace(hrefSrch,"");
					}

					$.post('/search/safe-value/', {searchFor:meVal}, function(safeSrchVal) {
						href = href+"search-for/"+safeSrchVal+"/";
						
						if (!CHORDC_LOAD_LISTS_VIA_AJAX && hrefComments) {
							href = href.replace("#comments","");
							href = href.replace("//","/");
							href = href+"#comments";
						}
						a.attr("href", href);
						
						if (CHORDC_LOAD_LISTS_VIA_AJAX) {
							ChordC.runListModule(a);
						} else {
							window.location = href;
						}
					});
				}
				return false;
			} else {
				if (CHORDC_LOAD_LISTS_VIA_AJAX) {
					ChordC.runListModule(a);
					return false;
				}
			}
		});
		
		return this;
	}
	$.fn.listModuleBtn = function(o) {
		if (!this[0] || !this[0]){return false;}
		
		$(this).unbind("click.listModuleBtn");
		$(this).bind  ("click.listModuleBtn", function(o) {
				o 		   = o || {};
			var me 		   = $(this),
				frm		   = me.parents("form:eq(0)"),
				cbChecked  = frm.find(".content dd input[type='checkbox']:checked"),
				cbAll	   = frm.find(".content dt input[type='checkbox']"),
				jsonMe 	   = me.getJsonAttr() || {},
				controller = me.attr("href"),
				json 	   = frm.serialize(),
				dl		   = frm.find("dl.contentDL:eq(0)"),
				cb,
				dd,
				jData;
			
			if (!cbChecked.length) {
				me.popupMsg({msgText:jsonMe.selectOneMsg});
				return false;
			}
			
			if (jsonMe.action === "delete" && !confirm(jsonMe.confirmDeleteMsg)) {
				return false;
			}
			
			$.ajax({
				type:    "POST",
				url:     controller,
				cache:   false,
				data:    json,
				error:   function() { /*TODO*/ },
				success: function(data) {
					jData = ($.trim(data) !== "") ? eval('(' + data + ')') : false;
					
					cbChecked.each(function() {
						cb = $(this);
						dd = cb.parents("dd:eq(0)");
						dd.removeClass("sel");
						// ADD
						if (jsonMe.action === "add") {
							if (cb.next().hasClass("checkbox")) {
								cb.next().remove();
							}
							cb.after('<img src="/img/share/common/blank.gif" class="checkbox iconS iTick" />');
						}
						if (jsonMe.action === "add_pending") {
							if (cb.next().hasClass("checkbox")) {
								cb.next().remove();
							}
							cb.attr("disabled", "disabled");
							cb.after('<small class="friendRequested">'+jsonMe.displayMsg+'</small>');
						}
						// REMOVE
						if (jsonMe.action === "remove") {
							if (cb.next().hasClass("checkbox")) {
								cb.next().remove();
							}
						}
						// DELETE
						if (jsonMe.action === "delete") {
							dd.slideUp(function() {
								$(this).remove();
								Callback.noMoreRecs(dl, jsonMe.noRecordsRoute);
							});
						}
						cb.attr("checked",false);
					});
							
					cbAll.attr("checked",false);
					me.popupMsg({'msgText':jsonMe.successMsg, 'timeout':4000});
					
					// update them numbers
					Callback.updateMyNumbers(jData);
				}
			});
			me.ajaxPreloader();
		});
		
		return this;
	};
	$.fn.listModuleComponent = function() { // use to effect the hash
		if (!this[0] || !this[0]){return false;}
		
		if ($(this).hasClass("listModuleFrm")) {
			$(this).unbind("submit.listModuleComponent");
			$(this).bind  ("submit.listModuleComponent", function(o) {
				$(this).find("a.listModuleSearchBtn").click();
				return false;
			});
		} else {
			if (!CHORDC_LOAD_LISTS_VIA_AJAX) { return this; }
			$(this).unbind("click.listModuleComponent");
			$(this).bind  ("click.listModuleComponent", function(o) {
				ChordC.runListModule($(this));
				return false;
			});
		}
		
		return this;
	};
	$.fn.listModuleViewAllItems = function(o) {
		// might be able to remove this one, photo thumbs still rely on it
		if (!this[0] || !this[0]){return false;}
		
		$(this).unbind("click.listModuleViewAllItems");
		$(this).bind  ("click.listModuleViewAllItems", function(o) {
			var me   			= $(this),
				listWrap	 	= me.parents(".photoThumbsWrap:eq(0)"),
				wrap 			= me.parents(".viewAll:eq(0)"),
				controller 		= me.attr("href"),
				jsonLW 			= listWrap.getJsonAttr(),
				listModuleRoute = jsonLW.listModuleRoute || false;
			
			if (me.hasClass("listModuleViewLessItems")) {
				wrap.parent().find("dd.more ~ dd").not("dd.viewAll").remove();
				wrap.parent().find("dd.more").remove();
				me.hide().prev().css("display","block");
				$("a.listModuleViewAllItems").listModuleViewAllItems();
				ListModuleEventsRouter.run(listModuleRoute);
				return false;
			}
			
			$.ajax({
				type:    "POST",
				url:     controller,
				cache:   false,
				error:   function() { /*TODO*/ },
				success: function(data) {
					wrap.parent().append(data);
					wrap.next().addClass("more");
					wrap.parent().append(wrap);
					me.hide().next().css("display","block");
					$("a.listModuleViewLessItems").listModuleViewAllItems();
					ListModuleEventsRouter.run(listModuleRoute);
				}
			});
			me.ajaxPreloader();
		});
		
		return this;
	};
	
	// actions
	$.fn.listModuleFilter = function(o) {
		if (!this[0] || !this[0]){return false;} // (drop downs)
		
		var a 		  = $(this),
			dl		  = a.parents("dl:eq(0)"),
			allMenus  = dl.find("dl.menu"),
			lastMenu  = dl.find("dd.selector:last dl.menu"),
			lastMenuW = lastMenu.width();
		
		a.each(function(i, val) {
			var me 		 = $(this), 										// the anchor inside the selector
				menu 	 = me.parents("dd.selector:eq(0)").find("dl.menu"),	// the drop down menus
				menuA    = menu.find("a"),
				menuASel = menu.find("a.sel"),
				meWidth  = me.innerWidth() + 3;
			
			me.unbind("click.lmf");
			me.bind  ("click.lmf", function(e) {
				if (menu.is(":visible")) {
					menu.hide();
					return false;
				}
				menu.show();
				ChordC.lmfID = $.data(e.currentTarget);
				var cssObj = {
			        "height": 	 "340px",
					"overflow":  "auto",
			        "overflowX": "hidden",
			        "overflowY": "scroll"
			    };
				if (menu.height() > 335) {	 					// Cap off sub menu so the ol will scroll
					menu.css(cssObj);
				}
				if (menuASel.length) { 							// set scroll position of selected item
					menu.scrollTop(menuASel.position().top);
				}
				if (menu.width() <= meWidth) { 	// set the width of the menu atleast as wide as the selector
					menu.width(meWidth);
				} else if (lastMenu.is(":visible")) {
					menu.css("left", -(lastMenuW - meWidth) + "px");
				}
			});
			
			me.unbind("mouseover.lmf");
			me.bind  ("mouseover.lmf", function(e) {
				e.stopPropagation();
				if (typeof TO !== "undefined") {
					clearTimeout(TO);
				}
				if (ChordC.lmfID !== $.data(e.currentTarget)) {
					allMenus.hide();
				} else {
					if (menu.is(":visible")) {
						menu.show();
					}
				}
			});
			
			me.unbind("mouseout.lmf");
			me.bind  ("mouseout.lmf", function(e) {
				e.stopPropagation(); 
				TO = setTimeout(function(){
					if (menu.is(":visible")) {
						menu.hide();
					}
				}, 150);
			});
			
			menu.unbind("mouseover.lmf");
			menu.bind  ("mouseover.lmf", function(e) {
				e.stopPropagation();
				clearTimeout(TO);
				$(this).show();
			});
			
			menu.unbind("mouseout.lmf");
			menu.bind  ("mouseout.lmf", function(e) {
				e.stopPropagation();
				var menuMe = $(this);
				TO = setTimeout(function(){
					if (menu.is(":visible")) {
						menuMe.hide();
					}
				}, 150);
			});
			
			menuA.unbind("click.lmf");
			menuA.bind  ("click.lmf", function(e) {
				menuA.removeClass("sel");
				me.addClass("sel");
				$(this).addClass("sel");
			});
		});
	};
	$.fn.listModuleToggleEditMode = function() {
		if (!this[0] || !this[0]){return false;}
		
		var lmFrmWrap = $(this).parents(".listModuleFrm:eq(0)"),
			me;
		
		$(this).unbind("click.listModuleToggleEditMode");
		$(this).bind  ("click.listModuleToggleEditMode", function() {
			me = $(this);
			me.removeClass("sel").siblings("a").addClass("sel");
			if (me.hasClass("edit")) { // edit button
				lmFrmWrap.removeClass("lmDisplayMode").find(".lmHideMe").show();
			} else if (me.hasClass("display")) { // display button
				lmFrmWrap.addClass("lmDisplayMode").find(".lmHideMe").hide();
				lmFrmWrap.find("div.flyoutForm, form.flyoutForm").slideUp();
				Validation.removeErrorMessages();
			}
		});
		
		return this;
	};
	$.fn.listCheckboxes = function() {
		if (!this[0] || !this[0]){return false;}

		var cbAll = $(this).find(".header .checkbox"),
			cb 	  = $(this).find("dd input[type='checkbox']");
		
		cbAll.unbind("click.checkAll");
		cbAll.bind  ("click.checkAll", function(o) {
			var me 		   = $(this),
				checkboxes = me.parents("dl:eq(0)").find("dd input[type='checkbox']");
			
			if (me.attr("checked") === false) {
				checkboxes.each(function() {
					$(this).attr("checked",false);
					$(this).parents("dd:eq(0)").removeClass("sel");
				});
			} else if (me.attr("checked") === true) {
				checkboxes.each(function() {
					if (!$(this).attr("disabled")) {
						$(this).attr("checked",true);
						$(this).parents("dd:eq(0)").addClass("sel");
					}
				});
			}
		});
		
		cb.each(function() {
			$(this).unbind("click.checkbox");
			$(this).bind  ("click.checkbox", function(o) {			
				var me = $(this);
				if (me.attr("checked") === false) {	
					me.attr("checked",false);
					me.parents("dd:eq(0)").removeClass("sel");
				} else {
					me.attr("checked",true);
					me.parents("dd:eq(0)").addClass("sel");
				}
				
				var tot = cb.length,
					cnt = 0;
				cb.each(function() {
					if ($(this).attr("checked") === true) {
						cnt++;
					}
				});
				if (cnt === tot) { cbAll.attr("checked",true); } else { cbAll.attr("checked",false); }
			});
		});
		
		return this;
	};
	
	/*--------------------
		CHORDS PLUGINS
	----------------------*/
	$.fn.showMatchedImageTrigger = function() { // song display page
		if (!this[0] || !this[0]){return false;}
		var a = $(this);
		
		a.unbind('click');
		a.click(function(){
			$(this).prev().click(); // this is the photo icon anchor
			return false;
		});
		
		return this;
	};
	
	$.fn.showMatchedImage = function() { // chord finder function
		if (!this[0] || !this[0]){return false;}
		var a 			 = $(this),
			matchedPhoto = $("div.matchedPhoto"),
			iClose		 = matchedPhoto.find("img.iClose"),
			me;
		
		a.unbind('click');
		a.click(function(){
			me = $(this);
			if (me.prev().is(":hidden")){
				matchedPhoto.hide();
				me.prev().show();
			} else {
				matchedPhoto.hide();
			}
			return false;
		});
		
		iClose.unbind('click');
		iClose.click(function(){
			$(this).parent().parent().hide();
		});
		
		return this;
	};
	$.fn.showMatchedDiagram = function() { // chord finder function
		if (!this[0] || !this[0]){return false;}
		var a = $(this);
		
		ChordFinder.interface.previousFretNumber = document.getElementById('fretChange').value;
		
		a.unbind('click');
		a.click(function() {
			var me 	         = $(this),
				json         = eval('('+ me.attr('json') +')'),
				dia          = json.d,
				diagram      = " ",
				matchedSplit = dia.split(' '), // convert to fingerless diagram
				finger,
				string,
				fret;
			
			for(var d in matchedSplit) {
				finger = matchedSplit[d].substr(matchedSplit[d].length-1);
				string = matchedSplit[d].substr(0,matchedSplit[d].length-1);
				if (d < 1) {
					ChordFinder.interface.currentFretNumber = matchedSplit[d];
				} else {
					if (finger == "o") {
						diagram += string+"o ";
					} else if (finger == "x") {
						diagram += string+"x ";
					} else {
						diagram += string+"0 ";
					}
				}
			}
			
			document.getElementById('fretChange').value = ChordFinder.interface.currentFretNumber;
			
			ChordFinder.setDiagramToFretboard( diagram );
			return false;
		});
		
		return this;
	};
	$.fn.addChordsToSong = function() {
		if (!this[0] || !this[0]){return false;}
		
		var wrap 	 	= $(this),
		    moduleWrap  = wrap.parents("div.songChordsWrap:eq(0)"),
		    json 	    = moduleWrap.getJsonAttr(),
		    baseUrl     = '/profile/'+json.username+'/song/'+json.songId+'/',
			majors 	 	= $("#majors"),
			types 	 	= $("#types"),
			diagrams 	= $("#diagrams"),
			formulas 	= $("#formulas"),
			majorsA	 	= majors.find("a"),
			typesA	 	= types.find("a"),
			chordsWrap 	= diagrams.find(">.wrap");
		
		// MAJORS
		majorsA.unbind("click.addChordsToSong");
		majorsA.bind  ("click.addChordsToSong", function() {
			var o 	   	  	= arguments[1] || {},
				noTypeEvent = o.noTypeEvent || false,
				me 		  	= $(this),
				chordType 	= $("#"+me.attr("chordType")),
				aType1 	  	= chordType.find("li:first-child a");
			
			// majors
			majorsA.removeClass("sel");
			me.addClass("sel");
			
			// types
			types.find(">ul").hide();
			chordType.show();
			if (!noTypeEvent) {
				types.scrollTop(0);
				aType1.trigger("click.addChordsToSong");
			}
		});
		
		// TYPES
		typesA.unbind("click.addChordsToSong");
		typesA.bind  ("click.addChordsToSong", function() {
			var me 	 	 = $(this),
				ul 	 	  = me.parents("ul:eq(0)"),
				a  	 	  = ul.find("li a"),
				meId 	  = me.attr("id"),
				scFormula = formulas.find("input[name='"+meId.split("_")[0]+"']").val(),
				obj;
			
			a.removeClass("sel");
			me.addClass("sel");
			
			obj = { "table_chordId":meId, "songChordsFormula":scFormula, "chordSymbol":me.text() };
			
			$.post(baseUrl+'chords/edit/', obj, function(data) {
				chordsWrap.empty().html(data);
				diagrams.find("a.action").addChordsToSongAction();
			});
		});
		
		return this;
	};
	$.fn.addChordsToSongAction = function() {
		if (!this[0] || !this[0]){return false;}
		
		var songChords 	  = $("#songChords"),
			saveIndicator = $("#addChordsSaveIndicator"),
			formulas 	  = $("#formulas"),
			moduleWrap    = $(this).parents("div.songChordsWrap:eq(0)"),
		    json 	      = moduleWrap.getJsonAttr(),
		    baseUrl       = '/profile/'+json.username+'/song/'+json.songId+'/';
				
		function saveIndicatorAction() {
			saveIndicator.fadeIn();
		}
		
		$(this).unbind("click.addChordsToSongAction");
		$(this).bind("click.addChordsToSongAction", function() {
			var me 	 	  	 = $(this),
				meId 	  	 = me.attr("id"),
				icon	   	 = me.find("img"),
				songChord 	 = songChords.find("div[tableChordIdDiagram='"+meId+"']"),
				split	  	 = meId.split("_"),
				formulaInput = formulas.find("input[name='"+split[0]+"']"),
				obj 	  	 = { "table_chordId_diagram":meId, "songChordFormula":formulaInput.val() },
				meIdAdjusted,
				otherMe,
				otherMeIcon;
			
			if (me.hasClass("remove") && me.hasClass("songChord")) {
				// REMOVE ACTION ON SONG CHORD
				meIdAdjusted = meId.replace("_id", "");
				songChord 	 = songChords.find("div[tableChordIdDiagram='"+meIdAdjusted+"']");
				otherMe		 = $("#"+meIdAdjusted);
				otherMeIcon  = otherMe.find("img");
				$.post(baseUrl+'remove/chord/', obj, function(data) {
					formulaInput.val(data);
					songChord.fadeOut(function() {
						$(this).remove();
						saveIndicatorAction();
						otherMe.removeClass("remove").addClass("add");
						otherMeIcon.removeClass("iDelete").addClass("iAdd");
					});
				});
			} else if (me.hasClass("remove")) {
				// REMOVE ACTION ON ADD SONG CHORD
				$.post(baseUrl+'remove/chord/', obj, function(data) {
					formulaInput.val(data);
					me.removeClass("remove").addClass("add");
					icon.removeClass("iDelete").addClass("iAdd");
					me.popupMsg({"msgText":'removed', "xPos":-10, "yPos":10, "timeout":1000});
					songChord.fadeOut(function() {
						$(this).remove();
						saveIndicatorAction();
					});
				});
			} else {
				// ADD ACTION
				$.post(baseUrl+'add/chord/', obj, function(data) {
					formulaInput.val(data);
					me.removeClass("add").addClass("remove");
					icon.removeClass("iAdd").addClass("iDelete");
					me.popupMsg({"msgText":'added', "xPos":-2, "yPos":10, "timeout":1000});
					$.post(baseUrl+'chord/edit/', obj, function(data2) {
						songChords.prepend(data2);
						songChords.find(">div.chord.hide").fadeIn(function() {
							saveIndicatorAction();
							songChords.find("h4 a.locateChord").addChordsSetScrollPosition();
							songChords.find("h4 a.remove").addChordsToSongAction();
						});
					});
				});
			}
			me.ajaxPreloader();
		});
		
		return this;
	};
	$.fn.addChordsSetScrollPosition = function() {
		if (!this[0] || !this[0]){return false;}
		
		var majors 	 	 = $("#majors"),
			types 	 	 = $("#types"),
			diagrams 	 = $("#diagrams"),
			diagramsWrap = diagrams.find("> div.wrap");
			
		function getDiagramScrollTop(diagram) {
			switch (diagram) {
				case "d5":
					return 584;
				case "d4":
					return 438;
				case "d3":
					return 292;
				case "d2":
					return 146;
				default:
					return 0;
			}
		}
		
		$(this).unbind("click.addChordsSetScrollPosition");
		$(this).bind("click.addChordsSetScrollPosition", function() {
			var me 	 	  	 = $(this),
				wrapId 	  	 = me.parents("div.chord:eq(0)").attr("tableChordIdDiagram"),
				split	  	 = wrapId.split("_"),
				major		 = majors.find("a[chordtype='type"+wrapId.charAt(5)+"']"),
				type		 = types.find("a[id='"+split[0]+"_"+split[1]+"']"),
				diagramWrap	 = diagramsWrap.find("a[id='"+wrapId+"']").parents("div.chord:eq(0)");
				
			major.trigger("click.addChordsToSong", {"noTypeEvent":true});
			type.trigger("click.addChordsToSong");
			
			var typePosition = type.position();
			types.scrollTop(typePosition.top + types.scrollTop());
			
			diagramsWrap.scrollTop(getDiagramScrollTop(split[2]));
				
			return false;
		});
		
		return this;
	};
	
	/*----------------
		SUBMIT FORM
	------------------*/
	$.fn.singleAction = function(o) { // kinda like submit form, ex: profile menu addFriend
		if (!this[0] || !this[0]){return false;}
		
		$(this).unbind("click.singleAction");
		$(this).bind  ("click.singleAction", function(o) {
				o = o || {};
			var me 		    = $(this),
				frm 	    = false,
				jsonMe 	    = me.getJsonAttr(),
				controller  = me.attr("href"),
				json 	    = [],
				xPosConfirm	= jsonMe.xPosConfirm || false,
				yPosConfirm	= jsonMe.yPosConfirm || false;
				
			$.extendForm(json, jsonMe.data);
			
			if (jsonMe.action === "delete" && !confirm(jsonMe.confirmDeleteMsg)) {
				return false;
			}
			
			$.ajax({
				type:    "POST",
				url:     controller,
				cache:   false,
				data:    json,
				error:   function() { /*TODO*/ },
				success: function(data) {
					jData = ($.trim(data) !== "") ? eval('(' + data + ')') : false;
					me.popupMsg({msgText:jsonMe.successMsg, xPos:xPosConfirm, yPos:yPosConfirm});
					Callback.main(me, frm, jsonMe, json, jData, false);
				}
			});
			me.ajaxPreloader();
		});
		
		return this;
	};
	$.fn.submitForm = function(o) {   // most forms use this
		if (!this[0] || !this[0]){return false;}
		
		$(this).unbind("click.submitForm");
		$(this).bind  ("click.submitForm", function(o) {
			if (Validation.flag) { return false; }
			
			var me 		   	  = $(this),
				frm		   	  = (!me.parents(".form:eq(0)").length) ? me.parents("form:eq(0)") : me.parents(".form:eq(0)"), // FORM TAG or ELEMENT WITH CLASS .form
				jsonMe 	   	  = me.getJsonAttr(),
				controller    = me.attr("href"),
				jsonMe		  = (jsonMe.useFormJson) ? frm.getJsonAttr() : jsonMe; // USE me JSON or frm JSON
			var customData 	  = jsonMe.customData || false,
				preloader	  = jsonMe.preloader || false;
				preloader	  = (preloader) ? eval(preloader) : me;
			var json		  = jsonMe.data || {},
				returnRegData = (jsonMe.returnRegData) ? true : false,
				xPosConfirm	  = jsonMe.xPosConfirm || false,
				yPosConfirm	  = jsonMe.yPosConfirm || false,
				regData, jData;
										
			// if you need to run something before the ajax call
			if (Boolean(jsonMe.preCallback)) {
				eval(jsonMe.preCallback);
			}

			if (frm[0].tagName.toLowerCase() === "form") { 	// THIS IS USED IN MOST CASES
				json = frm.serializeArray();
				$.extendForm(json, jsonMe.data);
			} else if (customData) {						// THIS IS NOT USED VERY MUCH, example private messages and send message on comments quick reply from the list.
				$.each(customData, function(i, val) {
					customData[i] = eval(val);
				});
				$.extend(json, customData);
			}
			
			if ((jsonMe.action === "delete"
			     && !confirm(jsonMe.confirmDeleteMsg))
			     || (jsonMe.action === "hide" && !confirm(jsonMe.confirmHideMsg))) {
				return false;
			}
			
			$.ajax({
				type:    "POST",
				url:     controller,
				cache:   false,
				data:    json,
				error:   function() { /*TODO*/ },
				success: function(data) {
					if (returnRegData) {
						regData = ($.trim(data) !== "") ? data : false;
					} else {
						jData 	= ($.trim(data) !== "") ? eval('(' + data + ')') : false;
					}
					if (jsonMe.successMsg) {
						me.popupMsg({msgText:jsonMe.successMsg, xPos:xPosConfirm, yPos:yPosConfirm});
					}
					Callback.main(me, frm, jsonMe, json, jData, regData);
				}
			});
			preloader.ajaxPreloader();
		});
		
		return this;
	};

})(jQuery);

/*------------------
	WORK IT PLAYA
--------------------*/
$(function() {
	ChordC.init();
});