var Behaviours = {
	enabled: [],
	options:{},
	initialized:false,
	_id_counter: 0,
	_stack: [],
	texts: {},
	javascripts:[],
	stylesheets:[],
	
	initialize: function(options, texts) {
		Behaviours.options = options
		Behaviours.texts = texts
		Behaviours.initialized = true
		$.each(Behaviours._stack, function(index, args) {
			Behaviours.enable.apply(null,args)
		})
		Behaviours._stack = []
		
	},
	getText: function(text) {
		return (text in this.texts) ? this.texts[text] : text
	},
	isEnabled: function(behaviour) {
		return Behaviours.enabled.indexOf(behaviour) !== -1;
	},
	generateId: function() {
		Behaviours._id_counter++
		return "behaviour_autoid" + Behaviours._id_counter
	},
	getElementId: function(el) {
		if (!el.attr("id")) {
			el.attr("id", Behaviours.generateId())
		}
		return el.attr("id")
	},
	enable: function(behaviour, target, force) {
		var args = arguments
		if (Behaviours.initialized) {
			if (!Behaviours.isEnabled(behaviour)) {
				Behaviours.enabled.push(behaviour)
				force = true
			}
			if (force) {
				behaviour(target ? target : $(document.body))
			}
		} else {
			Behaviours._stack.push(args)
		}
	},
	applyAll: function(target) {
		$.each(Behaviours.enabled, function(index, behaviour){
			Behaviours.enable(behaviour, target, true)
		})
	},
	addJavascript: function(url, callback) {
		if (url instanceof Array) {
			var urls = url
			url = urls.shift()
			if (urls.length) {
				var rcallback = callback
				callback = function() {
					Behaviours.addJavascript(urls, rcallback)
				}
			}
		}
		if(Behaviours.javascripts.indexOf(url) == -1) {
			Behaviours.javascripts.push(url)
			$.getScript(url, callback)
		} else if (callback) {
			callback()
		}
	},
	addStylesheet: function(url) {
		if (typeof url == "string") {
			url = [url]
		}
		$.each(url, function(index, url) {
			if(Behaviours.stylesheets.indexOf(url) == -1) {
				Behaviours.stylesheets.push(url)
				$("head").append('<link href="' + url + 
					'" rel="stylesheet" type="text/css" />')
			}
		})
	},
	toast: function(message, classNames) {
		var toast = $("<div class='toast " + classNames + "' style='display: none'><div></div></div>")
		toast.find("div").text(message)
		$("body").append(toast)
		toast
			.css("top", Math.max($(window).height()/2 - 50 + $("html").scrollTop(),0) + "px")
			.css("left", Math.max($(window).width()/2 - 100,0) + "px")
			.fadeIn("slow", function(){ 
				var widget = $(this)
				setTimeout(function() {
						widget.fadeOut("slow", function() { $(this).remove() })
					}, 2500)
			})
	}
}

var AJAXForm = {
	onMandatoryFieldChange: function() {
		AJAXForm.checkMandatoryField($(this))
		AJAXForm.checkFormErrors($(this).closest("form"))
	},
	onFormSubmit: function() {
		$(this).find("input.form_required,textarea.form_required").each(function() {
			AJAXForm.checkMandatoryField($(this))
		})
		if (AJAXForm.checkFormErrors($(this))) {
			return true
		} else {
			Behaviours.toast(Behaviours.texts.formErrorText)
			return false
		}
			
	},
	checkFormErrors: function(aForm) {
		var returnValue
		if (aForm.find(".form_error").size() > 0)
		{
			returnValue = false
		} else {
			returnValue = true
		}
		aForm.find(":submit").attr("disabled",!returnValue)
		return returnValue
	},
	checkMandatoryField: function(aField) {
		var wrapper = 
			(aField.closest("div").hasClass("textarea_wrapper")) 
			? aField.closest("div")
			: aField
		if (!aField.attr("disabled") && (aField.val().trim() == "")) {
			wrapper.addClass("form_error")
			return false
		} else {
			wrapper.removeClass("form_error")
			return true
		}
	}
}

