/* Constants */
var BOX_WIDTH = 250,
	BOX_START_Y = 100,
	BOX_MARGIN_X = 20,
	BOX_MARGIN_Y = 40,
	LEFT_PADDING = 30,
	RIGHT_PADDING = BOX_WIDTH + LEFT_PADDING + 10;

var lastfm = new LastFM({
	key: 'e028647914484cb5b289fd882e2e771d'
});

var MusicTree = Backbone.View.extend({
	mixin: ['DragDrop'],
	
	el: window, $el: $(window),
	
	tabs: [], active: null,
	artistList: [],
	areaID: 0,
	
	initialize: function() {
		this.changeType();
		
		this.$topBar = $('#top-bar');
		this.$tabArea = $('#tab-area');
		this.$boxContainer = $('#box-container');
		
		this.resize();
		this.mixin.DragDrop();
		
		tooltips.start();
	},
	
	search: function(title) {
		var tab = new Tab({
			id: this.areaID++,
			type: this.type,
			name: title
		});
		
		this.tabs.push( tab );
		tab.activate();
		
		this.resize();
	},
	
	resize: function() {
		var space = this.$el.width() - RIGHT_PADDING - LEFT_PADDING;
		
		this.$topBar.width( space );
		this.$boxContainer.width( space - ( LEFT_PADDING * 2 ) );
		
		if ( this.active !== null ) {
			this.active.top.view.reform();
		}
		
		var center = LEFT_PADDING + ( space / 2 ),
			position = 0, tabsWidth = 0, length = this.tabs.length;
		
		_.each( this.tabs, function( tab, i ) {
			tab.el.className = 'tab' + (musicTree.active == tab ? ' active' : '');
			
			if ( length > 1 ) {
				if ( i == 0 ) {
					tab.el.className += ' left';
				} else if ( i == length - 1 ) {
					tab.el.className += ' right';
				} else {
					tab.el.className += ' middle';
				}
			}
			
			tabsWidth += tab.el.offsetWidth;
		});
		
		position = center - ( tabsWidth / 2 );
		
		_.each( this.tabs, function( tab ) {
			tab.el.style.left = position + 'px';
			position += tab.el.offsetWidth;
		});
	},
	
	events: {
		'resize': 'resize',
		
		'change #search-type': 'changeType',
		'keydown #search-bar': function(e) {
			if ( e.keyCode == 13 && e.target.value != '' ) {
				this.search( e.target.value );
			}
		},
		
		'mousedown #box-container': 'drag'
	},
	
	changeType: function() {
		var select = $('#search-type')[0],
			option = select.options[select.selectedIndex],
			type = option.value;
		
		if ( type == 'artist' ) {
			this.type = Artist;
		}
		
		if ( type == 'tag' ) {
			this.type = Tag;
		}
	},
	
	drag: function(e) {
		if (!this.active || (e.target != document.getElementById('box-container') && e.target.nodeName != 'CANVAS')) {
			return;
		}
		
		this.mixin.DragDrop.drag(e);
	},
	
	move: function(e) {
		if (!this.active) {
			return;
		}
		
		var $area = $('#box-container');
		$area.scrollLeft($area.scrollLeft() + (this.prev.x - e.pageX));
		$area.scrollTop($area.scrollTop() + (this.prev.y - e.pageY));
		
		this.mixin.DragDrop.move(e);
	}
});

var Tab = Backbone.View.extend({
	scale: 1,
	
	templates: {
		list: {
			el: 'tab',
			area: 'box-area'
		},
		groups: [],
		$: ['el']
	},
	
	initialize: function() {
		this.template('el');
		
		var type = this.options.type.prototype.type,
			options = {areaID: this.options.id};
		
		options[type] = this.options.name;
		this.template('area');
		
		var box = this.top = new this.options.type(options);
		
		box.top = box;
		box.view.reform();
	},
	
	activate: function() {
		if (musicTree.active == this) {
			return;
		}
		
		this.el.className += ' active';
		this.area.style.display = 'block';
		
		if (musicTree.active) {
			musicTree.active.deactivate();
		}
		
		musicTree.active = this;
		
		return this;
	},
	
	deactivate: function() {
		this.$el.removeClass('active');
		this.area.style.display = 'none';
		
		musicTree.active = null;
	},
	
	close: function(e) {
		var tabs = musicTree.tabs, tab,
			index = _.indexOf( tabs, this );
		
		if ( musicTree.active == this ) {
			this.deactivate();
		
			if ( tabs[ index + 1 ] ) {
				tab = tabs[ index + 1 ].activate();
			}
			else if ( tabs[ index - 1 ] ) {
				tabs[ index - 1 ].activate();
			}
		}
		
		tabs.splice( index, 1 );
		$_(this.area).remove();
		this.$el.remove();
		
		musicTree.resize();
	},
	
	events: {
		'mousedown :not(.tab-close)': function(e) {
			e.preventDefault();
			this.activate();
		},
		'mousedown .tab-close': 'close'
	}
});

