/* 
 * WPaudio v4.0.0 (http://wpaudio.com)
 * by Todd Iceton (todd@wpaudio.com)
 *
 * Converts an mp3 link to a simple player styled by HTML & CSS, powered by HTML5
 *
 * Copyright 2011 Todd Iceton (email: todd@wpaudio.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */


/*
 * Player CSS
 */
_wpaudio.css = {
  inline: {
    '.wpaudio-container': {
      display: 'inline-block',
      'font-family': 'Sans-serif',
      'line-height': 1,
      zoom: 1
    },
    '.wpaudio-container a': {
      color: _wpaudio.style.link_color,
      'text-decoration': 'none'
    },
    '.wpaudio-container .wpaudio': {
      'font-family': _wpaudio.style.text_font,
      'font-size': _wpaudio.style.text_size,
      'font-weight': _wpaudio.style.text_weight,
      'letter-spacing': _wpaudio.style.text_letter_spacing
    },
    '.wpaudio-play': {
      display: 'inline-block',
      margin: '0 5px 0 0',
      width: '14px',
      height: '13px',
      background: '#ccc',
      'vertical-align': 'baseline'
    },
    '.wpaudio-slide': {
      display: 'none'
    },
    '.wpaudio-bar': {
      position: 'relative',
      margin: '2px 0 0 19px',
      height: '5px',
      'font-size': '1px',
      background: _wpaudio.style.bar_base_bg
    },
    '.wpaudio-bar-playable': {
      position: 'absolute',
      top: 0,
      left: 0,
      right: '100%',
      height: '5px',
      'z-index': 11,
      background: _wpaudio.style.bar_load_bg
    },
    '.wpaudio-bar-position': {
      position: 'absolute',
      top: 0,
      left: 0,
      right: '100%',
      height: '5px',
      'z-index': 12,
      background: _wpaudio.style.bar_position_bg
    },
    '.wpaudio-bar-click': {
      position: 'absolute',
      top: 0,
      left: 0,
      right: 0,
      width: '100%',
      height: '5px',
      'z-index': 13,
      cursor: 'pointer'
    },
    '.wpaudio-meta': {
      margin: '3px 0 0 19px',
      'font-size': '11px',
      color: _wpaudio.style.sub_color
    },
    '.wpaudio-download': {
      float: 'right'
    }
  },
  head: {
    '.wpaudio-container a:visited': {
      color: _wpaudio.style.link_color
    },
    '.wpaudio-container a:hover': {
      color: _wpaudio.style.link_hover_color
    }
  },
  default: {
    border: 0,
    margin: 0,
    padding: 0
  }
};


/*
 * Append CSS to head
 */
(function($){
  /*var css = 
    '.wpaudio-container {display:inline-block; zoom:1; *display:inline; line-height: 1; font-family: Sans-serif; font-size: 18px; line-height: 1;}' +
    '.wpaudio-container a, .wpaudio-container a:visited {color: #06c; text-decoration: none;}' +
    '.wpaudio-container a:hover {color: #03a;}' + 
    '.wpaudio-play {margin: 0 5px 0 0; border: 0; width: 14px; height: 13px; background: #666; vertical-align: baseline;}' +
    '.wpaudio-slide {display: none;}' +
    '.wpaudio-bar {position: relative; margin: 2px 0 0 19px; height: 5px; font-size: 1px; background: #eee;}' +
    '.wpaudio-bar-playable {position: absolute; top: 0; left: 0; right: 100%; height: 5px; z-index: 11; background: #ccc;}' +
    '.wpaudio-bar-position {position: absolute; top: 0; left: 0; right: 100%; height: 5px; z-index: 12; background: #06c;}' +
    '.wpaudio-bar-click {position: absolute; top: 0; left: 0; right: 0; width: 100%; height: 5px; z-index: 12; cursor: pointer;}' +
    '.wpaudio-meta {margin: 3px 0 0 19px; font-size: 11px; color: #888;}' +
    '.wpaudio-download {float: right;}';*/
  var css = $.map($.extend({}, _wpaudio.css.inline, _wpaudio.css.head), function(rules, selector) {
    var renderedRules = $.map($.extend({}, _wpaudio.css.default, rules), function (val, prop) {
      return [prop, val].join(':');
    }).join(';');
    return selector + '{' + renderedRules + '}';
  }).join('');
  $('head').append('<style type="text/css">' + css + '</style>');
}(jQuery));