/** Set rquired behaviors **/
function requiredBehaviour(target) {
	target.find("input.form_required,textarea.form_required")
		.bind("keyup blur change",AJAXForm.onMandatoryFieldChange)
		.each(function() {
			var form = $(this).closest("form")
			if (!form.data("isAJAXForm"))
			{
				form.data("isAJAXForm", true)
				form.submit(AJAXForm.onFormSubmit)
			}
		})
}

/** Set tooltip behaviors **/

function tooltipBehaviour(target) {
	tooltips = {}
	var counter = 0;
	var tooltipTimer
	target.find("div.help").each(function(idx, el) {
		var el = $(el)
		el.removeClass("help")
		el.addClass("tooltip")
		var parent = el.parent()
		parent.addClass("tooltip_anchor")
		tooltips[Behaviours.getElementId(parent)] = Behaviours.getElementId(el)
	})
	$("body").append(target.find("div.tooltip"))
	function getTooltip(tooltipAnchor) {
		var id = tooltipAnchor.attr("id")
		return (id in tooltips) 
			? $("#" + tooltips[id])
			: $("#" + id + "_tooltip")
	}
	target.find(".tooltip_anchor").each(function(idx, el) {
		var timer = null;
		var visible = false;
		var tooltipOffset = {top:0, left:0}
		function showToolTip(event) {
			var winHeight = $(window).height() + $(document).scrollTop()
			var tooltip = getTooltip($(el))
				.stop(true,true)
				.show("highlight", "slow")
			if ((tooltipOffset.top + tooltip.height()) > winHeight) {
				tooltipOffset.top -= tooltip.height() + 20;
			}
			if ((tooltipOffset.left + tooltip.width()) > winHeight) {
				tooltipOffset.left -= tooltip.width() + 20;
			}
			tooltip.offset(tooltipOffset)
			
			visible = true
			timer = null
		}
	    $(el)
		  .mousemove(function(event) {
			  	if (visible) {
			  		getTooltip($(this))
			  			.stop(true,true)
			  			.hide("highlight","fast")
			  		visible = false
			  	} else {
			  		tooltipOffset.top = event.pageY +10
			  		tooltipOffset.left = event.pageX + 10
			  		if (timer != null) {
			  			window.clearTimeout(timer)
			  		}
			  		timer = window.setTimeout(showToolTip,1000)
			  	}
		  })
		  .mouseleave(function(event) {
			  	if (timer != null) {
			  		window.clearTimeout(timer)
			  		timer = null
			  	}
			  	if (visible) {
				  	getTooltip($(this))
				  		.stop(true,true)
				  		.hide("highlight","fast")
				  	visible = false
			  	}
      })
	})
}

/** Set delete button behaviours **/

function deletableBehaviour(target) {
	if (!target.hasClass("item_deletable")) {
		target = target.find(".item_deletable")
	}
	target
		.mouseenter(function() {
			if (!$(this).parent().hasClass("ui-sortable-helper")) {
				$(this).find("div.item_delete")
					.stop(true, true)
					.show("highlight","slow")
			}
		})
	   .mouseleave(function() {
		   	$(this).find("div.item_delete")
		   		.stop(true, true)
		   		.hide("highlight")
	   })
	   .find("div.item_delete a")
	   .click(function() {
		   function removeLink(deleteLink, data) {
			   var deletable = deleteLink.closest(".item_deletable")
		   	   var callback = deletable.data("deletableSuccessCallback")
		   	   if (callback) {
		   			callback.call(deletable, data)
		   	   } else {
		   		   deletable.hide("normal", function() { $(this).remove() })
		   	   }
		   }
		   var confirmCallback = 
			   $(this).closest(".item_deletable").data("deletableConfirmCallback")
		   if (confirmCallback === undefined) {
			   confirmCallback = function() { return confirm(Behaviours.getText("confirm")) }
		   } else if (confirmCallback === false) {
			   confirmCallback = function() { return true }
		   }
		   
		   if (confirmCallback()) {
			   if ($(this).attr("href") == "#") {
				   removeLink($(this))
			   } else {
				   var ajaxParams = {
					   url:	$(this).attr("href"),
					   context: this,
					   type: "delete",
					   success: function(data, textStatus, jqXHR) {
					   		removeLink($(this), data)
				       }
				   }
				   if (Behaviours.options.CSRFToken) {
						ajaxParams.data = '&' + 
							(deletableBehaviour.CSRFFieldName 
								? Behaviours.options.CSRFFieldName 
								: "_csrf_token") + 
							"=" + Behaviours.options.CSRFToken
				   }
				   $.ajax(ajaxParams)
			   }
		   }
		   return false
	   })
		   
}