var Box = Backbone.Model.extend({
	mixin: ['TreeStruct'],
	
	initialize: function() {
		this.mixin.TreeStruct();
	},
	
	// create child boxes
	createBox: function(type, names) {
		if (!_.isArray(names)) {
			names = [names];
		}
		
		var Model = (type == 'artist') ? Artist : ((type == 'tag') ? Tag : User);
		
		for ( var i = 0, name; (name = names[i]); i++ ) {
			var options = { areaID: this.attributes.areaID };
			options[type] = name;
			
			var box = new Model(options);
			
			this.addChild( box );
			box.top = this.top;
		}
		
		this.view.calculate();
		this.top.view.reform();
		
		// FIX
		var container = document.getElementById('box-container');
		if (container.offsetHeight < container.scrollHeight) {
			tooltips.drag();
		}
	},
	
	addChild: function( child ) {
		this.mixin.TreeStruct.addChild( child );
		this.view.children.push( child.view );
	}
});

var BoxView = Backbone.View.extend({
	// the total width of the box (including children)
	width: BOX_WIDTH,
	
	templates: {
		list: {
			el: 'box',
			tab: 'box-tab',
			section: 'box-section',
			album: 'box-album',
			canvas: 'box-canvas'
		},
		groups: ['tab', 'section', 'album', 'album-links', 'album-loading', 'album-date', 'album-tracks'],
		$: ['el', 'header']
	},
	
	initialize: function() {
		this.sectionMap = {};
		this.tabWidths = [];
		this.children = [];
		
		this.template('el');
		this.template('canvas');
		
		_.bindAll(this, 'positionFront');
	},
	
	makeSections: function() {
		this.sectionsToLoad = arguments.length;
		
		for ( var i = 0, name; ( name = arguments[i] ); i++ ) {
			var className = name.replace(/ /g, '').toLowerCase(),
				data = { active: i == 0, name: name, className: className },
				tab = this.template( 'tab', data ),
				section = this.template( 'section', data );
			
			if ( !this.noLoad ) {
				$_(tab).css('opacity', 0.5);
			}
			// remove the loading image fron non-loading boxes
			else {
				$_(section).children().remove();
			}
			
			this.sectionMap[ name ] = { section: section, tab: tab };
			
			if ( i == 0 ) {
				this.active = $().add(tab).add(section);
			}
		}
		
		this.resize();
	},
	// make the tabs at the top of a box have equal size
	resize: function() {
		var tabWidth = 0;
		for ( var i = 0, el; (el = this.tab[i]); i++ ) {
			el.style.padding = '0';
			tabWidth += el.offsetWidth;
		}
		
		var boxWidth = this.$el.width(),
			space = boxWidth - tabWidth,
			padding = parseInt( space / this.tab.length );
		
		for ( var i = 0, el; ( el = this.tab[i] ); i++ ) {
			space -= padding;
			
			if ( i == this.tab.length - 1 ) {
				padding += space;
			}
			
			el.style.padding = '0 ' + ( padding / 2 ) + 'px';
		}
	},
	
	loaded: function(name, content, callback) {
		var self = this,
			parts = this.sectionMap[name],
			section = parts.section,
			tab = parts.tab;
			
		this.sectionsToLoad--;
		
		if (!this.noLoad) {
			$_(tab).css('opacity', 1);
									
			$_(section).children('.loading').animate( {opacity: 0}, function() {
				$(this).remove();
				
				$_(content)
					.css('display', 'none')
					.appendTo(section)
					.fadeIn(function() {
						callback && callback.call(self);
					});
			});
			
		}
		else {
			section.appendChild(content);
		}
	},
	
	calculate: function() {
		var box = this.model;
		
		while ( box ) {
			var childWidth = 0;
			
			for ( var i = 0, child; child = box.children[i]; i++ ) {
				childWidth += child.view.width;
				
				if ( box.children.length - 1 != i ) {
					childWidth += BOX_MARGIN_X;
				}
			}
			
			box.view.width = childWidth || BOX_WIDTH;
			box = box.parent;
		}
	},
	
	reform: function( center, depth ) {
		if ( !center ) {
			depth = 0;
			
			var screen = musicTree.$el.width(),
				space = screen - RIGHT_PADDING - ( LEFT_PADDING * 3 );
			
			if ( space < this.width ) {
				space = this.width;
			}
			
			center = space / 2;
			this.middle = center;
		}
		
		this.$el.css({
			left: ( center - ( BOX_WIDTH / 2 )) + 'px',
			top: ( BOX_START_Y + ( ( this.$el.height() + BOX_MARGIN_Y ) * depth ) ) + 'px'
		});
		
		var start = center - (this.width / 2);
		depth++;
		
		if (!this.children.length) {
			return;
		}
		
		var verticalStart = ( BOX_START_Y + ( ( this.$el.height() + BOX_MARGIN_Y ) * depth ) ) - BOX_MARGIN_Y;
		
		this.canvas.style.display = 'block';
		this.canvas.width = this.width;
		this.canvas.height = BOX_MARGIN_Y;
		
		this.canvas.style.left = start + 'px';
		this.canvas.style.top = verticalStart + 'px';
		var context = this.canvas.getContext('2d');
		
		context.strokeStyle = "#cc1f1f";
		context.lineWidth = 4;
		
		var end = this.width - (_.last(this.children).width / 2);
		// draw the top line above the children
		context.moveTo((this.children[0].width / 2) - 4, 20);
		context.lineTo(end, 20);
		// draw the line connecting the top bar to the parent
		context.moveTo((this.width / 2) - 2, 0);
		context.lineTo((this.width / 2) - 2, 20);
		
		var relative = 0;
		
		for (var i = 0, child; (child = this.children[i]); i++) {
			child.middle = start + (child.width / 2),
			child.vertical = verticalStart + BOX_MARGIN_Y;
			
			context.moveTo(relative + (child.width / 2) - 2, 20);
			context.lineTo(relative + (child.width / 2) - 2, BOX_MARGIN_Y);
			
			child.reform( child.middle, depth );
			
			relative += child.width + BOX_MARGIN_X;
			start += child.width + BOX_MARGIN_X;
		}
	
		// show the lines
		context.stroke();
	},
	
	loadAlbum: function(id) {
		var albumList = this.model.attributes.albums,
			album = albumList[id],
			name = (this.model.attributes.artist) ? album.name : album.artist.name + ' - ' + album.name,
			artist = album.artist.name || album.artist,
			content = this.template('album', {
				name: name,
				image: album.images.large,
				first: id == 0, last: id == albumList.length - 1
			}, {refID: id});
			
		// create the album links
		_.each(links.album, function(link) {
			var url = linkFormat(link, {
				artist: artist,
				album: album.name
			});
			
			this.albumLinks[id].addItem({name: link.name, value: url, image: link.icon});
		}, this);
		
		lastfm.album.getInfo(artist, album.name, {
			success: function(album) {
				var rows = new TrackRows({tracks: album.tracks, artist: artist});
				
				this.albumLoading[id].style.display = 'none';
				
				this.albumTracks[id].style.display = 'block';
				this.albumTracks[id].appendChild(rows.el);
				
				this.albumDate[id].style.display = 'block';
				this.albumDate[id].innerHTML = album.releasedate;
			}
		}, this);
		
		return content;
	},
	
	gotoAlbum: function(id, direction) {
		var albumList = this.model.attributes.albums,
			oldID = this.activeAlbum,
			area = this.sectionMap.Albums.section,
			content = this.album[id] || this.loadAlbum(id);
		
		this.activeAlbum = id;
		
		if (albumList[id + 1] && !this.album[id + 1]) {
			this.loadAlbum(id + 1);
		}
		
		// just display the first album
		if (oldID === undefined) {
			content.style.left = '0px';
			this.loaded('Albums', content);
		}
		else {
			var oldContent = this.album[oldID],
				move = (direction == 'left') ? 250 : -250,
				self = this;
			
			this.moving = true;
			$_(oldContent).animate({left: move}, function() {
				self.moving = false;
				this.parentNode.removeChild(this);
			});
			
			area.appendChild(content);
			content.style.left = -move + 'px';
			$_(content).animate({left: 0});
		}
	},
	
	albumPrev: function() {
		this.gotoAlbum(this.activeAlbum - 1, 'left');
	},
	
	albumNext: function() {
		this.gotoAlbum(this.activeAlbum + 1, 'right');
	},
	
	switchTab: function(tab) {
		var index = _.indexOf(this.tab, tab),
			section = this.section[index];
		
		// deactive the previous tab/section
		this.active && this.active.removeClass('active');
		
		this.active = $().add(tab).add(section).addClass('active');
	},
	
	openLink: function(link) {
		window.open(link);
	},
	
	openTag: function(tag) {
		this.model.createBox('tag', tag);
	},
	
	positioned: false,
	positionTimer: null,
	positionFront: function() {
		var imageWidth = this.frontImage.offsetWidth, imageHeight = this.frontImage.offsetHeight;
		
		if (!imageWidth || imageHeight < 30) {
			return;
		}
		
		this.frontRight.style.marginLeft = imageWidth + 'px';
		this.frontOuter.style.width = imageWidth + this.frontRight.offsetWidth + 'px';
		
		this.frontRight.style.top = 8 + (this.frontLeft.offsetHeight / 2) - (this.frontRight.offsetHeight / 2) + 'px';
		
		clearInterval(this.positionTimer);
	},
	
	updates: {
		// update the header when a title is set
		title: function( title ) {
			this.$header.text( title );
		}
	},
	
	events: {
		'mousedown .tab': function(e) {
			e.preventDefault();
			this.switchTab(e.target);
		},
		'click .album-prev': 'albumPrev',
		'click .album-next': 'albumNext'
	}
});

