/* ==========================================================
 * bootstrap-twipsy.js v1.4.0
 * http://twitter.github.com/bootstrap/javascript.html#twipsy
 * Adapted from the original jQuery.tipsy by Jason Frame
 * ==========================================================
 * Copyright 2011 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================== */


!function( $ ) {

	"use strict"

	/* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
	 * ======================================================= */

	var transitionEnd

	$(document).ready(function () {

		$.support.transition = (function () {
			var thisBody = document.body || document.documentElement
					, thisStyle = thisBody.style
					, support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined
			return support
		})()

		// set CSS transition event type
		if ( $.support.transition ) {
			transitionEnd = "TransitionEnd"
			if ( $.browser.webkit ) {
				transitionEnd = "webkitTransitionEnd"
			} else if ( $.browser.mozilla ) {
				transitionEnd = "transitionend"
			} else if ( $.browser.opera ) {
				transitionEnd = "oTransitionEnd"
			}
		}

	})


	/* TWIPSY PUBLIC CLASS DEFINITION
	 * ============================== */

	var Twipsy = function ( element, options ) {
		this.$element = $(element)
		this.options = options
		this.enabled = true
		this.fixTitle()
	}

	Twipsy.prototype = {

		show: function() {
			var pos
					, actualWidth
					, actualHeight
					, placement
					, $tip
					, tp

			if (this.hasContent() && this.enabled) {
				$tip = this.tip()
				this.setContent()

				if (this.options.animate) {
					$tip.addClass('fade')
				}

				$tip
						.remove()
						.css({ top: 0, left: 0, display: 'block' })
						.prependTo(document.body)

				pos = $.extend({}, this.$element.offset(), {
					width: this.$element[0].offsetWidth
					, height: this.$element[0].offsetHeight
				})

				actualWidth = $tip[0].offsetWidth
				actualHeight = $tip[0].offsetHeight

				placement = maybeCall(this.options.placement, this, [ $tip[0], this.$element[0] ])

				switch (placement) {
					case 'below':
						tp = {top: pos.top + pos.height + this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2}
						break
					case 'above':
						tp = {top: pos.top - actualHeight - this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2}
						break
					case 'left':
						tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - this.options.offset}
						break
					case 'right':
						tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + this.options.offset}
						break
				}

				$tip
						.css(tp)
						.addClass(placement)
						.addClass('in')
			}
		}

		, setContent: function () {
			var $tip = this.tip()
			$tip.find('.twipsy-inner')[this.options.html ? 'html' : 'text'](this.getTitle())
			$tip[0].className = 'twipsy'
		}

		, hide: function() {
			var that = this
					, $tip = this.tip()

			$tip.removeClass('in')

			function removeElement () {
				$tip.remove()
			}

			$.support.transition && this.$tip.hasClass('fade') ?
					$tip.bind(transitionEnd, removeElement) :
					removeElement()
		}

		, fixTitle: function() {
			var $e = this.$element
			if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
				$e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
			}
		}

		, hasContent: function () {
			return this.getTitle()
		}

		, getTitle: function() {
			var title
					, $e = this.$element
					, o = this.options

			this.fixTitle()

			if (typeof o.title == 'string') {
				title = $e.attr(o.title == 'title' ? 'data-original-title' : o.title)
			} else if (typeof o.title == 'function') {
				title = o.title.call($e[0])
			}

			title = ('' + title).replace(/(^\s*|\s*$)/, "")

			return title || o.fallback
		}

		, tip: function() {
			return this.$tip = this.$tip || $('<div class="twipsy" />').html(this.options.template)
		}

		, validate: function() {
			if (!this.$element[0].parentNode) {
				this.hide()
				this.$element = null
				this.options = null
			}
		}

		, enable: function() {
			this.enabled = true
		}

		, disable: function() {
			this.enabled = false
		}

		, toggleEnabled: function() {
			this.enabled = !this.enabled
		}

		, toggle: function () {
			this[this.tip().hasClass('in') ? 'hide' : 'show']()
		}

	}


	/* TWIPSY PRIVATE METHODS
	 * ====================== */

	function maybeCall ( thing, ctx, args ) {
		return typeof thing == 'function' ? thing.apply(ctx, args) : thing
	}

	/* TWIPSY PLUGIN DEFINITION
	 * ======================== */

	$.fn.twipsy = function (options) {
		$.fn.twipsy.initWith.call(this, options, Twipsy, 'twipsy')
		return this
	}

	$.fn.twipsy.initWith = function (options, Constructor, name) {
		var twipsy
				, binder
				, eventIn
				, eventOut

		if (options === true) {
			return this.data(name)
		} else if (typeof options == 'string') {
			twipsy = this.data(name)
			if (twipsy) {
				twipsy[options]()
			}
			return this
		}

		options = $.extend({}, $.fn[name].defaults, options)

		function get(ele) {
			var twipsy = $.data(ele, name)

			if (!twipsy) {
				twipsy = new Constructor(ele, $.fn.twipsy.elementOptions(ele, options))
				$.data(ele, name, twipsy)
			}

			return twipsy
		}

		function enter() {
			var twipsy = get(this)
			twipsy.hoverState = 'in'

			if (options.delayIn == 0) {
				twipsy.show()
			} else {
				twipsy.fixTitle()
				setTimeout(function() {
					if (twipsy.hoverState == 'in') {
						twipsy.show()
					}
				}, options.delayIn)
			}
		}

		function leave() {
			var twipsy = get(this)
			twipsy.hoverState = 'out'
			if (options.delayOut == 0) {
				twipsy.hide()
			} else {
				setTimeout(function() {
					if (twipsy.hoverState == 'out') {
						twipsy.hide()
					}
				}, options.delayOut)
			}
		}

		if (!options.live) {
			this.each(function() {
				get(this)
			})
		}

		if (options.trigger != 'manual') {
			binder   = options.live ? 'live' : 'bind'
			eventIn  = options.trigger == 'hover' ? 'mouseenter' : 'focus'
			eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur'
			this[binder](eventIn, enter)[binder](eventOut, leave)
		}

		return this
	}

	$.fn.twipsy.Twipsy = Twipsy

	$.fn.twipsy.defaults = {
		animate: true
		, delayIn: 0
		, delayOut: 0
		, fallback: ''
		, placement: 'above'
		, html: false
		, live: false
		, offset: 0
		, title: 'title'
		, trigger: 'hover'
		, template: '<div class="twipsy-arrow"></div><div class="twipsy-inner"></div>'
	}

	$.fn.twipsy.rejectAttrOptions = [ 'title' ]

	$.fn.twipsy.elementOptions = function(ele, options) {
		var data = $(ele).data()
				, rejects = $.fn.twipsy.rejectAttrOptions
				, i = rejects.length

		while (i--) {
			delete data[rejects[i]]
		}

		return $.extend({}, options, data)
	}

}( window.jQuery || window.ender );