/** Set textarea behaviors **/
function textareaBehaviour(target) {
	if (Behaviours.options.jqueryUIEnabled) {
		target.find("textarea")
			.each(function() {
				if (!$(this).hasClass("nicedit")) {
					var width =  $(this).attr("width") ? $(this).attr("width") :  $(this).width() 
					$(this)
						.width(width)
						.height(100)
						.resizable({
							handles: 's,se',
							minWidth: width+5,
							maxWidth: width+5})
						.wrap("<div class='textarea_wrapper'></div>")
				}
			})
	}
}
/** Set global requests behaviours **/

GlobalRequests = {
	count: 0,
	currentErrorXHR: null,
	addRequest: function()
	{
		if (!GlobalRequests.count) {
			$("#spinner").stop(true,true).show("highlight")
		}
		GlobalRequests.count++
	},
	removeRequest: function()
	{
		GlobalRequests.count--
		if (!GlobalRequests.count) {
			$("#spinner").stop(true,true).fadeOut()
		}
	},
	showError: function(jqXHR)
	{
		if (jqXHR != GlobalRequests.currentErrorXHR)
		{
			GlobalRequests.currentErrorXHR = jqXHR
			Behaviours.toast(Behaviours.texts.ajaxErrorText)
		}
	}
}
function spinnerBehaviour(target) {
	activeAjaxRequests = 0
	$("#spinner").ajaxSend(function(){
			GlobalRequests.addRequest()
		})
		.ajaxComplete(function(){
			GlobalRequests.removeRequest()
		})
		.ajaxError(function(event, jqXHR, ajaxSettings, thrownError){
			if ((jqXHR.readyState !=4) || (jqXHR.status != 0) || (jqXHR.statusText != "")) {
				GlobalRequests.showError(jqXHR)
			}
		})
}
/** Pager behaviors  **/
function pagerBehaviour(target) {
	function setTableEvents()
	{
		target.find("div.sf_admin_list").find("thead a, tfoot a").click(function() {
			GlobalRequests.addRequest();
			$.ajax({
				url: $(this).attr("href"),
				dataType: "html",
				context: $(this).closest("div.sf_admin_list"),
				success: function(data) {
					$(this).replaceWith(data)
					window.setTimeout(setTableEvents,0)
				},
				complete: function() {
					GlobalRequests.removeRequest();
				}
			})
			return false
		})
	}
	setTableEvents()
}