/* 
 * WPaudio common parent that will be appended to the mp3 link
 *
 * All interaction happens through this object, which calls the child players' control methods.
 * This takes care of click event listening and link decoration.
 */
function Wpaudio (elem) {
  this.elem = elem;
  var player;
  this.player = player;
  var $el = jQuery(elem);
  
  function getUrl() {
    return _wpaudio.enc[elem.id] ? _wpaudio.enc[elem.id] : elem.href;
  };
  this.getUrl = getUrl;
  
  function isPlaying() {
    return player.isPlaying();
  };
  this.isPlaying = isPlaying;
  
  function play() {
    // Pause all playing players before starting this one
    jQuery('.wpaudio-playing').each(function(i,v){ v.wpaudio.pause(); });
    player.play();
    // Add class and slide down
    $el.addClass('wpaudio-playing').parent().find('.wpaudio-slide:hidden').slideDown();
  };
  this.play = play;
  
  function pause() {
    player.pause();
    $el.removeClass('wpaudio-playing');
  };
  this.pause = pause;
  
  function seek(percent) {
    if (!isPlaying()) {
      play();
    }
    player.seek(percent);
  };
  this.seek = seek;
  
  // Update button image, progress bars, time
  function updateDisplay() {
    // Get info from player
    var info = player.getInfo();
    // Add/remove class if no click
    $el[info.is_playing ? 'addClass' : 'removeClass']('wpaudio-playing');
    // Set button image based on play/pause (check current and change if necessary)
    var button_url = _wpaudio.url + (info.is_playing ? '/wpaudio-pause.png' : '/wpaudio-play.png');
    if ( button_url !== $el.children('.wpaudio-play').attr('src') ) {
      // Change alt tag too
      var url_pieces = button_url.split('-');
      $el.children('.wpaudio-play').attr({
        alt: 'P' + url_pieces[url_pieces.length - 1].split('.')[0].slice(1),
        src: button_url
      });
    }
    // Set bar positions
    $el.parent().find('.wpaudio-bar-position').css({
      left: String((info.playable_start/info.duration) || 0) + '%',
      width: String((info.position - info.playable_start) / info.duration * 100 || 0) + '%'
    });
    $el.parent().find('.wpaudio-bar-playable').css({
      left: String((info.playable_start/info.duration) || 0) + '%',
      width: String((info.playable_end - info.playable_start) / info.duration * 100 || 0) + '%'
    });
    
    // Set time
    var min = Math.floor(info.position / 60);
    var sec = Math.floor(info.position % 60);
    var time_string = min + ':';
    if ( sec < 10 ) {
      time_string += '0'; // Add leading 0 to seconds if necessary
    }
    time_string += sec;
    $el.parent().find('.wpaudio-position').text(time_string);
  };
  this.updateDisplay = updateDisplay;
  
  // Define the slider HTML so the next bit doesn't get too messy
  var slider =
    '<div class="wpaudio-slide">' +
      '<div class="wpaudio-bar">' +
        '<div class="wpaudio-bar-playable"></div>' +
        '<div class="wpaudio-bar-position"></div>' +
        '<div class="wpaudio-bar-click"></div>' +
      '</div>' +
      '<div class="wpaudio-meta">' +
        String( $el.hasClass('wpaudio-nodl') ? '' : '<a class="wpaudio-download" href="' + elem.href + '">Download</a>' ) +
        '<div class="wpaudio-position"></div>' +
      '</div>' +
    '</div>';
  
  // Toggle play/pause on click and style the player
  $el.click(function(){
    isPlaying() ? pause() : play();
    jQuery(this).blur();
    return false;
  }).prepend('<img class="wpaudio-play" alt="Play" src="' + _wpaudio.url + '/wpaudio-play.png"/>').wrap('<span class="wpaudio-container"></span>').after(slider);

  // Fix slide width for IE -- in a timeout b/c Chrome shits otherwise
  $el.parent().children('.wpaudio-slide').width($el.width());

  // Click bar to seek
  $el.parent().find('.wpaudio-bar-click').mouseup(function (e) {
    if ( e.pageX ) {
      var percent = ( e.pageX - jQuery(this).offset().left ) / jQuery(this).width();
      seek(percent);
    }
  });
  
  // Initialize the player
  player = new this.Player(this);
}

