/*	usemedia.com . joes koppers . 04.2011
	thnx for reading this code */


/*	MRI main site
*/

function MRI(login,canvasmode,magick)
{
	var obj = this;

	//settings, defaults
	this.ipad = navigator.userAgent.match(/iPad/i) != null || navigator.userAgent.match(/iPhone/i) != null,
	this.more = false;
	this.srv = 'services/';
	this.page = $('#page');
	this.blue = magick;
	this.tweets = {
		enabled:false,
		loaded:false,
		ready:-1,
		items:[]
	};
	
	//login
	this.login = login || { login:false };
	if (this.login.verified) alert('Welcome, your MRI account has been verified.\n\nThank you for joining!')
	this.enableLogin();
	
	//window dimensions
	$(window)
		.resize(function() {
			obj.resize()
		})
		.scroll(function() {
			obj.scroll()
		})
		.trigger('resize');
		
	//event handling
	$(document).add('#page-centered').click(function() {

		/*	click anywhere: hide more, suggest, login panels
		*/
		if (obj.more) obj.toggleMore();
		$('#suggest,#login,#profile,#signup').hide();

	});
	$('#more, #nav, #search > input, #suggest, #account, #signup').click(function(e) {
		e.stopImmediatePropagation();
	});

	//init gui
	this.addMore();
	this.enableSearch();

	//get default items, or single item (hashtag)
	var filter;
	var h = window.location.hash.substr(1);
	if (h && parseInt(h)==h) filter = { id:h }

	this.getItems(filter);
	if (this.tweets.enabled) this.getTweets();


	/*	init interference and pattern sequence
		format = { t:seconds, amount:number of new patterns }
		each entry is sequential, delay is counted from last entry */
		
	this.addInterference([
		{ t:0, amount:3 }
		,{ t:60, amount:1 }
		,{ t:60, amount:1 }
		,{ t:60, amount:1 }
		,{ t:60, amount:1 }
		,{ t:60, amount:1 }
	], {
		canvas:canvasmode,
		refresh:30,
		minspeed:.45,
		maxspeed:1.25
	});
}

MRI.prototype.resize = function()
{
	/* 	window resize handling, update interference
	*/
	this.width = $(window).width();
	this.height = $(window).height();

	if (this.interference && this.interference.canvas) $('#interference > canvas').attr({ width:this.width, height:this.height });	

	//keep fixed header centered along with page
	$('#header').css('left',$('#page-centered').offset().left);
	
	//remove zoomed image
	$('#full').remove();
}

MRI.prototype.scroll = function()
{
	/*	page scroll handling, trigger load on media that is onscreen
	*/
	
	//console.log(new Date().getTime(),' trigger scroll')
	
	this.page
		.find('canvas.medium:not(.loaded)')
		.trigger('display',[$(window).scrollTop()+this.height])
}


MRI.prototype.enableLogin = function()
{
	/*	enable login, signup, profile and manage
	*/
	var obj = this;
	if (this.login.login) this.setProfile();
	$('#account > .login > a')
		.click(function() {
		
			/*	show/hide login or profile panel
			*/
			var type = $(this).blur().text()=='login'? 'login':'profile';
			$('#'+type)[$('#'+type+':visible').length? 'hide':'show']();
			$('#signup').hide();
			if (obj.more) obj.toggleMore();
			
		})
		.html(this.login.login? this.login.name:'login')
		.parent().prev().find('a')
		.click(function() {
			$('#signup')[$('#signup:visible').length? 'hide':'show']()
				.find('.signup-done').hide().siblings().show();
				
			$('#login,#profile').hide();
			if (obj.more) obj.toggleMore();
		});
	

	$('#login input').keydown(function(e) {
		if (e.keyCode==13) obj.doLogin();
	})
	$('#login-submit').click(function() {
		obj.doLogin();
	})
	$('#profile-submit').click(function() {
		obj.updateProfile();
	})
	$('#logout').click(function() {
		obj.doLogout();
	})
	$('#signup-submit').click(function() {
		obj.signup();
	})
	$('#admin').click(function() {
		window.location = '/admin';
	})
	[this.login.role>1? 'hide':'show']();
	
	$('#manage')
		[this.login.login? 'show':'hide']()
		.find('a.add').click(function() {
			obj.manageItem('add');
		}).end()
		.find('a.my').click(function() {
			obj.search('my entries');
		});
		
	//set default (help) texts im signup form
	var msg = {
		name:'this name appears with your posts',
		email:'used to verify your account',
		login:'minimum length is 4 characters'
	}
	$.each(msg, function(key,value) {
		$('#signup-form input[name="'+key+'"]')
			.data('msg',value)
			.val(value)
			.addClass('init')
			.focus(function() {
			
				/*	remove init class and clear message
				*/
				if ($(this).hasClass('init')) $(this).removeClass('init').val('');			
			})
			.blur(function() {
				if ($(this).val()=='') $(this).addClass('init').val($(this).data('msg'));
			})
	})
}

MRI.prototype.doLogin = function(rsp)
{
	if (!rsp)
	{
		//validate
		var login = $('#login input[name="login"]').val();
		var pass = $('#login input[name="password"]').val();
		if (login=='' || pass=='') return alert('Please enter both username and password!');
	
		//usebase user api login
		var obj = this;
		return $.getJSON('admin/api/user/',{ cmd:'login', user:login, pass:pass }, function(rsp) {
			obj.doLogin(rsp);
		})
	}

	if (rsp.isError) return this.error(rsp.errorMsg);
		
	//store login data, enable interface
	this.login = rsp.user;
	this.setProfile();
	
	$('#login').hide();
	$('#manage').show();
	
	this.getItems(this.filter);
}