var Artist = Box.extend({
	type: 'artist',
	
	initialize: function() {
		this.$super();
		
		// see if this artist has already been loaded
		var artistData = musicTree.artistList[ this.attributes.artist ];
		this.noLoad = !!artistData;
		
		this.view = new ArtistView({model: this});
		this.refresh();
		
		// load the main artist information
		lastfm.artist.getInfo(this.attributes.artist, {
			success: this.main,
			error: this.error
		}, this);
	},
	
	main: function(artist) {
		if (artist.bio.summary == '' && !artist.similar.length) {
			return this.notFound();
		}
		
		this.set({
			artist: artist.name, // set the corrected artist name
			image: artist.images.large,
			bio: artist.bio.summary,
			tags: artist.tags
		});
		
		// load the other data
		lastfm.artist.getTopTracks(this.attributes.artist, {
			success: function(tracks) {
				this.set({tracks: tracks});
			}
		}, this);
		
		lastfm.artist.getSimilar(this.attributes.artist, {
			success: function(similar) {
				this.set({similar: similar});
			}
		}, this);
		
		lastfm.artist.getTopAlbums(this.attributes.artist, {
			success: function(albums) {
				this.set({albums: albums});
			}
		}, this);
		
		lastfm.artist.getEvents(this.attributes.artist, {
			success: function(events) {
				this.set({events: events});
			}
		}, this);
	},
	
	error: function(code, message) {
		if (code == 6) {
			this.notFound();
		}
	},
	
	notFound: function() {
		var self = this, params = $.param({
			v: '1.0',
			q: this.attributes.artist + ' site:last.fm/music/ intitle:"Free listening"'
		});
		
		$.getJSON('http://ajax.googleapis.com/ajax/services/search/web?' + params + '&callback=?', function(data) {
			for (var i = 0, item; (item = data.responseData.results[i]); i++) {
				if (item.unescapedUrl.split('music/')[1].indexOf('/') != -1) continue;
				
				var hyphen = String.fromCharCode(8211),
					artist = item.titleNoFormatting.split(' ' + hyphen + ' ')[0];
				
				self.set({artist: artist});
				// load the main artist information
				lastfm.artist.getInfo(self.attributes.artist, {
					success: self.main,
					error: self.error
				}, self);
				
				break;
			}
			
			console.log(artist, i);
		});
		//lastfm.artist.search(this.attributes.artist, {
		//	success: function(data) {
		//		console.log(data);
		//	}
		//}, this);
	},
	
	updates: {
		artist: function(artist) {
			this.set({title: artist});
		}
	}
});

