

$.extend($, {
	twitter: {
		fetch: function(id, count, callback) {
			var url = 'http://twitter.com/status/user_timeline/'+id+'.json?callback=?';
			return $.getJSON(url, function(data) {
				data = $.grep(data, function(tweet) {
					return tweet.in_reply_to_screen_name == null;
				});
				data = data.slice(0, count);
				data = $.map(data, function(tweet) {
					return {
						text: $.twitter.formatText(tweet.text),
						created_at: $.twitter.parseTime(tweet.created_at)
					};
				});
				callback(data);
			});
		},
		
		formatText: function(t) {
			return t.replace(/(https?:\/\/[0-9A-Za-z_.\-+?&#/]+)/g, '<a href="$1" rel="external">$1</a>');
			return t;
		},
		
		parseTime: function(s) {
			var vals = s.split(' ');
			var ts = [ vals[1], ' ', vals[2], ', ', vals[5], ' ', vals[3] ].join('');
			return new Date( Date.parse(ts) );
		},
		
		relativeTime: function(d1, d2) {
			d2 = d2 || new Date();
			var dMin = (d2.getTime() - d1.getTime()) / (60*1000);
			dMin = dMin + d1.getTimezoneOffset();
			
			if (dMin < 60) {
				if (dMin < 2) {
					return 'a minute ago';
				} else {
					return parseInt(dMin) + ' minutes ago';
				}
			} else if (dMin < 24*60) {
				if (dMin < 2*60) {
					return 'an hour ago';
				} else {
					return parseInt(dMin/60) + ' hours ago';
				}
			} else {
				if (dMin < 2*24*60) {
					return 'yesterday';
				} else {
					return parseInt(dMin/24/60) + ' days ago';
				}
			}
		}
	}
});

$.extend($.fn, {	
	loadBackground: function(f) {
		return this.each(function(i, elem) {
			var bg = $(elem).css('background-image') || '';
			bg = bg.replace(/url\(['"]?([^'"]+)['"]?\)/, '$1');
			
			if (!bg) {
				f.apply(elem);
				return;
			}
			
			var img = new Image();
			
			$(img)
				.load(function() { f.apply(elem); })
				.attr('src', bg)
				;
		});
	},
	
	sanitizeEmail: function() {
		this.each(function() {
			var link = $(this);
			var addr = link.attr('href').substring(7);
			
			addr = addr.replace('@', '.')
			           .replace('.nospam', '')
			           .replace('nospam.', '')
			           .replace('.at.', '@')
			           .replace('.dot.', '.');
			
			return link.attr('href', 'mailto:'+addr)
			            .html(addr);
		});
	},
	
	makeExternal: function() {
		return this.attr('target', '_blank');
	},
	
	
	twitterFeed: function(id, count) {
		if (!this.length)
			return this;
		count = count || 3;
		var self = this;
		$.twitter.fetch(id, count, function(data) {
			var elems = $.map(data, function(tweet) {
				return [ 
					'<li>',
					tweet.text,
					'<em>',
					'Posted ', $.twitter.relativeTime(tweet.created_at),
					'</em></li>'
				].join('');
			}).join('');
			self.html(elems);
			self.find('a[rel=external]').attr('target', '_blank');
		});
		return this;
	},
	
	
	expander: function() {
		return this.click(function(e) {
			var self = $(this);
			var href = self.attr('href') || '';
			var regex = /#(.+)$/;
			var match = regex.exec(href);
			
			if (match) {
				var target = $('#'+match[1]);
				if (target.is(':visible')) {
					target.slideUp(250);
					self.animate({ 'opacity': 1 }, 250);
				} else {
					target.slideDown(250);
					self.animate({ 'opacity': .33 }, 250);
				}
				return false;
			}
		});
	},

	
	pairHover: function(other, hoverClass) {
		if (other.length != 1) {
			return this;
		}
		
		other = other.get(0);
		hoverClass = hoverClass || 'hover';
		
		return this.hover( function() {
			$(other).addClass(hoverClass);
		}, function() {
			$(other).removeClass(hoverClass);
		});
	},
	
	
	imageRotate: function(delay) {
		delay = delay || 4000;
		
		return this.each(function() {
			var self = $(this);
			
			var kids = self.children();
			if (kids.length <= 1) {
				return;
			}
			
			self._doImageRotate(delay);
		});
	},
	
	
	_doImageRotate: function(delay) {
		var kids = this.children().get();
		var nkids = kids.length;
		
		var current = 0;
		var timer = null;
		var hovering = false;
		
		this.append(
			'<span class="rotator-nav">' +
				'<a class="prev" href="#">Previous</a>' +
				'<a class="next" href="#">Next</a>' +
			'</span>'
		);
			
		this.find('.rotator-nav').css({ 'opacity': 0, 'z-index': 2 });
		this.find('.rotator-nav .next, .rotator-nav .prev').css({ 'opacity': .5 });
		
		this.hover(
			function() { 
				$(this).find('.rotator-nav').fadeTo(250, 1);
				hovering = true;
				clearTimeout(timer);
				timer = null;
			},
			function() { 
				$(this).find('.rotator-nav').fadeTo(250, 0);
				hovering = false;
				autoRotate();
			}
		);
		
		this.find('.rotator-nav .next, .rotator-nav .prev').hover(
			function() { $(this).fadeTo(250, .9); },
			function() { $(this).fadeTo(250, .5); }
		);
		
		this.find('.rotator-nav .next').click(function() {
			doRotate(+1);
			return false;
		});
		
		this.find('.rotator-nav .prev').click(function() {
			doRotate(-1);
			return false;
		});
		
		var autoRotate = function() {
			if (!hovering && timer == null) {
				timer = setTimeout(function() {
					timer = null;
					doRotate(+1);
				}, delay);
			}
		};
		
		var doRotate = function(step) {
			var prev = current;
			current = (current + nkids + step) % nkids;
			
			var currElem = kids[current];
			var prevElem = kids[prev];
			
			$(prevElem).css('z-index', 0);
			
			$(currElem)
				.css({ 'opacity': 0, 'z-index': 1 })
				.removeClass('hidden')
				.loadBackground(function() {
					$(this)
						.fadeTo(500, 1, function() {
							$(prevElem).addClass('hidden');
							autoRotate();
						})
				})
				;
		};
		
		autoRotate();
	}
});


$(document).ready(function() {
	var links = $('a');
	
	links.filter('[rel=email]').sanitizeEmail();
	links.filter('[rel=external]').attr('target', '_blank');
	
	$('#twitter-feed').twitterFeed('no_wait_yes');
	
	$('#leader .image-rotator').imageRotate(3000);
	
	$('.expander').expander();
	
	$('.portfolio-link').each( function() {
		var self = $(this);
		var other = $('#portfolio-preview-' + this.id.replace('portfolio-link-', ''));
		self.pairHover(other);
		other.pairHover(self);
	});
	
	try {
		var pageTracker = _gat._getTracker("UA-10354257-1");
		pageTracker._trackPageview();
	} catch (e) {
	}
});