MRI.prototype.doLogout = function()
{
	var obj = this;
	
	$.getJSON('admin/api/user/',{ cmd:'logout' }, function(rsp) {
		$('#account > .login > a').removeClass('logged').html('login');
		$('#profile, #manage').hide();
		
		obj.login = { login:false }
		
		//refresh page
		obj.getItems(obj.filter);
	})
}

MRI.prototype.setProfile = function()
{
	//set profile data
	$('#profile')
		.find('input[name="name"]').val(this.login.name).end()
		.find('input[name="email"]').val(this.login.email).end()
		.find('input[type="password"]').val('').end()
		.siblings('a')
		.html(this.login.login? this.login.name:'login')
		[(this.login.login? 'add':'remove')+'Class']('logged')

	$('#admin')[this.login.role>1? 'hide':'show']();
}

MRI.prototype.updateProfile = function()
{
	/*	update profile data (usebase API)
	*/
	var obj = this;
	
	var fail;
	var f = $('#profile').get(0);
	var validate = ['name','email'];
	
	if (f.pass0.value=='') return alert('Please enter your password in order to make changes');
	if (f.pass1.value!='') validate.push('pass1');
	
	$.each(validate, function(i,v) {
		if (!obj.validate(v,f[v].value))
		{
			fail = true;
			return false; //break
		}
	});
	if (fail) return;
	
	//password match
	if (!this.validate('match',f.pass1.value,f.pass2.value)) return;
	
	//update profile request
	$('#profile-submit').hide().after('<img src="media/spinner.gif" style="float:right; margin:8px 20px 1px 0"/>');
	
	$.post('admin/api/user/?cmd=profile',{
		pass:f.pass0.value,
		email:f.email.value,
		newpass:f.pass1.value || undefined,
		fullname:f.name.value
	}, function(rsp) {
		
 		eval('var rsp = '+rsp);
		if (rsp.isError)
		{
			if (rsp.errorCode=='password-fail')
			{
				alert('Entered (old) password is not valid!\n\nplease try again');
			}
			else
			{
				obj.error(rsp.errorMsg);
			}
		}
		else
		{
			//update local profile
			obj.login.name = f.name.value;
			obj.login.email = f.email.value
			obj.setProfile();
			
			$('#profile').hide();
		}
 		$('#profile-submit').show().next().remove();
	});
}

MRI.prototype.signup = function()
{
	/*	signup (usebase API)
	*/
	var obj = this;

	//validation
	var fail;
	var f = $('#signup-form').get(0);

	//all fields
	if (f.name.value=='' || f.name.value==$(f.name).data('msg') || f.email.value=='' || f.email.value==$(f.email).data('msg') || f.login.value=='' || f.login.value==$(f.login).data('msg') || f.pass1.value=='' || f.pass2.value=='') return alert('Please fill in all fields');
	
	$.each(['name','email','login','pass1'], function(i,v) {
		if (!obj.validate(v,f[v].value))
		{
			fail = true;
			return false; //break
		}
	})
	if (fail) return;

	//password match
	if (!this.validate('match',f.pass1.value,f.pass2.value)) return;

	//signup request
	$('#signup-submit').hide().after('<img src="media/spinner.gif" style="float:right; margin:8px 40px 0 0"/>');
	
	$.post('admin/api/user/?cmd=signup',{
		login:f.login.value,
		email:f.email.value,
		pass:f.pass1.value,
		fullname:f.name.value,
		process:'services/signup.php'
	}, function(rsp) {

		eval('var rsp = '+rsp);
		if (rsp.isError)
		{
			if (rsp.errorCode=='invalid-user')
			{
				alert('We\'re sorry, username \''+f.login.value+'\' is already taken.\n\nplease choose another')
			}
			else
			{
				obj.error(rsp.errorMsg);
			}
		}
		else
		{
			//signup success, display verification message
			$('#signup > .signup-done').show().siblings().hide();		
		}
		
		$('#signup-submit').show().next().remove();
	})
}

MRI.prototype.validate = function(type,v,v2)
{
	/*	form input validation
	*/
	switch (type)
	{
		case 'name': 	//min length 4
			if (v.length<4) return alert('Please enter a full name with a minimum length of 4 characters');
			break;
			
		case 'email':	//valid email address
			var p = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
			if (!p.test(v)) return alert('Please enter a valid email address');
			break;
			
		case 'login':	//no special chars, min length 4
			var p = /^([a-z0-9_\-\.]+)$/;
			if (!p.test(v.toLowerCase()) || v.length<4) return alert('Please choose a username without any special characters and a minumum length of 4');
			break;
			
		case 'pass1':	//min length 6
			if (v.length<6) return alert('Please choose a password with a minimum length of 6 characters');
			break;
			
		case 'match':
			if (v!=v2) return alert('Repeated password does not match!');
			break;
	}
	
	return true;
}

MRI.prototype.manageItem = function(type,item)
{
	/*	add, edit or delete an item in usebase
	*/
	var obj = this;
	if (type=='edit' || type=='add')
	{
		/*	edit item in usebase, create a POST form and submit it
		*/
		var f = $('<form/>')
			.attr({
				method:'POST',
				action:'/admin/'
			})
			.appendTo('body');
			
		var v = {
			cms_page:'item.php',
			cms_action:'item_'+type
		}
		if (type=='edit') v.item_id = item.id
		else v.section_id = 10; //add items in public section
			
			
		$.each(v, function(key,val) {
			$('<input type="hidden"/>')
				.attr('name',key)
				.val(val)
				.appendTo(f)
		});
		
		f.submit();
	}
	else
	{
		/*	remove item (via usebase API), confirm first
		*/
		if (confirm('Warning!\nentry will be deleted permanently, there\'s no undo.\n\nare you sure?'))
		{
			$.getJSON('admin/api/item/',{
				cmd:'delete',
				id:item.id
			}, function(rsp) {
				if (rsp.isError) obj.error(rsp.errorMsg); //->optionally implement errorCode handling later
				
				//refresh page, will remove item
				obj.getItems(obj.filter);
			})
		}
	}
}


