/*

  SoundManager 2 Demo: Play MP3 links "in-place"
  ----------------------------------------------

  http://schillmania.com/projects/soundmanager2/

  A simple demo making MP3s playable "inline"
  and easily styled/customizable via CSS.

  Requires SoundManager 2 Javascript API.

*/

function InlinePlayer() {
  var self = this;
  var pl = this;
  var sm = soundManager; // soundManager instance
  this.excludeClass = 'inline-exclude'; // CSS class for ignoring MP3 links
  this.links = [];
  this.sounds = [];
  this.soundsByURL = [];
  this.indexByURL = [];
  this.lastSound = null;
  this.soundCount = 0;
  var isIE = (navigator.userAgent.match(/msie/i));

  this.config = {
	playNext: false, // stop after one sound, or play through list until end
	autoPlay: false  // start playing the first sound right away
  }

  this.css = {
	// CSS class names appended to link during various states
	sDefault: 'sm2_link', // default state
	sLoading: 'sm2_loading',
	sPlaying: 'sm2_playing',
	sPaused: 'sm2_paused'
  }

  this.addEventHandler = function(o,evtName,evtHandler) {
	typeof(attachEvent)=='undefined'?o.addEventListener(evtName,evtHandler,false):o.attachEvent('on'+evtName,evtHandler);
  }

  this.removeEventHandler = function(o,evtName,evtHandler) {
	typeof(attachEvent)=='undefined'?o.removeEventListener(evtName,evtHandler,false):o.detachEvent('on'+evtName,evtHandler);
  }

  this.classContains = function(o,cStr) {
	return (typeof(o.className)!='undefined'?o.className.match(new RegExp('(\\s|^)'+cStr+'(\\s|$)')):false);
  }

  this.addClass = function(o,cStr) {
	if (!o || !cStr || self.classContains(o,cStr)) return false;
	o.className = (o.className?o.className+' ':'')+cStr;
  }

  this.removeClass = function(o,cStr) {
	if (!o || !cStr || !self.classContains(o,cStr)) return false;
	o.className = o.className.replace(new RegExp('( '+cStr+')|('+cStr+')','g'),'');
  }

  this.getSoundByURL = function(sURL) {
	return (typeof self.soundsByURL[sURL] != 'undefined'?self.soundsByURL[sURL]:null);
  }

  this.isChildOfNode = function(o,sNodeName) {
	if (!o || !o.parentNode) {
	  return false;
	}
	o = o.parentNode;
	sNodeName = sNodeName.toLowerCase();
	do {
	  o = o.parentNode;
	} while (o && o.parentNode && o.nodeName.toLowerCase() != sNodeName);
	return (o.nodeName.toLowerCase() == sNodeName?o:null);
  }

  this.events = {

	// handlers for sound events as they're started/stopped/played

	play: function() {
	  pl.removeClass(this._data.oLink,this._data.className);
	  this._data.className = pl.css.sPlaying;
	  pl.addClass(this._data.oLink,this._data.className);
	},

	stop: function() {
	  pl.removeClass(this._data.oLink,this._data.className);
	  this._data.className = '';
	},

	pause: function() {
	  pl.removeClass(this._data.oLink,this._data.className);
	  this._data.className = pl.css.sPaused;
	  pl.addClass(this._data.oLink,this._data.className);
	},

	resume: function() {
	  pl.removeClass(this._data.oLink,this._data.className);
	  this._data.className = pl.css.sPlaying;
	  pl.addClass(this._data.oLink,this._data.className);      
	},

	finish: function() {
	  pl.removeClass(this._data.oLink,this._data.className);
	  this._data.className = '';
	  if (pl.config.playNext) {
		var nextLink = (pl.indexByURL[this._data.oLink.href]+1);
		if (nextLink<pl.links.length) {
		  pl.handleClick({'target':pl.links[nextLink]});
		}
	  }
	}

  }

  this.stopEvent = function(e) {
   if (typeof e != 'undefined' && typeof e.preventDefault != 'undefined') {
	  e.preventDefault();
	} else if (typeof event != 'undefined' && typeof event.returnValue != 'undefined') {
	  event.returnValue = false;
	}
	return false;
  }

  this.getTheDamnLink = (isIE)?function(e) {
	// I really didn't want to have to do this.
	return (e && e.target?e.target:window.event.srcElement);
  }:function(e) {
	return e.target;
  }

  this.handleClick = function(e) {
	// a sound link was clicked
	var o = self.getTheDamnLink(e);
	if (o.nodeName.toLowerCase() != 'a') {
	  o = self.isChildOfNode(o,'a');
	  if (!o) return true;
	}
	var sURL = o.getAttribute('href');
	if (!o.href || !o.href.match(/\.mp3(\\?.*)$/i) || self.classContains(o,self.excludeClass)) {
	  if (isIE && o.onclick) {
		return false; // IE will run this handler before .onclick(), everyone else is cool?
	  }
	  return true; // pass-thru for non-MP3/non-links
	}
	sm._writeDebug('handleClick()');
	var soundURL = (o.href);
	var thisSound = self.getSoundByURL(soundURL);
	if (thisSound) {
	  // already exists
	  if (thisSound == self.lastSound) {
		// and was playing (or paused)
		thisSound.togglePause();
	  } else {
		// different sound
		thisSound.togglePause(); // start playing current
		sm._writeDebug('sound different than last sound: '+self.lastSound.sID);
		if (self.lastSound) self.stopSound(self.lastSound);
	  }
	} else {
	  // create sound
	  thisSound = sm.createSound({
	   id:'inlineMP3Sound'+(self.soundCount++),
	   url:soundURL,
	   onplay:self.events.play,
	   onstop:self.events.stop,
	   onpause:self.events.pause,
	   onresume:self.events.resume,
	   onfinish:self.events.finish
	  });
	  // tack on some custom data
	  thisSound._data = {
		oLink: o, // DOM node for reference within SM2 object event handlers
		className: self.css.sPlaying
	  };
	  self.soundsByURL[soundURL] = thisSound;
	  self.sounds.push(thisSound);
	  if (self.lastSound) self.stopSound(self.lastSound);
	  thisSound.play();
	  // stop last sound
	}

	self.lastSound = thisSound; // reference for next call

	if (typeof e != 'undefined' && typeof e.preventDefault != 'undefined') {
	  e.preventDefault();
	} else {
	  event.returnValue = false;
	}
	return false;
  }

  this.stopSound = function(oSound) {
	soundManager.stop(oSound.sID);
	soundManager.unload(oSound.sID);
  }

  this.init = function() {
	sm._writeDebug('inlinePlayer.init()');
	var oLinks = document.getElementsByTagName('a');
	// grab all links, look for .mp3
	var foundItems = 0;
	for (var i=0; i<oLinks.length; i++) {
	  if (oLinks[i].href.match(/\.mp3/i) && !self.classContains(oLinks[i],self.excludeClass)) {
		self.addClass(oLinks[i],self.css.sDefault); // add default CSS decoration
		self.links[foundItems] = (oLinks[i]);
		self.indexByURL[oLinks[i].href] = foundItems; // hack for indexing
		foundItems++;
	  }
	}
	if (foundItems>0) {
	  self.addEventHandler(document,'click',self.handleClick);
	  if (self.config.autoPlay) {
		self.handleClick({target:self.links[0],preventDefault:function(){}});
	  }
	}
	sm._writeDebug('inlinePlayer.init(): Found '+foundItems+' relevant items.');
  }

  this.init();

}

var inlinePlayer = null;

soundManager.url = '/sup/flash/'; // path to directory containing SM2 SWF

soundManager.onload = function() {
  // soundManager.createSound() etc. may now be called
  inlinePlayer = new InlinePlayer();
}

