/*
Warnings:
---------
This class requires JQuery, so don't forget to include the JQuery library like this:
<script type="text/javascript" src="path/to/jquery-file.9.9.9.js"></script>
Remember also that the JQuery include must be before the include of this file.

Likewise, you'll need the SWFObject library, which can be included like sewww...
<script type="text/javascript" src="/scripts/swfobject.js"></script>


General Notes:
--------------
Created by Action Jackson Gabbard, March 20th, 2005

This is an unobtrusive alternative to the procedural JS previously used to 
achieve discography functionality. This class does the following:

1) 	Cleans up funky linking (i.e. links missing a protocol)
	and adds the iTunes badge to iTunes links
	-------------------------------------------------------
	Function(s):		sanitizeLinks
	Parameters: 		None
	Class Variables: 	buyLinkClass, itunesURL, itunesImageHtml
	
	Usage:
	First set the class variable, buyLinkClass, to
	the class name you are using for links generated by echotools.
	When you call the function, all the links in the page with a class
	name matching the one you set will be analyzed and modified (if possible)
	depending on whether or not the link is malformed or an iTunes link.
	
	The itunesURL is the URL that will be searched for when the class
	looks for iTunes links. If the href attribute of a given link
	has that string contained itunesUrl anywhere in it, the link's html will 
	be replaced with the itunesImageHtml variable's contents.
	
	
2)	Establishes hide/show functionality for lyrics lists
	--------------------------------------------------------
	Function(s):		setupLyricsControls, expandLyrics, collapseLyrics
	Parameters: 		None, 1, 1
	Class Variables:  	expandLinkHtml, collapseLinkHtml, 
						collapsedLyricsContainerClass, lyricsContainerClass
						lyricsControllerClass
	
	Usage:
	
	Warning // For the setupLyricsControls function to work properly the lyricsControllerClass
	elements and the lyricsContainerClass elements MUST be in the same order. The lyricsContainerClass
	elements may precede the controllers in the HTML, but there must be a one-to-one relationship in 
	the same order or the expand/collapse functions will reference the wrong elements. //end Warning
	
	Prior to running the setupLyricsControls, the class variables listed
	above will need to be either implemented in your HTML or modified
	on the class instance to match your HTML. That is to say,
	you can either change your HTML or set the property when you run the page.
	
	Example of Changing the Class Instance Properties:
	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	<html>
	...
	<script type="text/javascript">
		// de is a class instance
		var de = new DiscographyEnhancer (true);
		// this is the site builder changing the properties of the class instance without modifying the JS file
		de.expandLinkHtml = "<strong>I want the user to click this text to open the lyrics</strong>";
		de.collapseLinkHtml = "<strong>Once the lyrics are open, the user should click this to close them.</strong>";
		de.lyricsContainerClass = "theNameInMyCSSForTheBoxThatHasLyricsInIt";
		de.lyricsControllerClass = "theNameInMyCSSForWhateverTheUserClicksToOpenAndCloseTheLyrics";
		
		// etc.
		
	</script>
	<body>
	...
	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	
	Once you have configured things so that the JS and HTML/CSS match up, you'll probably want
	to customize the expandLyrics and collapseLyrics functions.
	
	These functions accept one parameter, which will be a jQuery object of the HTML element
	containing the lyrics (actually the element with the class name which should also contain the
	lyrics). By default, the function do jQuery fadeIn and fadeOut functions, respectively. However,
	there's plenty of room in the jQuery effects library to almost anything you would like to do with the lyrics container.
	
	Example of Overriding the Class expandLyrics/collapseLyrics function:
	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	<html>
	...
	<script type="text/javascript">
		// de is a class instance
		var de = new DiscographyEnhancer (true);
		...
		de.expandLyrics = function (jqObj) {
			jqObj.slideDown(2000);
		}
		de.collapseLyrics = function (jqObj) {
			jqObj.fadeOut(2000);
		}
		// etc.
		
	</script>
	<body>
	...
	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	
	Changing this function this way allows you to use the DiscographyEnhancer class
	and still implement the design uniquely. You should practically NEVER have to 
	modify the DiscographyEnahncer JS file unless functionality is required that
	does not exist in the class (i.e. the ability to have unordered lyrics
	container classes and controller classes or something similar).
	

3)	Embeds and adds external interface functionality to Flash single MP3 players
	----------------------------------------------------------------------------
	Function(s):		buildPlayers
	Parameters: 		None
	Class Variables:  	audioPlayerClass, audioPlayerVariables, audioPlayerSwfPath
						audioPlayerSwfWidth, audioPlayerSwfHeight
	
	Usage:
	Prior to running the buildPlayers function, the HTML will have to be modified slightly
	to accomodate the player. The SWF will be embedded in any HTML element that is classed
	as whatever audioPlayerClass is set to. So, div, span, td, p, whatever you want can work fine.
	
	Whatever element type you choose, you will have to set the title attribute to be the path to the MP3.
	
	When you've got your HTML sorted out and the title attribute set properly, calling the buildPlayers
	function will cause the DE to walk through the HTML, finding any audiPlayerClass element and looking
	at their title attribute. If it is not null, the attribute value will be extracted and used in creating
	an instance of the single mp3 player class.
	
	The player IDs are loaded into an array and using the default SWF, when the user clicks the play button
	in the SWF, the SWF will call an external interface and stop all other players.
	
	To keep the encapsulation of the DE class, your implementation of the DE should also include setting 
	up a function called stopPlayers that references your instance of the DE.
	
	Example of Creating a Global function to Stop Players:
	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	<html>
	...
	<script type="text/javascript">
		// de is a class instance
		var de = new DiscographyEnhancer (true);
		...
		function stopTracks (track) {
			de.stopTracks(track);
		}
		
	</script>
	<body>
	...
	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	
	Creating the global this way allows the flash player and other things
	to use the DE without needing a reference to it. 


4)	Adds Leopard Striping to the Track Listing
	----------------------------------------------------------------------------
	Function(s):		addStriping
	Parameters: 		None
	Class Variables:  	leopardStripeElligibiltyClass, leopardStripingAltClass, stripeEvens
	
	Usage:
	Prior to running the addStriping function, the rows (or divs!) will have to have a class
	assigned to them that either matches the preset value (.leopardMe) in the DE prototype or
	set the instance property leopardStripeElligibilityClass to match the class in the html.
	
	Example of Setting the Instance Property for Leopard Striping:
	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	<html>
	...
	<script type="text/javascript">
		// de is a class instance
		var de = new DiscographyEnhancer (true);
		de.leopardStripingElligibilityClass = "theClassNameImUsingForTheRowsTheTracksAreListedIn"
		...
	</script>
	<body>
	...
	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	
	Once the HTML and JS are in sync, the addStriping function can be called to walk the HTML
	adding the striping class (leopardStripingAltClass) to every other element.
	
	The stripeEvens property can be set true or false to stripe either the even rows or the
	odd rows.
	
	
5)	Adds hover responses to 
	----------------------------------------------------------------------------
	Function(s):		addHovering
	Parameters: 		None
	Class Variables:  	hoverElligibilityClass, hoverStateClass
	
	Usage:
	Prior to running the addHoveringfunction, the rows (or divs!) will have to have a class
	assigned to them that either matches the preset value (.hover) in the DE prototype or
	set the instance property hoverElligibilityClass to match the class in the html.
	
	Example of Setting the Instance Property for Leopard Striping:
	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	<html>
	...
	<script type="text/javascript">
		// de is a class instance
		var de = new DiscographyEnhancer (true);
		de.hoverElligibilityClass = "theClassNameImUsingForTheStuffThatCanBeHoveredOver
		...
	</script>
	<body>
	...
	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	
	Once the HTML and JS are in sync, the addHovering function can be called to walk the HTML
	adding the striping class (hoverStateClass) to every other element.

*/

