
var useAnimations = false;
var useAnimatedOverlay = false;
var isWii = (window.opera && opera.wiiremote);
var isOpera = window.opera;

// The proxy is needed on the wii because of what I can only guess is
// security issues streaming across domains. This is unfortunate...
//var useProxy = isWii;

// shouldn't need proxy when hosted on mp3tunes.com domain
var useProxy = true;

var isIe = (YAHOO.env.ua.ie !== 0.0);

/**
 * Finds a child of an element by the ID and optionally by its type.
 * 
 * @param {Object} id The id of the element to find.
 * @param {Object} type An optional type to restrict the search to.
 */
function findChildById(parent, id, type) {
	return YAHOO.util.Dom.getElementsBy(
		function(child) {
			return child.id == id;
		},
		type,
		parent
	)[0];
};

function removeChildElements(element) {
	while (element.childNodes.length) {
		element.removeChild(element.childNodes[0]);
	}
}

function setOpacity(element, opacity) {
	element.style.opacity = opacity;
	element.style.mozOpacity = opacity;
	element.style.filter = "alpha(opacity=" + (opacity * 100) + ")";
}

/*
Script by RoBorg
RoBorg@geniusbug.com
http://javascript.geniusbug.com | http://www.roborg.co.uk
Please do not remove or edit this message
Please link to this website if you use this script!
*/
function clone(myObj) {
	if(typeof(myObj) != 'object') return myObj;
	if(myObj == null) return myObj;

	var myNewObj = new Object();

	for(var i in myObj)
		myNewObj[i] = clone(myObj[i]);

	return myNewObj;
}
 

/**
 * Base class for all effects.
 */
var Effect = Base.extend({
	__animation: null,
	__active: false,
	__listeners: null,

	constructor: function() {
		this.__listeners = [];
	},

	addEffectListener: function(listener) {
		this.__listeners.push(listener);
	},

	removeEffectListener: function(listener) {
		var index = this.__listeners.indexOf(listener);

		if (index != -1) {
			this.__listeners.splice(index, 1);
		}
	},

	start: function() {
		this.stop();
		this.active = true;
		this.fireEffectStart();
	},

	stop: function() {
		if (this.__active !== true) {
			return;
		}

		this.fireEffectComplete();
		this.active = false;
	},

	fireEffectStart: function() {
		for (var i in this.__listeners) {
			if (this.__listeners[i].onEffectStart !== undefined) {
				this.__listeners[i].onEffectStart(this);
			}
		}
	},

	fireEffectComplete: function() {
		for (var i in this.__listeners) {
			if (this.__listeners[i].onEffectComplete !== undefined) {
				this.__listeners[i].onEffectComplete(this);
			}
		}
	}
});

/**
 * Performs an opacity fade of an element from its current opacity
 * to the desired opacity.
 */
var OpacityEffect = Effect.extend({
	target: null,
	duration: null,
	fadeStep: 0.0,
	fadeOpacity: 0.0,
	timeout: null,

	constructor: function(target, duration, opacity) {
		this.base();

		this.target = target;
		this.duration = duration;

		if (this.target.style.opacity === undefined) {
			this.target.style.opacity = 0.0;
		} else if (this.target.style.opacity === "") {
			this.target.style.opacity = 0.0;
		} else if (typeof this.target.style.opacity != "number") {
			this.target.style.opacity = parseFloat(this.target.style.opacity);
		}

		if (opacity === undefined) {
			opacity = 0.75;
		}

		this.fadeOpacity = opacity;
	},

	start: function() {
		this.base();

		this.fadeStep = (this.fadeOpacity - this.target.style.opacity) / (this.duration * 10.0);
		this.__updateOpacity();
	},

	stop: function(notifyComplete) {
		if (this.timeout !== null) {
			clearTimeout(this.timeout);
			this.timeout = null;
		}

		this.base(notifyComplete);
	},

	__updateOpacity: function() {
		var currentOpacity = parseFloat(this.target.style.opacity);

		currentOpacity += this.fadeStep;

		if (
			(this.fadeStep < 0 && currentOpacity < this.fadeOpacity) ||
			(this.fadeStep > 0 && currentOpacity > this.fadeOpacity)
		) {
			currentOpacity = this.fadeOpacity;
		}

		setOpacity(this.target, currentOpacity);
		this.target.style.display = (currentOpacity === 0) ? "none" : "";

		if (currentOpacity == this.fadeOpacity) {
			this.stop(true);
		} else {
			var self = this;

			this.timeout = setTimeout(
				function() { self.__updateOpacity(); },
				10
			);
		}
	}
});

/**
 * Class used to turn a div with the appropriate child elements into
 * a graphical scrollbar.
 */
var Scrollbar = Base.extend({
	__previousElement: null,
	__container: null,
	__listeners: null,
	__nextElement: null,
	__thumbElement: null,
	__timerId: null,
	extent: 1,
	max: 10,
	min: 1,
	speed: 1,
	value: 5,

	constructor: function(scrollbar) {
		if (scrollbar === null) {
			throw "Require a container element for the scrollbar.";
		}

		this.__listeners = [];
		this.__container = scrollbar;

		var containerId = this.__container.id;

		this.__previousElement = findChildById(this.__container, containerId + "Previous");
		this.__nextElement = findChildById(this.__container, containerId + "Next");
		this.__thumbElement = findChildById(this.__container, containerId + "Thumb");

		var self = this;

		if (this.__previousElement) {
			this.__previousElement.onmousedown = function() { self.scrollPrevious(); };
			this.__previousElement.onmouseup = function() { self.stopScroll(); };
		}

		if (this.__nextElement) {
			this.__nextElement.onmousedown = function() { self.scrollNext(); };
			this.__nextElement.onmouseup = function() { self.stopScroll(); };
		}

		if (this.__thumbElement) {
			this.__thumbElement.onmousedown = function() { };
			this.__thumbElement.onmouseup = function() { };
		}
	},

	setRange: function(min, max, extent) {
		this.min    = min;
		this.max    = max - extent;
		this.extent = extent;
		this.__updateThumb();
		this.__updateButtonStates();
	},

	setValue: function(value) {
		if (this.value != value) {
			this.value = value;
	
			if (this.value < this.min) {
				this.value = this.min;
			}
	
			if (this.value > this.max) {
				this.value = this.max;
			}
	
			this.fireScroll();
			this.__updateThumb();
			this.__updateButtonStates();
		}
	},

	__updateButtonStates: function() {
		if (this.value > this.min) {
			setOpacity(this.__previousElement, 1);
		} else {
			setOpacity(this.__previousElement, 0.125);
		}

		if (this.value < this.max) {
			setOpacity(this.__nextElement, 1);
		} else {
			setOpacity(this.__nextElement, 0.125);
		}
	},

	addScrollListener: function(listener) {
		this.__listeners.push(listener);
	},

	removeScrollListener: function(listener) {
		var index = this.__listeners.indexOf(listener);

		if (index != -1) {
			this.__listeners.splice(index, 1);
		}
	},

	fireScroll: function() {
		for (var i in this.__listeners) {
			this.__listeners[i].onScroll(this);
		}
	},

	scrollPrevious: function() {
		this.scroll(-this.speed);
	},

	scrollNext: function() {
		this.scroll(this.speed);
	},

	scroll: function(speed) {
		this.stopScroll();

		var self = this;

		this.__timerId = setInterval(function() { self.__doScroll(speed); }, Scrollbar.__scrollInterval);
	},

	stopScroll: function() {
		if (this.__timerId !== null) {
			clearInterval(this.__timerId);
			this.__timerId = null;
		}
	},

	__doScroll: function(speed) {
		this.setValue(this.value + speed);
	},

	__startDrag: function() {
	},

	__stopDrag: function() {
	},

	__updateThumb: function() {
	}
},{
	horizontal: 1,
	vertical: 2,
	__scrollInterval: 100
});

