/**
 * Created by intelWorx on 19/11/2015.
 */
(function () {
  'use strict';

  /**
   * Main module, your application should depend on this
   * @module {mdWavesurfer}
   */
  var app = angular.module('mdWavesurfer', ['ngMaterial']);

  /**
   * @ngdoc service
   * @name $mdWavesurferUtils
   *
   * @description
   *
   * Utility service for this directive, exposes method:
   *  - getLength(url), which returns a promise for the length of the audio specified by URL
   *
   * ```js
   * app.directive('myFancyDirective', function(mdWavesurferUtils) {
   *   return {
   *     restrict: 'e',
   *     link: function(scope, el, attrs) {
   *       mdWavesurferUtils(attrs.url)
   *       .then(function(l){
   *        scope.length = l;
   *       }, function(){
   *          someErrorhandler()
   *       })
   *       ;
   *     }
   *   };
   * });
   * ```
   */
  app.factory('mdWavesurferUtils', ['$q', '$document', '$timeout',
    function ($q, $document, $timeout) {
      return {
        getLength: function (object) {
          var deferred = $q.defer();
          var estimateLength = function (url) {
            var audio = $document[0].createElement('audio');
            audio.src = url;
            audio.addEventListener('loadeddata', function listener() {
              deferred.resolve(this.duration);
              audio.removeEventListener('loadeddata', listener);
              audio.src = 'data:audio/mpeg,0';//destroy loading.
            });

            audio.addEventListener('error', function (e) {
              deferred.resolve(e.target.error);
            });
          };

          if (typeof object === 'string') {
            //this is a URL
            estimateLength(object);
          } else {
            $timeout(function () {
              deferred.reject(new DOMError("NotSupportedError", "Specified argument is not supported"));
            });
          }

          return deferred.promise;
        }
      };
    }
  ]);

  /**
   * @ngdoc filter
   * @name mdWavesurferTimeFormat
   *
   * Simple filter to convert value in seconds to MM:SS format
   *
   * @param Number duration in seconds
   */
  app.filter('mdWavesurferTimeFormat', function () {
    return function (input) {
      if (!input) {
        return "00:00";
      }

      var minutes = Math.floor(input / 60);
      var seconds = Math.ceil(input) % 60;

      return (minutes < 10 ? '0' : '')
        + minutes
        + ":"
        + (seconds < 10 ? '0' : '') + seconds;
    };
  });


  app.controller('mdWavesurferAudioController', ['$attrs', '$element',
    function (attributes, $element) {
      var audio = this;

      audio.tracks = [];
      audio.selectedIndex = audio.selectedIndex || 0;
      audio.currentTrack = null;

      //adds to an audio track
      audio.addTrack = function (trackScope) {
        if (audio.tracks.indexOf(trackScope) < 0) {
          audio.tracks.push(trackScope);
        }

        if (!audio.currentTrack) {
          audio.currentTrack = audio.tracks[audio.selectedIndex];
        }
      };

      //remove audio track
      audio.removeTrack = function (trackScope) {
        var idx = audio.tracks.indexOf(trackScope);
        if (idx >= 0) {
          audio.tracks.splice(idx, 1);
        }
      };

      audio.playerProperties = {}
      var nKey;
      for (var attr in attributes) {
        if (attr.match(/^player/)) {
          nKey = attr.replace(/^player([A-Z])/, function (m, $1) {
            return $1.toLowerCase();
          });
          audio.playerProperties[nKey] = attributes[attr];
        }
      }

      var getPlayer = function(){
        return $element.find('md-wavesurfer-player').controller('mdWavesurferPlayer');
      };
      var setAutoPlay = function (forcePlay) {
        var controller = getPlayer();
        if (controller && (forcePlay || controller.surfer.isPlaying())) {
          controller.autoPlay = true;
        }
      };
      audio.setTrack = function (idx, forcePlay) {
        if (audio.tracks.length > idx) {
          if (audio.selectedIndex === idx) {
            var ctrl = getPlayer();
            ctrl.surfer.playPause();
          } else {
            setAutoPlay(forcePlay);
            audio.currentTrack = audio.tracks[idx];
            audio.selectedIndex = idx;
          }
        }
      };

      audio.extraButtons = [{
        icon: 'zmdi zmdi-skip-previous',
        title: 'Previous',
        action: function ($event) {
          if (audio.selectedIndex > 0) {
            audio.setTrack(audio.selectedIndex - 1);
          }
        },
        class: ''
      }, {
        icon: 'zmdi zmdi-skip-next',
        title: 'Next',
        action: function ($event) {
          if (audio.selectedIndex < audio.tracks.length - 1) {
            audio.setTrack(audio.selectedIndex + 1);
          }
        },
        class: ''
      }];


    }
  ]);

  /**
   * @ngdoc directive
   * @name md-wavesurfer-audio
   *
   * Directive for playing a set of audio files. This directive is analogous to `<audio>` HTML tag.
   * The audio files, should be specified using the  `md-wavesurfer-source`
   *
   * WaveSurfer properties can be passed in using the prefix : player-* for attributes, e.g. `player-wave-color` is
   * equivalent to WaveSurfer's waveColor option.
   *
   * Must be used as an element.
   *
   * @usage
   * ```html
   * <md-wavesurfer-audio player-wave-color="gray" player-progress-color="black" player-backend="MediaElement">
   *   <md-wavesurfer-source src="source1" title="Title-1"></md-wavesurfer-source>
   *   <md-wavesurfer-source src="source2" title="Title-2"></md-wavesurfer-source>
   *   <md-wavesurfer-source src="source3" title="Title-3"></md-wavesurfer-source>
   *   ...
   *   <md-wavesurfer-source src="sourceN" title="Рассказы о сновидениях"></md-wavesurfer-source>
   * </md-wavesurfer-audio>
   * ```
   *
   * @param string player-* specifies WaveSurfer properties.
   *
   */
  app.directive('mdWavesurferAudio', [
    function () {
      return {

        restrict: 'E',
        templateUrl: 'md-player-audio.partial.html',
        transclude: true,
        controller: 'mdWavesurferAudioController',
        controllerAs: 'audio'
      };
    }
  ]);

  /**
   * @ngdoc directive
   *
   * @name md-wavesurfer-source
   *
   * This directive is used within the `md-wavesurfer-audio` directive to specify an audio file source, it is
   * synonymous to `<source>` tag in HTML
   *
   * The directive cannot be used as standalone.
   *
   * @usage
   *
   * ```html
   *   <md-wavesurfer-source src="source3" title="Title-3" album-art="Album-Art-Url" duration=""></md-wavesurfer-source>
   * ```
   * @param String src the URL to the audio file, this is required.
   * @param String title track title
   * @param String album-art the album art URL
   * @param Number duration the length of the audio file in seconds, will be auto-detected if not specified.
   *
   */
  app.directive('mdWavesurferSource', ['mdWavesurferUtils',
    function (mdWavesurferUtils) {
      return {
        restrict: 'E',
        require: '^mdWavesurferAudio',
        scope: {
          src: '@',
          albumArt: '@',
          title: '@',
          duration: '='
        },
        link: function (scope, element, attrs, audio) {
          audio.addTrack(scope);

          if (!scope.duration) {
            mdWavesurferUtils.getLength(scope.src).then(function (dur) {
              scope.duration = dur;
            }, function (e) {
              scope.duration = 0;
              console.log('Failed to get audio length, reason: ', e.message);
            });
          }

          element.on('$destroy', function () {
            audio.removeTrack(audio);
          });
        }
      };
    }
  ]);

  app.controller('mdWavesurferPlayerController', ['$element', '$scope', '$attrs', '$interval', '$mdTheming',
    function ($element, $scope, attributes, $interval, $mdTheme) {
      var control = this, timeInterval;

      control.themeClass = "md-" + $mdTheme.defaultTheme() + "-theme";
      control.isReady = false;
      control.surfer = null;

      control.toggleMute = function () {
        if (control.surfer) {
          control.surfer.toggleMute();
          control.isMute = !control.isMute;
        }
      };

      var initWaveSurfer = function () {
        control.isReady = false;
        control.currentTime = 0;
        if (!control.surfer) {
          var options = {
            container: $element[0].querySelector('.waveSurferWave')
          }, defaults = {
            scrollParent: true,
            waveColor: 'violet',
            progressColor: 'purple'
          };

          options = angular.extend(defaults, attributes, (control.properties || {}), options);
          control.surfer = WaveSurfer.create(options);

          control.surfer.on('ready', function () {
            control.isReady = true;
            if (control.autoPlay) {
              control.surfer.play();
            }
            $scope.$apply();
          });

          control.surfer.on('pause', function () {
            stopInterval();
          });

          control.surfer.on('finish', function () {
            stopInterval();
          });

          control.surfer.on('play', function () {
            startInterval();
          });

        }

        control.title = control.title || control.src.split('/').pop();
        control.surfer.load(control.src);
      };

      var startInterval = function () {
        timeInterval = $interval(function () {
          control.currentTime = control.isReady ? control.surfer.getCurrentTime() : 0;
        }, 1000);
      }, stopInterval = function () {
        $interval.cancel(timeInterval);
      };


      initWaveSurfer();

      $scope.$watch('control.src', function (src1, src2) {
        if (src1 != src2) {
          initWaveSurfer();
        }
      });

      $element.on('$destroy', function () {
        if (control.surfer) {
          control.surfer.destroy();
        }
        stopInterval();
      });

      $scope.$watch(function () {
        var div = $element[0].querySelector('.audioPlayerWrapper');
        return div ? div.offsetWidth : 0;
      }, function (width) {
        if (width < 1) {
          //hidden
          control.surfer.pause();
        }
      });
    }
  ]);

  /**
   * @ngdoc directive
   *
   * @name md-wavesurfer-player
   *
   * @usage
   * This directive can be used as a stand-alone directive to display Audio WaveSurfer with a few controls, by default
   * this will only display play/pause, fast-forward, rewind and mute toggle buttons, however, you can add extra
   * buttons using the `extra-buttons` parameters.
   *
   * ```html
   *  <md-wavesurfer-player url="trackUrl" title="Track Title"
   *         extra-buttons="extraButtons" properties="properties">
   *  </md-wavesurfer-player>
   * ```
   *
   * @param {string} url the URL of the audio file
   * @param {string} title title of the audio track
   * @param {object} properties an object specifying init options for WaveSurfer
   * @param {boolean} auto-play specifies if the player should start as soon as it's loaded.
   * @param {object[]} extra-buttons a list of extra buttons to add to the control panel
   *    each button should be an object with the following properties:
   *    {
   *      title: "button title"
   *      action: "call back to call when button is clicked, executed in parent scope",
   *      icon: "md-font-icon parameter for the button"
   *      class: "extra classes to add to the button."
   *    }
   *
   * Every other attribute passed to this directive is assumed to a WaveSurver init parameter.
   */
  app.directive('mdWavesurferPlayer', function () {
    return {
      restrict: 'E',
      templateUrl: 'md-player.partial.html',
      scope: {
        src: '@url',
        title: '@',
        extraButtons: '=',
        toolbarClass: '@',
        autoPlay: '=',
        properties: '='
      },
      controller: 'mdWavesurferPlayerController',
      controllerAs: 'control',
      bindToController: true
    };
  });
  ;
})();