// constructor
function DiscographyEnhancer (enableLogging) { 
	this.loggingEnabled = Boolean(enableLogging);
	this.log("DiscographyEnhancer instantiated"); 
}

// class vars
DiscographyEnhancer.prototype.itunesImageHtml = '<img src="/images/itunes_btn.gif" alt="iTunes" title="get album from iTunes" border="0" />';
DiscographyEnhancer.prototype.buyLinkClass = "buyLink";
DiscographyEnhancer.prototype.itunesUrl = "phobos.apple.com";
DiscographyEnhancer.prototype.expandLinkHtml = 'show lyrics';
DiscographyEnhancer.prototype.collapseLinkHtml = 'hide lyrics';
DiscographyEnhancer.prototype.collapsedLyricsContainerClass = "collapsed";
DiscographyEnhancer.prototype.lyricsContainerClass = "lyricsContainer";
DiscographyEnhancer.prototype.lyricsControllerClass = "lyricsController";
DiscographyEnhancer.prototype.audioPlayerClass = "de_audioPlayer";
DiscographyEnhancer.prototype.audioPlayerVariables = [];
DiscographyEnhancer.prototype.audioPlayerSwfPath = "/fws/singleMp3Player/echo_single_mp3_button_with_preloader.swf";
DiscographyEnhancer.prototype.audioPlayerSwfWidth = 70;
DiscographyEnhancer.prototype.audioPlayerSwfHeight = 19;
DiscographyEnhancer.prototype.leopardStripeElligibiltyClass = "leopardMe"; // yes.
DiscographyEnhancer.prototype.leopardStripingAltClass = "ls_alt";
DiscographyEnhancer.prototype.stripeEvens = false;
DiscographyEnhancer.prototype.hoverElligibilityClass = "hover";
DiscographyEnhancer.prototype.hoverStateClass = "over";

