//define the events mootools doesn't know
Element.NativeEvents['popstate'] = 2;
Element.NativeEvents['hashchange'] = 1;

var History = new Class({
	urls: {},
	ignore: false,
	initialize: function(urls)
	{
		this.urls = urls;
		var hasPushState = ('pushState' in history);
		var event = hasPushState ? 'popstate' : 'hashchange';
		
		window.addEvent(event, function() {
			if(!this.ignore)
			{
				this.ignore = true;
				this.dispatch();
			}
			
			this.ignore = false;
		}.bind(this));
	},
	set: function(hash, suppl)
	{
		hash = '#!/' + hash + (suppl ? '/' + suppl : '');
		
		if(window.location.hash != hash)
		{
			this.ignore = true;
			window.location.hash = hash;
		}
	},
	dispatch: function()
	{
		var hash = window.location.hash.split('!');
		
		if(hash[1])
		{
			hash = hash[1].split('/');
			suppl = hash[2];
			hash = hash[1];
			
			if(this.urls[hash])
			{
				this.urls[hash](suppl);
			}
		}
		else
		{
			this.set('index');
		}
	}
});

var Overlay = new Class({
	element: null,
	Implements: Events,
	initialize: function()
	{
		this.element = $('overlay');
		this.element.addEvent('click', this.hide.bind(this));
	},
	show: function()
	{
		this.element.show();
	},
	hide: function()
	{
		this.element.hide();
		this.fireEvent('close');
		this.removeEvents('close');
		delete this.$events['close']; //fix for a possible(?) bug in mootools class.extra
	}
});

var Memo = new Class({
	element: null,
	player: null,
	active: null,
	shown: null,
	initiated : null,
	Implements : [Options, Events],
	initialize: function(options)
	{
		this.setOptions(options);
		this.element = $('memo-wrapper');
		this.createPlayer();
		this.initiated = false;
	},
	createPlayer: function()
	{
		this.player = new Swiff('player_mp3_js.swf', {
			'id' : 'memo-player',
			'params': {
				'allowScriptAccess' : 'always',
			},
			'properties' : {
				'height' : 1,
				'width' : 1
			},
			'vars' : {
				'listener' : 'Memo.listener',
				'interval' : 500
			}
		});
		
		this.element.adopt(this.player);
		
		this.player = this.player.object;
	},
	loadContent: function(content)
	{
		var ul = new Element('ul');
		this.element.adopt(ul);
		
		for(var x = 0, l = content.length; x < l; x++)
		{
			ul.adopt(
				new Element('li').adopt(
					new Element('a', {
						'href' : 'content/' + content[x].id + '.mp3',
						'text' : content[x].label,
						'class' : content[x].type,
						'rel' : content[x].id,
						'id' : 'memo-' + content[x].id,
						'events' : {
							'click' : this.play.bind(this)
						}
					})
				)
			);
		}
		
		this.initiated = true;
	},
	stop: function()
	{
		if(this.active) this.active.removeClass('active');
		if(this.player.SetVariable) this.player.SetVariable('method:stop', '');
		this.active = null;
	},
	play: function(e, el)
	{
		if(e && e.preventDefault) e.preventDefault();
		el = (e && e.target) ? $(e.target) : el;
		
		if(this.active) this.active.removeClass('active');
		el.addClass('active');
		this.active = el;
		
		var type = el.className.split(' ');
		var url = el.href;
		
		if(type[0] == 'mp3')
		{
			this.player.SetVariable('method:stop', '');
			this.player.SetVariable('method:setUrl', url);
			this.player.SetVariable('method:play', '');
		}
		
		this.fireEvent('play', el.rel);
	},
	position: function()
	{
		var dim = this.element.getDimensions();
		var wdim = window.getSize();
		
		var x = Math.max(0, Math.floor((wdim.x - dim.x) / 2));
		var y = Math.max(0, Math.floor((wdim.y - dim.y) / 2));
		
		this.element.setStyles({
			'top' : y,
			'left' : x
		});
	},
	initiate: function(id)
	{
		var j = new Request.JSON({
			'url' : 'content.json',
			onSuccess: function(content) {
				this.loadContent(content);
				this.show(id);
			}.bind(this)
		});
		
		j.send();
	},
	show: function(id)
	{
		if(!this.initiated)
		{
			this.initiate(id);
		}
		else
		{
			this.position();
			this.element.show();
			
			if(id)
			{
				this.playId(id);
			}
			
			if(!this.shown)
			{
				this.fireEvent('show');
			}
			
			this.shown = true;
		}
	},
	playId: function(id)
	{
		var el = $('memo-' + id);
		
		if(el)
		{
			this.play.delay(500, this, [null, el]);
		}
	},
	hide: function()
	{
		this.stop();
		this.element.hide();
		
		this.shown = false;
		
		this.fireEvent('hide');
	}
});

Memo.listener = {
	onInit: function() {},
	onUpdate: function() {}
};

