/* ==========================================================

* 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 );