(function(window, angular, undefined){
  'use strict';
  var module = angular.module('nsPopover', []);
  var $el = angular.element;
  var isDef = angular.isDefined;
  var forEach = angular.forEach;
  /**
   * Extends the destination objec 'dst' by copying all of the properties from the 'src' object(s)
   * to 'dst'. Multiple src objects could be specified. 'undefined' values are not copied.
   *
   * @param {Object} dst The destination object.
   * @param {Object} src The spurce object.
   * @returns {Object} Reference to 'dst'.
   */
  var extend_ = function extend(dst, src) {
    forEach(arguments, function(obj) {
      if (obj !== src) {
        forEach(obj, function(value, key) {
          if (isDef(value)) {
            dst[key] = value;
          }
        });
      }
    });
  };
  /*module.provider('nsPopover', function() {
    var defaults_ = this.default_ = {
      placement: 'right',
      plain: false
    };
    var globalId_ = 0;
    this.$get('$document','$templateCache', '$compile', '$q', '$http', '$rootScope', '$timeout',
      function ($document, $templateCache, $compile, $q, $http, $rootScope, $timeout) {
        var $body = $document.find('body');
        var methods_ = {
          show: function(opts) {
            var options = angular.copy(defaults_);
            opts = opts || {};
            extend_(options, opts);
            globalId_ += 1;
            var scope = angular.isObject(options.scope) ? options.scope : $rootScope.$new();
            var $popover;
            $q.when(loadTemplate(options.template)).then(function(template) {
              template = angular.isString(template) ?
                template :
                template.data && angular.isString(template.data) ?
                  template.data :
                  '';
              $popover = $el('
 class="ns-popover" id="ns-popover' + globalId_ + '">
');
              $popover.html(template);
              if (options.theme) {
                $popover.addClass(options.theme);
              }
              $timeout(function() {
                $compile($popover)(scope);
              });
              scope.$on('$destroy', function() {
                $popover.remove();
              });
              $body.append($popover);
              return methods_;
            });
            function loadTemplate(template) {
              if (!template) {
                return 'Empty template';
              }
              if (angular.isString(template) && options.plain) {
                return template;
              }
              return $templateCache.get(template) || $http.get(template, { cache : true });
            }
          }
        }
      });
  });*/
  module.directive('nsPopover', function($timeout, $templateCache, $q, $http, $compile, $document) {
    return {
      restrict: 'A',
      link: function(scope, elm, attrs) {
        var options = {
          template: attrs.nsPopoverTemplate,
          theme: attrs.nsPopoverTheme || 'ns-popover-default-theme',
          plain: attrs.nsPopoverPlain,
          trigger: attrs.nsPopoverTrigger || 'click',
          container: attrs.nsPopoverContainer
        };
        var timeoutId_ = {};
        var $container = $el(options.container);
        if (!$container.length) {
          $container = $document.find('body');
        }
        var $popover = $el('');
        $q.when(loadTemplate(options.template)).then(function(template) {
          template = angular.isString(template) ?
            template :
            template.data && angular.isString(template.data) ?
              template.data :
              '';
          $popover.html(template);
          if (options.theme) {
            $popover.addClass(options.theme);
          }
          $timeout(function() {
            $compile($popover)(scope);
          });
          scope.$on('$destroy', function() {
            $popover.remove();
          });
          $popover
            .css('position', 'absolute')
            .css('display', 'none');
          $container.append($popover);
        });
        elm.on(options.trigger, function(e) {
          e.preventDefault();
          $timeout.cancel(timeoutId_);
          var rect = elm[0].getBoundingClientRect();
          $popover
            .css('display', 'block')
            .css('top', rect.bottom + 1 + 'px')
            .css('left', rect.left + 'px');
          $popover.on('click', function() {
            timeoutId_ = hide(0);
          });
        });
        $popover
          .on('mouseout', function(e) {
            timeoutId_ = hide();
          })
          .on('mouseover', function() {
            $timeout.cancel(timeoutId_);
          });
        function hide(delay) {
          $timeout.cancel(timeoutId_);
          // delay the hide to 1.5s by default.
          if (!isDef(delay)) {
            delay = 1500;
          }
          return $timeout(function() {
            $popover.css('display', 'none');
          }, delay);
        }
        function loadTemplate(template) {
          if (!template) {
            return '';
          }
          if (angular.isString(template) && options.plain) {
            return template;
          }
          return $templateCache.get(template) || $http.get(template, { cache : true });
        }
      }
    };
  });
})(window, window.angular);