var Marquee = Base.extend({
	__contentElement: null,
	__containerElement: null,
	__timerId: null,
	__intervalId: null,
	__scrollPaused: false,
	__scrollDirection: 1,

	constructor: function(mouseOverScroll) {
		this.__contentElement = document.createElement("span");
		this.__contentElement.style.whiteSpace = "nowrap";

		this.__containerElement = document.createElement("div");
		this.__containerElement.id = "SlidingMarquee" + Marquee.__marqueeId++;
		this.__containerElement.style.overflow = "hidden";
		this.__containerElement.style.width = "100px";
		this.__containerElement.appendChild(this.__contentElement);
		this.__containerElement.marquee = this;

		if (mouseOverScroll === true) {
			if (isOpera) {
				this.__contentElement.onmouseover = "javascript: Marquee.__startScroll('" + this.__containerElement.id + "');";
				this.__contentElement.onmouseout  = "javascript: Marquee.__stopScroll('" + this.__containerElement.id + "');";
			} else {
				var self = this;
			
				this.__contentElement.onmouseover = function() { self.startScroll(); };
				this.__contentElement.onmouseout  = function() { self.stopScroll(); };
			}
		}
	},

	getContentElement: function() {
		return this.__contentElement;
	},

	setParent: function(parent) {
		if (this.__containerElement.parentNode != null) {
			this.__containerElement.parentNode.removeChild(this.__containerElement);
		}

		parent.appendChild(this.__containerElement);
		this.updateBounds();
	},

	updateBounds: function() {
		this.__containerElement.style.width = this.__containerElement.parentNode.offsetWidth + "px";
	},

	startScroll: function() {
		this.stopScroll();

		this.updateBounds();

		if (this.__contentElement.offsetWidth <= this.__containerElement.offsetWidth) {
			return;
		}

		var self = this;

		this.__scrollPaused = true;
		this.__timerId = setTimeout(function() { self.__scrollPaused = false; }, Marquee.__endPause);
		this.__intervalId = setInterval(function() { self.__doScroll(); }, 100);
	},

	stopScroll: function() {
		if (this.__intervalId) {
			clearInterval(this.__intervalId);
			this.__intervalId = null;
		}

		if (this.__timerId) {
			clearTimeout(this.__timeId);
			this.__timeId = null;
		}

		this.__containerElement.scrollLeft = 0;
	},

	__doScroll: function() {
		if (this.__scrollPaused) {
			return;
		}

		var current = this.__containerElement.scrollLeft;
		var reversed = false;

		current += this.__scrollDirection * Marquee.__scrollSpeed;

		if (current < 0) {
			current = 0;
			this.__scrollDirection *= -1;
			reversed = true;
		} else if (current > this.__containerElement.scrollWidth - this.__containerElement.offsetWidth) {
			current = this.__containerElement.scrollWidth - this.__containerElement.offsetWidth;
			this.__scrollDirection *= -1;
			reversed = true;
		}

		this.__containerElement.scrollLeft = current;
		current = 0;

		if (reversed) {
			var self = this;
			this.__scrollPaused = true;
			this.__timerId = setTimeout(function() { self.__scrollPaused = false; }, Marquee.__endPause);
		}
	}
},{
	__marqueeId: 0,
	__scrollSpeed: 5,
	__endPause: 1000,

	__startScroll: function(marqueeId) {
		var marqueeElement = document.getElementById(marqueeId);
		var marqueeChild = marqueeElement.childNodes[0];
		var marquee = marqueeElement.marquee;

		marquee.startScroll();
	},

	__stopScroll: function(marqueeId) {
		var marqueeElement = document.getElementById(marqueeId);
		var marquee = marqueeElement.marquee;

		marquee.stopScroll();
	}
});

/**
 * Object used to paint the background of another element.
 */
var Background = Base.extend({
	paint: function(element, canvas) { }
});

/**
 * Paints a background with rounded corners, all a solid color.
 */
var RoundedBackground = Background.extend({
	cornerRadius: 10,
	borderColor: "#000000",
	borderWidth: 4,
	fillStyle: "#FFFFFF",

	paint: function(element, canvas) {
		var width  = element.offsetWidth;
		var height = element.offsetHeight;

		// This will cause the Wii to crash if we don't do this check...
		if (width < this.cornerRadius || height < this.cornerRadius) {
			return;
		}

		canvas.fillStyle = "#0000FF";
		canvas.beginPath();
			canvas.arc(this.cornerRadius, this.cornerRadius, this.cornerRadius, Math.PI, 3 / 2 * Math.PI, false);
			canvas.arc(width - this.cornerRadius, this.cornerRadius, this.cornerRadius, 3 / 2 * Math.PI, 0, false);
			canvas.arc(width - this.cornerRadius, height - this.cornerRadius, this.cornerRadius, 0, Math.PI / 2, false);
			canvas.arc(this.cornerRadius, height - this.cornerRadius, this.cornerRadius, Math.PI / 2, Math.PI, false);
		canvas.closePath();
		canvas.fill();

		canvas.fillStyle = this.fillStyle;
		canvas.globalCompositeOperation = 'source-in';
		canvas.fillRect(0, 0, width, height);

		var halfLineWidth = (this.borderWidth - 1) / 2;

		canvas.globalCompositeOperation = 'source-over';
		canvas.fillStyle = this.borderColor;
		canvas.lineWidth = this.borderWidth;
		canvas.beginPath();
			canvas.arc(this.cornerRadius + halfLineWidth, this.cornerRadius + halfLineWidth, this.cornerRadius, Math.PI, 3 / 2 * Math.PI, false);
			canvas.arc(width - this.cornerRadius - halfLineWidth, this.cornerRadius + halfLineWidth, this.cornerRadius, 3 / 2 * Math.PI, 0, false);
			canvas.arc(width - this.cornerRadius - halfLineWidth, height - this.cornerRadius - halfLineWidth, this.cornerRadius, 0, Math.PI / 2, false);
			canvas.arc(this.cornerRadius + halfLineWidth, height - this.cornerRadius - halfLineWidth, this.cornerRadius, Math.PI / 2, Math.PI, false);
		canvas.closePath();
		canvas.stroke();
	}
});

/**
 * Paints a background with rounder corners and a gradient fill.
 */
var GradientBackground = Background.extend({
	cornerRadius: 10,

	paint: function(element, canvas) {
		var width  = element.offsetWidth;
		var height = element.offsetHeight;

		// This will cause the Wii to crash if we don't do this check...
		if (width < this.cornerRadius || height < this.cornerRadius) {
			return;
		}

		canvas.fillStyle = "#0000FF";
		canvas.beginPath();
			canvas.arc(this.cornerRadius, this.cornerRadius, this.cornerRadius, Math.PI, 3 / 2 * Math.PI, false);
			canvas.arc(width - this.cornerRadius, this.cornerRadius, this.cornerRadius, 3 / 2 * Math.PI, 0, false);
			canvas.arc(width - this.cornerRadius, height - this.cornerRadius, this.cornerRadius, 0, Math.PI / 2, false);
			canvas.arc(this.cornerRadius, height - this.cornerRadius, this.cornerRadius, Math.PI / 2, Math.PI, false);
		canvas.closePath();
		canvas.fill();

		var gradient = canvas.createLinearGradient(0, 0, 0, height);

		gradient.addColorStop(0.00,  "#2fa7ff");
		gradient.addColorStop(0.50,  "#a7daff");
		gradient.addColorStop(0.75,  "#bbdcff");
		gradient.addColorStop(1.00,  "#e5f2ff");

		canvas.fillStyle = gradient;
		canvas.globalCompositeOperation = 'source-in';
		canvas.fillRect(0, 0, width, height);

		var halfLineWidth = 1.5;

		canvas.globalCompositeOperation = 'source-over';
		canvas.fillStyle = "#000000";
		canvas.lineWidth = 4;
		canvas.beginPath();
			canvas.arc(this.cornerRadius + halfLineWidth, this.cornerRadius + halfLineWidth, this.cornerRadius, Math.PI, 3 / 2 * Math.PI, false);
			canvas.arc(width - this.cornerRadius - halfLineWidth, this.cornerRadius + halfLineWidth, this.cornerRadius, 3 / 2 * Math.PI, 0, false);
			canvas.arc(width - this.cornerRadius - halfLineWidth, height - this.cornerRadius - halfLineWidth, this.cornerRadius, 0, Math.PI / 2, false);
			canvas.arc(this.cornerRadius + halfLineWidth, height - this.cornerRadius - halfLineWidth, this.cornerRadius, Math.PI / 2, Math.PI, false);
		canvas.closePath();
		canvas.stroke();
	}
});

/**
 * Paints a background with rounded corners, all a solid color.
 */
var FadedBackground = Background.extend({
	cornerRadius: 20,
	backgroundColor: "rgba(96, 96, 96, 0.175)",

	paint: function(element, canvas) {
		var width  = element.offsetWidth;
		var height = element.offsetHeight;

		// This will cause the Wii to crash if we don't do this check...
		if (width < this.cornerRadius || height < this.cornerRadius) {
			return;
		}

		canvas.clearRect(0, 0, width, height);
		canvas.fillStyle = this.backgroundColor;
		canvas.beginPath();
			canvas.arc(this.cornerRadius, this.cornerRadius, this.cornerRadius, Math.PI, 3 / 2 * Math.PI, false);
			canvas.arc(width - this.cornerRadius, this.cornerRadius, this.cornerRadius, 3 / 2 * Math.PI, 0, false);
			canvas.arc(width - this.cornerRadius, height - this.cornerRadius, this.cornerRadius, 0, Math.PI / 2, false);
			canvas.arc(this.cornerRadius, height - this.cornerRadius, this.cornerRadius, Math.PI / 2, Math.PI, false);
		canvas.closePath();

		canvas.fill();
	}
});

var WindowPosition = Base.extend({

},{
	Floating: 0,	
	Centered: 1,
	Anchored: 2
});

