text: 'use strict';
  angular.module('ngAudio', [])
  .directive('ngAudio', ['$compile', '$q', 'ngAudio', function($compile, $q, ngAudio) {
      return {
          restrict: 'AEC',
          scope: {
              volume: '=',
              start: '=',
              currentTime: '=',
              loop: '=',
              clickPlay: '='
          },
          controller: function($scope, $attrs, $element, $timeout) {
  
              var audio = ngAudio.load($attrs.ngAudio);
              $scope.$audio = audio;
              // audio.unbind();
              
              $element.on('click', function() {
                  if ($scope.clickPlay === false) {
                      return;
                  }
  
                  audio.audio.play();
                  
                  audio.volume = $scope.volume || audio.volume;
                  audio.loop = $scope.loop;
                  audio.currentTime = $scope.start || 0;
  
                  $timeout(function() {
                      audio.play();
                  }, 5);
              });
          }
      };
  }])
  
  .service('localAudioFindingService', ['$q', function($q) {
  
      this.find = function(id) {
          var deferred = $q.defer();
          var $sound = document.getElementById(id);
          if ($sound) {
              deferred.resolve($sound);
          } else {
              deferred.reject(id);
          }
  
          return deferred.promise;
      };
  }])
  
  .service('remoteAudioFindingService', ['$q', function($q) {
  
      this.find = function(url) {
          var deferred = $q.defer();
          var audio = new Audio();
  
          audio.addEventListener('error', function() {
              deferred.reject();
          });
  
          audio.addEventListener('loadstart', function() {
              deferred.resolve(audio);
          });
  
          // bugfix for chrome...
          setTimeout(function() {
              audio.src = url;
          }, 1);
  
          return deferred.promise;
  
      };
  }])
  
  .service('cleverAudioFindingService', ['$q', 'localAudioFindingService', 'remoteAudioFindingService', function($q, localAudioFindingService, remoteAudioFindingService) {
      this.find = function(id) {
          var deferred = $q.defer();
  
          id = id.replace('|', '/');
  
          localAudioFindingService.find(id)
              .then(deferred.resolve, function() {
                  return remoteAudioFindingService.find(id);
              })
              .then(deferred.resolve, deferred.reject);
  
          return deferred.promise;
      };
  }])
  
  .value('ngAudioGlobals', {
      muting: false,
      songmuting: false,
      performance: 25,
      unlock: true
  })
  
  .factory('NgAudioObject', ['cleverAudioFindingService', '$rootScope', '$interval', '$timeout', 'ngAudioGlobals', function(cleverAudioFindingService, $rootScope, $interval, $timeout, ngAudioGlobals) {
      return function(id) {
  
          if (ngAudioGlobals.unlock) {
  
              window.addEventListener("click",function twiddle(){
                  audio.play();
                  audio.pause();
                  window.removeEventListener("click",twiddle);
              });
          
          }
  
  
          var $audioWatch,
              $willPlay = false,
              $willPause = false,
              $willRestart = false,
              $volumeToSet,
              $looping,
              $isMuting = false,
              $observeProperties = true,
              audio,
              audioObject = this;
  
          this.id = id;
          this.safeId = id.replace('/', '|');
          this.loop = 0;
  
          this.unbind = function() {
              $observeProperties = false;
          };
  
          this.play = function() {
              $willPlay = true;
          };
  
          this.pause = function() {
              $willPause = true;
          };
  
          this.restart = function() {
              $willRestart = true;
          };
  
          this.stop = function() {
              this.restart();
          };
  
          this.setVolume = function(volume) {
              $volumeToSet = volume;
          };
  
          this.setMuting = function(muting) {
              $isMuting = muting;
          };
  
          this.setProgress = function(progress) {
              if (audio && audio.duration) {
                  audio.currentTime = audio.duration * progress;
              }
          };
  
          this.setCurrentTime = function(currentTime) {
              if (audio && audio.duration) {
                  audio.currentTime = currentTime;
              }
          };
  
          function $setWatch() {
              $audioWatch = $rootScope.$watch(function() {
                  return {
                      volume: audioObject.volume,
                      currentTime: audioObject.currentTime,
                      progress: audioObject.progress,
                      muting: audioObject.muting,
                      loop: audioObject.loop,
                  };
              }, function(newValue, oldValue) {
                  if (newValue.currentTime !== oldValue.currentTime) {
                      audioObject.setCurrentTime(newValue.currentTime);
                  }
  
                  if (newValue.progress !== oldValue.progress) {
                      audioObject.setProgress(newValue.progress);
                  }
                  if (newValue.volume !== oldValue.volume) {
                      audioObject.setVolume(newValue.volume);
                  }
  
                  if (newValue.volume !== oldValue.volume) {
                      audioObject.setVolume(newValue.volume);
                  }
  
                  $looping = newValue.loop;
  
                  if (newValue.muting !== oldValue.muting) {
                      audioObject.setMuting(newValue.muting);
                  }
              }, true);
          }
  
          cleverAudioFindingService.find(id)
              .then(function(nativeAudio) {
                  audio = nativeAudio;
                  audio.addEventListener('canplay', function() {
                      audioObject.canPlay = true;
                  });
              }, function(error) {
                  audioObject.error = true;
                  console.warn(error);
              });
  
  
          $interval(function() {
              if ($audioWatch) {
                  $audioWatch();
              }
              if (audio) {
  
                  if ($isMuting || ngAudioGlobals.isMuting) {
                      audio.volume = 0;
                  } else {
                      audio.volume = audioObject.volume !== undefined ? audioObject.volume : 1;
                  }
  
                  if ($willPlay) {
                      audio.play();
                      $willPlay = false;
                  }
  
                  if ($willRestart) {
                      audio.pause();
                      audio.currentTime = 0;
                      $willRestart = false;
                  }
  
                  if ($willPause) {
                      audio.pause();
                      $willPause = false;
                  }
  
                  if ($volumeToSet) {
                      audio.volume = $volumeToSet;
                      $volumeToSet = undefined;
                  }
  
                  if ($observeProperties) {
                      audioObject.currentTime = audio.currentTime;
                      audioObject.duration = audio.duration;
                      audioObject.remaining = audio.duration - audio.currentTime;
                      audioObject.progress = audio.currentTime / audio.duration;
                      audioObject.paused = audio.paused;
                      audioObject.src = audio.src;
  
                      if ($looping && audioObject.currentTime >= audioObject.duration) {
                          if ($looping !== true) {
                              $looping--;
                              audioObject.loop--;
                              // if (!$looping) return;
                          }
                          audioObject.setCurrentTime(0);
                          audioObject.play();
  
                      }
                  }
  
                  if (!$isMuting && !ngAudioGlobals.isMuting) {
                      audioObject.volume = audio.volume;
                  }
  
                  audioObject.audio = audio;
              }
  
              $setWatch();
          }, ngAudioGlobals.performance);
      };
  }])
  .service('ngAudio', ['NgAudioObject', 'ngAudioGlobals', function(NgAudioObject, ngAudioGlobals) {
      this.play = function(id) {
  
          var audio = new NgAudioObject(id);
          audio.play();
          return audio;
      };
  
      this.load = function(id) {
          return new NgAudioObject(id);
      };
  
      this.mute = function() {
          ngAudioGlobals.muting = true;
      };
  
      this.unmute = function() {
          ngAudioGlobals.muting = false;
      };
  
      this.toggleMute = function() {
          ngAudioGlobals.muting = !ngAudioGlobals.muting;
      };
  }]);
  