var AlbumBrowser = new Class({
	albums: null,
	currentAlbum: null,
	active: false,
	Implements: [Options, Events],
	options: {
		//onOpen: null
	},
	initialize: function(elements, options)
	{
		this.setOptions(options);
		
		this.albums = {};
		
		var albums = $$(elements);
		
		for(var x = 0, l = albums.length; x < l; x++)
		{
			this.addAlbum(albums[x]);
		}
	},
	addAlbum: function(element)
	{
		var cover = $(element);
		var id = cover.id;
		var info = $(id + '-info');
		
		info.set('reveal', {
			duration: 420,
			link: 'cancel',
			fps: 45
		});
		
		var album = {
			'id' : id,
			'coverElement' : cover,
			'infoElement' : info,
			'tracksLoaded' : false
		};

		this.setTracksData(album);
		this.setEvents(album);
		
		this.albums[id] = album;
	},
	setTracksData: function(album)
	{
		var tracks = {};
		
		var vals = album.infoElement.get('class').split(' ').filter(function(cls) {
			return cls.test(':');
		});

		for(var x = 0, l = vals.length; x < l; x++)
		{
			var split = vals[x].split(':');
			
			tracks[split[0]] = split[1];
		}

		album.tracks = tracks;
	},
	setEvents: function(album)
	{
		album.coverElement.addEvent('click', this.select.bind(this, album));
	},
	select: function(album, e)
	{
		if(e) e.stop();
		
		if(this.active || album == this.currentAlbum) return;

		this.active = true;
		
		var self = this;
		
		//refactor this using Fx.Chain ?
		album.infoElement.get('reveal').$events = {};
		
		if(this.currentAlbum)
		{
			this.removeTracks(this.currentAlbum); //have to do this for IE (otherwise it crashes)
			this.currentAlbum.infoElement.get('reveal').$events = {};
			this.currentAlbum.infoElement.dissolve({
				'onComplete': function() {
					album.infoElement.reveal({
						'onComplete': function() {
							self.showTracks(album);
							self.active = false;
						}
					});
				}
			});
			
			this.currentAlbum.coverElement.removeClass('active');
		}
		else
		{
			album.infoElement.reveal({
				'onComplete': function() {
					self.showTracks(album);
					self.active = false;
				}
			});
		}
		
		album.coverElement.addClass('active');
		album.coverElement.blur();
		
		this.currentAlbum = album;
		
		this.fireEvent('open', album.id);
	},
	removeTracks: function(album)
	{
		for(var prop in album.tracks)
		{
			var track = album.tracks[prop].toElement();
			var parent = track.parentNode;
			parent.removeChild(track);
			//console.log(album.tracks[prop]);
		}
	},
	showTracks: function(album)
	{
		for(var prop in album.tracks)
		{
			var element = $$('#' + prop + ' .sc-player');
			
			if(element)
			{
				var track;
				
				if(!album.tracksLoaded)
				{
					track = new SoundcloudPlayer(prop, album.tracks[prop]);
					album.tracks[prop] = track;
				}
				else
				{
					track = album.tracks[prop];
				}
				element.adopt(track);
			}
		}
		
		album.tracksLoaded = true;
	}
});

var SoundcloudPlayer = new Class({
	Extends: Swiff,
	options: {
		'params': {
			'allowScriptAccess' : false,
			'swLiveConnect' : false,
			'wmode' : 'opaque'
		},
		'properties' : {
			'height' : 81,
			'width' : '100%'
		},
		'vars' : {
			'url' : null,
			'color' : 172344,
			'autoplay' : false,
			'show_comments' : false
		}
	},
	initialize: function(id, track_id, options)
	{
		this.options.vars.url = 'http://api.soundcloud.com/tracks/' + track_id;
		this.options.id = id;

		this.parent('http://player.soundcloud.com/player.swf', options);
	}
});

window.addEvent('domready', function() {
	var album = null;
	var overlay = new Overlay();
	
	var albumBrowser = new AlbumBrowser('.albums a', {
		'onOpen' : function(id) {
			history.set('album', id);
			album = id;
		}
	});
	
	var memo = new Memo({
		'onShow' : function() {
			overlay.show();
			
			if(!this.active)
			{
				history.set('memo');
			}
		},
		'onHide' : function() {
			if(album)
			{
				history.set('album', album);
			}
			else
			{
				history.set('index');
			}
		},
		'onPlay' : function(id) {
			history.set('memo', id);
		}
	});
	
	function showMemo(e, id)
	{
		if(e && e.preventDefault) e.preventDefault();
		
		memo.stop();
		
		overlay.addEvent('close', memo.hide.bind(memo));
		
		if(!memo.shown)
		{
			memo.show(id);
		}
		else
		{
			memo.playId(id);
		}
	}
	
	var history = new History({
		'index' : function() {
			overlay.hide();
		},
		'album' : function(suppl) {
			if(!suppl) return;
			
			overlay.hide();
			
			var el = albumBrowser.albums[suppl];
			
			if(el)
			{
				albumBrowser.select(el);
			}
		},
		'memo' : function(suppl) {
			showMemo(null, suppl);
		}
	});
	
	$('memo-link').addEvent('click', showMemo);
});