var Window = Base.extend({
	canvas: null,
	contentPane: null,
	__background: null,
	__canvasElement: null,
	__divElement: null,
	__hideEffect: null,
	__nocanvas: isIe,
	__positioning: WindowPosition.Floating,
	__oldZIndex: 1,
	__showEffect: null,

	constructor: function(id) {
		this.__divElement = document.createElement("div");

		this.__divElement.id = "window" + Window.__nextWindowId++;
		this.__divElement.style.top = 0;
		this.__divElement.style.left = 0;
		this.__divElement.style.position = "absolute";
		this.__divElement.style.display = "none";
		this.__divElement.style.overflow = "hidden";
		this.__divElement.style.backgroundColor = "transparent";
		document.body.appendChild(this.__divElement);

		var existing = document.getElementById(id);

		if (existing !== null) {
			this.contentPane = existing;
			this.contentPane.parentNode.removeChild(this.contentPane);
		} else {
			this.contentPane = document.createElement("div");
			this.contentPane.id = id;
			this.initializeComponents();
		}

		this.__divElement.appendChild(this.contentPane);

		this.contentPane.style.width = "100%";
		this.contentPane.style.height = "100%";
		this.contentPane.style.position = "absolute";
		this.contentPane.style.zIndex = "10";

		if (this.__nocanvas !== true) {
			this.__background = new GradientBackground();

			if (this.contentPane.style.backgroundColor != "") {
				this.__background.backgroundColor = this.contentPane.style.backgroundColor;
			}

			this.__canvasElement = document.createElement("canvas");
			this.__canvasElement.style.position = "absolute";
			this.__canvasElement.style.width = "100%";
			this.__canvasElement.style.height = "100%";
			this.__canvasElement.style.zIndex = "0";
			this.__divElement.appendChild(this.__canvasElement);

			this.canvas = this.__canvasElement.getContext("2d");
		}

		if (isIe == false) {
			this.contentPane.style.backgroundColor = "transparent";
		}
/*
		var colors = [ "red", "blue", "green", "cyan", "magenta", "white", "brown", "yellow" ];

		if (Window.i === undefined) {
			Window.i = 0;
		} else {
			Window.i++;
		}

		this.contentPane.style.backgroundColor = colors[Window.i];
*/
		this.__updatePosition();

		this.self = this;
	},

	initializeComponents: function() { },

	findChild: function(id, type) {
		return findChildById(this.contentPane, id, type);
	},

	paint: function() {
		if (this.__background !== null) {
			this.__background.paint(this.__canvasElement, this.canvas);
		}
	},

	setShowEffect: function(effect) {
		if (this.__showEffect !== null) {
			this.__showEffect.removeEffectListener(this);
		}

		this.__showEffect = effect;

		if (this.__showEffect !== null) {
			this.__showEffect.addEffectListener(this);
		}
	},

	setHideEffect: function(effect) {
		if (this.__hideEffect !== null) {
			this.__hideEffect.removeEffectListener(this);
		}

		this.__hideEffect = effect;

		if (this.__hideEffect !== null) {
			this.__hideEffect.addEffectListener(this);
		}
	},

	center: function() {
		this.__positioning = WindowPosition.Centered;

		this.__divElement.style.left = "50%";
		this.__divElement.style.top = "50%";
		this.__updatePosition();
	},

	setPosition: function(x, y) {
		this.__positioning = WindowPosition.Floating;

		this.__divElement.style.left = x + "px";
		this.__divElement.style.top = y + "px";
		this.__updatePosition();
	},

	getSize: function() {
		return { x: this.__divElement.offsetWidth, y: this.__divElement.offsetHeight };
	},

	setSize: function(width, height) {
		this.__divElement.style.width = width + ((typeof width === "number") ? "px" : "");
		this.__divElement.style.height = height + ((typeof height === "number") ? "px" : "");
		this.contentPane.style.width = this.__divElement.style.width;
		this.contentPane.style.height = this.__divElement.style.height;
		this.__updatePosition();
	},

	setOpacity: function(opacity) {
		setOpacity(this.__divElement, opacity);
	},

	__updatePosition: function() {
		if (this.__positioning == WindowPosition.Centered) {
			this.__divElement.style.marginLeft = -(this.__divElement.offsetWidth / 2) + "px";
			this.__divElement.style.marginTop = -(this.__divElement.offsetHeight / 2) + "px";
		} else {
			this.__divElement.style.marginLeft = "0px";
			this.__divElement.style.marginTop = "0px";
		}

		if (this.__nocanvas !== true) {
			this.__canvasElement.width = this.__divElement.offsetWidth;
			this.__canvasElement.height = this.__divElement.offsetHeight;

			this.paint();
		}
	},

	isVisible: function() {
		return this.__divElement.style.display != "none";
	},

	show: function() {
		if (this.__hideEffect !== null) {
			this.__hideEffect.stop();
		}

		if (this.__showEffect === null) {
			this.__divElement.style.display = "";
			this.__updatePosition();
		} else {
			this.__showEffect.start();
		}

		Window.__inputListeners.push(this);
	},

	showModal: function() {
		if (Window.__modalOverlay === null) {
			Window.__modalOverlay = new Overlay("black", 1, 0.50);
		}

		if (Window.__modalWindow !== null) {
			return;
		}

		Window.__modalWindow = this;

		Window.__modalOverlay.show();
		this.__oldZIndex = this.__divElement.style.zIndex;
		this.__divElement.style.zIndex = "" + (parseInt(Window.__modalOverlay.__divElement.style.zIndex, 10) + 1);
		this.show();
	},

	hide: function() {
		if (!this.isVisible()) {
			return;
		}

		if (this.__showEffect !== null) {
			this.__showEffect.stop();
		}

		if (this.__hideEffect === null) {
			this.__divElement.style.display = "none";
		} else {
			this.__hideEffect.start();
		}

		if (Window.__modalWindow == this) {
			Window.__modalWindow = null;
			Window.__modalOverlay.hide();
			this.__divElement.style.zIndex = this.__oldZIndex;
		}

		for (var i = 0; i < Window.__inputListeners; ++i) {
			if (Window.__inputListeners[i] == this) {
				Window.__inputListeners.splice(i, 1);
				break;
			}
		}
	},

	isVisible: function() {
		return this.__divElement.style.display != "none";
	},

	onEffectStart: function(effect) {
		if (this.__showEffect == effect) {
			this.__divElement.style.display = "";
			this.__updatePosition();
		}
	},

	onEffectComplete: function(effect) {
		if (this.__hideEffect == effect) {
			this.__divElement.style.display = "none";
		}
	},

	onButtonPressed: function(button) { },

	onButtonReleased: function(button) { }
},{
	__modalOverlay: null,
	__modalWindow: null,
	__nextWindowId: 0,
	__inputListeners: new Array(),

	onButtonPressed: function(button) {
		var listeners = Window.__inputListeners.slice();

		for (var i in listeners) {
			if (listeners[i].onButtonPressed(button) == true) {
				break;
			}
		}
	},

	onButtonReleased: function(button) {
		var listeners = Window.__inputListeners.slice();

		for (var i in listeners) {
			if (listeners[i].onButtonReleased(button) == true) {
				break;
			}
		}
	}
});

var Overlay = Window.extend({
	opacity: 0.5,
	__nocanvas: true,

	constructor: function(color, speed, opacity) {
		this.base(null);

		if (color === undefined) {
			color = "black";
		}

		this.__divElement.style.zIndex = "10";
		this.__divElement.style.width = "100%";
		this.__divElement.style.height = "100%";
		this.__divElement.display = "none";
		this.__divElement.style.backgroundColor = color;

		this.opacity = opacity;

		if (useAnimatedOverlay) {
			this.setOpacity(0);
			this.setShowEffect(new OpacityEffect(this.__divElement, speed, opacity));
			this.setHideEffect(new OpacityEffect(this.__divElement, speed, 0.0));
		}
	},

	getColor: function() {
		return this.__divElement.style.backgroundColor;
	},

	setColor: function(color) {
		this.__divElement.style.backgroundColor = color;
	},

	show: function() {
		this.base();

		if (this.__showEffect === null) {
			this.setOpacity(this.opacity);
		}
	}
});

var MessageBox = Window.extend({
	__titlePane: null,
	__messagePane: null,
	__buttonPane: null,
	__type: 0,
	__oldOverlayColor: null,

	constructor: function(id) {
		this.base(id);

		this.__titlePane = this.findChild("Title", "span");
		this.__messagePane = this.findChild("Message", "span");
		this.__buttonPane = this.findChild("Buttons", "span");

		this.center();

		this.setSize(600, 400);
	},

	setTitle: function(title) {
		this.__titlePane.innerHTML = title;
	},

	setMessage: function(message) {
		this.__messagePane.innerHTML = message;
	},

	setButtons: function(buttons) {
		var self = this;

		this.__buttonPane.innerHTML = "";

		for (var i in buttons) {
			var button = buttons[i];
			var buttonElement = document.createElement("button");
			buttonElement.appendChild(document.createTextNode(button.caption));
			buttonElement.onclick = function() {
				self.hide();

				if (Window.__modalOverlay.__hideEffect === null) {
					button.onclick();
				} else {
					setTimeout(
						function() { button.onclick(); },
						1000 * Window.__modalOverlay.__hideEffect.duration
					);
				}
			};
			this.__buttonPane.appendChild(buttonElement);
		}
	},

	setType: function(type) {
		this.__type = type;
	},

	showModal: function() {
		this.base();

		this.setSize(600, this.__titlePane.offsetHeight + this.__messagePane.offsetHeight + this.__buttonPane.offsetHeight + "px");

		this.__oldOverlayColor = Window.__modalOverlay.getColor();

		if (this.__type == MessageBox.Warning) {
			Window.__modalOverlay.setColor("yellow");
		} else if (this.__type == MessageBox.Error) {
			Window.__modalOverlay.setColor("red");
		}
	},

	hide: function() {
		var self = this;

		this.base();

		if (useAnimatedOverlay) {
			setTimeout(function() { Window.__modalOverlay.setColor(self.__oldOverlayColor); }, 1000);
		} else {
			Window.__modalOverlay.setColor(self.__oldOverlayColor);
		}
	}
},{
	Info: 0,
	Warning: 1,
	Error: 2,
	__instance: null,

	initialize: function(id) {
		MessageBox.__instance = new MessageBox(id);
	},

	show: function(title, message, buttons, type) {
		MessageBox.__instance.setTitle(title);
		MessageBox.__instance.setMessage(message);
		MessageBox.__instance.setButtons(buttons);
		MessageBox.__instance.setType(type);

		MessageBox.__instance.showModal();
	}
});