MRI.prototype.get = function(service,callback,param,rsp)
{
	/*	get data from service
	*/
	if (!rsp) 
	{
		var obj = this;
		return $.getJSON(this.srv+'get-'+service+'.php',param,function(rsp) { obj.get(service,callback,param,rsp) });
	}
	if (rsp.isError) return this.error(rsp.errorMsg);
	
	callback(rsp)
}

MRI.prototype.error = function(msg)
{
	/*	handle (request) error messages
	*/
	alert('We\'re sorry, an error has occurred.\n\n['+msg+']')
}

MRI.prototype.suggest = function(query)
{
	/*	smart suggest, display list of matching: 0) special, 1) tags, 2) users, 3) item titles
	*/
	var obj = this;
	q = query.toLowerCase();
	
	var suggest = $('#suggest').empty().show();
	
	if (q=='') return;
	
	//spinner
	$('#spinner').remove();
	$('#search').append('<img id="spinner" src="media/spinner.gif"/>');
	
	//find matching tags (local)
	var matched = $.grep(this.tags, function(t) {
		return (t.tag.toLowerCase().indexOf(q)===0 || t.tag.toLowerCase().indexOf(' '+q)!=-1)
	});
	
	//add users (local)
	var users = $.grep(this.users, function(u) { 
		return (!u.tagged && (u.user.toLowerCase().indexOf(q)===0 || u.name.toLowerCase().indexOf(q)===0 || u.name.toLowerCase().indexOf(' '+q)!=-1))
	});
	for (var i=0; i<users.length; i++) matched.push({ id:users[i].user, type:'author', tag:users[i].name, tagged:users[i].tag });
	
	//special queries (local)
	if (this.login.login && String('my entries').indexOf(query)!=-1)
	{
		matched.splice(0,0,{ id:this.login.login, tag:'my entries' });	
	}
	
	//console.log('matched (local)',matched);

	//add item titles (service)
	this.get('suggest',function(rsp) {

		for (var i=0; i<rsp.items.length; i++)
		{
			//add items to matched collection
			matched.push({ id:rsp.items[i].id, type:'item', tag:rsp.items[i].title });
		}

		/*	display all suggested
		*/
		for (var i=0; i<matched.length; i++)
		{
			var r = new RegExp('\\b'+query,"gi");
			$('<a/>')
				.attr('href','javascript://')
				.data('suggest',matched[i])
				.html(matched[i].tag.replace(r,'<strong>'+query+'</strong>'))
				.appendTo(suggest)
				.mouseover(function() {
					$(this).addClass('selected').siblings().removeClass('selected');
				})
				.mouseout(function() {
					$(this).removeClass('selected');
				})
				.click(function() {
				
					/*	execute smart search
					*/
					$('#suggest').hide();
					var s = $(this).data('suggest');
					obj.search(s.tag,{ type:s.type, id:s.id });
				
				});
		}
		if (obj.more) obj.toggleMore();
		$('#spinner').remove();
		
	}, { search:q });
}

MRI.prototype.search = function(query,smart)
{
	/*	(smart) search items
	*/
	if (!smart) smart = { type:'none' };
	var filter = {};
	
	//console.log('[search] type=',smart.type,smart,'query=',query);
	
// section
// tags	
// search
// author
// item
	
	switch (smart.type)
	{
		case 'artist':
			//check if there's a matching author
			var a = $.grep(this.users, function(u) { return u.name==query });
			if (a.length) filter.author = a[0].user;
			//no break, (also) add as tag..
			
		case 'tag':
			filter.tags = smart.id;
			break;
			
		case 'mri':
		case 'item':
			filter.id = smart.id;
			break;
			
		case 'section': //agenda, twitter
			if (query=='agenda') filter.sections = 20;
			break;
			
		case 'author':
			filter.author = smart.id;
// 			var a = $.grep(this.users, function(u) { return u.user==smart.user });
// 			if (a.length) filter.author = a[0].user;

			break;
	
		default:
		
			/*	parse query, filter out tags first
			*/
			console.log('[search] parse query')
			
			switch (query)
			{
				case 'my entries':
					if (this.login.login) filter.author = this.login.login;
					else filter.search = query;
					break;
					
				default:
					filter.search = query;
			}
			
			//filter.search = query;
			
			
			break;
	}
	
	$('#search > input')
		.removeClass('init')
		.val(query)
		.next()
		.show();
		
	$('#suggest').empty();
 	if (this.more) this.toggleMore();

	/*	update page
	*/
	$(window).scrollTop(0);
 	if (smart.type=='section' && query=='twitter')
 	{
 		//tweets only
		$('#page').empty();
		this.filter = undefined;
 		this.items = true; 
 		this.getTweets();
 	}
 	else
 	{
 		this.getItems(filter);
 	}
}

