/*
 ngprogress 1.1.2 - slim, site-wide progressbar for AngularJS 
 (C) 2013 - Victor Bjelkholm 
 License: MIT 
 Source: https://github.com/VictorBjelkholm/ngProgress 
 Date Compiled: 2015-07-27 
 */
angular.module('ngProgress.provider', ['ngProgress.directive'])
    .service('ngProgress', function () {
      'use strict';
      return ['$document', '$window', '$compile', '$rootScope', '$timeout', function($document, $window, $compile, $rootScope, $timeout) {
        this.autoStyle = true;
        this.count = 0;
        this.height = '2px';
        this.$scope = $rootScope.$new();
        this.color = '#bbb';
        this.parent = $document.find('body')[0];
        this.count = 0;

        // Compile the directive
        this.progressbarEl = $compile('<ng-progress></ng-progress>')(this.$scope);
        // Add the element to body
        this.parent.appendChild(this.progressbarEl[0]);
        // Set the initial height
        this.$scope.count = this.count;
        // If height or color isn't undefined, set the height, background-color and color.
        if (this.height !== undefined) {
          this.progressbarEl.eq(0).children().css('height', this.height);
        }
        if (this.color !== undefined) {
          this.progressbarEl.eq(0).children().css('background-color', this.color);
          this.progressbarEl.eq(0).children().css('color', this.color);
        }
        // The ID for the interval controlling start()
        this.intervalCounterId = 0;

        // Starts the animation and adds between 0 - 5 percent to loading
        // each 400 milliseconds. Should always be finished with progressbar.complete()
        // to hide it
        this.start = function () {
          // TODO Use requestAnimationFrame instead of setInterval
          // https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame
          this.show();
          var self = this;
          clearInterval(this.intervalCounterId);
          this.intervalCounterId = setInterval(function () {
            if (isNaN(self.count)) {
              clearInterval(self.intervalCounterId);
              self.count = 0;
              self.hide();
            } else {
              self.remaining = 100 - self.count;
              self.count = self.count + (0.15 * Math.pow(1 - Math.sqrt(self.remaining), 2));
              self.updateCount(self.count);
            }
          }, 200);
        };
        this.updateCount = function (new_count) {
          this.$scope.count = new_count;
          if(!this.$scope.$$phase) {
            this.$scope.$apply();
          }
        };
        // Sets the height of the progressbar. Use any valid CSS value
        // Eg '10px', '1em' or '1%'
        this.setHeight = function (new_height) {
          if (new_height !== undefined) {
            this.height = new_height;
            this.$scope.height = this.height;
            if(!this.$scope.$$phase) {
              this.$scope.$apply();
            }
          }
          return this.height;
        };
        // Sets the color of the progressbar and it's shadow. Use any valid HTML
        // color
        this.setColor = function(new_color) {
          if (new_color !== undefined) {
            this.color = new_color;
            this.$scope.color = this.color;
            if(!this.$scope.$$phase) {
              this.$scope.$apply();
            }
          }
          return this.color;
        };
        this.hide = function() {
          this.progressbarEl.children().css('opacity', '0');
          var self = this;
          self.animate(function () {
            self.progressbarEl.children().css('width', '0%');
            self.animate(function () {
              self.show();
            }, 500);
          }, 500);
        };
        this.show = function () {
          var self = this;
          self.animate(function () {
            self.progressbarEl.children().css('opacity', '1');
          }, 100);
        };
        // Cancel any prior animations before running new ones.
        // Multiple simultaneous animations just look weird.
        this.animate = function(fn, time) {
          if(this.animation !== undefined) { $timeout.cancel(this.animation); }
          this.animation = $timeout(fn, time);
        };
        // Returns on how many percent the progressbar is at. Should'nt be needed
        this.status = function () {
          return this.count;
        };
        // Stops the progressbar at it's current location
        this.stop = function () {
          clearInterval(this.intervalCounterId);
        };
        // Set's the progressbar percentage. Use a number between 0 - 100.
        // If 100 is provided, complete will be called.
        this.set = function (new_count) {
          this.show();
          this.updateCount(new_count);
          this.count = new_count;
          clearInterval(this.intervalCounterId);
          return this.count;
        };
        this.css = function (args) {
          return this.progressbarEl.children().css(args);
        };
        // Resets the progressbar to percetage 0 and therefore will be hided after
        // it's rollbacked
        this.reset = function () {
          clearInterval(this.intervalCounterId);
          this.count = 0;
          this.updateCount(this.count);
          return 0;
        };
        // Jumps to 100% progress and fades away progressbar.
        this.complete = function () {
          this.count = 100;
          this.updateCount(this.count);
          var self = this;
          clearInterval(this.intervalCounterId);
          $timeout(function () {
            self.hide();
            $timeout(function () {
              self.count = 0;
              self.updateCount(self.count);
            }, 200);
          }, 500);
          return this.count;
        };
        // Set the parent of the directive, sometimes body is not sufficient
        this.setParent = function(newParent) {
          if(newParent === null || newParent === undefined) {
            throw new Error('Provide a valid parent of type HTMLElement');
          }

          if(this.parent !== null && this.parent !== undefined) {
            this.parent.removeChild(this.progressbarEl[0]);
          }

          this.parent = newParent;
          this.parent.appendChild(this.progressbarEl[0]);
        };
        // Gets the current element the progressbar is attached to
        this.getDomElement = function () {
          return this.progressbarEl;
        };
        this.setAbsolute = function() {
          this.progressbarEl.css('position', 'absolute');
        };
      }];
    })
    .factory('ngProgressFactory', ['$injector', 'ngProgress', function($injector, ngProgress) {
      var service = {
        createInstance: function () {
          return $injector.instantiate(ngProgress);
        }
      };
      return service;
    }]);
angular.module('ngProgress.directive', [])
    .directive('ngProgress', ["$window", "$rootScope", function ($window, $rootScope) {
      var directiveObj = {
        // Replace the directive
        replace: true,
        // Only use as a element
        restrict: 'E',
        link: function ($scope, $element, $attrs, $controller) {
          // Watch the count on the $rootScope. As soon as count changes to something that
          // isn't undefined or null, change the counter on $scope and also the width of
          // the progressbar. The same goes for color and height on the $rootScope
          $scope.$watch('count', function (newVal) {
            if (newVal !== undefined || newVal !== null) {
              $scope.counter = newVal;
              $element.eq(0).children().css('width', newVal + '%');
            }
          });
          $scope.$watch('color', function (newVal) {
            if (newVal !== undefined || newVal !== null) {
              $scope.color = newVal;
              $element.eq(0).children().css('background-color', newVal);
              $element.eq(0).children().css('color', newVal);
            }
          });
          $scope.$watch('height', function (newVal) {
            if (newVal !== undefined || newVal !== null) {
              $scope.height = newVal;
              $element.eq(0).children().css('height', newVal);
            }
          });
        },
        // The actual html that will be used
        template: '<div id="ngProgress-container"><div id="ngProgress"></div></div>'
      };
      return directiveObj;
    }]);

angular.module('ngProgress', ['ngProgress.directive', 'ngProgress.provider']);