var LoginWindow = Window.extend({
	onLogin: null,

	constructor: function(id) {
		this.base(id);

		var self = this;
		var loginButton = this.findChild("LoginButton", "Button");

		loginButton.onclick = function() {
			var emailAddress = self.findChild("EmailAddress", "input");
			var password = self.findChild("Password", "input");

			if (self.onLogin != null) {
				self.onLogin(emailAddress.value, password.value);
			}
		}

		this.center();
		this.setSize(500, 205);
	},

	show: function() {
		InputManager.getInstance().setActive(false);
		this.base();
	},

	hide: function() {
		InputManager.getInstance().setActive(true);
		this.base();
	}
});

var PlayListWindow = Window.extend({
	playlists: null,
	__collapsed: false,
	__currentPlaylist: null,
	__playlistList: null,
	__spinner: null,
	__closeButton: null,
	__createPlaylistButton: null,
	__deletePlaylistButton: null,
	onCreatePlaylist: null,
	onClose: null,
	__deleteMode: false,
	__scrollbar: null,
	__title: null,

	constructor: function(id) {
		this.base(id);
		this.setPosition(30, 30);
		this.setSize(740, document.fixedHeight - 60);

		this.__title = this.findChild("Title");
		this.__createPlaylistButton = this.findChild("PlaylistCreate");

		if (this.__createPlaylistButton != null) {
			var self = this;

			this.__createPlaylistButton.onclick = function() {
				if (!self.__deleteMode && self.onCreatePlaylist != null) {
					self.onCreatePlaylist();
				}
			}
		}

		this.__deletePlaylistButton = this.findChild("PlaylistDelete");

		if (this.__deletePlaylistButton != null) {
			var self = this;

			this.__deletePlaylistButton.onclick = function() {
				self.toggleDeleteMode();
			}
		}

		this.__closeButton = this.findChild("PlaylistClose");

		if (this.__closeButton != null) {
			var self = this;

			this.__closeButton.onclick = function() {
				if (self.__currentPlaylist != null && !self.__deleteMode && self.onClose != null) {
					self.onClose();
				}
			}
		}

		this.__playlistList = this.findChild("PlaylistList");
		this.__playlistList.style.display = "none";
		this.__playlistList.style.height = (document.fixedHeight - 190) + "px";

		this.__spinner = this.findChild("Spinner");
		this.__spinner.style.display = "none";

		this.__scrollbar = new Scrollbar(this.findChild("PlaylistScrollbar"));
		this.__scrollbar.addScrollListener(this);
		this.__scrollbar.speed = 20;

		if (useAnimations) {
			this.setOpacity(0);
			this.setShowEffect(new OpacityEffect(this.__divElement, 1.0, 1.0));
			this.setHideEffect(new OpacityEffect(this.__divElement, 1.0, 0.0));
		}
	},

	onScroll: function(scrollbar) {
		this.__playlistList.scrollTop = scrollbar.value;
	},

	show: function() {
		setOpacity(this.__closeButton, (this.__currentPlaylist !== null) ? 1 : 0.125);
		this.base();
		this.__playlistList.scrollTop = this.__scrollbar.value;
	},

	setLoading: function() {
		this.__spinner.style.display = "";
		this.__playlistList.style.display = "none";

		removeChildElements(this.__playlistList);
	},

	setPlaylists: function(playlists) {
		this.playlists = playlists;

		this.__spinner.style.display = "none";
		this.__playlistList.style.display = "";

		removeChildElements(this.__playlistList);

		for (var i in this.playlists) {
			var playlist = this.playlists[i];

			this.__addPlaylistElement(playlist);			
		}

		this.__scrollbar.setRange(0, this.__playlistList.scrollHeight, this.__playlistList.offsetHeight);
		this.__scrollbar.setValue(0);
	},

	removePlaylist: function(playlist) {
		this.__playlistList.removeChild(playlist.linkElement);
		this.__scrollbar.setRange(0, this.__playlistList.scrollHeight, this.__playlistList.offsetHeight);
	},

	__addPlaylistElement: function(playlist) {
		var self = this;

		var outerSpan = document.createElement("span");

		outerSpan.onmouseover = function() {
			self.__applyPlaylistStyles(playlist, true);
		}

		outerSpan.onmouseout = function() {
			self.__applyPlaylistStyles(playlist, false);
		}

		outerSpan.onclick = function() {
			self.__selectPlaylist(playlist);
		}

		this.__playlistList.appendChild(outerSpan);

		var span = document.createElement("span");
		span.className = "listItemContents";
		outerSpan.appendChild(span);

		var marquee = new Marquee(true);
		marquee.setParent(span);

		var link = marquee.getContentElement();
		link.appendChild(document.createTextNode(playlist.title));

		playlist.linkElement = outerSpan;
		this.__applyPlaylistStyles(playlist, false);
	},

	__selectPlaylist: function(playlist) {
		if (this.__deleteMode) {
			if (this.onConfirmDelete !== null) {
				this.onConfirmDelete(playlist);
			}

			this.toggleDeleteMode();
		} else {
			if (this.__currentPlaylist != null) {
				this.__currentPlaylist.selected = false;
				this.__applyPlaylistStyles(this.__currentPlaylist, false);
			}

			this.__currentPlaylist = playlist;
			this.__currentPlaylist.selected = true;
			this.__applyPlaylistStyles(this.__currentPlaylist, false);

			if (this.onPlaylistSelected) {
				this.onPlaylistSelected(playlist);
			}
		}
	},

	toggleDeleteMode: function() {
		this.__deleteMode = !this.__deleteMode;

		var opacity = 1.0;

		if (this.__deleteMode) {
			opacity = 0.125;
		}

		setOpacity(this.__closeButton, (this.__currentPlaylist !== null) ? opacity : 0.125);
		this.__closeButton.enabled = !this.__deleteMode;

		setOpacity(this.__createPlaylistButton, opacity);
		this.__createPlaylistButton.enabled = !this.__deleteMode;

		removeChildElements(this.__title);
		this.__title.appendChild(document.createTextNode((this.__deleteMode) ? "Delete Playlist" : "Select Playlist"));
	},

	__applyPlaylistStyles: function(playlist, highlight) {
		if (!playlist || !playlist.linkElement) {
			return;
		}

		var newClass = "listNormal";

		if (highlight) {
			if (this.__deleteMode) {
				if (playlist.selected) {
					newClass = "listDeleteSelectedHighlighted";
				} else {
					newClass = "listDeleteHighlighted";
				}
			} else {
				if (playlist.selected) {
					newClass = "listSelected";
				} else {
					newClass = "listHighlighted";
				}
			}
		} else if (playlist.selected) {
			newClass = "listSelected";
		}

		playlist.linkElement.className = "listItem " + newClass;
	}
});

var CreatePlaylistWindow = Window.extend({
	onCreate: null,
	onCancel: null,

	constructor: function(id) {
		this.base(id);

		var self = this;
		var createButton = this.findChild("CreateButton");

		createButton.onclick = function() {
			if (self.onCreate !== null) {
				var playlistTitle = self.findChild("PlaylistTitle", "input");

				self.onCreate(playlistTitle.value);
			}
		}

		var cancelButton = this.findChild("CancelButton");

		cancelButton.onclick = function() {
			if (self.onCancel !== null) {
				self.onCancel();
			}
		}

		this.center();
		this.setSize(500, 160);

		if (useAnimations) {
			this.setOpacity(0);
			this.setShowEffect(new OpacityEffect(this.__divElement, 1.0, 1.0));
			this.setHideEffect(new OpacityEffect(this.__divElement, 1.0, 0.0));
		}
	},

	show: function() {
		InputManager.getInstance().setActive(false);
		this.base();
	},

	hide: function() {
		InputManager.getInstance().setActive(true);
		this.base();
	}
});