// util functions
DiscographyEnhancer.prototype.log = function (str) {
	if (this.loggingEnabled) {
		try {
			console.log(str);
		} catch (e) {
			// nu'en
		}
	}
}

// page manipulation functions
DiscographyEnhancer.prototype.sanitizeLinks = function () {
	/* 
	
	This function attempts to clean up sloppily posted URLs.
	If an URL has been posted without a protocol, this function
	will automagically assign it the HTTP://
	
	If the link is empty, this function will remove it.
	
	If the link's href attribute contains the itunesUrl string,
	the link's innerHTML will be replaced with the itunesImageHtml
	string.
	
	All links that are picked up by this function are given a target 
	of _blank.
	
	*/
	var de = this;
	$("a."+this.buyLinkClass).each(function (i) {
		var link = $(this);
		var linkHref = $(this).attr("href") || "";
		if (linkHref.length == 0) {
			de.log("Removing empty a.buyLink");
			link.replaceWith("");
			return;
		}
		if (linkHref.indexOf("http://")==-1) { // if the wizard who entered the link didn't add the protocol...
			$(this).attr("href","http://"+linkHref); // add it for him/her.
		}
		if (linkHref.indexOf(de.itunesUrl)!= -1) { // if it's an itunes link, replace the link text with an iTunes link image.
			link.html(de.itunesImageHtml);
		}
		link.attr("target","_blank"); // for good measure, explicitly set the target to a blank winder
	});
}

DiscographyEnhancer.prototype.collapseAllLyrics = function () {
	/* 
	This function walks through the HTML looking for elements
	classed with the lyricsContainerClass value. Where those are
	found, they are collapsed and given the 
	collapsedLyricsContainerClass value. The collapseLyricsContainerClass
	is used to toggle the expanded/collapsed state when the user clicks the controller.
	*/
	var de = this;
	$("."+de.lyricsContainerClass).each(function (i) {
		$(this).hide();
		$(this).addClass(de.collapsedLyricsContainerClass);
	});
}

DiscographyEnhancer.prototype.createExpandLyricsLinks = function () {
	/*
	Walk through all the lyricsControllerClass-ed elements, with each:
		1) 	Change the HTML (which probably should be null by default for good unobstrusiveness)
			to whatever value is set as the expandLinkHtml
		2)	Setup the click event on the controller to call the toggle function
		3) 	If the lyricsContainer that corresponds with the controller has no
			HTML, empty the controller of HTML so that the user doesn't see it
			and do not set up click events
	*/
	this.log("createExpandLyricsLinks called (setting up lyrics show/hide functionality)");
	var de = this;
	$("."+this.lyricsControllerClass).each(function (i) {
		de.log("Lyrics controller found, number "+i+" "+this.className); 	
		var lc = $(this);
		var targetLyricsContainer = $("."+de.collapsedLyricsContainerClass).get(i); // get the next item in the set
		de.log(typeof(targetLyricsContainer));
		
		if ($(targetLyricsContainer).html().length) {
			de.log("Enabled hiding and showing of the lyrics for lyrics controller "+i+".");
			lc.html('<a href="#">'+de.expandLinkHtml+'</a>');
			$(lc.children("a").get(0)).click(function () {
				de.toggleLyricsContainer(targetLyricsContainer,this);
				return false; 
			});
		} else {
			lc.empty();
		}
	});
}