var ArtistView = BoxView.extend({
	templates: {
		list: {
			main: 'artist-main',
			event: 'event'
		},
		groups: [],
		$: ['main']
	},
	
	initialize: function() {
		this.$super();
		
		this.makeSections('Main', 'Tracks', 'Albums', 'Similar');
		this.albums = {};
	},
	
	loaded: function(name, content, callback) {
		this.$super.loaded(name, content, callback);
		
		if ( this.sectionsToLoad == 0 ) {
			musicTree.artistList[this.model.attributes.artist] = this.model.attributes;
		}
	},
	
	updates: {
		bio: function() {
			var self = this;
			this.template('main');
			
			// create the artist links
			_.each(links.artist, function(link) {
				var url = linkFormat(link, { artist: this.model.attributes.artist });
				this.artistLinks.addItem({ name: link.name, value: url, image: link.icon });
			}, this);
			
			this.loaded('Main', this.main, function() {
				tooltips.linksA(this);
			});
			
			this.positionTimer = setInterval(this.positionFront, 30);
			
			/* MORE TO DO HERE */
		},
		
		tags: function(tags) {
			// add the tags to the tag menu
			_.each(tags, function(tag) {
				this.artistTags.addItem({ name: tag.name, value: tag.name });
			}, this);
		},
		
		tracks: function(tracks) {
			var artist = this.model.attributes.artist,
				rows = new TrackRows({tracks: tracks, artist: artist, noArtist: true});
			
			this.loaded('Tracks', rows.el);
		},
		
		similar: function( similar ) {
			var rows = new SimilarRows({ similar: similar, parent: this.model });
			
			this.loaded('Similar', rows.el);
			$_(this.footerText).fadeIn();
		},
		
		albums: function(albums) {
			if (albums.length) {
				this.gotoAlbum(0);
			} else {
				this.loaded('Albums', $('<div>No Albums Found</div>')[0]);
			}
		},
		
		events: function(events) {
			for (var i = 0, event; (event = events[i]); i++) {
				
				var date = new Date(event.startDate);
				
				this.artistEvents.addItem({
					name: this.template('event', {
						date: date.getDate() + '/' + date.getMonth(),
						title: event.title + ' @ ' + event.venue.name
					}),
					value: event.url
				});
				
				if (event.venue.location.country == country) {
					var item = 	$(_.last(this.artistEvents.item)).addClass('active');
				}
			}
			
			if (!events.length) {
				this.artistEvents.disable();
			}
		}
	},
	
	events: {
		'mousedown .artist-albums': function(e) {
			if (this.moving) {
				e.preventDefault();
			}
		},
		'mousedown .album-prev, .album-next': function(e) {
			e.preventDefault();
		},
		'mousedown .footer-text': function() {
			var similar = this.model.attributes.similar;
			this.model.createBox('artist', [similar[0].name, similar[1].name, similar[2].name]);
		},
		
		'mousedown .artist-links': function() {
			tooltips.linksB(this);
		}
	}
});