var ConfirmPlaylistDeleteWindow = Window.extend({
	onDelete: null,
	onCancel: null,
	playlist: null,
	__playlistTitle: null,

	constructor: function(id) {
		this.base(id);

		this.__playlistTitle = this.findChild("DeletePlaylistName");

		var self = this;
		var yesButton = this.findChild("ConfirmDeleteYesButton");

		yesButton.onclick = function() {
			if (self.onDelete !== null) {
				self.onDelete(self.playlist);
			}
		}

		var noButton = this.findChild("ConfirmDeleteNoButton");

		noButton.onclick = function() {
			if (self.onCancel !== null) {
				self.onCancel();
			}
		}

		this.center();
		this.setSize(500, 235);

		if (useAnimations) {
			this.setOpacity(0);
			this.setShowEffect(new OpacityEffect(this.__divElement, 1.0, 1.0));
			this.setHideEffect(new OpacityEffect(this.__divElement, 1.0, 0.0));
		}
	},

	show: function() {
		removeChildElements(this.__playlistTitle);
		this.__playlistTitle.appendChild(document.createTextNode(this.playlist.title));
		this.base();
	}
});

var PlayMode = Base.extend({
	__playlist: null,
	currentTrack: 0,
	repeat: true,

	constructor: function(playlist) {
		this.__playlist = playlist;
	},

	setPlaylist: function(playlist) {
		this.__playlist = playlist;
		this.currentTrack = 0;
	},

	setTrack: function(track) { },

	removeTrack: function(track) { },

	hasNext: function() { return false; },

	next: function() { },

	hasPrevious: function() { return false; },

	previous: function() { },

	__isValidPlaylist: function() {
		return (this.__playlist && this.__playlist.tracks && this.__playlist.length !== 0);
	}
});

var SequentialPlayMode = PlayMode.extend({
	constructor: function(playlist) {
		this.base(playlist);
	},

	setTrack: function(track) {
		this.currentTrack = track.index;
	},

	hasNext: function() {
		return (this.repeat) || (this.currentTrack < this.__playlist.tracks.length - 1);
	},

	next: function() {
		if (!this.__isValidPlaylist()) {
			return;
		}

		++this.currentTrack;

		if (this.currentTrack >= this.__playlist.tracks.length) {
			this.currentTrack = 0;
		}
	},

	hasPrevious: function() {
		return (this.repeat) || (this.currentTrack > 0);
	},

	previous: function() {
		if (!this.__isValidPlaylist()) {
			return;
		}

		--this.currentTrack;

		if (this.currentTrack < 0) {
			this.currentTrack = this.__playlist.tracks.length - 1;
		}
	}
});

var ShufflePlayMode = PlayMode.extend({
	__randomTracks: null,
	__currentRandomTrack: 0,

	constructor: function(playlist) {
		this.base(playlist);
		this.__randomizedPlaylist();
	},

	setPlaylist: function(playlist) {
		this.__playlist = playlist;
		this.currentTrack = 0;
		this.__currentRandomTrack = 0;
		this.__randomizedPlaylist();
	},

	setTrack: function(track) {
		for (var i in this.__randomTracks) {
			if (this.__randomTracks[i] == track) {
				this.__currentRandomTrack = i;
				break;
			}
		}

		this.currentTrack = this.__randomTracks[this.__currentRandomTrack].index;
	},

	removeTrack: function(track) {
		var index = 0;

		for (var i in this.__randomTracks) {
			if (this.__randomTracks[i] == track) {
				index = i;
				break;
			}
		}

		this.__randomTracks.splice(index, 1);

		if (this.currentTrack >= this.__randomTracks.length) {
			this.currentTrack = this.__randomTracks.length - 1;
		}		
	},

	hasNext: function() {
		return (this.repeat) || (this.__currentRandomTrack < this.__randomTracks.length - 1);
	},

	next: function() {
		if (!this.__isValidPlaylist()) {
			return;
		}

		++this.__currentRandomTrack;

		if (this.__currentRandomTrack >= this.__randomTracks.length) {
			this.__randomizedPlaylist();
			this.__currentRandomTrack = 0;
		}

		this.currentTrack = this.__randomTracks[this.__currentRandomTrack].index;
	},

	hasPrevious: function() {
		return (this.repeat) || (this.__currentRandomTrack > 0);
	},

	previous: function() {
		if (!this.__isValidPlaylist()) {
			return;
		}

		--this.__currentRandomTrack;

		if (this.__currentRandomTrack < 0) {
			this.__currentRandomTrack = this.__randomTracks.length - 1;
		}

		this.currentTrack = this.__randomTracks[this.__currentRandomTrack].index;
	},

	__randomizedPlaylist: function() {
		if (!this.__isValidPlaylist()) {
			return;
		}

		this.__randomTracks = this.__playlist.tracks.slice();

		this.__randomTracks.sort(function(a, b) {
			return Math.round(2 * Math.random()) - 1;
		});

		for (var i in this.__randomTracks) {
			this.__randomTracks[i].randomIndex = i;
		}
	}
});

var PlayerWindow = Window.extend({
	__playlist: null,
	__trackPosition: null,
	__playlistTitle: null,
	__trackTitleMarquee: null,
	__trackTitle: null,
	__trackArtist: null,
	__trackAlbum: null,
	__trackInfo: null,
	__emptyCaption: null,
	__loadingCaption: null,
	__currentTrack: null,
	__playMode: null,
	__shuffle: false,
	__repeatMode: 0,
	__playTimer: null,
	__playerRepeatStatus: null,
	__playerShuffleStatus: null,
	__albumArt: null,

	constructor: function(id) {
		this.base(id);
		this.__background = null;

		this.__playMode = new SequentialPlayMode();

		this.__playlistTitle = this.findChild("PlayListTitle");
		this.__trackTitle = this.findChild("PlayListTrackTitle");
		this.__trackArtist = this.findChild("PlayListTrackArtist");
		this.__trackAlbum = this.findChild("PlayListTrackAlbum");
		this.__trackInfo = this.findChild("PlayListTrackInfo");
		this.__emptyCaption = this.findChild("PlayListEmpty");
		this.__loadingCaption = this.findChild("PlayListLoading");
		this.__trackPosition = this.findChild("TrackPosition");
		this.__playerRepeatStatus = this.findChild("PlayerRepeatStatus");
		this.__playerShuffleStatus = this.findChild("PlayerShuffleStatus");
		this.__albumArt = this.findChild("PlayerWindowAlbumArt");

		var self = this;

		this.__playlistTitle.onclick = function() {
			if (self.onSelectPlaylist !== null) {
				self.onSelectPlaylist();
			}
		}

		this.__trackTitle.onclick = function() {
			if (self.onSelectTrack !== null) {
				self.onSelectTrack();
			}
		}

		this.__emptyCaption.onclick = function() {
			if (self.onSelectTrack !== null) {
				self.onSelectTrack();
			}
		}

		if (this.__playerRepeatStatus) {
			this.__playerRepeatStatus.onclick = function() {
				self.toggleRepeat();
			}
		}

		if (this.__playerShuffleStatus) {
			this.__playerShuffleStatus.onclick = function() {
				self.toggleShuffle();
			}
		}

		this.__emptyCaption.style.display = "none";
		this.__trackInfo.style.display = "none";

		this.__playlistTitleMarquee = new Marquee(false);
		this.__playlistTitleMarquee.setParent(this.__trackTitle);

		this.__updateStatusIcons();

		this.setSize(document.fixedWidth, document.fixedHeight);

		if (useAnimations) {
			this.setOpacity(0);
			this.setShowEffect(new OpacityEffect(this.__divElement, 1.0, 1.0));
			this.setHideEffect(new OpacityEffect(this.__divElement, 1.0, 0.0));
		}
	},

	toggleRepeat: function() {
		this.__repeatMode = (this.__repeatMode + 1) % 3;

		this.__playMode.repeat = (this.__repeatMode == 0);

		this.__updateStatusIcons();

		if (this.onRepeatModeChanged) {
			this.onRepeatModeChanged(this.__repeatMode);
		}
	},

	toggleShuffle: function() {
		this.__shuffle = !this.__shuffle;

		if (this.__shuffle) {
			this.__playMode = new ShufflePlayMode();
		} else {
			this.__playMode = new SequentialPlayMode();
		}		

		this.__playMode.setPlaylist(this.__playlist);
		this.__playMode.repeat = (this.__repeatMode == 0);

		if (this.__currentTrack) {
			this.__playMode.setTrack(this.__currentTrack);
		}

		this.__updateStatusIcons();

		if (this.onShuffleModeChanged) {
			this.onShuffleModeChanged(this.__shuffle);
		}
	},

	__updateStatusIcons: function() {
		if (this.__playerRepeatStatus) {
			if (this.__repeatMode == 1) {
				this.__playerRepeatStatus.src = "Images/RepeatTrack.png";
			} else {
				this.__playerRepeatStatus.src = "Images/Repeat.png";
			}

			setOpacity(this.__playerRepeatStatus, (this.__repeatMode != 2) ? 1.0 : 0.25);
		}

		if (this.__playerShuffleStatus) {
			setOpacity(this.__playerShuffleStatus, (this.__shuffle) ? 1.0 : 0.25);
		}
	},

	show: function() {
		this.base();

		if (this.__updateRequired == true) {
			this.__updateTrackInfo();
			this.__updateRequired = false;
		}
	},

	setPlaylist: function(playlist) {
		this.__playlist = playlist;
		this.refreshPlaylist();
		this.play();
	},

	refreshPlaylist: function() {
		this.__playMode.setPlaylist(this.__playlist);

		removeChildElements(this.__playlistTitle);
		this.__playlistTitle.appendChild(document.createTextNode(this.__playlist.title));

		this.__emptyCaption.style.display = "none";
		this.__loadingCaption.style.display = "none";
		this.__trackInfo.style.display = "none";

		var trackTitleElement = this.__playlistTitleMarquee.getContentElement();
		removeChildElements(trackTitleElement);

		if (this.__playlist.tracks && this.__playlist.tracks.length) {
			this.__trackInfo.style.display = "";
		} else if (this.__playlist.loading) {
			this.__loadingCaption.style.display = "";
		} else {
			this.__emptyCaption.style.display = "";
		}
	},

	removeTrack: function(track) {
		this.__playMode.removeTrack(track);
	},

	play: function(forceRestart) {
		if (this.__playlist.tracks == null || this.__playlist.tracks.length == 0) {
			return;
		}

		var oldTrack = this.__currentTrack;
		this.__currentTrack = this.__playlist.tracks[this.__playMode.currentTrack];

		// Don't restart if we're already playing the current track.
		if (!forceRestart && oldTrack == this.__currentTrack) {
			return;
		}

		if (oldTrack !== null) {
			oldTrack.playing = false;
		}

		this.__currentTrack.playing = true;

		if (this.onTrackChanged !== null) {
			this.onTrackChanged(oldTrack, this.__currentTrack);
		}

		if (forceRestart) {
			player.stop();
		}

		if (this.__albumArt) {
			if (this.__currentTrack.albumArtURL) {
				this.__albumArt.style.display = "";
				this.__albumArt.src = this.__currentTrack.albumArtURL;
			} else {
				this.__albumArt.style.display = "none";
			}
		}

		// We use a timeout so that we can consoladate quick changes into one request.
		// This should just be friendly to the mp3tunes servers.
		if (this.__playTimer != null) {
			clearTimeout(this.__playTimer);
		}

		var self = this;
		this.__playTimer = setTimeout(function() { self.__beginStream(); }, 500);
	},

	__beginStream: function() {
		this.__playTimer = null;

		var streamUrl;

		if (useProxy) {
			var path = this.__currentTrack.playURL;

			var startIndex = path.indexOf('/', 7);
			startIndex = path.indexOf('/', startIndex + 1);
			startIndex = path.indexOf('/', startIndex + 1);

			path = path.substring(startIndex + 1);

			streamUrl = Mp3Tunes.baseUrl + Mp3Tunes.lockerScript + "?path=" + escape(path);
		} else {
			streamUrl = this.__currentTrack.playURL;
		}

		player.open(streamUrl);

		this.__updateTrackInfo();
	},

	playTrack: function(track) {
		this.__playMode.setTrack(track);
		this.play();
	},

	nextSong: function(forceRestart) {
		if (this.__repeatMode == 1) {
			this.play(forceRestart);
		} else if (this.__playMode.hasNext()) {
			this.__playMode.next();
			this.play();
		}
	},

	previousSong: function(forceRestart) {
		if (this.__repeatMode == 1) {
			this.play(forceRestart);
		} else if (this.__playMode.hasPrevious()) {
			this.__playMode.previous();
			this.play();
		}
	},

	__updateTrackInfo: function() {
		if (this.isVisible() == false) {
			this.__updateRequired = true;
			return;
		}

		if (this.__currentTrack === null) {
			return;
		}

		var trackTitleElement = this.__playlistTitleMarquee.getContentElement();

		removeChildElements(trackTitleElement);
		trackTitleElement.appendChild(document.createTextNode(this.__currentTrack.trackTitle));

		this.__playlistTitleMarquee.updateBounds();
		this.__playlistTitleMarquee.startScroll();

		removeChildElements(this.__trackAlbum);
		this.__trackAlbum.appendChild(document.createTextNode(this.__currentTrack.albumTitle));

		removeChildElements(this.__trackArtist);
		this.__trackArtist.appendChild(document.createTextNode(this.__currentTrack.artistName));
	}
});