MRI.prototype.getTweets = function()
{
	/*	add tweets
	*/
	var obj = this;
	
	if (this.tweets.wait) window.clearTimeout(this.tweets.wait);
	if (!this.tweets.loaded)
	{
		/*	get tweets via twitter api, 
			user timeline and search #metamaticresearch  */
		
		$.getJSON('http://api.twitter.com/1/statuses/user_timeline.json?callback=?',{ user_id:280498221, include_rts:true }, function(rsp) {
			obj.parseTweets(rsp);
			obj.tweets.ready++;
			obj.getTweets();
		});

		$.getJSON('http://search.twitter.com/search.json?callback=?',{ q:'#metamatic' }, function(rsp) {
			obj.parseTweets(rsp.results);
			obj.tweets.ready++;
			obj.getTweets();
		});
		
		this.tweets.loaded = true;
		return 0;
	}
	
	//wait for both api calls to be done
	if (!this.tweets.ready || !this.items)
	{
		this.tweets.wait = window.setTimeout(function() { obj.getTweets() },100);
		return 0;
	}

	//do not insert any tweets when there's a filter, except for search queries	
	if (this.filter && !this.filter.search) return 0;
	
	/*	insert tweets into page
	*/
	if (!$('#page > .item').length) $('#page').append('<div class="item"/>');
	
 	for (var i=0; i<this.tweets.items.length; i++)
 	{
 		var tweet = this.tweets.items[i];
 		var index;
 		
 		//match contents against query
 		if (this.filter && this.filter.search)
 		{
 			if ($(tweet.item).text().toLowerCase().indexOf(this.filter.search.toLowerCase())==-1) continue;
 		}
 		
 		//do not add duplicate tweets
 		if ($('#tweet-'+tweet.id).length) continue;
 		
 		tweet.item.clone(true).insertBefore(
			$('.item').each(function(i) {
				var t = $(this).data('timestamp');
				if (t<tweet.timestamp || !t)
				{
					index = i;
					return false;
				}
			}).eq(index)
		)
 	}
	return this.tweets.items.length;
}

MRI.prototype.parseTweets = function(tweets)
{
	/*	parse twitter api data to tweet item
	*/
	for (var i=0; i<tweets.length; i++)
	{
		if ($.browser.msie) 
		{
			//Date object in IE expects 'UTC' in datestring
			var d = tweets[i].created_at.split('+');
			var t = new Date(d[0]+'UTC+'+d[1]).getTime();
		}
		else var t = new Date(tweets[i].created_at).getTime();
		var r = tweets[i].retweeted_status;
		var u = r? r.user:tweets[i].user;
		
		this.tweets.items.push({
			timestamp:t,
			id:tweets[i].id,
			item:this.createTweet({
				id:tweets[i].id,
				timestamp:t,
				user:u? this.ify.clean((r? 'RT ':'')+'@'+u.screen_name):this.ify.clean('@'+tweets[i].from_user),
				text:this.ify.clean(r? r.text:tweets[i].text)
			})
		});
	}
}

MRI.prototype.getItems = function(filter)
{
	/*	get items
	*/
	this.items = false;
	
	$('#page').empty();
	$('#spinner').remove();
	$('#search').append('<img id="spinner" src="media/spinner.gif"/>');

	//store current filter (for login refresh)
	this.filter = filter;

	var obj = this;
	this.get('items',function(rsp) {

		for (var i=0; i<rsp.items.length; i++) obj.createItem(rsp.items[i]);
		obj.scroll();
		obj.items = true;
		
		//add tweets to page
		var r = 0;
		if (obj.tweets.enabled && obj.tweets.ready) r = obj.getTweets();
		
		//expand single item results
		if (rsp.items.length==1)
		{
			$('div.item:first a.more').click();
			
			//update search if the item was retrieved by hashtag
			if (obj.filter && obj.filter.id==window.location.hash.substr(1))
			{
				$('#search > input')
					.removeClass('init')
					.val(rsp.items[0].title)
					.next()
					.show();
			}
		}
		
		//highlight search query if any
		obj.highlight('.intro');
		
		$('#spinner').remove();


		
	},filter);
}

MRI.prototype.getItemContent = function(id,rsp)
{
	if (!rsp)
	{
		var obj = this;
		return $.getJSON(this.srv+'get-item.php',{ id:id },function(rsp) { obj.getItemContent(id,rsp) });
	}
	if (rsp.isError) return this.error(rsp.errorMsg);
	
	//apply content
	var item = $('#item-'+id);
		item.children('.body').html(rsp.text.replace('&#034','"'));
		
	//add downloads
	for (var i=rsp.files.length-1; i>=0; i--)
	{
		var f = rsp.files[i];
		$('<a/>')
			.attr({
				'href':'/downloads/'+f.file,
				'target':'_blank'
			})
			.addClass('download')
			.html(f.kind+' - '+(f.caption!=''? f.caption:f.file.substr(f.file.indexOf('_')+1)))
			.prependTo(item.children('.body'))
	}
	
	//highlight search query if any
	this.highlight('.body');
			
	this.viewItem(item);
}

MRI.prototype.highlight = function(selector)
{
	/*	highlight search query in given elements
	*/
	if (!this.filter || !this.filter.search) return;
	
	$.each(this.filter.search.split(' '),function(i,v) {
		$(selector).highlight(v);
	})
}