var Tag = Box.extend({
	type: 'tag',
	
	initialize: function(options) {
		this.$super(options);
		
		this.view = new TagView({model: this});
		this.refresh();
		
		// load the tag information
		lastfm.tag.getInfo(this.attributes.tag, {
			success: this.main
		}, this);
	},
	
	main: function(tag) {
		this.set({
			bio: tag.wiki.summary
		});
		
		lastfm.tag.getTopArtists(this.attributes.tag, {
			success: function(artists) {
				this.set({artists: artists});
			}
		}, this);
		
		lastfm.tag.getTopTracks(this.attributes.tag, {
			success: function(tracks) {
				this.set({tracks: tracks});
			}
		}, this);
		
		lastfm.tag.getTopAlbums(this.attributes.tag, {
			success: function(albums) {
				this.set({albums: albums});
			}
		}, this);
	},
	
	updates: {
		tag: function(tag) {
			this.set({title: tag});
		}
	}
});

var TagView = BoxView.extend({
	templates: {
		main: 'tag-main'
	},
	
	initialize: function() {
		this.$super();
		
		this.makeSections('Main', 'Artists', 'Tracks', 'Albums');
	},
	
	updates: {
		bio: function() {
			this.template('main');
			
			_.each(links.tag, function(link) {
				var url = linkFormat(link, {
					tag: this.model.attributes.tag,
				});
				
				this.tagLinks.addItem({ name: link.name, value: url, image: link.icon });
			}, this);
			
			this.loaded('Main', this.main);
			
			this.positionTimer = setInterval(this.positionFront, 30);
		},
		
		artists: function(artists) {
			this.collageLoading.style.display = 'none';
			this.collage.style.display = 'block';
			
			var images = $_(this.collage).children();
			for (var i = 0, image; i < 4 && (image = images[i]); i++) {
				image.src = artists[i].images.medium;
			}
			//this.image.src = artists[0].images.large;
			//this.image.className += ' loaded';
			
			var rows = new SimilarRows({similar: artists, parent: this.model});
			
			this.loaded('Artists', rows.el);
		},
		
		tracks: function(tracks) {
			var rows = new TrackRows({tracks: tracks});
			
			this.loaded('Tracks', rows.el);
		},
		
		albums: function() {
			this.gotoAlbum(0);
		}
	}
});