var TracksListWindow = Window.extend({
	__playlist: null,
	__closeButton: null,
	__addTracksButton: null,
	__deleteTracksButton: null,
	__deleteMode: false,
	__scrollbar: null,
	__tracksList: null,
	__title: null,

	constructor: function(id) {
		this.base(id);
		this.setPosition(30, 30);
		this.setSize(740, document.fixedHeight - 60);

		this.__title = this.findChild("Title");
		this.__addTracksButton = this.findChild("TracksListAdd");

		if (this.__addTracksButton != null) {
			var self = this;

			this.__addTracksButton.onclick = function() {
				if (!self.__deleteMode && self.onAddTracks != null) {
					self.onAddTracks();
				}
			}
		}

		this.__deleteTracksButton = this.findChild("TracksListDelete");

		if (this.__deleteTracksButton != null) {
			var self = this;

			this.__deleteTracksButton.onclick = function() {
				self.toggleDeleteMode();
			}
		}

		this.__closeButton = this.findChild("TracksListClose");

		if (this.__closeButton != null) {
			var self = this;

			this.__closeButton.onclick = function() {
				if (!self.__deleteMode && self.onClose != null) {
					self.onClose();
				}
			}
		}

		this.__tracksList = this.findChild("TracksListList");
		this.__tracksList.style.height = (document.fixedHeight - 190) + "px";

		this.__scrollbar = new Scrollbar(this.findChild("TracksListScrollbar"));
		this.__scrollbar.addScrollListener(this);
		this.__scrollbar.speed = 20;

		if (useAnimations) {
			this.setOpacity(0);
			this.setShowEffect(new OpacityEffect(this.__divElement, 1.0, 1.0));
			this.setHideEffect(new OpacityEffect(this.__divElement, 1.0, 0.0));
		}
	},

	onScroll: function(scrollbar) {
		this.__tracksList.scrollTop = scrollbar.value;
	},

	setPlaylist: function(playlist) {
		this.__playlist = playlist;

		if (this.isVisible() == false) {
			this.__updateRequired = true;
		} else {
			this.__updateDisplay();
		}
	},

	addTrack: function(track) {
		this.__updateRequired = true;
	},

	removeTrack: function(track) {
		this.__tracksList.removeChild(track.linkElement);
		this.__scrollbar.setRange(0, this.__tracksList.scrollHeight, this.__tracksList.offsetHeight);
	},

	onTrackChanged: function(oldTrack, newTrack) {
		if (this.__updateRequired == false) {
			if (oldTrack !== null) {
				this.__applyTrackStyles(oldTrack, false);
			}
	
			this.__applyTrackStyles(newTrack, false);
		}
	},

	show: function() {
		this.base();

		if (this.__updateRequired == true) {
			this.__updateDisplay();
		}

		this.__tracksList.scrollTop = this.__scrollbar.value;
	},

	__updateDisplay: function() {
		removeChildElements(this.__tracksList);

		for (var i in this.__playlist.tracks) {
			var track = this.__playlist.tracks[i];

			this.__addTrackElement(track);			
		}

		this.__scrollbar.setRange(0, this.__tracksList.scrollHeight, this.__tracksList.offsetHeight);
		this.__scrollbar.setValue(0);
		this.__updateRequired = false;
	},

	__addTrackElement: function(track) {
		var self = this;

		var outerSpan = document.createElement("span");

		outerSpan.onmouseover = function() {
			self.__applyTrackStyles(track, true);
		}

		outerSpan.onmouseout = function() {
			self.__applyTrackStyles(track, false);
		}

		outerSpan.onclick = function() {
			self.__selectTrack(track);
		}

		this.__tracksList.appendChild(outerSpan);

		var span = document.createElement("span");
		span.className = "listItemContents";
		outerSpan.appendChild(span);

		var marquee = new Marquee(true);
		marquee.setParent(span);

		var link = marquee.getContentElement();
		link.appendChild(document.createTextNode(track.trackTitle));

		track.linkElement = outerSpan;

		this.__applyTrackStyles(track, false);
	},

	__applyTrackStyles: function(track, highlight) {
		if (!track || !track.linkElement) {
			return;
		}

		var newClass = "listNormal";

		if (highlight) {
			if (this.__deleteMode) {
				if (track.playing) {
					newClass = "listDeleteSelectedHighlighted";
				} else {
					newClass = "listDeleteHighlighted";
				}
			} else {
				if (track.playing) {
					newClass = "listSelected";
				} else {
					newClass = "listHighlighted";
				}
			}
		} else if (track.playing) {
			newClass = "listSelected";
		}

		track.linkElement.className = "listItem " + newClass;
	},

	__selectTrack: function(track) {
		if (this.__deleteMode) {
			if (this.onTrackDelete) {
				this.onTrackDelete(track);
			}
		} else if (this.onTrackSelected) {
			this.onTrackSelected(track);
		}
	},

	toggleDeleteMode: function() {
		this.__deleteMode = !this.__deleteMode;

		var opacity = 1.0;

		if (this.__deleteMode) {
			opacity = 0.125;
		}

		setOpacity(this.__closeButton, opacity);
		this.__closeButton.enabled = !this.__deleteMode;

		setOpacity(this.__addTracksButton, opacity);
		this.__addTracksButton.enabled = !this.__deleteMode;

		removeChildElements(this.__title);
		this.__title.appendChild(document.createTextNode((this.__deleteMode) ? "Delete Track" : "Select Track"));
	}
});