MRI.prototype.enableSearch = function()
{
	/*	search input event handling (focus, reset, suggest)
	*/
	var obj = this;
	var val = 'search...'; //default value
	this.inputIgnoredKeys = { 9:'tab',16:'shift',17:'ctrl',18:'alt',224:'apple',37:'arrow-left',38:'arrow-up',39:'arrow-right',40:'arrow-down' };
	
	$('#search > input')
		.data({
			val:val,
			callback:function(q) {
			
				if (q===false) obj.getItems();
				if (q.length>1) obj.search(q);
			
			},
			suggest:function(q) {
				obj.suggest(q);
			}
		})
		.val(val)
		.focus(function() {
			if ($(this).hasClass('init')) $(this).removeClass('init').val('')
			//if ($(this).val()!='') $('#suggest').show();
			if ($(this).val()!='') obj.suggest($(this).val());
		})
		.blur(function() {
			if (!$(this).val().length)
 			{
				$(this).addClass('init').val($(this).data('val')).next().hide();
 				//refresh items	
 				//obj.getItems();
 			}
 			//hide suggest
 			//if (!$('#suggest > a.hover').length) $('#suggest').hide();
		})
		.keydown(function(e) {

			var k = e.keyCode;
			var i = $(this);
			
			if (!obj.inputIgnoredKeys[k])
			{
				if (this.livesearch) window.clearTimeout(this.livesearch);

				//show reset button
				i.next().show();

				if (k==13)
				{	
					/*	enter, execute callback, or trigger suggested item
					*/
					var s = $('#suggest > a.selected');
					if (s.length) 
					{
						i.blur();
						s.click();
					}
					else
					{
						if ($(this).val().length<=1) return;
						i.blur().data('callback')(i.val());
					}
				}
				else
				{
					//delayed suggest
					this.livesearch = window.setTimeout(function() {
						i.data('suggest')(i.val());
					},250);
				}
			}
			else if ($('#suggest').children().length)
			{
				/*	down/up arrow interaction with suggested panel
				*/
				var s = $('#suggest > a.selected');
				if (s.length)
				{
					s.removeClass('selected')[k==40? 'next':'prev']().addClass('selected');
				}
				else
				{
					$('#suggest > a:'+(k==40? 'first':'last')).addClass('selected');
				}
				e.preventDefault();
			}

			//return key to input
			return e.returnValue;
		})
		.bind('rset',function() {
			//clear input, callback with empty value
			$(this).val('').blur().data('callback')(false);
		})
		.bind('remote',function(e,v) {
			//execute search from remote source
			$(this).removeClass('init').val(v).data('callback')(v);
			$(this).next().show();
		})
		.next()
		.click(function() {
			$(this).blur().prev().trigger('rset');
		})
		.hide();
		
	//enable click on find-button (search submit)
	$('#nav > a.find').click(function(e) {
		if (e.altKey || e.shiftKey) return obj.interference.pause(obj.interference.paused); //->development feature, pause/resume interference
	
		var input = $('#search > input');
		if (input.val()!=val) input.data('callback')(input.val());
	})
}

MRI.prototype.addMore = function()
{
	/*	populate the 'more' panel (tags, mri, users)
	*/
	var obj = this;
	this.tags = [];
	
	//tags
	this.get('tags',function(rsp) {

		for (var i=0; i<rsp.tags.length; i++)
		{
			var tag = rsp.tags[i];
			
			//store in tags list
			obj.tags.push({ id:tag.id, type:tag.artist? 'artist':'tag', tag:tag.tag });
			
			//add to panel
			$('<a/>')
				.addClass('tag')
				.attr({
					'href':'javascript://search..'
				})
				.html(tag.tag)
				.appendTo('#more > .column:eq('+(tag.artist? 0:1)+')')
				.data('id',tag.id)
				.click(function() {
					obj.search($(this).text(),{ type:'tag', id:$(this).data('id') });
				});
		}
		
		obj.tagsLoaded = true;
	});
	
	//mri section items
	this.get('tags-mri',function(rsp) {
	
		for (var i=0; i<rsp.tags.length; i++)
		{
			var tag = rsp.tags[i];
			
			//store
			obj.tags.push({ id:tag.id, type:'mri', tag:tag.tag });
			
			//add to panel
			$('<a/>')
				.addClass('tag')
				.attr({
					'href':'javascript://'+tag.tag.replace(' ','-')
				})
				.html(tag.tag)
				.appendTo('#more > .column:eq(2)')
				.data('id',tag.id)
				.click(function() {
					obj.search($(this).text(),{ type:'mri', id:$(this).data('id') });
				});
		}
		
		//add agenda and twitter to this column
		var c = $('#more > .column:eq(2)').append('<br/>');
		var options = ['agenda']; 
		if (obj.tweets.enabled) options.splice(0,0,'twitter');
		$.each(options, function(i,v) {
			$('<a/>')
				.addClass('tag')
				.attr({
					'href':'javascript://'+v
				})
				.html(v)
				.appendTo(c)
				.click(function() {
					obj.search($(this).text(),{ type:'section' });
				});

			//store			
			obj.tags.push({ id:v, type:'section', tag:v });
		});
		
	});

	//contributors
	this.get('users',function(rsp) {
	
		obj.users = [];
		for (var i=0; i<rsp.users.length; i++)
		{
			var user = rsp.users[i];
			
			//store
			obj.users.push(user);
			
			//add to panel
			$('<a/>')
				.addClass('tag')
				.attr({
					'href':'javascript://'+user.name.replace(' ','-')
				})
				.appendTo('#more > .column:last')
				.html(user.name)
				.data('login',user.user)
				.click(function() {
					obj.search($(this).text(),{ type:'author', id:$(this).data('login') });
				});
		}
		
		//define which users have matiching tags (artists)
		var hasTag = function() {
			if (!obj.tagsLoaded) return window.setTimeout(function() { hasTag() },100); //wait for tags to be loaded;
				
			for (var i=0; i<obj.users.length; i++)
			{
				var u = obj.users[i];
				var a = $.grep(obj.tags, function(t) { return t.tag==u.name });
				if (a.length) obj.users[i].tagged = true;
			}
		};
		
		hasTag();		
	});
}