function syntaxhighlighterBehaviour(target)
{
	function highlight() {
		function path() {
			var args = arguments, result = []
			$.each(arguments, function(index, arg) {
				result.push(arg.replace("@",Behaviours.options.syntaxhighlighterJsPath))
			})
			return result
		}
		target.find("pre").each(function() {
			var brushName = $(this).attr("className").substr(7)
			syntaxhighlighterBehaviour.loadedBrushes.push(brushName)
		})
		SyntaxHighlighter.autoloader.apply(null, path(
			  'applescript            @/shBrushAppleScript.js',
			  'actionscript3 as3      @/shBrushAS3.js',
			  'bash shell             @/shBrushBash.js',
			  'coldfusion cf          @/shBrushColdFusion.js',
			  'cpp c                  @/shBrushCpp.js',
			  'c# c-sharp csharp      @/shBrushCSharp.js',
			  'css                    @/shBrushCss.js',
			  'delphi pascal          @/shBrushDelphi.js',
			  'diff patch pas         @/shBrushDiff.js',
			  'erl erlang             @/shBrushErlang.js',
			  'groovy                 @/shBrushGroovy.js',
			  'java                   @/shBrushJava.js',
			  'jfx javafx             @/shBrushJavaFX.js',
			  'js jscript javascript  @/shBrushJScript.js',
			  'perl pl                @/shBrushPerl.js',
			  'php                    @/shBrushPhp.js',
			  'text plain             @/shBrushPlain.js',
			  'py python              @/shBrushPython.js',
			  'ruby rails ror rb      @/shBrushRuby.js',
			  'sass scss              @/shBrushSass.js',
			  'scala                  @/shBrushScala.js',
			  'sql                    @/shBrushSql.js',
			  'vb vbnet               @/shBrushVb.js',
			  'xml xhtml xslt html    @/shBrushXml.js'
			));
		SyntaxHighlighter.all()
	}
	if (!syntaxhighlighterBehaviour.initialized) {
		syntaxhighlighterBehaviour.initialized = true

		Behaviours.addStylesheet(
		  [
			Behaviours.options.syntaxhighlighterCssPath +
			"/shCore.css",
			Behaviours.options.syntaxhighlighterCssPath +
			"/shThemeDefault.css"
		])

		Behaviours.addJavascript(
				[ Behaviours.options.syntaxhighlighterJsPath +
					"/shCore.js",
				  Behaviours.options.syntaxhighlighterJsPath +
				    "/shAutoloader.js",
			      Behaviours.options.syntaxhighlighterJsPath +
			        "/shBrushPlain.js"
				], highlight)
	} else {
		target.find("pre").each(function() {
			var brushName = $(this).attr("className").substr(7)
			if (syntaxhighlighterBehaviour.loadedBrushes.indexOf(brushName) === -1) {
				$(this).attr("className", "brush: plain")
			}
		})
		SyntaxHighlighter.highlight()
	}
}

syntaxhighlighterBehaviour.initialized = false
syntaxhighlighterBehaviour.loadedBrushes = []

/** Page modal dialog **/