/*
 * HTML5 player
 *
 * This contains controls and event handling for the native player
 */
function WpaudioHTML5 (parent) {
  var player = document.createElement('audio');
  this.player = player;
  
  this.parent = parent;
  player.src = parent.getUrl();
  player.volume = 1;
  jQuery(player).bind('play pause ended timeupdate progress canplaythrough', parent.updateDisplay);
    
  function isPlaying() {
    return !player.paused;
  };
  this.isPlaying = isPlaying;
  
  function getInfo() {
    var pos, dur, start, end;
    try {
      pos = player.currentTime;
      dur = player.duration;
      start = player.buffered.start(0);
      end = player.buffered.end(0);
    }
    catch (e) {
      pos = 0;
      dur = 0;
      start = 0;
      end = 0;
    }
    return {
      is_playing: isPlaying(),
      position: pos,
      duration: dur,
      playable_start: start,
      playable_end: end
    };
  };
  this.getInfo = getInfo;
  
  function play() {
    player.play();
  };
  this.play = play;
  
  this.pause = function() {
    player.pause();
  };
  
  this.seek = function(fraction) {
    player.currentTime = player.duration * fraction;
  };
  
  return this;
}


/*
 * WPaudio ready
 *
 * When WPaudio is loaded, style and autoplay. Consider moving autoplay to the Wpaudio object (play if autoplay and no .wpaudio-playing).
 */
function wpaudioReady () {
  // Apply CSS
  jQuery.each( _wpaudio.css.inline, function ( css_group, css_rules ) {
    jQuery( css_group ).css( css_rules );
    // Zero margin, border, and padding if they're not specified
    if ( !css_rules.margin ) {
      jQuery( css_group ).css('margin', 0);
    }
    if ( !css_rules.border ) {
      jQuery( css_group ).css('border', 0);
    }
    if ( !css_rules.padding ) {
      jQuery( css_group ).css('padding', 0);
    }
  });
  // Autoplay
  if ( jQuery('.wpaudio-autoplay:first').length ) {
    jQuery('.wpaudio-autoplay:first')[0].wpaudio.play();
  }
}


/*
 * Initialize WPaudio players
 *
 * Detect HTML5 support, set WPaudio player to either HTML5 or SM2, and initialize WPaudio players
 */
jQuery(document).ready(function(){
  var wpaudio_selector = '.wpaudio, .wpaudio-autoplay';
  // Handle all mp3 links if selected
  if ( _wpaudio.convert_mp3_links ) {
    jQuery('a[href$=".mp3"]').addClass('wpaudio');
  }
  // Detect HTML5
  var _wpaudio_html5 = document.createElement('audio');
  if (!!(_wpaudio_html5.canPlayType && _wpaudio_html5.canPlayType('audio/mpeg;').replace(/no/, ''))) {
    Wpaudio.prototype.Player = WpaudioHTML5;
    jQuery(wpaudio_selector).each(function(i,v){
      v.wpaudio = new Wpaudio(v);
    });
    wpaudioReady();
  }
});


// Preload play + pause images -- play first!
(function(){
  var play = new Image(), pause = new Image();
  play.src = _wpaudio.url + '/wpaudio-play.png';
  jQuery(play).load(function() {
    pause.src = _wpaudio.url + '/wpaudio-pause.png';
  });
}());