MRI.prototype.createItem = function(item)
{
	/*	create and append complete item gui (minus body text)
	*/
	var obj = this;
	var admin = item.author.login==this.login.login || this.login.role<=1;
	
	var div = $('<div/>')
		.addClass('item'+(!item.online? ' offline':''))
		.attr('id','item-'+item.id)
		.data('timestamp',item.creationdate*1000)
		.html('<div class="header"/><div class="media"/><div class="body"/>')
		.appendTo('#page');
		
	//random background offset
	var bg = Math.round(Math.random()*730)+'px '+Math.round(Math.random()*440)+'px';
		
	//header
	var a = div.find('div.header')
		.css('background-position',bg)
		.html('<div class="date"/><div class="title"/><div class="share"/><div class="meta"/><div class="intro"/>')
		.children('.date')
		.html(new Date(item.creationdate*1000).format('shorthumandate')).end()
		.children('.title')
		.html(item.title).end()
		.children('.intro')
		.html(item.short).end()
		.children('.meta')
		.html('<span class="author">added by </span><div class="clear"/>')
		.find('.author');
		
		//tags
		$.each(item.tags, function(i,tag) {
			$('<a/>')
				.addClass('tag')
				.attr('href','javascript://search')
				.data('id',tag.id)
				.html(tag.name)
				.insertBefore(a)
				.click(function() {

					/*	search by tag
					*/
					obj.search($(this).text(),{ type:'tag', id:$(this).data('id') });
				});
		});

		//author
		$('<a/>')
			.attr('href','javascript://search')
			.html(item.author.name)
			.appendTo(a)
			.data('login',item.author.login)
			.click(function() {

				/*	search by author
				*/
				obj.search($(this).text(),{ type:'author', id:$(this).data('login') });

			});
			
		//dates (agenda)
		if (item.startdate)
		{
			var end = item.enddate!=item.startdate;
			var d = $('<div/>')
				.addClass('dates')
				.html(new Date(item.startdate*1000).format(end? 'shorthumandate':'longhumandate'))
				.prependTo(div.find('.intro'));
				
			if (end) d.append(' - '+new Date(item.enddate*1000).format('shorthumandate'));
			
			//prepend agenda tag to meta
			$('<a/>')
				.addClass('tag')
				.attr('href','javascript://agenda')
				.html('agenda')
				.prependTo(div.find('.meta'))
				.click(function() {
				
					/*	list agenda items
					*/
					obj.search($(this).text(),{ type:'section' });
				});
		}
		
		//share
		var s = div.find('div.header > .share')
		var url = 'http://'+window.location.host+'/#'+item.id;
		$.each(['url','facebook','twitter'], function(i,v) {
		
			$('<a/>')
				.attr({
					href:v=='url'? url:'javascript://share',
					title:v=='url'? 'Permanent link to this entry':'Share on '+v
				})
				.addClass(v)
				.data('type',v)
				.appendTo(s)
				.html(v=='url'? 'link':'')
				.click(function() {
					if ($(this).data('type')=='url') return obj.getItems({ id:item.id }); //display only this item

					/*	open twitter or facebook share in popup window
					*/
					var l = $(this).data('type')=='facebook'? 'http://www.facebook.com/sharer.php?u='+encodeURIComponent(url):'http://twitter.com/share?url='+encodeURIComponent(url);
					if (obj.sharewin) obj.sharewin.close();
					obj.sharewin = window.open(l,'share','scrollbars=yes,resizable=yes,toolbar=no,location=yes,width=550,height=420');
				});
		});

		//more
		if (item.body)
		{
			$('<a/>')
				.addClass('more')
				.attr('href','javascript://read')
				.html('more')
				.appendTo(div.find('div.intro'))
				.click(function() {

					/*	expand/collapse item
					*/
					obj.toggleItem(item.id,$(this).blur(),item.generatedshort);
				});
		}
		
		//manage
		if (admin)
		{
			$.each(['edit','remove'], function(i,v) {
				$('<a/>')
					.attr('href','javascript://'+v)
					.addClass('manage '+v)
					.html(v)
					.appendTo(div.find('div.header').addClass('manage'))
					.click(function() {
					
						/*	edit or remove item (usebase)
						*/
						obj.manageItem(v,item);
					})
			})
		}
	
	//media
	var container = div.find('div.media')[item.media.length? 'show':'hide']();
	var index = count = 0;
	for (var i=0; i<item.media.length; i++)
	{
		var m = item.media[i];
		if (m.type=='image') 
		{
			//keep track of index for zoomed navigation
			m.index = index;
			index++;
		}
		var bg = Math.round(Math.random()*730)+'px '+Math.round(Math.random()*440)+'px';
		
		if (m.type!='image')
		{
			//thumbnail size of video based on original dimensions
			m.h = 160;
			var w = (160/m.zh) * m.zw;
			m.w = w;
		}

		var c = $('<canvas/>')
			.addClass('medium')
			.css({
				width:m.w,
				height:m.h,
				backgroundPosition:bg
			})
			.attr({
				width:m.w,
				height:m.h
			})
			.appendTo(container)
			.data('medium',m)
			.bind('display', function(e,scroll) {
				
				/*	load actual thumb via canvas and apply pattern (when item is in view)
				*/
				if ($(this).offset().top>scroll) return;
				
				obj.addMedium(this);
	
			})
			.get(0);
			
		if (m.type=='image')
		{
			$(c).bind('mouseover click', function() {
				if (!$(this).hasClass('loaded') || $(this).hasClass('disabled') || obj.video) return;
				
				/*	mouseover zoomed image + caption
				*/
				$('.medium-over').remove();
				obj.zoomMedium(this);

			});
		}
		else
		{
			$(c).click(function(e) {
				if (!$(this).hasClass('loaded')) return;

				/*	mouseclick for video embed + caption
				*/
				e.stopImmediatePropagation();
				$('.medium-over').remove();
				obj.zoomVideo(this);
			})
			.css('cursor','pointer')
		}
	}

	container.append('<div class="clear"/>');
}