var ControlBox = BoxView.extend({
	noLoad: true,
	playlist: null,
	
	templates: {
		'controls': 'control-area'
	},
	
	initialize: function() {
		this.$super();
		
		this.el.id = 'control-box';
		document.body.appendChild(this.el);
		
		this.makeSections('Playlist', 'Links', 'Options', 'About');
		
		this.playlist = new Playlist();
		this.loaded('Playlist', this.playlist.el);
		this.header.innerHTML = 'Playlist';
		
		this.template('controls', {videoHeight: youtube.height});
	},
	
	switchTab: function(tab) {
		this.$super.switchTab(tab);
		
		this.header.innerHTML = tab.innerHTML;
	},
	
	events: {
		'click #control-next': function() {
			this.playlist.next();
		},
		'click #control-prev': function() {
			this.playlist.prev();
		}
	}
});

var Rows = Backbone.View.extend({
	data: null,
	values: null,
	
	templates: {
		list: {
			el: 'rows-el',
			rows: 'rows-rows',
			row: 'rows-row'
		},
		groups: ['row'], $: []
	},
	
	initialize: function( data ) {
		this.data = data;
		this.values = [];
		this.template('el');
	},
	
	addRow: function( title ) {
		this.values.push( title );
		
		return this.template('row', {
			pos: this.row.length + 1,
			title: title
		});
	},
	
	addRows: function( callback ) {
		var data = [];
		for ( var i = 0, item; ( item = this.data[i] ); i++ ) {
			var values = callback.call( this, item );
			
			if ( typeof values == 'string' ) {
				values = [ values, values ];
			}
			
			data.push({
				pos: i + 1,
				title: values[1]
			});
			
			this.values.push(values[0]);
		}
		
		var row = this.template('rows', data);
		this.el.appendChild(row);
	},
	
	events: {
		'click .row': 'handleClick',
		'mousedown': function(e) {
			e.preventDefault();
		}
	},
	
	handleClick: function(e) {
		var i = _.indexOf(this.row, e.currentTarget);
		
		this.action(this.values[i], e.currentTarget, i);
	}
});