DiscographyEnhancer.prototype.toggleLyricsContainer = function (targ,caller) {
	// just in case, make them jQuery objects 
	targ = $(targ);
	caller = $(caller);
	
	// if the container is already collapsed, 
	if (targ.hasClass(this.collapsedLyricsContainerClass)) {
		// change the controller to show the collapseLinkHtml
		caller.html(this.collapseLinkHtml);
		// remove the flag-class from the container
		targ.removeClass(this.collapsedLyricsContainerClass);
		// expand the lyrics container using the expandFunction
		this.expandLyrics(targ);
	} else {
		// change the controller to show the collapseLinkHtml
		caller.html(this.expandLinkHtml);
		// add the flag-class to the lyrics container
		targ.addClass(this.collapsedLyricsContainerClass);
		// collapse the container using the collapseLyrics function
		this.collapseLyrics(targ);
	}
}

DiscographyEnhancer.prototype.setupLyricsControls = function () {
	/*
	Function to call to do all the lyrics container/controller setup work
	*/
	this.collapseAllLyrics();
	this.createExpandLyricsLinks();
}

DiscographyEnhancer.prototype.expandLyrics = function (jqObj) {
	// this method should be overrided per implementation, all
	// it needs to do is show the lyrics for base functionality
	jqObj.fadeIn("slow");
}

DiscographyEnhancer.prototype.collapseLyrics = function (jqObj) {
	// see the preceding, but go the other way
	jqObj.fadeOut("slow");
}

// flash handling functions
DiscographyEnhancer.prototype.players = []; // an array to store the player IDs in

DiscographyEnhancer.prototype.stopTracks = function(track) {
	/* External interface function that walks the players array
	calling the stopTrack method of each that has an id
	other than that passed */
	this.log("Stopping all tracks but "+track);				
	for (var i =0 ; i < this.players.length ; i ++) {
		if( this.players[i] != track) {
			this.thisMovie(this.players[i]).stopTrack();
		}
	}				
}

DiscographyEnhancer.prototype.thisMovie = function (movieName) {
	// Ye oade Macromedia thisMovie method
	if (navigator.appName.indexOf("Microsoft") != -1) {
		return window[movieName];
	} else {
		return document[movieName];
	}
}
DiscographyEnhancer.prototype.buildPlayers = function () {
	/* 
	Function responsible for walking the HTML looking for elements
	class as audioPlayerClass. If the elements found have a non-empty
	title attribute, it will have a SWF embedded in it that attempts
	to load and play whatever path is in the title attribute.
	*/
	var de = this;
	de.log("Building Flash audio players...");
	$("."+this.audioPlayerClass).each(function (i) {
		var ap = $(this);
		if (ap.attr("title") != undefined && ap.attr("title") != null) {
			this.id = "player"+i;
			var track = "p"+i;
			de.players.push(track);
			de.log("Building player "+track+" for URL "+ap.attr("title")+".");
			var fo = new SWFObject(de.audioPlayerSwfPath, track, de.audioPlayerSwfWidth, de.audioPlayerSwfHeight, "7", "#ffffff");
			fo.addVariable("mp3",ap.attr("title"));
			fo.addVariable("trackNum",track);
			fo.addParam("wmode","transparent");
			fo.addParam("allowScriptAccess","always");
			for (var i in de.audioPlayerVariables) {
				fo.addVariable(de.audioPlayerVariables[i].param,de.audioPlayerVariables[i].value);
			}
			fo.write(this.id);
		}
	});
	de.log(this.players.length+" players added. ("+this.players.join(",")+").");
}
// add leopard striping to the tracks
DiscographyEnhancer.prototype.addStriping = function () {
	var de = this;
	$("."+this.leopardStripeElligibiltyClass).each(function (i) {
		var container = $(this);
		var stripeDecider;
		if (de.stripeEvens) {
			
			stripeDecider = function (c) {
				if (c % 2 == 1) { // if it's an odd numbered row
					return true;
				} else {
					return false;
				}
			}
			
		} else {
			
			stripeDecider = function (c) {
				if (c % 2 == 0) { // if it's an even numbered row
					return true;
				} else {
					return false;
				}
			}
			
		}
		
		if (stripeDecider(i)) {
			de.log("Adding striping to row "+i+".");
			container.addClass(de.leopardStripingAltClass);
		}
	});
}

// add hover ability
DiscographyEnhancer.prototype.addHovering = function () {
	var de = this;
	$("."+this.hoverElligibilityClass).each(function (i) {
		
		$(this).hover(
			function () { 
				de.doHover($(this)); 
			},
			function () { 
				de.doUnhover($(this)); 
			} 
		);
		
	});
}
DiscographyEnhancer.prototype.doHover = function (jqObj) {
	jqObj.addClass(this.hoverStateClass);
}
DiscographyEnhancer.prototype.doUnhover = function (jqObj) {
	jqObj.removeClass(this.hoverStateClass);
}