MRI.prototype.createTweet = function(item)
{
	/*	create and return tweet item gui
	*/
	var obj = this;
	
	var div = $('<div/>')
		.addClass('item tweet')
		.attr('id','tweet-'+item.id)
		.data('timestamp',item.timestamp)
		.html('<div class="header"/>')
		
	//radom background offset
	var bg = Math.round(Math.random()*730)+'px '+Math.round(Math.random()*440)+'px';
	
	div.find('div.header')
		.css('background-position',bg)
		.html('<div class="date"/><div class="title"/><div class="meta"/><div class="intro"/>')
		.children('.date')
		.html(new Date(item.timestamp).format('shorthumandate')).end()
		.children('.title')
		.html(item.user).end()
		.children('.intro')
		.html(item.text).end()
 		.children('.meta')
 		.html('<a class="tag" href="javascript://search">twitter</a><div class="clear"/>')
 		.find('a.tag')
		.click(function() {
			obj.search('twitter',{ type:'section' });
		});
 	 	 	
	return div;
}

MRI.prototype.addMedium = function(canvas)
{
	/*	load medium (image) and apply pattern
	*/
	var obj = this;
	var m = $(canvas).data('medium');
	
	var src = 'media/content/'+m.id+'_'+(m.type=='image'? 'thumb':'poster')+'.jpg';
	if (this.blue) src = 'media/magick/?id='+m.id+(m.type!='image'? '&type=poster':'')
	
	$(canvas)
		.addClass('loaded')
	
	if (m.type!='image')
	{
		//add wrapper and play button for videos
		$(canvas)
			.wrap('<div class="medium wrapper">')
			.parent()
			.append('<div class="play">PLAY</div>')
			.find('.play')
			.click(function(e) {
				e.stopImmediatePropagation();
				$(this).prev().trigger('click');
			})
	}

	$('<img/>')
		.attr({
			width:m.w,
			height:m.h
		})
		//.appendTo(canvas)
		.load(function(e,alpha) {

			$(canvas)
				.addClass('loaded')
				.css('background-image','none')
				
			if (typeof(G_vmlCanvasManager)=='object') G_vmlCanvasManager.initElement(canvas); //init canvas element for IE

			var ctx = canvas.getContext('2d');
			
			if (!alpha)
			{
				//first copy image onto canvas
				ctx.drawImage(this,0,0,this.width,this.height);

				if (!obj.interference) return window.setTimeout(function() { $(img).trigger('load') },100);
			
				//get (first) alpha mask from interference
				for (var id in obj.interference.patterns)
				{
					alpha = obj.interference.patterns[id].elm.get(0); 
					break;
				}
			}	
			
			//make sure alpha is loaded..
			var img = this;
			if (!alpha || $(alpha).hasClass('loading')) return window.setTimeout(function() { $(img).trigger('load',alpha) },100);
					
			//add alpha at offset
			var mx = -(1000 - this.width);
			var my = -(707 - this.height);
							
			var ox = Math.random() * mx;
			var oy = Math.random() * my;

			//$(canvas).css('background-image','none');

			//ctx.globalAlpha = .8;
 			ctx.globalCompositeOperation = 'xor';
 			ctx.drawImage(alpha,ox,oy,1000,707)
		})
		.attr('src',src);
}

MRI.prototype.zoomMedium = function(elm)
{
	/*	show zoomed thumb image + caption
	*/
	var media = $(elm).parent();
	var count = media.children('canvas.medium').length-1;
	var m = $(elm).data('medium');
	var x = $(elm).position().left-10;
	var y = $(elm).position().top-10;
	var w = $(elm).width();
	var ox = (m.mw - m.w)/2;

	var div = $('<div/>')
		.addClass('medium-over')
		.html('<img src="media/content/'+m.id+'_thumb.jpg" style="width:100%"/><div class="caption"></div>')
		.css({
			left:x,
			top:y,
			width:w,
		})
		.appendTo($(elm).parent())
		.mouseout(function() {
			$(this).remove();
		})
		.mousedown(function(e) {
			e.preventDefault()
		})
		.click(function() {
		
			/*	zoom image to fullscreen
			*/
			
			//add fullscreen dimm
			var div = $('<div/>')
				.attr('id','full')
				.html('<div id="dimm"/>')
				.appendTo('body')
				.find('#dimm').show().end()
				.click(function() {
					$(this).remove();
				});
				
			var p = $(this).offset();

			//define max zoom
			var zh = Math.min(m.zh,$(window).height() - 170);
			var zw = Math.min(1000,(zh/m.zh) * m.zw);
			
			var obj = $(this)
				.unbind('mouseout')
				.appendTo(div)
				.css({ backgroundColor:'transparent', left:p.left, top:p.top - $(window).scrollTop() })
				.unbind('click')
			
			new Slide(function(v) {
				obj.css({
					left:v.x,
					top:v.y,
					width:v.w
				});
			},function() {

				//zoom done, load hi-res source, add navigation
				div.find('img').attr('src','media/content/'+m.id+'_large.jpg');
				div.append(
					'<div class="navigation">'+
					'<a href="javascript://previous">previous</a>'+
					'<a href="javascript://next">next</a>'+
					'<a href="media/content/'+m.file+'" target="_blank">original size</a>'+
					'<a href="javascript://close">close</a>'+
					'</div>')
					.find('a:lt(2)')
					[count? 'show':'hide']()
					.click(function(e) {
						e.stopImmediatePropagation();
						
						/*	update to prev or next medium
						*/
						var o = $(this).index()==0? -1:1;
						var index = m.index+o;
						if (index<0) index = count;
						if (index>count) index = 0;

						m = media.children('canvas.medium').eq(index).data('medium');

						var zh = Math.min(m.zh,$(window).height() - 170);
						var zw = Math.min(1000,(zh/m.zh) * m.zw);
						
						$('#full')
							.find('img').fadeOut(100,function() { 
								$(this)
									.load(function() {
										$(this).fadeIn(250).next().html(m.caption.replace(/\|/g,'<br>'))
										
									})
									.attr('src','media/content/'+m.id+'_large.jpg')
									.parent().css({
										left:($(window).width()-zw)/2,
										width:zw
									})
									.next().find('a:eq(2)').attr('href','media/content/'+m.file)
							})
							.next().empty();
					});

			},.45).start({ 
				x:[p.left,($(window).width()-zw)/2],
				y:[p.top - $(window).scrollTop(),20],
 				w:[$(this).width(),zw]
			});
		
		});
		
	//hover zoom
	new Slide(function(v) {
		div.css({
			left:v.left,
			top:v.top,
			width:v.width
		});
	},function() {
		//load higher quality image, add caption
		div.find('img').attr('src','media/content/'+m.id+'_small.jpg');
		div.find('.caption').html(m.caption.replace(/\|/g,'<br>'));
	},.6,20).start({
		left:[x,x-ox],
		top:[y,y-15],
		width:[w,m.mw]
	});
}

