/* vim: expandtab sw=2 ts=2 ai list */

Array.prototype.unshiftA = function(v) {
	this.unshift(v);

	return this;
}

// From Prototypejs.org
function $A(iterable) {
	if (!iterable) return [];
	if (iterable.toArray) return iterable.toArray();
	var length = iterable.length || 0, results = new Array(length);
	while (length--) results[length] = iterable[length];
	return results;
}


/**
 * Javascript interface for flash "JW Player"
 *
 * @author  Nicolas Toniazzi <nicolas@toniazzi.net>
 * @version 0.1
 * @license TODO
 */
(function($){
  var player   = null;  // reference to player
  var info     = null;  // reference to actual playlist item
  var t        = null;  // waiting timeout reference
  var s        = null;  // waiting start date
  var x        = 0;     // refresh counter
	var dragging = false; // true when the user is moving the slider

	var eventHandlers = {
		STATE:  stateChange,
		LOADED: songLoading,
		// ERROR:  console.error,
		TIME:   progress
	}

  function createPlayer(id) {
    var flashvars = {
			id:       "player1",
      file:     "music/playlist.xml", 
      autostart:"false"
    }
    var params = {
      allowfullscreen:  "true", 
      allowscriptaccess:"always"
    }
    var attributes = {
      id:   "player1",  
      name: "player1"
    }
    
    swfobject.embedSWF("player.swf", id, "320", "196", "9.0.115", false, flashvars, params, attributes);
  }

  /**
   * Called when the flash player has been loaded
   *
   * @access public
   * @param  Object
   * @return void
   */
	function playerReady(thePlayer) {
		//console.log("running playerReady");
    player = document.getElementById(thePlayer.id);

		// Register event handlers
		//console.log("placing event handlers");
		jQuery.each(eventHandlers, function(k) {
				// console.log("event " + k);
			var func = '(function(){handlePlayerEvent.apply(null,$A(arguments).unshiftA("'+k+'"));})';
			player.addModelListener(k, func);
		});

    waitForPlaylist();
  }

	/**
   * Generic public callback for handling events
   *
   * @access public
   * @param  string Event name
   * @param  mixed
   * @return void
   */
	function handleEvent() {
		var args = $A(arguments);
		var e = args.shift();
		if(undefined != eventHandlers[e]) {
			eventHandlers[e].apply(null, args);
		}
		else {
			// console.log('Event '+e+' not handled');
		}
	}

	/**
   * Update slider position
   *
   * @access private
   */
  function progress(o) {
    // refresh only every 1/2 second
    if(x++ < 5) { return; }

		// Don't refresh is user is moving the slider
		if (dragging) { return; }

    // reset counter
    x = 0;

    if(info) {
      var i        = player.getConfig().item;
      var song     = player.getPlaylist()[i];
      var duration = song.duration;

      // update slider
      info.find('.track').slider('value', o.position / song.duration * 100);
    }
  }

	/**
   * Wait for the playlist to load
   */
  function waitForPlaylist() {
		// console.log("> waitForPlaylist");
    if(null == s) s = new Date().getTime();
		// console.log("s=" + s);

    // console.log('waiting... ');
		try {
			var pl = player.getPlaylist();
		}
		catch(e) {
			// console.error(e);
		}

    if(null == pl) {
      if(new Date().getTime() - s > 4000) {
        s = null;
        // console.log('TIMEOUT');
        return;
      }
			// console.log('waiting 100ms');
      t = setTimeout(waitForPlaylist, 100);
    }
    else {
      clearTimeout(t);
			// console.log("playlist loaded, building");
      buildList();
      s = null;
    }
  }

	/**
   * Show song loading progress
   */
  function songLoading(o) {
    // console.log('Loading: '+parseInt(o.loaded/o.total*100)+'%');
  }

	/**
   * Build HTML list from player's playlist
   */
  function buildList() {
		// console.log("Build list of " + player.getPlaylist().length + " items.");
    var list = jQuery('#list').empty();

    var playlist = player.getPlaylist();
    jQuery.each(playlist, function(i,o){
      var item = jQuery('<li>'+
        '<a href="#" class="button" title=""> </a>'+
        '<div class="title">'+o.title+'</div>'+
        '<div class="progress"><div class="left"></div><div class="right"></div><div class="track"></div></div>'+
        '</li>');

      item.find('.button').bind('click', function(e){
        e.preventDefault();
        if(player.getConfig().item == i) {
          // already playing: pause
          player.sendEvent('PLAY');
        }
        else {
          // start playing this item
          player.sendEvent('ITEM', i);
        }
      });

      item.appendTo(list);
      item.find('.progress .track').slider({
        stop: function(event, ui) {
					dragging = false;
          var i    = player.getConfig().item;
          var song = player.getPlaylist()[i];
          var pos  = ui.value / 100 * song.duration;
          // console.log('set pos ', ui.value, ' time: ', pos);
          player.sendEvent('SEEK', pos);
        },
				start: function(event, ui) {
					dragging = true;
				}
      });
    });
  }

	/**
   * Called each time the player's state is changed
   * IDLE, BUFFERING, COMPLETED, PLAYING, PAUSED
   */
  function stateChange(o) {
    // console.log('State changed from '+o.oldstate+' to '+o.newstate);
    switch(o.newstate) {
      case 'IDLE':
      case 'COMPLETED':
        jQuery('#list li.active').removeClass('active');
        break;
      case 'BUFFERING':
        break;
      case 'PLAYING':
        var i = player.getConfig().item;
        jQuery('#list li:eq('+i+')').removeClass('paused').addClass('active');
        info = jQuery('#list li.active .progress');
        break;
      case 'PAUSED':
        jQuery('#list li.active').addClass('paused');
        break;
    }
  }

	// public access
  window.createPlayer      = createPlayer;
  window.playerReady       = playerReady;
	window.handlePlayerEvent = handleEvent;

})(jQuery);
