text: angular.module('cgBusy',[]);
  
  //loosely modeled after angular-promise-tracker
  angular.module('cgBusy').factory('_cgBusyTrackerFactory',['$timeout','$q',function($timeout,$q){
  
      return function(){
  
          var tracker = {};
          tracker.promises = [];
          tracker.delayPromise = null;
          tracker.durationPromise = null;
          tracker.delayJustFinished = false;
  
          tracker.reset = function(options){
              tracker.minDuration = options.minDuration;
  
              tracker.promises = [];
              angular.forEach(options.promises,function(p){
                  if (!p || p.$cgBusyFulfilled) {
                      return;
                  }
                  addPromiseLikeThing(p);
              });
  
              if (tracker.promises.length === 0) {
                  //if we have no promises then dont do the delay or duration stuff
                  return;
              }
  
              tracker.delayJustFinished = false;
              if (options.delay) {
                  tracker.delayPromise = $timeout(function(){
                      tracker.delayPromise = null;
                      tracker.delayJustFinished = true;
                  },parseInt(options.delay,10));
              }
              if (options.minDuration) {
                  tracker.durationPromise = $timeout(function(){
                      tracker.durationPromise = null;
                  },parseInt(options.minDuration,10) + (options.delay ? parseInt(options.delay,10) : 0));
              }            
          };
  
          tracker.isPromise = function(promiseThing){
              var then = promiseThing && (promiseThing.then || promiseThing.$then ||
                  (promiseThing.$promise && promiseThing.$promise.then));
  
              return typeof then !== 'undefined';            
          };
  
          tracker.callThen = function(promiseThing,success,error){
              var promise;
              if (promiseThing.then || promiseThing.$then){
                  promise = promiseThing;
              } else if (promiseThing.$promise){
                  promise = promiseThing.$promise;
              } else if (promiseThing.denodeify){
                  promise = $q.when(promiseThing);
              }
                         
              var then = (promise.then || promise.$then);
  
              then.call(promise,success,error);
          };
  
          var addPromiseLikeThing = function(promise){
  
              if (!tracker.isPromise(promise)) {
                  throw new Error('cgBusy expects a promise (or something that has a .promise or .$promise');
              }
  
              if (tracker.promises.indexOf(promise) !== -1){
                  return;
              }
              tracker.promises.push(promise);
  
              tracker.callThen(promise, function(){
                  promise.$cgBusyFulfilled = true;
                  if (tracker.promises.indexOf(promise) === -1) {
                      return;
                  }
                  tracker.promises.splice(tracker.promises.indexOf(promise),1);
              },function(){
                  promise.$cgBusyFulfilled = true;
                  if (tracker.promises.indexOf(promise) === -1) {
                      return;
                  }
                  tracker.promises.splice(tracker.promises.indexOf(promise),1);
              });
          };
  
          tracker.active = function(){
              if (tracker.delayPromise){
                  return false;
              }
  
              if (!tracker.delayJustFinished){
                  if (tracker.durationPromise){
                      return true;
                  }
                  return tracker.promises.length > 0;
              } else {
                  //if both delay and min duration are set, 
                  //we don't want to initiate the min duration if the 
                  //promise finished before the delay was complete
                  tracker.delayJustFinished = false;
                  return tracker.promises.length > 0;
              }
          };
  
          return tracker;
  
      };
  }]);
  
  angular.module('cgBusy').value('cgBusyDefaults',{});
  
  angular.module('cgBusy').directive('cgBusy',['$compile','$templateCache','cgBusyDefaults','$http','_cgBusyTrackerFactory',
      function($compile,$templateCache,cgBusyDefaults,$http,_cgBusyTrackerFactory){
          return {
              restrict: 'A',
              link: function(scope, element, attrs, fn) {
  
                  //Apply position:relative to parent element if necessary
                  var position = element.css('position');
                  if (position === 'static' || position === '' || typeof position === 'undefined'){
                      element.css('position','relative');
                  }
  
                  var templateElement;
                  var backdropElement;
                  var currentTemplate;
                  var templateScope;
                  var backdrop;
                  var tracker = _cgBusyTrackerFactory();
  
                  var defaults = {
                      templateUrl: 'angular-busy.html',
                      delay:0,
                      minDuration:0,
                      backdrop: true,
                      message:'Please Wait...',
                      wrapperClass: 'cg-busy cg-busy-animation'
                  };
  
                  angular.extend(defaults,cgBusyDefaults);
  
                  scope.$watchCollection(attrs.cgBusy,function(options){
  
                      if (!options) {
                          options = {promise:null};
                      }
  
                      if (angular.isString(options)) {
                          throw new Error('Invalid value for cg-busy. cgBusy no longer accepts string ids to represent promises/trackers.');
                      }
  
                      //is it an array (of promises) or one promise
                      if (angular.isArray(options) || tracker.isPromise(options)) {
                          options = {promise:options};
                      }
  
                      options = angular.extend(angular.copy(defaults),options);
  
                      if (!options.templateUrl){
                          options.templateUrl = defaults.templateUrl;
                      }
  
                      if (!angular.isArray(options.promise)){
                          options.promise = [options.promise];
                      }
  
                      // options.promise = angular.isArray(options.promise) ? options.promise : [options.promise];
                      // options.message = options.message ? options.message : 'Please Wait...';
                      // options.template = options.template ? options.template : cgBusyTemplateName;
                      // options.minDuration = options.minDuration ? options.minDuration : 0;
                      // options.delay = options.delay ? options.delay : 0;
  
                      if (!templateScope) {
                          templateScope = scope.$new();
                      }
  
                      templateScope.$message = options.message;
  
                      if (!angular.equals(tracker.promises,options.promise)) {
                          tracker.reset({
                              promises:options.promise,
                              delay:options.delay,
                              minDuration: options.minDuration
                          });
                      }
  
                      templateScope.$cgBusyIsActive = function() {
                          return tracker.active();
                      };
  
  
                      if (!templateElement || currentTemplate !== options.templateUrl || backdrop !== options.backdrop) {
  
                          if (templateElement) {
                              templateElement.remove();
                          }
                          if (backdropElement){
                              backdropElement.remove();
                          }
  
                          currentTemplate = options.templateUrl;
                          backdrop = options.backdrop;
  
                          $http.get(currentTemplate,{cache: $templateCache}).success(function(indicatorTemplate){
  
                              options.backdrop = typeof options.backdrop === 'undefined' ? true : options.backdrop;
  
                              if (options.backdrop){
                                  var backdrop = '<div class="cg-busy cg-busy-backdrop cg-busy-backdrop-animation ng-hide" ng-show="$cgBusyIsActive()"></div>';
                                  backdropElement = $compile(backdrop)(templateScope);
                                  element.append(backdropElement);
                              }
  
                              var template = '<div class="'+options.wrapperClass+' ng-hide" ng-show="$cgBusyIsActive()">' + indicatorTemplate + '</div>';
                              templateElement = $compile(template)(templateScope);
  
                              angular.element(templateElement.children()[0])
                                  .css('position','absolute')
                                  .css('top',0)
                                  .css('left',0)
                                  .css('right',0)
                                  .css('bottom',0);
                              element.append(templateElement);
  
                          }).error(function(data){
                              throw new Error('Template specified for cgBusy ('+options.templateUrl+') could not be loaded. ' + data);
                          });
                      }
  
                  },true);
              }
          };
      }
  ]);
  
  