/*

* # Semantic - Popup
* http://github.com/jlukic/semantic-ui/
*
*
* Copyright 2014 Contributor
* Released under the MIT license
* http://opensource.org/licenses/MIT
*
*/

;(function ($, window, document, undefined) {

“use strict”;

$.fn.popup = function(parameters) {

var
  $allModules    = $(this),
  $document      = $(document),

  moduleSelector = $allModules.selector || '',

  hasTouch       = ('ontouchstart' in document.documentElement),
  time           = new Date().getTime(),
  performance    = [],

  query          = arguments[0],
  methodInvoked  = (typeof query == 'string'),
  queryArguments = [].slice.call(arguments, 1),

  returnedValue
;
$allModules
  .each(function() {
    var
      settings        = ( $.isPlainObject(parameters) )
        ? $.extend(true, {}, $.fn.popup.settings, parameters)
        : $.extend({}, $.fn.popup.settings),

      selector           = settings.selector,
      className          = settings.className,
      error              = settings.error,
      metadata           = settings.metadata,
      namespace          = settings.namespace,

      eventNamespace     = '.' + settings.namespace,
      moduleNamespace    = 'module-' + namespace,

      $module            = $(this),
      $context           = $(settings.context),
      $target            = (settings.target)
        ? $(settings.target)
        : $module,

      $window            = $(window),
      $body              = $('body'),
      $popup,
      $offsetParent,

      searchDepth        = 0,
      triedPositions     = false,

      element            = this,
      instance           = $module.data(moduleNamespace),
      module
    ;

    module = {

      // binds events
      initialize: function() {
        module.debug('Initializing module', $module);
        module.refresh();
        if(settings.on == 'click') {
          $module
            .on('click' + eventNamespace, module.toggle)
          ;
        }
        else if( module.get.startEvent() ) {
          $module
            .on(module.get.startEvent() + eventNamespace, module.event.start)
            .on(module.get.endEvent() + eventNamespace, module.event.end)
          ;
        }
        if(settings.target) {
          module.debug('Target set to element', $target);
        }
        $window
          .on('resize' + eventNamespace, module.event.resize)
        ;
        if( !module.exists() ) {
          module.create();
        }
        else if(settings.hoverable) {
          module.bind.popup();
        }
        module.instantiate();
      },

      instantiate: function() {
        module.verbose('Storing instance of module', module);
        instance = module;
        $module
          .data(moduleNamespace, instance)
        ;
      },

      refresh: function() {
        if(settings.popup) {
          $popup = $(settings.popup);
        }
        else {
          if(settings.inline) {
            $popup = $target.next(settings.selector.popup);
          }
        }
        if(settings.popup) {
          $popup.addClass(className.loading);
          if($popup.offsetParent()[0] !== $module.offsetParent()[0]) {
            module.debug('Moving popup to the same offset parent as activating element');
            $offsetParent = $module.offsetParent();
            $popup
              .detach()
              .appendTo($offsetParent)
            ;
          }
          $popup.removeClass(className.loading);
        }
        else {
          $offsetParent = (settings.inline)
            ? $target.offsetParent()
            : $body
          ;
        }
        if( $offsetParent.is('html') ) {
          module.debug('Page is popups offset parent');
          $offsetParent = $body;
        }
      },

      reposition: function() {
        module.refresh();
        module.set.position();
      },

      destroy: function() {
        module.debug('Destroying previous module');
        if($popup && !settings.preserve) {
          module.removePopup();
        }
        clearTimeout(module.hideTimer);
        clearTimeout(module.showTimer);
        $module
          .off(eventNamespace)
          .removeData(moduleNamespace)
        ;
      },

      event: {
        start:  function(event) {
          var
            delay = ($.isPlainObject(settings.delay))
              ? settings.delay.show
              : settings.delay
          ;
          clearTimeout(module.hideTimer);
          module.showTimer = setTimeout(function() {
            if(module.is.hidden() && !( module.is.active() && module.is.dropdown()) ) {
              module.show();
            }
          }, delay);
        },
        end:  function() {
          var
            delay = ($.isPlainObject(settings.delay))
              ? settings.delay.hide
              : settings.delay
          ;
          clearTimeout(module.showTimer);
          module.hideTimer = setTimeout(function() {
            if(module.is.visible() ) {
              module.hide();
            }
          }, delay);
        },
        resize: function() {
          if( module.is.visible() ) {
            module.set.position();
          }
        }
      },

      // generates popup html from metadata
      create: function() {
        var
          html      = $module.data(metadata.html)      || settings.html,
          variation = $module.data(metadata.variation) || settings.variation,
          title     = $module.data(metadata.title)     || settings.title,
          content   = $module.data(metadata.content)   || $module.attr('title') || settings.content
        ;
        if(html || content || title) {
          module.debug('Creating pop-up html');
          if(!html) {
            html = settings.templates.popup({
              title   : title,
              content : content
            });
          }
          $popup = $('<div/>')
            .addClass(className.popup)
            .addClass(variation)
            .html(html)
          ;
          if(variation) {
            $popup
              .addClass(variation)
            ;
          }
          if(settings.inline) {
            module.verbose('Inserting popup element inline', $popup);
            $popup
              .insertAfter($module)
            ;
          }
          else {
            module.verbose('Appending popup element to body', $popup);
            $popup
              .appendTo( $context )
            ;
          }
          if(settings.hoverable) {
            module.bind.popup();
          }
          $.proxy(settings.onCreate, $popup)(element);
        }
        else if($target.next(settings.selector.popup).size() !== 0) {
          module.verbose('Pre-existing popup found, reverting to inline');
          settings.inline = true;
          module.refresh();
          if(settings.hoverable) {
            module.bind.popup();
          }
        }
        else {
          module.debug('No content specified skipping display', element);
        }
      },

      // determines popup state
      toggle: function() {
        module.debug('Toggling pop-up');
        if( module.is.hidden() ) {
          module.debug('Popup is hidden, showing pop-up');
          module.unbind.close();
          module.hideAll();
          module.show();
        }
        else {
          module.debug('Popup is visible, hiding pop-up');
          module.hide();
        }
      },

      show: function(callback) {
        callback = $.isFunction(callback) ? callback : function(){};
        module.debug('Showing pop-up', settings.transition);
        if(!settings.preserve && !settings.popup) {
          module.refresh();
        }
        if( !module.exists() ) {
          module.create();
        }
        if( $popup && module.set.position() ) {
          module.save.conditions();
          module.animate.show(callback);
        }
      },

      hide: function(callback) {
        callback = $.isFunction(callback) ? callback : function(){};
        module.remove.visible();
        module.unbind.close();
        if( module.is.visible() ) {
          module.restore.conditions();
          module.animate.hide(callback);
        }
      },

      hideAll: function() {
        $(selector.popup)
          .filter(':visible')
            .popup('hide')
        ;
      },

      hideGracefully: function(event) {
        // don't close on clicks inside popup
        if(event && $(event.target).closest(selector.popup).size() === 0) {
          module.debug('Click occurred outside popup hiding popup');
          module.hide();
        }
        else {
          module.debug('Click was inside popup, keeping popup open');
        }
      },

      exists: function() {
        if(!$popup) {
          return false;
        }
        if(settings.inline || settings.popup) {
          return ( module.has.popup() );
        }
        else {
          return ( $popup.closest($context).size() > 1 )
            ? true
            : false
          ;
        }
      },

      removePopup: function() {
        module.debug('Removing popup', $popup);
        if( module.has.popup() ) {
          $popup.remove();
        }
        $.proxy(settings.onRemove, $popup)(element);
      },

      save: {
        conditions: function() {
          module.cache = {
            title: $module.attr('title')
          };
          if (module.cache.title) {
            $module.removeAttr('title');
          }
          module.verbose('Saving original attributes', module.cache.title);
        }
      },
      restore: {
        conditions: function() {
          element.blur();
          if(module.cache && module.cache.title) {
            $module.attr('title', module.cache.title);
            module.verbose('Restoring original attributes', module.cache.title);
          }
          return true;
        }
      },
      animate: {
        show: function(callback) {
          callback = $.isFunction(callback) ? callback : function(){};
          if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
            module.set.visible();
            $popup
              .transition({
                animation  : settings.transition + ' in',
                queue      : false,
                debug      : settings.debug,
                verbose    : settings.verbose,
                duration   : settings.duration,
                onComplete : function() {
                  module.bind.close();
                  $.proxy(callback, $popup)(element);
                  $.proxy(settings.onVisible, $popup)(element);
                }
              })
            ;
          }
          else {
            module.set.visible();
            $popup
              .stop()
              .fadeIn(settings.duration, settings.easing, function() {
                module.bind.close();
                $.proxy(callback, element)();
              })
            ;
          }
          $.proxy(settings.onShow, $popup)(element);
        },
        hide: function(callback) {
          callback = $.isFunction(callback) ? callback : function(){};
          module.debug('Hiding pop-up');
          if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
            $popup
              .transition({
                animation  : settings.transition + ' out',
                queue      : false,
                duration   : settings.duration,
                debug      : settings.debug,
                verbose    : settings.verbose,
                onComplete : function() {
                  module.reset();
                  $.proxy(callback, $popup)(element);
                  $.proxy(settings.onHidden, $popup)(element);
                }
              })
            ;
          }
          else {
            $popup
              .stop()
              .fadeOut(settings.duration, settings.easing, function() {
                module.reset();
                callback();
              })
            ;
          }
          $.proxy(settings.onHide, $popup)(element);
        }
      },

      get: {
        startEvent: function() {
          if(settings.on == 'hover') {
            return 'mouseenter';
          }
          else if(settings.on == 'focus') {
            return 'focus';
          }
          return false;
        },
        endEvent: function() {
          if(settings.on == 'hover') {
            return 'mouseleave';
          }
          else if(settings.on == 'focus') {
            return 'blur';
          }
          return false;
        },
        offstagePosition: function(position) {
          var
            position = position || false,
            boundary  = {
              top    : $(window).scrollTop(),
              bottom : $(window).scrollTop() + $(window).height(),
              left   : 0,
              right  : $(window).width()
            },
            popup     = {
              width  : $popup.width(),
              height : $popup.height(),
              offset : $popup.offset()
            },
            offstage  = {},
            offstagePositions = []
          ;
          if(popup.offset && position) {
            module.verbose('Checking if outside viewable area', popup.offset);
            offstage = {
              top    : (popup.offset.top < boundary.top),
              bottom : (popup.offset.top + popup.height > boundary.bottom),
              right  : (popup.offset.left + popup.width > boundary.right),
              left   : (popup.offset.left < boundary.left)
            };
          }
          // return only boundaries that have been surpassed
          $.each(offstage, function(direction, isOffstage) {
            if(isOffstage) {
              offstagePositions.push(direction);
            }
          });
          return (offstagePositions.length > 0)
            ? offstagePositions.join(' ')
            : false
          ;
        },
        positions: function() {
          return {
            'top left'      : false,
            'top center'    : false,
            'top right'     : false,
            'bottom left'   : false,
            'bottom center' : false,
            'bottom right'  : false,
            'left center'   : false,
            'right center'  : false
          };
        },
        nextPosition: function(position) {
          var
            positions          = position.split(' '),
            verticalPosition   = positions[0],
            horizontalPosition = positions[1],
            opposite = {
              top    : 'bottom',
              bottom : 'top',
              left   : 'right',
              right  : 'left'
            },
            adjacent = {
              left   : 'center',
              center : 'right',
              right  : 'left'
            },
            backup = {
              'top left'      : 'top center',
              'top center'    : 'top right',
              'top right'     : 'right center',
              'right center'  : 'bottom right',
              'bottom right'  : 'bottom center',
              'bottom center' : 'bottom left',
              'bottom left'   : 'left center',
              'left center'   : 'top left'
            },
            adjacentsAvailable = (verticalPosition == 'top' || verticalPosition == 'bottom'),
            oppositeTried = false,
            adjacentTried = false,
            nextPosition  = false
          ;
          if(!triedPositions) {
            module.verbose('All available positions available');
            triedPositions = module.get.positions();
          }

          module.debug('Recording last position tried', position);
          triedPositions[position] = true;

          if(settings.prefer === 'opposite') {
            nextPosition  = [opposite[verticalPosition], horizontalPosition];
            nextPosition  = nextPosition.join(' ');
            oppositeTried = (triedPositions[nextPosition] === true);
            module.debug('Trying opposite strategy', nextPosition);
          }
          if((settings.prefer === 'adjacent') && adjacentsAvailable ) {
            nextPosition  = [verticalPosition, adjacent[horizontalPosition]];
            nextPosition  = nextPosition.join(' ');
            adjacentTried = (triedPositions[nextPosition] === true);
            module.debug('Trying adjacent strategy', nextPosition);
          }
          if(adjacentTried || oppositeTried) {
            module.debug('Using backup position', nextPosition);
            nextPosition = backup[position];
          }
          return nextPosition;
        }
      },

      set: {
        position: function(position, arrowOffset) {
          var
            windowWidth   = $(window).width(),
            windowHeight  = $(window).height(),

            targetWidth   = $target.outerWidth(),
            targetHeight  = $target.outerHeight(),

            popupWidth    = $popup.outerWidth(),
            popupHeight   = $popup.outerHeight(),

            parentWidth   = $offsetParent.outerWidth(),
            parentHeight  = $offsetParent.outerHeight(),

            distanceAway  = settings.distanceAway,

            targetElement = $target[0],

            marginTop     = (settings.inline)
              ? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-top'), 10)
              : 0,
            marginLeft    = (settings.inline)
              ? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-left'), 10)
              : 0,

            target        = (settings.inline || settings.popup)
              ? $target.position()
              : $target.offset(),

            positioning,
            offstagePosition
          ;
          position    = position    || $module.data(metadata.position)    || settings.position;
          arrowOffset = arrowOffset || $module.data(metadata.offset)      || settings.offset;

          if(searchDepth == settings.maxSearchDepth && settings.lastResort) {
            module.debug('Using last resort position to display', settings.lastResort);
            position = settings.lastResort;
          }

          if(settings.inline) {
            module.debug('Adding targets margin to calculation');
            if(position == 'left center' || position == 'right center') {
              arrowOffset  += marginTop;
              distanceAway += -marginLeft;
            }
            else if (position == 'top left' || position == 'top center' || position == 'top right') {
              arrowOffset  += marginLeft;
              distanceAway -= marginTop;
            }
            else {
              arrowOffset  += marginLeft;
              distanceAway += marginTop;
            }
          }
          module.debug('Calculating popup positioning', position);
          switch(position) {
            case 'top left':
              positioning = {
                top    : 'auto',
                bottom : parentHeight - target.top + distanceAway,
                left   : target.left + arrowOffset,
                right  : 'auto'
              };
            break;
            case 'top center':
              positioning = {
                bottom : parentHeight - target.top + distanceAway,
                left   : target.left + (targetWidth / 2) - (popupWidth / 2) + arrowOffset,
                top    : 'auto',
                right  : 'auto'
              };
            break;
            case 'top right':
              positioning = {
                bottom :  parentHeight - target.top + distanceAway,
                right  :  parentWidth - target.left - targetWidth - arrowOffset,
                top    : 'auto',
                left   : 'auto'
              };
            break;
            case 'left center':
              positioning = {
                top    : target.top + (targetHeight / 2) - (popupHeight / 2) + arrowOffset,
                right  : parentWidth - target.left + distanceAway,
                left   : 'auto',
                bottom : 'auto'
              };
            break;
            case 'right center':
              positioning = {
                top    : target.top + (targetHeight / 2) - (popupHeight / 2) + arrowOffset,
                left   : target.left + targetWidth + distanceAway,
                bottom : 'auto',
                right  : 'auto'
              };
            break;
            case 'bottom left':
              positioning = {
                top    : target.top + targetHeight + distanceAway,
                left   : target.left + arrowOffset,
                bottom : 'auto',
                right  : 'auto'
              };
            break;
            case 'bottom center':
              positioning = {
                top    : target.top + targetHeight + distanceAway,
                left   : target.left + (targetWidth / 2) - (popupWidth / 2) + arrowOffset,
                bottom : 'auto',
                right  : 'auto'
              };
            break;
            case 'bottom right':
              positioning = {
                top    : target.top + targetHeight + distanceAway,
                right  : parentWidth - target.left  - targetWidth - arrowOffset,
                left   : 'auto',
                bottom : 'auto'
              };
            break;
          }
          if(positioning === undefined) {
            module.error(error.invalidPosition, position);
          }

          module.debug('Calculated popup positioning values', positioning);

          // tentatively place on stage
          $popup
            .css(positioning)
            .removeClass(className.position)
            .addClass(position)
            .addClass(className.loading)
          ;
          // check if is offstage
          offstagePosition = module.get.offstagePosition(position);

          // recursively find new positioning
          if(offstagePosition) {
            module.debug('Popup cant fit into viewport', offstagePosition);
            if(searchDepth < settings.maxSearchDepth) {
              searchDepth++;
              position = module.get.nextPosition(position);
              module.debug('Trying new position', position);
              return ($popup)
                ? module.set.position(position)
                : false
              ;
            }
            else if(!settings.lastResort) {
              module.debug('Popup could not find a position in view', $popup);
              module.error(error.cannotPlace);
              module.remove.attempts();
              module.remove.loading();
              module.reset();
              return false;
            }
          }

          module.debug('Position is on stage', position);
          module.remove.attempts();
          module.set.fluidWidth();
          module.remove.loading();
          return true;
        },

        fluidWidth: function() {
          if( settings.setFluidWidth && $popup.hasClass(className.fluid) ) {
            $popup.css('width', $offsetParent.width());
          }
        },

        visible: function() {
          $module.addClass(className.visible);
        }
      },

      remove: {
        loading: function() {
          $popup.removeClass(className.loading);
        },
        visible: function() {
          $module.removeClass(className.visible);
        },
        attempts: function() {
          module.verbose('Resetting all searched positions');
          searchDepth    = 0;
          triedPositions = false;
        }
      },

      bind: {
        popup: function() {
          module.verbose('Allowing hover events on popup to prevent closing');
          if( $popup && module.has.popup() ) {
            $popup
              .on('mouseenter' + eventNamespace, module.event.start)
              .on('mouseleave' + eventNamespace, module.event.end)
            ;
          }
        },
        close:function() {
          if(settings.hideOnScroll === true || settings.hideOnScroll == 'auto' && settings.on != 'click') {
            $document
              .one('touchmove' + eventNamespace, module.hideGracefully)
              .one('scroll' + eventNamespace, module.hideGracefully)
            ;
            $context
              .one('touchmove' + eventNamespace, module.hideGracefully)
              .one('scroll' + eventNamespace, module.hideGracefully)
            ;
          }
          if(settings.on == 'click' && settings.closable) {
            module.verbose('Binding popup close event to document');
            $document
              .on('click' + eventNamespace, function(event) {
                module.verbose('Pop-up clickaway intent detected');
                $.proxy(module.hideGracefully, element)(event);
              })
            ;
          }
        }
      },

      unbind: {
        close: function() {
          if(settings.hideOnScroll === true || settings.hideOnScroll == 'auto' && settings.on != 'click') {
            $document
              .off('scroll' + eventNamespace, module.hide)
            ;
            $context
              .off('scroll' + eventNamespace, module.hide)
            ;
          }
          if(settings.on == 'click' && settings.closable) {
            module.verbose('Removing close event from document');
            $document
              .off('click' + eventNamespace)
            ;
          }
        }
      },

      has: {
        popup: function() {
          return ($popup.size() > 0);
        }
      },

      is: {
        active: function() {
          return $module.hasClass(className.active);
        },
        animating: function() {
          return ( $popup && $popup.is(':animated') || $popup.hasClass(className.animating) );
        },
        visible: function() {
          return $popup && $popup.is(':visible');
        },
        dropdown: function() {
          return $module.hasClass(className.dropdown);
        },
        hidden: function() {
          return !module.is.visible();
        }
      },

      reset: function() {
        module.remove.visible();
        if(settings.preserve || settings.popup) {
          if($.fn.transition !== undefined) {
            $popup
              .transition('remove transition')
            ;
          }
        }
        else {
          module.removePopup();
        }
      },

      setting: function(name, value) {
        if( $.isPlainObject(name) ) {
          $.extend(true, settings, name);
        }
        else if(value !== undefined) {
          settings[name] = value;
        }
        else {
          return settings[name];
        }
      },
      internal: function(name, value) {
        if( $.isPlainObject(name) ) {
          $.extend(true, module, name);
        }
        else if(value !== undefined) {
          module[name] = value;
        }
        else {
          return module[name];
        }
      },
      debug: function() {
        if(settings.debug) {
          if(settings.performance) {
            module.performance.log(arguments);
          }
          else {
            module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
            module.debug.apply(console, arguments);
          }
        }
      },
      verbose: function() {
        if(settings.verbose && settings.debug) {
          if(settings.performance) {
            module.performance.log(arguments);
          }
          else {
            module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
            module.verbose.apply(console, arguments);
          }
        }
      },
      error: function() {
        module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
        module.error.apply(console, arguments);
      },
      performance: {
        log: function(message) {
          var
            currentTime,
            executionTime,
            previousTime
          ;
          if(settings.performance) {
            currentTime   = new Date().getTime();
            previousTime  = time || currentTime;
            executionTime = currentTime - previousTime;
            time          = currentTime;
            performance.push({
              'Name'           : message[0],
              'Arguments'      : [].slice.call(message, 1) || '',
              'Element'        : element,
              'Execution Time' : executionTime
            });
          }
          clearTimeout(module.performance.timer);
          module.performance.timer = setTimeout(module.performance.display, 100);
        },
        display: function() {
          var
            title = settings.name + ':',
            totalTime = 0
          ;
          time = false;
          clearTimeout(module.performance.timer);
          $.each(performance, function(index, data) {
            totalTime += data['Execution Time'];
          });
          title += ' ' + totalTime + 'ms';
          if(moduleSelector) {
            title += ' \'' + moduleSelector + '\'';
          }
          if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
            console.groupCollapsed(title);
            if(console.table) {
              console.table(performance);
            }
            else {
              $.each(performance, function(index, data) {
                console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
              });
            }
            console.groupEnd();
          }
          performance = [];
        }
      },
      invoke: function(query, passedArguments, context) {
        var
          object = instance,
          maxDepth,
          found,
          response
        ;
        passedArguments = passedArguments || queryArguments;
        context         = element         || context;
        if(typeof query == 'string' && object !== undefined) {
          query    = query.split(/[\. ]/);
          maxDepth = query.length - 1;
          $.each(query, function(depth, value) {
            var camelCaseValue = (depth != maxDepth)
              ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
              : query
            ;
            if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
              object = object[camelCaseValue];
            }
            else if( object[camelCaseValue] !== undefined ) {
              found = object[camelCaseValue];
              return false;
            }
            else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
              object = object[value];
            }
            else if( object[value] !== undefined ) {
              found = object[value];
              return false;
            }
            else {
              return false;
            }
          });
        }
        if ( $.isFunction( found ) ) {
          response = found.apply(context, passedArguments);
        }
        else if(found !== undefined) {
          response = found;
        }
        if($.isArray(returnedValue)) {
          returnedValue.push(response);
        }
        else if(returnedValue !== undefined) {
          returnedValue = [returnedValue, response];
        }
        else if(response !== undefined) {
          returnedValue = response;
        }
        return found;
      }
    };

    if(methodInvoked) {
      if(instance === undefined) {
        module.initialize();
      }
      module.invoke(query);
    }
    else {
      if(instance !== undefined) {
        module.destroy();
      }
      module.initialize();
    }
  })