var TrackRows = Rows.extend({
	initialize: function(options) {
		this.$super(options.tracks);
		
		this.addRows(function(track) {
			if (options.artist) {
				return [
					options.artist + ' - ' + track.name,
					track.name
				];
			} else {
				return track.artist.name + ' - ' + track.name;
			}
		});
		
		if (!options.tracks.length) {
			$_(this.empty).show().text('No Tracks Found');
		}
		
		this.menu = new TrackMenu();
		var self = this;
		$(this.menu.menu).mouseleave(function(e) {
			if (self.overRow != e.relatedTarget) {
				self.hideMenu();
			}
		});
		/* FIX! MOVE TO CSS */
		this.menu.el.style.top = '5px';
	},
	
	action: function(value) {
		controlBox.playlist.addRow(value);
		
		tooltips.playlist();
	},
	
	events: {
		'mouseenter .row': 'showMenu',
		'mouseleave .row': 'hideMenu'
	},
	
	handleClick: function(e) {
		if (e.target == this.menu.button || $_(e.target).hasClass('ui-menu-item')) {
			return;
		}
		
		this.$super.handleClick(e);
	},
	
	showMenu: function(e) {
		if (this.overRow == e.currentTarget) {
			return;
		}
		
		var row = e.currentTarget,
			index = _.indexOf(this.row, row),
			track = this.values[index];
		this.overRow = row;
		
		row.appendChild(this.menu.el);
		
		_.each(links.track, function(link) {
			var url = linkFormat(link, {
				artist: this.options.artist,
				track: this.options.tracks[index].name
			});
			
			this.menu.addItem({ name: link.name, value: url, image: link.icon });
		}, this);
	},
	
	hideMenu: function(e) {
		if (e && $(e.relatedTarget).closest('.ui-menu').length) {
			return;
		}
		
		this.overRow.removeChild(this.menu.el);
		this.overRow = null;
		this.menu.reset();
		this.menu.hide();
	}
});

var TrackMenu = Menu.extend({
	initialize: function(options) {
		options = options || {};
		options.label = '>';
		
		this.$super(options);
		
		this.$el.addClass('track-links');
		this.button.style.cursor = 'pointer';
	},
	
	action: function(link) {
		window.open(link);
	}
})

var SimilarRows = Rows.extend({
	initialize: function( options ) {
		this.$super( options.similar );
		this.parent = options.parent;
		
		this.addRows(function(similar) {
			return similar.name;
		});
	},
	
	action: function( artist ) {
		this.parent.createBox('artist', artist);
	}
});

var Playlist = Rows.extend({
	mixin: ['DragDrop'],
	
	active: null,
	
	initialize: function() {
		this.$super();
		this.mixin.DragDrop();
		
		onYoutubePlayerChange = _.bind(this.stateChange, this);
		this.areaEl.removeChild(this.empty);
	},
	
	addRow: function( title ) {
		var self = this, i = this.row.length,
			row = this.$super.addRow(title);
		
		$_(row).css('opacity', 0.5);
		self.values[i] = null;
		
		if (i == 0) {
			this.play(0);
		}
		
		youtube.search(title, function(id) {
			self.values[i] = id;
			$_(row).animate({opacity: 1});
			
			if (self.loading) {
				self.loading = false;
				self.play(i);
			}
		});
	},
	
	play: function(i) {
		if ( this.active !== null ) {
			$_(this.row[this.active]).removeClass('active');
		}
		
		$_(this.row[i]).addClass('active');
		this.active = i;
		
		if (!this.values[i]) {
			this.loading = true;
			return;
		}
		
		youtube.load(this.values[i]);
	},
	
	next: function() {
		this.loading = false;
		
		if (this.active == this.row.length - 1) {
			this.play(0);
		} else {
			this.play(this.active + 1);
		}
	},
	
	prev: function() {
		this.loading = false;
		
		if (this.active == 0) {
			this.play(this.row.length - 1);
		} else {
			this.play(this.active - 1);
		}
	},
	
	action: function(id, row, i) {
		this.play(i);
	},
	
	stateChange: function( state ) {
		if (state === 0) {
			this.next();
		}
	},
	
	events: {
		'mousedown .row': function(e) {
			var $el = $(e.currentTarget).addClass('selected');
			$(document).bind('mouseup.selectedRow mouseleave.selectedRow', function() {
				$(document).unbind('.selectedRow');
				$el.removeClass('selected');
			});
			
			this.threshold(e, 5, function(e) {
				this.drag(e);
			});
		},
		'dblclick .row': 'handleClick',
		'click .row': null,
	},
	
	/* Drag and Drop */
	
	dragType: 'tracks',
	dragValues: ['values', 'row'],
	areaOrientation: 'vertical',
	
	drag: function(e) {
		$(this.el).addClass('dragging');
		this.mixin.DragDrop.drag(e);
	},
	
	move: function(e) {
		this.mixin.DragDrop.move(e);
		this.updateDrop();
		//this.moveElement();
	},
	
	drop: function() {
		if (!this.overArea) {
			this.remove();
		}
		
		this.insertDrop();
		this.mixin.DragDrop.drop();
		
		for (var i = 0, row; (row = this.row[i]); i++) {
			$_(row).find('.row-pos').text(i + 1);
		}
	},
	
	remove: function() {
		var index = _.indexOf(this.row, this.dragElement);
		this.row.splice(index, 1);
		this.values.splice(index, 1);
		
		$(this.dragElement).remove()
	}
});


