;(function($){
	/*
	 * Finds and initializes qbuilder widgets for all descending elements
	 */
	$.fn.qbuilder = function() {
		$(this).bindSimpleButtons();

		// Bind quick enabler forms
		$(this).find(".enablerForm").each(function() {
			$(this).quickEnableForm();
		});

		$(this).bindQuickAdd();
		$(this).bindQuickAddAndEdit();
		$(this).bindQuickDelete();
		$(this).bindQuickEdit();
		
		$(this).bindRichTextEditor();

		$(this).bindCitationForm();
		
		$(this).bindQuickRefresh();
		$(this).bindQuickClickAndRefresh();
		
		// Binds answers sortable listing
		$(this).bindCritical();
		
		$(this).bindQuestionImporter();

		var o = $.extend({}, $.fn.qbuilder.defaults);
		$(this).find(".answersListing .sortableParent").bindSortable({
	 		'handle': "* .sortableHandle",
			'update': function() {
				$(this).parents(".answersListing:first").find(o.criticalField).change();
			}
		});

		// Binds questions sortable listing
		$(this).find(".questionsListing .sortableParent").bindSortable({
	 		'handle': "* .sortableHandle"
		});

		// Initializes checkbox		
		$(".enabledCheckBox").each(function() {
			// Takes care of initial state of the row
			if (this.checked == true) {
				$(this).parents("tr:first").removeClass("disabled");
			} else {
				$(this).parents("tr:first").addClass("disabled");
			}
			
			// TODO define as non-anon function
			$(this).click(function() {
				if (this.checked == true) {
					$(this).parents("tr:first").removeClass("disabled");
				} else {
					$(this).parents("tr:first").addClass("disabled");
				}
			});
		});

		// This must go after the .enabledCheckBox		
		// Binds the updater for percentages
		$(this).find(".questionsListing").each(function() {
			$(this).percentages();
		});
		
		// Propery jQuery way
		$("#writtenExpressionStories .writtenExpressionStories div").inPageResponse("a.inPageEdit, a:contains('Cancel'), form");
		$("#writtenExpressionStories .actions").inPageResponse("a.inPageAdd");
		return this;
	};

	
	/*
	 * Simple logger
	 */
	$.fn.log = function(msg) {
		console.log("%s: %o", msg, this);
		return this;
  	};
  	
 
	/*
	 * Refreshes all nested DOM elements by:
	 *
	 * 1. Finding all nested 'refresh url' (see implementation).
	 * 2. Refreshes the parent refreshable (see implementation).
	 * 
	 */
	  
	$.fn.refresh = function(callback) {
		// The refresh url
		var selector = "input[type=hidden][name=refreshUrl]";
		
		$(this).find(selector).each(function() {
			var url = $(this).attr("value");
			
			// The parent to refresh
			$(this).parents(".refreshable:first").load(url, null, callback);
		});
		
		return $(this);
	};
	
	/*
	 * Generates an APA short citation given a input field containing the full field
	 * @param selector the jQuery or selector to the full citation input field
	 */
	$.fn.shortCitation = function(selector) {
		// full citation to apa
		var shortCitation = $(this);
		shortCitation.after('<span class="generateCitation">Generate</span>').next().click(function() {
			var s = $(selector).attr('value');
			
			var year = s.replace(/^.+?\(([0-9]{4})\).*$/, "$1");
			
			var names = s.replace(/(.+?)\([0-9]{4}\).+$/, "$1").replace(/&|\./g, "").split(",");
			var lastNames = new Array();
			
			for(i = 0; i < names.length; i++) {
				var name = names[i].replace(/^\s*(.+?)\s*$/, "$1");
				if (name.length > 1) {
					lastNames.push(name);
				}
			}
	
			var short = "";
			for(i = 0; i < lastNames.length; i++) {
				short += lastNames[i];
				
				if (lastNames.length == 1) {
					// do nothing
				} else if (lastNames.length == 2) {
					if (i == 0) {
						short += " & ";  
				 	}
				} else {
					if (i < lastNames.length - 1) {
						if (i == lastNames.length - 2) {
							short += ", & ";
						} else {
							short += ", ";										
						}
					}
				}
			}
			
			short += ", " + year;
			shortCitation.attr("value", short);
		});
	};
	
	/*
	 * updates percentage on question weights
	 */
	$.fn.percentages = function() {
		var weightField = ".questionItemWeight fieldset input";
		
		var base = $(this);
		base.find(weightField).each(function() {
			$(this).change(function() {
				var total = 0;
				
				base.find(weightField).each(function() {
					if ($(this).parents(".disabled").size() == 0) {
						total += Number($(this).attr("value"));
					} else {
						$(this).next().html("N/A");
					}
				})

				if (total != 0) {
					base.find(weightField).each(function() {
						if ( $(this).next().attr("class") != 'percentage' ) {
							$(this).after("<span class='percentage'></span>");
						}
						
						if ( $(this).parents(".disabled").size() == 0) {
							var percent = Math.round($(this).attr("value") / total * 10000) / 100;
							$(this).next().html(percent + "%");
						}
					})
				}
			});
		});
		
		// Needed for disable
		base.find("input.enabledCheckBox[type='checkbox']").click(function() {
			$(this).parents("tr").find(weightField).change();
		});
	};
	
	$.fn.quickEnableForm = function() {
		$(this).find("input[type='submit']").hide();
		
		var checkbox = $(this).find("input[type='checkbox']");

		if (checkbox.length != 1) {
			console.error("More than one checkbox was found for %o", this);
		}

		checkbox.click(function() {
			$(this).parents("form:first").ajaxSubmit({
				success: function() {
					checkbox.parents(".refreshable:first").refresh(function() {
						$(this).qbuilder();
					});
				}
			});
		});
	};
	
	/*
	 * Simulates a button (meant to be used with a href's) 
	 */

	$.fn.bindSimpleButtons = function(selector) {
		if (selector == null) {
			selector = ".simpleButton:not(.simpleButtonDisabled)"
		}

		// Debug mode...		
		$(this).find(selector).each(function() {
			var url = $(this).attr("href");
			$(this).attr("title", url);
		});
		
		$(this).find(selector).mouseover(function() {
			$(this).addClass("simpleButtonMouseOver");
		});
		
		$(this).find(selector).mouseout(function() {
			$(this).removeClass("simpleButtonMouseOver");
		});
		
		return this;
	};
	
	/*
	 * Converts all tested <a class="quickRefresh"> into AJAX URLs
	 *
	 */
	
	$.fn.bindQuickRefresh = function(selector) {
		if (selector == null) {
			selector = 'a.quickRefresh';
		}
		
		$(this).find(selector).each(function() {
			var a = $(this);
			
			var refreshable = a.parents(".refreshable:first");
			if (refreshable.length > 0) {
				
				var url = a.attr("href");
				a.removeAttr("href");
						
				a.mouseover(function() {
					a.addClass("simpleButtonMouseOver");
				});
			
				a.mouseout(function() {
					a.removeClass("simpleButtonMouseOver");
				});
			
				a.click(function() {
					refreshable.load(url, null, function() {
						$(this).qbuilder();
					});
				});
			}
		});
		
		return $(this);
	};
	
	/*
	 * Modifies an <a href="" /> to an AJAX delete and then updates a refreshable 
	 * parent component which is defined by a parent DOM element with the class
	 * refreshable and a nested <input type="hidden" name="refreshUrl" value="url" />
	 *
	 */
	$.fn.bindQuickDelete = function(selector) {
		if (selector == null) {
			selector = ".quickDelete"
		}
		
		$(this).find(selector).each(function() {
			var url = $(this).attr("href");
			$(this).removeAttr("href");
			
			$(this).click(function() {
				$(this).after("<span></span").next().hide().load(url, null, function() {
					var a = $(this).find("a:first");
					var label = a.html();
					
					$(this).parents(".refreshable:first").refresh(function() {
						$(this).qbuilder();
					});
				});
			});
		});
		
		return $(this);
	};
	
	/*
	 * Modifies an <a href="" /> to an AJAX edit.
	 */
	$.fn.bindQuickEdit = function(selector) {
		if (selector == null) {
			selector = ".quickEdit";
		}
		
		$(this).find(selector).each(function() {
			var url = $(this).attr("href");
			$(this).removeAttr("href");
				
			$(this).click(function() {
				// First determine the colspan by looking at footer
				var colspan = $(this).parents("table:first").find("tfoot tr td").attr("colspan");
				$(this).parents("tr:first").hide().after('<tr class="adminEdit"><td colspan="' + colspan + '3"></td></tr>')
					.next().find("td:first").load(url, null, function() {
					
					$(this).bindQuickForm();
					$(this).parents("tr:first").show();
				});
			});
		});
		
		return $(this);
	};

	/*
	 * Modifies an <a class=".quickAdd" href="" /> to an AJAX add.
	 */
	$.fn.bindQuickAdd = function(selector) {
		if (selector == null) {
			selector = ".quickAdd";
		}

		$(this).find(selector).each(function() {
			var url = $(this).attr("href");
			
			$(this).removeAttr("href");
			
			$(this).after("<span></span>").next().hide().load(url, null, function() {
				$(this).bindQuickForm();
			});
			
			$(this).click(function() {
				$(this).hide().next().show();
			});
		});
		
		return this;
	};
	
	$.fn.bindQuickAddAndEdit = function(selector) {
		if (selector == null) {
			selector = ".quickAddAndEdit";
		}
		
		$(this).bindAddAction(selector, function() {
			$(this).find('input[type="submit"]:first')
				.after('<input type="button" class="simpleButton cancelButton" value="Cancel">')
				.next().click(function() {
					$(this).parents("form:first").parent().hide().prev().show();
				});
				
			$(this).bindSimpleButtons();
		});
	};
	
	$.fn.bindAddAction = function(selector, callback) {
		if (selector == null) {
			console.error("No selector specified");
		}

		$(this).find(selector).each(function() {
			var url = $(this).attr("href");
			
			$(this).removeAttr("href");
			
			$(this).after("<span></span>").next().hide().load(url, null, callback);
			
			$(this).click(function() {
				$(this).hide().next().show();
			});
		});

		return this;
	};
	
	/*
	 *
	 * Converts a form into an ajax form
	 */
	$.fn.bindQuickForm = function() {
		$(this).find('input[type="submit"]:first').after(
			'<input type="button" class="simpleButton cancelButton" value="Cancel">'
		).next().click(function() {
			$(this).parents(".refreshable:first").refresh(function() {
				$(this).qbuilder();
			});
		});

		var form = $(this).find("form:first");
		
		$(form).ajaxForm(function(responseText) {
			var parent = $(form).parent().hide();
			
			$(parent).html(responseText);
			
			if (! responseText.match('<form')) {
				// success! refresh refreshable
				var a = $(parent).find("a:first");
				var label = a.html();
				
				$(parent).parents(".refreshable:first").refresh(function() {
					$(this).qbuilder();
				});
				
			} else {
				$(parent).bindQuickForm().show();
			} 
		});
		
		$(this).qbuilder();
		
		return this;
	};

	/*
	 * Modifies an <a href="" /> to an AJAX click and then updates a refreshable 
	 * parent component which is defined by a parent DOM element with the class
	 * refreshable and a nested <input type="hidden" name="refreshUrl" value="url" />
	 *
	 */
	$.fn.bindQuickClickAndRefresh = function(selector) {
		if (selector == null) {
			selector = ".quickClickAndRefresh"
		}
		
		$(this).find(selector).each(function() {
			var url = $(this).attr("href");
			$(this).removeAttr("href");
			
			$(this).click(function() {
				$(this).after(' <span class="loading">Working...</span').next().load(url, null, function() {
					var a = $(this).find("a:first");
					var label = a.html();
					
					$(this).parents(".refreshable:first").refresh(function() {
						$(this).qbuilder();
					});
				});
			});
		});
		
		return $(this);
	};
	
	$.fn.bindSortable = function(options) {
		$(this).find(".sortableChild").mouseover(function() {
			$(this).find(".actionButtons").css("visibility", "visible");
		});
		
		$(this).find(".sortableChild").mouseout(function() {
			$(this).find(".actionButtons").css("visibility", "hidden");
		});

		$(this).sortable(options);
		
		return this;
	}
	

	/*
	 * Options for the critical items relating (in the context of answers)
	 */
	$.fn.qbuilder.defaults = {
		answer: 		".answer",
		criticalField:	"input[name='data[Question][critical]']",
		criticalButton: ".cutOffButton"
	};
	
	/*
	 * Binds rich text editor (niceditor)
	 */
		
	$.fn.bindRichTextEditor = function(options) {
		$(this).find(".rtf").each(function() {
			var opts = $.fn.extend({},
				{fullPanel: true},
				options
			 );
		
			$(this).nicEditor(opts);
		});
	}
	
	/*
	 * Binds question answers listing to critical cutoff and vice-versa
	 */ 
	 
	 $.fn.bindCritical = function(options) {
		var o = $.extend({}, $.fn.qbuilder.defaults, options);
		
		$(this).find(o.criticalField).each(function() {
			$(this).bindCriticalChange();
		});
		
		$(this).find(o.criticalButton).each(function() {
			$(this).bindCriticalClick();
		});
		
	 };
	 
	/*
	 * Triggers on critical cut-off button clicked.
	 */
	$.fn.bindCriticalClick = function(options){
		var o = $.extend({}, $.fn.qbuilder.defaults, options);

		var answersListing = $(this).parents(".answersListing:first");

		if (answersListing.length == 0) {
			console.error("Could not find '.answersListing:first'");
		}
			
		$(this).click(function() {

			var buttons = $(answersListing).find(o.answer + " * " + o.criticalButton);
			var total = buttons.length;
		
			var index = 0;
	
			// Determine the index;	
			for (var i = 0; i < total; i++) {
				if (this == buttons[i]) {
					index = i;
					i = total;
				}
			}
	
			// This calculation helps take care of floating/double inaccuracies
			var critValue = Math.floor( (index + 1) * 100 / total * 10000 + 1) / 10000;
			answersListing.find(o.criticalField).attr("value", critValue).change();
		});
		
		return this;
	};

	/*
	 * Triggers on critical field edit changes
	 */
	$.fn.bindCriticalChange = function(options) {
		var o = $.extend({}, $.fn.qbuilder.defaults, options);
		
		$(this).change(function() {
			var cutOff = $(this).attr("value");
			if (cutOff == null) {
				console.error("Could not find cut-off field");
			}
			
			var answers = $(this).parents(".answersListing:first").find(o.answer);
			
			if (answers.length > 0) {
				var index = answers.length * cutOff / 100 - 1
		
				answers.removeClass("criticalAnswer");
				answers.removeClass("nonCriticalAnswer");
				answers.each(function(i) {
					if (i <= index) {
						$(this).addClass("criticalAnswer");
					} else {
						$(this).addClass("nonCriticalAnswer");
					}
				});
			}
		});
		
		$(this).change();
		
		return this;
	};
	
	/*
	 * Binds lookup for citation forms
	 */
	 
	$.fn.bindCitationForm = function() {
			
		var shortCitation = $(this).find("#CitationShortCitation");
		shortCitation.each(function() {
			$(this).shortCitation($(this).parents("form:first").find("#CitationName"));
		});
		
		var citation = $(this).find("#CitationAdminAddToQuestionnaireForm").find("#CitationName");
		
		if (citation.length != 0) {
			citation.each(function() {
				var lookUpUrl = $(this).parents("form:first").find("#CitationNameLookUpUrl");
				
				if (lookUpUrl.length == 0) {
					console.error("Could not find '#CitationNameLookUpUrl'");
				}
				
			 	$(this).autocomplete(lookUpUrl.attr("value")).result(function(event, data, formatted) {
		
					if (formatted != null) {
						var asAssociation = $(this).parents("form:first").find("input[name='asAssociation']");
						
						var label = $(this).parents("form:first").find("label[for='data[Citation][name]']");
						
						label.html("Citation <div class='formHelp'>(Will be saved as an association)</div>");
						asAssociation.attr("value", "true");
						
						$(this).parents("fieldset:first").next().hide();
						
						$(this).keypress(function() {
							label.html("Citation");
							asAssociation.removeAttr("value");
							$(this).parents("fieldset:first").next().show();
						});
					}
				});
			});
		}
	};

	/**
	  * Lists the questions from a selected questionnaire via AJAX
	  */ 
	$.fn.bindQuestionImporter = function() {
		$(this).find(".questionImporter input[type='submit']:first").hide();
		$(this).find("select[name='data[Questionnaire][id]']:first").change(function() {
			if ( $(this).find("option:selected").attr("value") != "" ) {
				var listing = $(this).parents("form:first").parent().parent().find('.questionImporterListing');
				
				$(this).parents("form:first").ajaxSubmit(
					{
						target: listing,
						beforeSubmit: function() {
							listing.html("<span class='loading'>Loading</span>");
						},
						success: function() {

						}
					}
				);
			}
		});
	};
	
	$.fn.bindQuestionImporterListing = function() {
		
	};
	
	/**
	 * selector - selection whose response will be loaded 
	 */
	$.fn.inPageResponse = function(selector) {
		$(this).each(function() {
			var parent = $(this);

			parent.find(selector).each(function() {
				var self = $(this);
				if (! self.hasClass("inPageResponse")) {
					self.addClass("inPageResponse");
					
					if (self.is("a")) {
						var href= self.attr("href");
						if (href !== undefined) {
							self.click(function(e) {
								e.preventDefault();
								
								parent.load(href, null, function() {
									parent.inPageResponse(selector);
								});
							});
						}
					}
					
					if (self.is("form")) {
						self.ajaxForm({
							success: function(responseXml) {
								parent.html(responseXml);
								parent.inPageResponse(selector);
							}
						});
					}
				}

			});
		});
	};
	
	/**
	 * wordCounter() should be applied to a textarea
	 * 
	 * HTML required:
	 * <element>
	 *   <textarea></textarea>
	 *   <element class="wordCount">
	 *   	<element class="count">0</element>
	 *   	<element class="minimum">20</element>
	 *   	<element class="maximum">20</element>
	 *   </element>
	 * </element>
	 */
	$.fn.wordCounter = function(options) {
		var settings = $.extend({
			okay: function(target) {},	// good validation
			error: function(target) {}	// bad validation
		}, options);
		
		var target = $(this);
		var parent = target.parent();
		
		var minimum = Number(parent.find(".wordCount .minimum").text());
		var maximum = Number(parent.find(".wordCount .maximum").text());
		
		var getWordCount = function(text) {
			if (text === undefined || text.length === 0) { 
				return 0;	
			} else {
				// Replace non-alpha with single space and then remove trailing/leading spaces
				// Then split and return number of words
				return text.replace(/[^\w']+/g, " ")
							.replace(/\ $/, "")
							.replace(/^\ /, "")
							.split(" ").length;
			}
		};
		
		var updateWordCount = function() {
			var c = getWordCount(target.val());
			
			var count = parent.find(".wordCount .count");
			count.text(c);
			
			if (c <= maximum && c >= minimum) {
				count.removeClass("wordCountError");
				settings.okay(target);
			} else {
				count.addClass("wordCountError");
				settings.error(target);
			}
		};
		
		
		updateWordCount();
		
		target.keyup(updateWordCount);
		target.mouseenter(updateWordCount);
	};
	
	/**
	 * 
	 */
	$.fn.refreshable = function(options) {
		var settings = $.extend({
			selector : ".quickRefresh",	// a href to do quick refresh
			callback : function() {}	// to apply to refreshable
		}, options);
		
		var refreshable = $(this);
		refreshable.each(settings.callback);
		
		refreshable.each(function() {
			var selection = refreshable.find(settings.selector);
			
			selection.each(function() {
				var a = $(this);
				var url = a.attr("href");
				a.removeAttr("href");
						
				a.mouseover(function() {
					a.addClass("simpleButtonMouseOver");
				});
			
				a.mouseout(function() {
					a.removeClass("simpleButtonMouseOver");
				});
			
				a.click(function() {
					refreshable.load(url, null, function() {
						refreshable.refreshable(settings);
					});
				});
			});
		});
		
		return $(this);
	};
})(jQuery);


$(document).ready(function() {
	$(document).qbuilder();
	
	$(".showFormButton").click(function() {
		$(this).parent().hide();
		$(this).parent().siblings(".formPanel").show();
	});

	$(".formPanel .submitButton, .formPanel .cancelButton").click(function() {
		$(this).parents(".formPanel").hide();
		$(this).parents(".formPanel").siblings(".buttonPanel").show();
		return false;
	});
	
	$("#flashMessage.message").each(function() {
		setTimeout(function() {
				$(this).fadeOut(1000);	
			},
			5000
		)
	});
});