;

return (returnedValue !== undefined)
  ? returnedValue
  : this
;

};

$.fn.popup.settings = {

name         : 'Popup',

debug        : false,
verbose      : true,
performance  : true,
namespace    : 'popup',

onCreate     : function(){},
onRemove     : function(){},

onShow       : function(){},
onVisible    : function(){},
onHide       : function(){},
onHidden     : function(){},

variation    : '',
content      : false,
html         : false,
title        : false,

on           : 'hover',
closable     : true,
hideOnScroll : 'auto',

context      : 'body',

position     : 'top left',
prefer       : 'opposite',
lastResort   : false,

delay        : {
  show : 30,
  hide : 0
},

setFluidWidth  : true,

target         : false,
popup          : false,
inline         : false,
preserve       : true,
hoverable      : false,

duration       : 200,
easing         : 'easeOutQuint',
transition     : 'scale',

distanceAway   : 0,
offset         : 0,
maxSearchDepth : 20,

error: {
  invalidPosition : 'The position you specified is not a valid position',
  cannotPlace     : 'No visible position could be found for the popup',
  method          : 'The method you called is not defined.'
},

metadata: {
  content   : 'content',
  html      : 'html',
  offset    : 'offset',
  position  : 'position',
  title     : 'title',
  variation : 'variation'
},

className   : {
  active    : 'active',
  animating : 'animating',
  dropdown  : 'dropdown',
  fluid     : 'fluid',
  loading   : 'loading',
  popup     : 'ui popup',
  position  : 'top left center bottom right',
  visible   : 'visible'
},

selector    : {
  popup    : '.ui.popup'
},

templates: {
  escape: function(string) {
    var
      badChars     = /[&<>"'`]/g,
      shouldEscape = /[&<>"'`]/,
      escape       = {
        "&": "&amp;",
        "<": "&lt;",
        ">": "&gt;",
        '"': "&quot;",
        "'": "&#x27;",
        "`": "&#x60;"
      },
      escapedChar  = function(chr) {
        return escape[chr];
      }
    ;
    if(shouldEscape.test(string)) {
      return string.replace(badChars, escapedChar);
    }
    return string;
  },
  popup: function(text) {
    var
      html   = '',
      escape = $.fn.popup.settings.templates.escape
    ;
    if(typeof text !== undefined) {
      if(typeof text.title !== undefined && text.title) {
        text.title = escape(text.title);
        html += '<div class="header">' + text.title + '</div>';
      }
      if(typeof text.content !== undefined && text.content) {
        text.content = escape(text.content);
        html += '<div class="content">' + text.content + '</div>';
      }
    }
    return html;
  }
}

};

// Adds easing $.extend( $.easing, {

easeOutQuad: function (x, t, b, c, d) {
  return -c *(t/=d)*(t-2) + b;
}

});

})( jQuery, window , document );