/** Links **/

var links = {
	artist: [
		{ name: 'Last.fm', link: 'http://www.last.fm/music/{{artist}}', icon: 'http://www.last.fm/favicon.ico' },
		{ name: 'Wikipedia', link: 'http://www.google.com/search?q=Wikipedia {{artist}}&btnI', icon: 'http://en.wikipedia.org/favicon.ico' },
		{ name: 'Google', link: 'http://www.google.com/search?q={{artist}}', icon: 'http://www.google.com/favicon.ico' },
		{ name: 'What.cd', link: 'http://what.cd/artist.php?artistname={{artist}}', icon: 'http://what.cd/favicon.ico' }
	],
	
	album: [
		{ name: 'Last.fm', link: 'http://www.last.fm/music/{{artist}}/{{album}}', icon: 'http://www.last.fm/favicon.ico' },
		{ name: 'What.cd', link: 'http://what.cd/torrents.php?artistname={{artist}}&groupname={{album}}&format=MP3', icon: 'http://what.cd/favicon.ico' }
	],
	
	track: [
		{ name: 'Google MP3 Search', link: "http://www.google.com/search?q='{{artist}} - {{track}}' intitle:index.of mp3 -html -htm -php -asp -txt -pls", icon: 'http://www.google.com/favicon.ico' },
		{ name: 'What.cd', link: 'http://what.cd/torrents.php?artistname={{artist}}&filelist={{track}}&format=MP3&order_way=desc&order_by=seeders', icon: 'http://what.cd/favicon.ico' }
	],
	
	tag: [
		{ name: 'What.cd', link: 'http://what.cd/torrents.php?taglist={{tag}}', icon: 'http://what.cd/favicon.ico', replace: [[' ', '.']] }
	]
}

var linkFormat = function(link, data) {
	var url = link.link;
	
	for (var name in data) {
		var value = data[name];
		if (link.replace) for (var i = 0, item; (item = link.replace[i]); i++) {
			value = value.replace(new RegExp(item[0], 'g'), item[1]);
		}
		url = url.replace('{{' + name + '}}', value);
	}
	
	return url;
}


/** Youtube **/

youtube = {
	player: null,
	
	params: $.param({
		enablejsapi: 1,
		autoplay: 1,
		autohide: 1,
		showinfo: 0,
		rel: 0,
		iv_load_policy: 3,
		probably_logged_in: 0,
		//version: 3,
		//theme: 'dark'
	}),
	
	width: BOX_WIDTH,
	height: Math.round(BOX_WIDTH / (16/10))
};

youtube.ready = function() {
	youtube.player = document.getElementById('youtube-video');
	youtube.player.addEventListener( 'onStateChange', 'onYoutubePlayerChange' );
}

youtube.search = function( title, callback ) {
	var url = 'http://gdata.youtube.com/feeds/api/videos?q=' + escape( title ) + '&max-results=10&format=5&v=2&alt=jsonc&callback=?';
	
	$.getJSON(url, function(data) {
		var id = data.data.items[0].id;
		
		callback(id);
	});
}

youtube.load = function( id ) {
	if (youtube.player) {
		youtube.player.loadVideoById(id, 0, 'medium');
	}
	else {
		swfobject.embedSWF(
			'http://www.youtube.com/v/' + id + '?' + youtube.params,
			'youtube-video', youtube.width, youtube.height, '8', null, null, { allowScriptAccess: 'always', wmode: 'transparent' }, null
		);
	}
}

var onYouTubePlayerReady = youtube.ready,
	onYoutubePlayerChange;


/* Start */

var musicTree, controlBox;
// when the page loads, create the application view
$(function() {
	musicTree = new MusicTree();
	controlBox = new ControlBox();
});
