$.log = function(msg) {
	console && console.log && console.log(msg);
}
var chrislovejoy;
var ChrisLovejoy = function() {
	if (typeof this.init === 'function') this.init();
	chrislovejoy = this;
}
$.extend(ChrisLovejoy.prototype, eventDispatcher.prototype);
$.extend(ChrisLovejoy.prototype, {
	data:{},
	date:null,
	timeZone:0,
	hash:'',
	hashInterval:null,
	dims:{
		thumbs:{w:270,h:70}
	},
	tag:{
		names:[],
		list:{},
		listLite:{},
		max:0,
		selected:[]
	},
	init:function(){
		var z = this;
		z.date = new Date();
		z.timeZone = -z.date.getTimezoneOffset();
		typeof data !== 'undefined'? z.parse(data) : z.getData();
		z.dispatchEvent('INIT');
	},
	getData:function(){
		$.ajax({
			url:'/chrislovejoy.json',
			success:function(data, status, request) {
				z.parse(data);
			},
			error:function(request, status, error) {
				$.log(status);
			},
			dataType:'json'
		});
		z.dispatchEvent('GET_DATA');
	},
	parse:function(data) {
		var z = this;
		z.dispatchEvent('PARSE_BEGIN', data);
		if (!data.hasOwnProperty('content')) { z.data = data; return; }
		var sortNodes = function(a,b){
			return b.date - a.date;
		};
		data.content = data.content.sort(sortNodes);
		data.indexedContent = {};
		for (var i = 0; i < data.content.length; i++)
		{
			var node = data.content[i];
			if (!node.hasOwnProperty('id')) { node.id = 'node' + i; }
			data.indexedContent[node.id] = node;
			node.date = new Date(node.date - z.timeZone * 60000);
			node.element = null;
		}

		z.data = data;
		z.populateTags();
		z.drawBody();
		if (!z.hashListener())
		{
			z.drawTags();
			z.drawNodes(z.data.content);
		}
		z.startHashListener();
		z.dispatchEvent('PARSE_COMPLETE', data);
	},
	populateTags:function(){
		var z = this;
		z.tag.names = [];
		for (var name in z.tag.list) {
			z.tag.list[name].element.remove();
		}
		z.tag.list = {};
		z.tag.max = 0;
		for (var i = 0; i < z.data.content.length; i++)
		{
			var node = z.data.content[i];
			if (!node.hasOwnProperty('tags')) continue;
			for (var j = 0; j < node.tags.length; j++)
			{
				var tagName = node.tags[j];
				if (!z.tag.list.hasOwnProperty(tagName)) {
					z.tag.list[tagName] = {nodeIDs:[],element:null};
					z.tag.names.push(tagName);
				}
				z.tag.list[tagName].nodeIDs.push(node.id);
				if (z.tag.list[tagName].nodeIDs.length > z.tag.max) z.tag.max = z.tag.list[tagName].nodeIDs.length;
			}
		}
		var sortTags = function(a,b) {
			aName = a.toLowerCase();
			bName = b.toLowerCase();
			if (aName > bName) return 1;
			if (aName < bName) return -1;
			return 0;
		};
		z.tag.names = z.tag.names.sort(sortTags);
	},
	drawBody:function(){
		var z = this;

		$('.logo').click(function(event){z.selectTag();});
		if (z.data.hasOwnProperty('background')) {
			$('.header').css({'background':'url('+z.data.background+')'});
			$('body').css({
				'background':'url('+z.data.background+')',
				'background-color':'#000',
				'background-attachment':'fixed',
				'background-repeat':'no-repeat'
				});
		} else {
			$('body').css({background:''});
		}
		z.dispatchEvent('DRAW_BODY');
	},
	drawNodes:function(nodes){
		var z = this;
		var content = $('.content');
		content.find('.node').remove();
		for (var i = 0; i < nodes.length; i++)
		{
			var node = nodes[i];
			if (typeof node === 'string') node = z.data.indexedContent[node];
			z.drawNode(node);
			content.append(node.element);
		}
		content.append($('.tail'));
		z.dispatchEvent('DRAW_NODES', {target:content});
	},
	startHashListener:function()
	{
		var z = this;
		clearInterval(this.hashInterval);
		this.hashInterval = setInterval(function(){z.hashListener();}, 200);
	},
	hashListener:function()
	{
		if (window.location.hash == this.hash)
			return false;
		this.hash = window.location.hash;
		var hash = queryToObject(window.location.hash);
		if (!hash.hasOwnProperty('tag'))
			return false;
		this.selectTag(hash.tag.split(/\s*,\s*/));
		return true;
	},
	fancyboxTypePattern: /\.(mp4|m4v|ogv|webm|swf|jpg|jpeg|png|gif)(\?.*$)?(#.*)?$/,
	fancyboxOptions: {
		titlePosition:'inside',
		titleFormat:function (title, currentArray, currentIndex, currentOps) {
			return title+'<div class="fancy-counter">'+(currentIndex+1)+' of '+currentArray.length+'</div>';
		},
		//autoScale:false,
		overlayColor:'#000',
		margin:6,
		padding:8,
		cyclic:true,
		speedIn:100,
		speedOut:100,
		onStart:function(links, index, options) {
			var link = $(links).eq(index);
			var id = link.closest('.node').attr('id');
			var node = chrislovejoy.data.indexedContent[id];
			var data;
			for (var i = 0; i < node.data.length; i++) {
				if (node.data[i].src == options.href) {
					data = node.data[i];
					break;
				}
			}
			if (data && data.hasOwnProperty('type'))
				options.type = data.type;
			if (/\.(m4v|mp4)$/.test(link.attr("href"))) {
				if (!data)
					return false;

				var dims = {
					width: data.hasOwnProperty("width")? data.width: 640,
					height: data.hasOwnProperty("height")? data.height: 360
				};
				dims.aspect = dims.width / dims.height;

				var constraints = {
					width: $(window).width() - 150,
					height: $(window).height() - 150
				}
				constraints.aspect = constraints.width / constraints.height;

				if (dims.width > constraints.width || dims.height > constraints.height) {
					if (dims.aspect > constraints.aspect) {
						dims.width = constraints.width;
						dims.height = Math.floor(dims.width / dims.aspect);
					} else {
						dims.height = constraints.height;
						dims.width = Math.floor(dims.height * dims.aspect);
					}
				}

				var playerMarkup = '<video id="content_video" controls="true" poster="'+data.thumb+'" width="'+dims.width+'" height="'+dims.height+'" autoplay="true">';
				playerMarkup += '<source src="'+data.src+'" type=\'video/mp4; codecs="avc1.42E01E, mp4a.40.2"\' />';
				if (data.hasOwnProperty('ogv'))
					playerMarkup += '<source src="'+data.ogv+'" type=\'video/ogg; codecs="theora, vorbis"\' />';
				if (data.hasOwnProperty('webm'))
					playerMarkup += '<source src="'+data.webm+'" type=\'video/webm; codecs="vp8, vorbis"\' />';
				playerMarkup += '<object id="flash_fallback_1" class="vjs-flash-fallback" width="'+dims.width+'" height="'+dims.height+'"';
				playerMarkup += ' type="application/x-shockwave-flash"';
				playerMarkup += ' data="http://releases.flowplayer.org/swf/flowplayer-3.2.1.swf">';
				playerMarkup += '  <param name="movie" value="http://releases.flowplayer.org/swf/flowplayer-3.2.1.swf" />';
				playerMarkup += '  <param name="allowfullscreen" value="true" />';
				playerMarkup += '  <param name="flashvars" value=\'config={"playlist":["'+data.thumb+'", {"url": "'+data.src+'","autoPlay":true,"autoBuffering":true}]}\' />';
				playerMarkup += '  <img src="'+data.thumb+'" width="'+dims.width+'" height="'+dims.height+'" alt="Poster Image" title="No video playback capabilities." />';
				playerMarkup += '</object></video>';
				var videoPlayer = $(playerMarkup);

				setTimeout(function() {
					$.fancybox(videoPlayer);
					//VideoJS.setup(videoPlayer[0]);
				}, 0);
				return false;
			}
			return true;
		}
	},
	drawNode:function(node)
	{
		var z = this;
		var element = $('<div/>').addClass('node').attr({id:node.id});
		var name = $('<div/>').addClass('node--name').appendTo(element);
		var dataIndex = node.hasOwnProperty('hero')? node.hero : 0;
		var href = node.data.length? node.data[dataIndex].src : '#';
		if (node.data.length == 1) href = node.data[0].src;
		$('<a target="_blank" href="'+href+'">'+node.name+'</a>').appendTo(name).click(function(event){z.clickNode(event);});;
		var formattedDate = node.date.getFullYear() + '.' + (node.date.getMonth() + 1) + '.' + node.date.getDate();
		var date = $('<span/>').addClass('node--date').html(formattedDate);
		var byline = $('<div/>').addClass('byline').append(date);
		if (node.hasOwnProperty('tags')) {
			var tags = $('<span/>').addClass('node--tags');
			var concat = '';
			for (var j = 0; j < node.tags.length; j++)
			{
				var tag = $('<a/>').addClass('tag').html(node.tags[j]).attr({'href':'#tag='+node.tags[j]}).click(function(event){z.clickTag(event); return false;});
				tags.append(concat).append(tag);
				concat = ', ';
			}
			byline.append(tags);
		}

		var thumbs = $('<div/>').addClass('thumbs');
		for (var j = 0; j < node.data.length; j++)
		{
			var datum = node.data[j];
			if (datum.hasOwnProperty('thumb') && !datum.thumb) { continue; }

			var src = datum.hasOwnProperty('thumb')? datum.thumb: datum.src;
			var a = $('<a target="_blank" href="'+datum.src+'" rel="'+node.id+'"></a>');
			var thumb = z.phpThumb(src, z.dims.thumbs.w, z.dims.thumbs.h, true);
			if (datum.hasOwnProperty('info')) { a.attr({title:datum.info}); }
			a.append(thumb).appendTo(thumbs);
			if (z.fancyboxTypePattern.test(datum.src) || datum.hasOwnProperty("type"))
				a.fancybox($.extend({type:datum.type}, z.fancyboxOptions));
		}
		if (thumbs.children().length) element.append(thumbs);

		if (node.hasOwnProperty('info') && node.info)
		{
			var markedUp = node.info.replace(/\[link ([^\]]*)\]([^\]]*)\[\/link\]/g, '<a href="$1" target="_blank" title="$1">$2</a>');
			var info = $('<div/>').addClass('node--info').html(markedUp).appendTo(element);
			/*
			//TODO: catch links to youtube, etc, and load an iframe in fancybox instead
			$('a', info).click(function(event){
				var href = $(this).attr('href');
				if (z.fancyboxTypePattern.test(href)) {
					event.preventDefault();
					a.fancybox($.extend({type:datum.type}, z.fancyboxOptions));
				}
			});
			*/
		}

		element.append(byline);

		node.element = element;
		$('#'+node.id).replaceWith(node.element);
		z.dispatchEvent('DRAW_NODE', {target:node.element,data:node});
	},
	clickNode:function(event) {
		var z = this;
		var id = $(event.currentTarget).parents('.node').attr('id');
		var node = z.data.indexedContent[id];
		var dataIndex = node.hasOwnProperty('hero')? node.hero : 0;
		z.showData(node, dataIndex) || event.preventDefault();
		// only works if called from click on an anchor tag with an href attr.
	},
	clickData:function(event) {
		var z = this;
		var nodeId = $(event.currentTarget).attr('rel')
		return z.showData($(event.currentTarget).attr('rel'), $(event.currentTarget).attr('name'));
		// only works if called from click on an anchor tag with an href attr.
	},
	showData:function(node, index) {
		var z = this;
		if (typeof node.data[index].src == 'string') {
			if (z.fancyboxTypePattern.test(node.data[index].src)) {
				$.fancybox({href:node.data[index].src});
				return false;
			} else {
				return true; /* let a click pass through */
			}
		}
		return false;
	},
	drawTags:function(){
		var z = this;
		var tagHelp = 'To narrow your selection, hold the shift key and click to chose multiple tags.';
		var tags = $('#global-tags');
		if (!tags.length) tags = $('<ul/>').attr({'id':'global-tags'}).appendTo('.header');
		tags.attr({title:tagHelp});
		var everythingTag = $('#global-tags .everything');
		if (!everythingTag.length) {
			everythingTag = $('<li class="tag everything"><div>everything</div></li>').click(function(event){z.clickTag(event)}).prependTo('#global-tags');
		}
		$('#global-tags .tag').removeClass('selected').removeClass('intersecting');
		if (!z.tag.selected.length)
			everythingTag.addClass('selected');
		for (var i = 0; i < z.tag.names.length; i++)
		{
			var tagName = z.tag.names[i];
			var tag = z.tag.list[tagName];
			if (!tag.element) {
				tag.element = $('<li class="tag"><div>'+tagName+'</div></li>').click(function(event){z.clickTag(event)});
				tag.element.appendTo('#global-tags');
			}

			var minSize = 10;
			var maxSize = 15;
			var fontSize = minSize + maxSize * (tag.nodeIDs.length / z.tag.max) + 'px';
			tag.element.css({"font-size":fontSize});

			var selected = false;
			var intersection = z.tag.selected.length? tag.nodeIDs: [];
			for (var j = 0; j < z.tag.selected.length; j++)
			{
				var selectedTagName = z.tag.selected[j];
				if (selectedTagName == tagName)
				{
					selected = true;
					continue;
				}
				else if (intersection.length) {
					intersection = tag.nodeIDs.intersect(z.tag.list[selectedTagName].nodeIDs);
				}
			}
			selected?
				tag.element.addClass('selected'):
				tag.element;
			selected || (intersection && intersection.length)?
				tag.element.addClass('intersecting'):
				tag.element.removeClass('intersecting');
		}
		z.dispatchEvent('DRAW_TAGS');
	},
	clickTag:function(event) {
		var z = this;
		var tagName = $(event.currentTarget).text();
		z.selectTag(tagName, event.shiftKey);
	},
	selectTag:function(tagNames, append) {
		var z = this;
		if (!append) z.tag.selected = [];
		var matches = [];
		if (tagNames && tagNames.length)
		{
			if (typeof tagNames === 'string') tagNames = tagNames.split(/\s*,\s*/);
			for (var i = 0; i < tagNames.length; i++) {
				var tagName = tagNames[i];
				if (tagName == 'everything')
				{
					z.selectTag();
					return;
				}
				z.tag.list.hasOwnProperty(tagName) && z.tag.selected.push(tagName);	
			}
		}
		for (var i = 0; i < z.tag.selected.length; i++) {
			var tagName = z.tag.selected[i];
			if (matches.length) matches = matches.intersect(z.tag.list[tagName].nodeIDs);
			else matches = z.tag.list[tagName].nodeIDs;
		}
		if (!matches.length) matches = z.data.content;
		z.drawNodes(matches);
		z.drawTags();
		z.hash = z.tag.selected.length? '#tag=' + encodeURIComponent(z.tag.selected.join(',')) : '';
		window.location.hash = z.hash;
		z.dispatchEvent('SELECT_TAG', {target:z.tag.selected});
	},
	phpThumb:function(url, w, h, zc){
		var z = this;
		return $('<img/>').attr({
			src:z.phpThumbURI(url, w, h, zc),
			width:w,
			height:h,
			border:0
		});
	},
	phpThumbURI:function(url, w, h, zc){
		url = '/php/phpThumb.php?src='+encodeURIComponent(url);
		if (w) url += '&w='+encodeURIComponent(w);
		if (h) url += '&h='+encodeURIComponent(h);
		if (zc) url += '&zc=1';
		return url;
	}
});