var ModalDialog = {
	current: null,
	createDialogFromLink: function(link) {
		var dialog = ModalDialog.createDialog($(link).attr("title"))
		$.ajax({
			url: $(link).attr("href"),
			dataType: "html",
			success: function(data, textStatus, jqXHR) {
				dialog.find(".contents").html(data)
			}
		})
	},
	createDialog: function(title) {
		editor = $("#page_modal_dialog")
		if (editor.length) {
			editor.remove()
		}
		editor = $("body").append("<div id='page_modal_dialog'><div class='contents'></div></div>")
			.find("#page_modal_dialog")
		if (title) {
			editor.attr("title", title)
		}
		editor.dialog({
			width: Math.max(200, Math.min(820, $(window).width()-100)),
			height: Math.max(200, $(window).height()-100),
			modal: true
		})
		ModalDialog.current = Behaviours.getElementId(editor)
		return editor
	}
}
function modalDialogBehaviour(target)
{
	target.find(".modal_dialog a").click(function() {
		ModalDialog.createDialogFromLink(this)
		return false
	})
}
/** Editable behaviours **/
var EditableFields = {
	current: null,
	currentDialog:null,
	openForm: function(editableElement, formHtml, title) {
		var editor, root
		EditableFields.hideForm()
		if (editableElement.data("dialog")) {
			editor = ModalDialog.createDialog(title) 
			editor.find(".contents").addClass("item_editor").html("<div class='item_editor_form'></div>")
			root = editableElement
		} else {
			editableElement
				.wrapAll("<div class='item_editor'></div>")
				.closest("div.item_editor")
				.append("<div class='item_editor_form'></div>")
				.find("div.item_editor_form")
				.html(formHtml)
			editor = editableElement.closest("div.item_editor")
			ModalDialog.current = null;
			root = editor
		}
		EditableFields.current = Behaviours.getElementId(root)
		editor.find(".item_editor_form").html(formHtml)
		Behaviours.applyAll(editor.find("div.item_editor_form"))
		function submit() {
			var form = editor.find("form")
			$.ajax({
					url: form.attr("action"),
					type: "post",
					context: root,
					data: form.serialize(),
					success: function(data) {
						if (editableElement.data("editableSuccessCallback")) {
							editableElement.data("editableSuccessCallback").call(null, data)
						}
						else {
							var desc = root.find("div.item_editable_description")
							desc.html(data)
							Behaviours.applyAll(desc)
							EditableFields.closeForm()
						}
					},
					error: function(data) {
						var editorForm = editor.find("div.item_editor_form")
						editorForm.html(data.responseText)
						Behaviours.applyAll(editorForm)
					}
				})
			return false
		}
		var submitCallback = editableElement.data("editableSubmitCallback")
			
		editor
			.submit(submitCallback ? function() { return submitCallback(submit) } : submit)
			.find(".editable_buttons")
			.find("button,input:submit")
			.button()
			.filter("button")
			.click(EditableFields.closeForm)
	},
	showForm: function(editor) {
		EditableFields.hideForm()
		editor.find("div.item_editable").hide()
		editor.find("div.item_editor_form").show()
		EditableFields.current = editor.attr("id")
	},
	hideForm: function() {
		if (EditableFields.getCurrentDialog()) {
			EditableFields.closeForm()
		} else {
			var current = EditableFields.getCurrent()
			if (current) {
				current.find("div.item_editor_form").hide()
				current.find("div.item_editable").show()			
			}
		}
	},
	closeForm: function() {
		var currentDialog = EditableFields.getCurrentDialog()
		if (currentDialog && currentDialog.length)
		{
			currentDialog.dialog("destroy").remove()
			ModalDialog.current = null
			EditableFields.current = null
		} else {
			var current = EditableFields.getCurrent()
			if (current) {
				current.find("div.item_editor_form").remove()
				current.find("div.item_editable").unwrap()
				EditableFields.current = null
			}
		}
	},
	loadForm: function(editable, url, title)
	{
		if (!url) {
			url = $(editable).find(".item_edit a").attr("href")
		}
		if (!title) {
			title = $(editable).find(".item_edit").attr("title")
		}
			
		$.ajax({
			url: url,
			dataType: "html",
			context: $(editable),
			success: function(data) {
				EditableFields.openForm($(this), data, title)
			}
		})
	},
	getCurrent: function() {
		return EditableFields.current 
			? $("#" + EditableFields.current)
			: null
	},
	onEditClick: function() {
   		var editable = $(this).closest(".item_editable")
   		if (editable.data("editableEditCallback")) {
   			editable.data("editableEditCallback").call(editable, $(this).attr("href"))
   		} else if (editable.parent().hasClass("item_editor")) {
			EditableFields.showForm(editable.parent(), $(this).attr("href"))
		} else {
			EditableFields.loadForm(editable, $(this).attr("href"), $(this).closest(".item_edit").attr("title"))
		}
		return false
	},
	getCurrentDialog: function() {
				return ModalDialog.current 
					? $("#" + ModalDialog.current)
					: null
			}
}
function editableBehaviour(target)
{
	if (!target.hasClass("item_editable")) {
		target = target.find(".item_editable")
	}
	target
		.mouseenter(function() {
			if (!$(this).parent().hasClass("ui-sortable-helper")) {
				$(this).find("div.item_edit")
					.stop(true, true)
					.show("highlight","slow")
			}
		})
	    .mouseleave(function() {
		   	$(this).find("div.item_edit")
		   		.stop(true, true)
		   		.hide("highlight")
	   	})
	   	.find("div.item_edit a").click(EditableFields.onEditClick)
	 target
	   	.find("div.item_edit_button a").click(EditableFields.onEditClick)
	   	.button()
	
}
function flashBehaviour(target) {
	window.setTimeout(function() {
		target.find("div.error, div.notice").hide("normal")
	},2000)
}

function buttonBehaviour(target) {
	if (Behaviours.options.jqueryUIEnabled) {
		$("input:submit,input:button").button()
	}
}