MRI.prototype.zoomVideo = function(elm)
{
	/*	show video player + caption
	*/
	var m = $(elm).data('medium');
	var ox = (410 - m.w)/2;

	var div = $('<div/>')
		.addClass('medium-over')
		.html('<div id="media-player"></div><div class="caption">'+m.caption.replace(/\|/g,'<br>')+'</div>')
		.css({
			left:$(elm).parent().position().left-ox,
			top:$(elm).parent().position().top-20,
			'max-width':390
		})
		.appendTo($(elm).parents('.media'))
		.click(function(e) {
			e.stopImmediatePropagation();
			$(this).blur();
		});
		
	//add jwplayer
	this.video = true;
	jwplayer('media-player').setup({
        flashplayer:'media/mediaplayer-5.6-licensed/player.swf',
		//skin:'media/mediaplayer-5.6-licensed/bekle.zip',
        file:'media/content/'+m.file,
        height:220,
        width:390,
        autostart:true,
        youtube: { quality:'highres' },
//         modes:[
// 			{ type:'html5' },
// 			{ type:'flash', src:'media/mediaplayer-5.6-licensed/player.swf'}
// 		]
    });
    
	//pause interference while playing for better playback performance
    var obj = this;
	jwplayer().onPlay(function(event) {
		if (!obj.interference.paused) obj.interference.pause();
	});
	jwplayer().onPause(function(event) {
		if (obj.interference.paused) obj.interference.pause(true);
	});
    
	//click anywhere to remove video
	$(document).add('#page-centered').bind('click.mediaplayer', function() {
		obj.video = false;
		div.remove();
		$(document).add('#page-centered').unbind('click.mediaplayer');
		if (obj.interference.paused) obj.interference.pause(true);
	});
}

MRI.prototype.toggleMore = function()
{
	/*	collapse or expand navigation
	*/
	this.more = !this.more;
	$('#more')[this.more? 'show':'hide']();
	if (this.more) $('#suggest,#login,#profile,#signup').hide();
}

MRI.prototype.toggleItem = function(id,elm,generated)
{
	/*	collapse or expand item
	*/
	var item = $('#item-'+id);
		item.toggleClass('expanded');
	var expanded = item.hasClass('expanded')
		
	if (expanded)
	{
		elm.html('less');

		//get extended content if not done already
		if (item.children('.body:empty').length) this.getItemContent(id);
		else this.viewItem(item);
	}
	else
	{
		elm.html('more');
	}

	//hide auto-generated short 	
	if (generated)
	{
		elm.css('margin-left',expanded? 0:10).prev()[expanded? 'hide':'show']();
	}
}

MRI.prototype.viewItem = function(item)
{
	/*	auto-scroll item to top
	*/
	var max = $('body').height() - $(window).height();
	var top = Math.min(item.offset().top - 90,max);

	window.setTimeout(function() { 
		new Slide(function(v) {
			$(window).scrollTop(v.top)
		},false,.25).start({ top:[$(window).scrollTop(),top] });
	},300);
} 

/*
 * Twita@talinkahashifyer
 * http://www.dustindiaz.com
 * http://www.dustindiaz.com/basement/ify.html
 *
 * Copyright (c) 2009 Dustin Diaz
 * licensed under public BSD
 */
MRI.prototype.ify = function() {
  return {
    "link": function(t) {
      return t.replace(/(^|\s+)(https*\:\/\/\S+[^\.\s+])/g, function(m, m1, link) {
      	if (link.lastIndexOf('/')==link.length-1) link = link.substring(0,link.length-1); //small fix to get urls with a trailing slash working
        return ((m1 != '') ? ' ' : '') + '<a target="_blank" href=' + link + '>' + link + '</a>';
      });
    },
    "at": function(t) {
      return t.replace(/(^|\s+)\@([a-zA-Z0-9_]{1,15})/g, function(m, m1, m2) {
        return ((m1 != '') ? ' ' : '') + '<a target="_blank" href="http://twitter.com/' + m2 + '">@' + m2 + '</a>';
      });
    },
    "hash": function(t) {
      return t.replace(/(^|\s+)\#([a-zA-Z0-9_]+)/g, function(m, m1, m2) {
        return ((m1 != '') ? ' ' : '') + '<a target="_blank" href="http://search.twitter.com/search?q=%23' + m2 + '">#' + m2 + '</a>';
      });
    },
    "clean": function(tweet) {
      return this.hash(this.at(this.link(tweet)));
    }
  };
}();