var BrowseTracksWindow = Window.extend({
	browseMethod: "Track",
	__browseTokens: null,
	__browseTokensItem: null,
	__closeButton: null,
	__currentToken: null,
	__scrollbar: null,
	__tracksList: null,
	__title: null,

	constructor: function(id) {
		this.base(id);
		this.setPosition(30, 30);
		this.setSize(740, document.fixedHeight - 60);

		this.__title = this.findChild("Title");

		var self = this;

		this.__title.onclick = function() {
			if (self.onSelectBrowseMethod) {
				self.onSelectBrowseMethod();
			}
		}

		this.__closeButton = this.findChild("BrowseTracksClose");

		if (this.__closeButton != null) {
			this.__closeButton.onclick = function() {
				if (self.onClose != null) {
					self.onClose();
				}
			}
		}

		this.__browseTokens = this.findChild("BrowseTracksTokens");
		this.__initializeBrowseTokens();

		this.__tracksList = this.findChild("BrowseTracksList");
		this.__tracksList.style.height = (document.fixedHeight - 190) + "px";

		this.__scrollbar = new Scrollbar(this.findChild("BrowseTracksScrollbar"));
		this.__scrollbar.addScrollListener(this);
		this.__scrollbar.speed = 20;

		if (useAnimations) {
			this.setOpacity(0);
			this.setShowEffect(new OpacityEffect(this.__divElement, 1.0, 1.0));
			this.setHideEffect(new OpacityEffect(this.__divElement, 1.0, 0.0));
		}
	},

	onScroll: function(scrollbar) {
		this.__tracksList.scrollTop = scrollbar.value;
	},

	setBrowseMethod: function(browseMethod) {
		removeChildElements(this.__title);
		this.__title.appendChild(document.createTextNode("Browse by " + browseMethod));

		this.browseMethod = browseMethod;
	},

	__initializeBrowseTokens: function() {
		var tokens = "-ABCDEFGHIJKLMNOPQRSTUVWXYZ";
		var self = this;

		this.__browseTokensItem = [];

		var table = document.createElement("table");
		var row = table.insertRow(0);

		table.cellSpacing = 0;
		table.cellpadding = 0;
		table.appendChild(row);

		this.__browseTokens.appendChild(table);

		var current = 0;

		for (var i = 0; i < tokens.length; ++i) {
			var token = tokens.substr(i, 1);

			var cell = row.insertCell(current++);

			this.__browseTokensItem[token] = document.createElement("span");
			this.__browseTokensItem[token].appendChild(document.createTextNode(token));

			this.__browseTokensItem[token].onmouseover = function() {
				self.__setTokenStyle(this, true);
			}

			this.__browseTokensItem[token].onmouseout = function() {
				self.__setTokenStyle(this, false);
			}

			this.__browseTokensItem[token].onclick = function() {
				if (this.enabled) {
					self.selectToken(this.token);
				}
			}

			this.__browseTokensItem[token].enable = function() {
				this.enabled = true;
				setOpacity(this, 1);
			}

			this.__browseTokensItem[token].disable = function() {
				this.enabled = false;
				setOpacity(this, 0.25);
			}

			this.__browseTokensItem[token].token = token;
			this.__browseTokensItem[token].disable();
			this.__setTokenStyle(this.__browseTokensItem[token], false);

			cell.appendChild(this.__browseTokensItem[token]);
		}
	},

	__setTokenStyle: function(token, highlight) {
		if (!token) {
			return;
		}

		var newClass = "tokenNormal";

		if (token.enabled) {
			if (highlight) {
				if (token.selected) {
					newClass = "tokenSelectedHighlighted";
				} else {
					newClass = "tokenHighlighted";
				}
			} else if (token.selected) {
				newClass = "tokenSelected";
			}
		}

		token.className = "token " + newClass;
	},

	clearBrowseTokens: function() {
		for (var i in this.__browseTokensItem) {
			this.__browseTokensItem[i].disable();
		}
	},

	setBrowseTokens: function(browseTokens) {
		this.clearBrowseTokens();

		for (var i in browseTokens) {
			this.__browseTokensItem[browseTokens[i].token].enable();			
		}
	},

	selectToken: function(token) {
		if (this.__currentToken != null) {
			this.__currentToken.selected = false;
			this.__setTokenStyle(this.__currentToken, false);
		}

		this.__currentToken = this.__browseTokensItem[token];
		this.__currentToken.selected = true;

		this.__setTokenStyle(this.__currentToken, true);

		if (this.onSelectToken) {
			this.onSelectToken(token);
		}
	},

	show: function() {
		this.base();

		this.__tracksList.scrollTop = this.__scrollbar.value;
		this.__scrollbar.setRange(0, this.__tracksList.scrollHeight, this.__tracksList.offsetHeight);
	},

	setTracks: function(tracks) {
		removeChildElements(this.__tracksList);

		for (var i in tracks) {
			var track = tracks[i];

			this.__addTrackElement(track);
		}

		this.__scrollbar.setRange(0, this.__tracksList.scrollHeight, this.__tracksList.offsetHeight);
		this.__scrollbar.setValue(0);
	},

	__addTrackElement: function(track) {
		var self = this;

		var outerSpan = document.createElement("span");

		outerSpan.onmouseover = function() {
			self.__applyTrackStyles(track, true);
		}

		outerSpan.onmouseout = function() {
			self.__applyTrackStyles(track, false);
		}

		outerSpan.onclick = function() {
			self.__selectTrack(track);
		}

		this.__tracksList.appendChild(outerSpan);

		var span = document.createElement("span");
		span.className = "listItemContents";
		outerSpan.appendChild(span);

		var marquee = new Marquee(true);
		marquee.setParent(span);

		var link = marquee.getContentElement();
		link.appendChild(document.createTextNode(track.trackTitle));

		track.linkElement = outerSpan;

		this.__applyTrackStyles(track, false);
	},

	__applyTrackStyles: function(track, highlight) {
		if (!track || !track.linkElement) {
			return;
		}

		var newClass = "listNormal";

		if (highlight) {
			if (track.playing) {
				newClass = "listSelected";
			} else {
				newClass = "listHighlighted";
			}
		}

		track.linkElement.className = "listItem " + newClass;
	},

	__selectTrack: function(track) {
		if (this.onSelectTrack) {
			var linkElement = track.linkElement;
			delete track.linkElement;
			this.onSelectTrack(clone(track));
			track.linkElement = linkElement;
		}
	}
});

var BrowseByTypeSelectionWindow = Window.extend({
	onSelectBrowseMethod: null,
	onCancel: null,

	constructor: function(id) {
		this.base(id);

		var self = this;
		var createButton = this.findChild("OkButton");

		createButton.onclick = function() {
			if (self.onSelectBrowseMethod !== null) {
				var browseMethod = self.findChild("BrowseByTypeSelect", "select");

				self.onSelectBrowseMethod(browseMethod.value);
			}
		}

		var cancelButton = this.findChild("CancelButton");

		cancelButton.onclick = function() {
			if (self.onCancel !== null) {
				self.onCancel();
			}
		}

		this.center();
		this.setSize(341, 245);

		if (useAnimations) {
			this.setOpacity(0);
			this.setShowEffect(new OpacityEffect(this.__divElement, 1.0, 1.0));
			this.setHideEffect(new OpacityEffect(this.__divElement, 1.0, 0.0));
		}
	},

	show: function() {
		InputManager.getInstance().setActive(false);
		this.base();
	},

	hide: function() {
		InputManager.getInstance().setActive(true);
		this.base();
	}
});

var AddingTrackWindow = Window.extend({
	__addingTrackInfo: null,

	constructor: function(id) {
		this.base(id);

		this.__addingTrackInfo = this.findChild("AddingTrackInfo");

		this.center();
		this.setSize(600, 145);

		if (useAnimations) {
			this.setOpacity(0);
			this.setShowEffect(new OpacityEffect(this.__divElement, 1.0, 1.0));
			this.setHideEffect(new OpacityEffect(this.__divElement, 1.0, 0.0));
		}
	},

	showModal: function() {
		this.base();
		this.setSize(600, this.__addingTrackInfo.offsetHeight);
	},

	setTrack: function(track) {
		var message = "Adding '" + track.trackTitle + "'.";

		removeChildElements(this.__addingTrackInfo);
		this.__addingTrackInfo.appendChild(document.createTextNode(message));
	}
});

var VolumeOverlay = Window.extend({
	__minusDown: false,
	__plusDown: false,
	__interval: null,
	__hideTimeout: null,
	step: 10,

	constructor: function(id) {
		this.base(id);
		this.setSize(200, 200);
		this.center();

		this.__background = new FadedBackground();

		if (useAnimatedOverlay) {
			this.setOpacity(0);
			this.setShowEffect(new OpacityEffect(this.__divElement, 1.0, 1.0));
			this.setHideEffect(new OpacityEffect(this.__divElement, 1.0, 0.0));
		}
	},

	paint: function() {
		if (this.__background !== null) {
			this.__background.paint(this.__canvasElement, this.canvas);
		}

		if (this.__divElement.offsetWidth <= 0) {
			return;
		}

		var width   = this.__divElement.offsetWidth;
		var height  = this.__divElement.offsetHeight;
		var center  = width / 2;
		var percent = (player.getVolume() / Player.MaxVolume);

		var end    =  percent * Math.PI * 2;
		var offset = -Math.PI / 2;
		var largeRadius = center * 0.8;
		var smallRadius = center * 0.65;
		var sliceSize = Math.PI * 2 / VolumeOverlay.slices;
		var i = 0;

		for (i = 0; i < VolumeOverlay.slices; ++i) {
			if ((i / VolumeOverlay.slices) < percent) {
				this.canvas.fillStyle = "#FFFFFF";
			} else {
				this.canvas.fillStyle = "rgba(0, 0, 0, 0.25)";
			}

			this.canvas.beginPath();
				this.canvas.arc(center, center, largeRadius, i * sliceSize + offset, (i + 1) * sliceSize - sliceSize / 2 + offset, false);
				this.canvas.arc(center, center, smallRadius, (i + 1) * sliceSize - sliceSize / 2 + offset, i * sliceSize + offset, true);
			this.canvas.closePath();
			this.canvas.fill();
		}
	},

	show: function() {
		if (this.__hideTimeout != null) {
			clearTimeout(this.__hideTimeout);
		}

		this.base();

		var wiimote = InputManager.getInstance().wiimote;

		this.__minusDown = wiimote.minus;
		this.__plusDown  = wiimote.plus;
	},

	hide: function() {
		if (this.__hideTimeout != null) {
			clearTimeout(this.__hideTimeout);
		}

		this.__hideTimeout = null;
		this.base();
	},

	onButtonPressed: function(button) {
		if (button == Wiimote.minus) {
			this.__minusDown = true;
		}

		if (button == Wiimote.plus) {
			this.__plusDown = true;
		}

		if (this.__interval == null && (this.__minusDown || this.__plusDown)) {
			var self = this;

			this.__interval = setInterval(
				function() {
					self.__adjustVolume();
				},
				100
			);
		}

		return (button == Wiimote.minus || button == Wiimote.plus);
	},

	onButtonReleased: function(button) {
		if (!this.isVisible()) {
			return;
		}

		if (button == Wiimote.minus) {
			this.__minusDown = false;
		}

		if (button == Wiimote.plus) {
			this.__plusDown = false;
		}

		if (this.__interval && !this.__minusDown && !this.__plusDown) {
			clearInterval(this.__interval);
			this.__interval = null;
		}

		if (!this.__minusDown && !this.__plusDown) {
			var self = this;

			this.__hideTimeout = setTimeout(function() { self.hide(); }, VolumeOverlay.hideDelay);
		}

		return (button == Wiimote.minus || button == Wiimote.plus);
	},

	__adjustVolume: function() {
		var volume = player.getVolume();
		
		if (this.__minusDown) {
			volume -= this.step;
		}

		if (this.__plusDown) {
			volume += this.step;
		}

		player.setVolume(volume);
		this.paint();
	}
},{
	hideDelay: 1000,
	slices: 20
});

var ActionOverlay = Window.extend({
	__actionCaption: null,
	__hideTimeout: null,

	constructor: function(id) {
		this.base(id);
		this.setPosition(30, 30);
		this.setSize(240, 75);

		this.__background    = new FadedBackground();
		this.__actionCaption = this.findChild("ActionCaption");

		if (useAnimatedOverlay) {
			this.setOpacity(0);
			this.setShowEffect(new OpacityEffect(this.__divElement, 1.0, 1.0));
			this.setHideEffect(new OpacityEffect(this.__divElement, 1.0, 0.0));
		}
	},

	showAction: function(action, autoHide) {
		if (this.__hideTimeout != null) {
			clearTimeout(this.__hideTimeout);
		}

		removeChildElements(this.__actionCaption);
		this.__actionCaption.appendChild(document.createTextNode(action));
		this.show();

		if (autoHide == undefined || autoHide === true) {
			var self = this;
	
			this.__hideTimeout = setTimeout(function() { self.hide(); }, ActionOverlay.hideDelay);
			this.base();
		}
	},

	hide: function() {
		if (this.onHide && this.onHide() == false) {
			return;
		}

		if (this.__hideTimeout != null) {
			clearTimeout(this.__hideTimeout);
		}

		this.__hideTimeout = null;
		this.base();
	}
},{
	hideDelay: 3000
});

WiimoteHelp = Window.extend({
	constructor: function(id) {
		this.base(id);
		this.setSize(480, 480);
		this.center();

		this.__background = new RoundedBackground();

		var self = this;
		this.__divElement.onclick = function() { self.hide(); };

		if (useAnimatedOverlay) {
			this.setOpacity(0);
			this.setShowEffect(new OpacityEffect(this.__divElement, 1.0, 1.0));
			this.setHideEffect(new OpacityEffect(this.__divElement, 1.0, 0.0));
		}
	}
});

var Wiimote = Base.extend({
	a: false,
	b: false,
	c: false,
	down: false,
	left: false,
	minus: false,
	one: false,
	plus: false,
	right: false,
	two: false,
	up: false,
	z: false,

	constructor: function() { }
},{
	a: 1,
	b: 2,
	c: 3,
	down: 4,
	left: 5,
	minus: 6,
	one: 7,
	plus: 8,
	right: 9,
	two: 10,
	up: 11,
	z: 12
});

function preventDefault(event) {
	event.preventDefault();
}

var InputManager = Base.extend({
	wiimote: null,
	__listeners: null,
	active: true,

	constructor: function() {
		if (InputManager.__instance != null) {
			throw "Input manager already created.";
		}

		var self = this;
		var storeButtons = function(event) { self.__storeButtonState(event) };

		this.wiimote = new Wiimote();
		this.__listeners = [];

		document.addEventListener('mousedown', storeButtons, false);
		document.addEventListener('mouseup', storeButtons, false);
		document.addEventListener('keydown', storeButtons, false);
		document.addEventListener('keyup', storeButtons, false);

		// Prevent all normal Wii behavior. We're a custom app.
		this.setActive(true);
	},

	setActive: function(state) {
		if (state) {
			document.addEventListener('keypress', preventDefault, false);
		} else {
			document.removeEventListener('keypress', preventDefault, false);
		}

		this.active = state;
	},

	addInputListener: function(listener) {
		this.__listeners.push(listener);
	},

	removeInputListener: function(listener) {
		var index = this.__listeners.indexOf(listener);

		if (index != -1) {
			this.__listeners.splice(index, 1);
		}
	},

	fireButtonPressed: function(button) {
		for (var i in this.__listeners) {
			if (this.__listeners[i].onButtonPressed(button) == true) {
				break;
			}
		}
	},

	fireButtonReleased: function(button) {
		for (var i in this.__listeners) {
			if (this.__listeners[i].onButtonReleased(button) == true) {
				break;
			}
		}
	},

	fireButtonEvent: function(button, state) {
		if (this.active == true) {
			if (state) {
				this.fireButtonPressed(button);
			} else {
				this.fireButtonReleased(button);
			}
		}
	},

	__storeButtonState: function(event) {
		var newState = (event.type == 'mousedown' || event.type == 'keydown' ) ? true : false;
	
		if (event.type == 'mousedown' || event.type == 'mouseup' || event.keyCode == 13 ) {
			this.wiimote.a = newState;
			this.fireButtonEvent(Wiimote.a, newState);
		}

		switch (event.keyCode) {
			case 45:
			case 109:
			case 170:
				this.wiimote.minus = newState;
				this.fireButtonEvent(Wiimote.minus, newState);
				break;

			case 66:
			case 171:
				this.wiimote.b = newState;
				this.fireButtonEvent(Wiimote.b, newState);
				break;

			case 49:
			case 172:
				this.wiimote.one = newState;
				this.fireButtonEvent(Wiimote.one, newState);
				break;

			case 50:
			case 173:
				this.wiimote.two = newState;
				this.fireButtonEvent(Wiimote.two, newState);
				break;

			case 61:
			case 107:
			case 174:
				this.wiimote.plus = newState;
				this.fireButtonEvent(Wiimote.plus, newState);
				break;
	
			case 38:
			case 175:
				this.wiimote.up = newState;
				this.fireButtonEvent(Wiimote.up, newState);
				break;

			case 40:
			case 176:
				this.wiimote.down = newState;
				this.fireButtonEvent(Wiimote.down, newState);
				break;

			case 39:
			case 177:
				this.wiimote.right = newState;
				this.fireButtonEvent(Wiimote.right, newState);
				break;

			case 37:
			case 178:
				this.wiimote.left = newState;
				this.fireButtonEvent(Wiimote.left, newState);
				break;
		}
	}
},{
	__instance: null,

	getInstance: function() {
		if (InputManager.__instance == null) {
			InputManager.__instance = new InputManager();
		}

		return InputManager.__instance;
	}
});

InputManager.getInstance().addInputListener(Window);

