function urlsEqualUpToFragment(left, right) {
	var leftFragmentIndex = left.indexOf('#');
	var leftSubstring = leftFragmentIndex == -1 ? left : left.substring(0, leftFragmentIndex);

	var rightFragmentIndex = right.indexOf('#');
	var rightSubstring = rightFragmentIndex == -1 ? right : right.substring(0, rightFragmentIndex);

	return leftSubstring == rightSubstring;
}

(function($, document, window, undefined) {
	var $document = $(document);
	var $window = $(window);

	$(function() {
		var $body = $('body');

		var $header = $('header');
		var headerHeight = $header.height();

		var h2s = [];
		function updateH2s() {
			h2s.length = 0;
			$('#content div[id] h2').each(function() {
				$this = $(this);
				h2s.push($this.data('offsetTop', $this.offset().top));
			});
		}

		// Keep track of the last h2 past which the user scrolled.
		var current = null;
		function updateCurrentH2(next) {
			if(current != null)
				current.css('z-index', ''); // Show current in front of #current-h2.
			current = next;
			$('#current-a').removeAttr('id');
			$('#current-h2').remove();

			if(current == null)
				$header.css('border-bottom-width', '');
			else {
				$header.css('border-bottom-width', '0');

				$('header ul a[href$="#' + current.parent().attr('id') + '"]').attr('id', 'current-a');
				$body.append(current.clone().attr('id', 'current-h2').css('top', headerHeight + 'px'));
				current.css('z-index', '-1'); // Hide current behind #current-h2 and header.
			}
		}
		function checkCurrentH2() {
			var viewportTop = $window.scrollTop() + headerHeight;

			var next = null;
			$.each(h2s, function() {
				var h2 = $(this);
				if(viewportTop >= h2.data('offsetTop'))
					next = h2;
				else
					// At this point, next is the last h2 which is above or at viewportTop.
					// Since each h2 is below the previous, stop looping once we've found the first h2 below viewportTop.
					return false;
			});
			if(next == null ? current != null : !next.is(current)) // If current and next are different:
				updateCurrentH2(next);
		}

		// Pad the bottom of body just enough so the last h2 on the page can be current.
		var previousPadding = parseInt($body.css('padding-bottom'));
		function padBottom() {
			previousPadding = Math.max(0, ($window.height() - headerHeight) - (($document.height() - previousPadding) - h2s[h2s.length - 1].data('offsetTop')) + 1); // FIXME: + 1 is an IE bugfix.
			$body.css('padding-bottom', previousPadding + 'px');
		}

		// Binding events.
		$window.resize(function(event) {
			updateH2s();
			padBottom();
			checkCurrentH2();
		});
		$window.scroll(function(event) {
			checkCurrentH2();
		});
		$('a').click(function(event) {
			var hash = this.hash;
			var target_element = $(hash + ' h2');

			if(urlsEqualUpToFragment(location.href, this.href) && hash && target_element.length) {
				event.preventDefault();
				$('html, body').animate({
					scrollTop: (target_element.offset().top - headerHeight + 1) + 'px' // FIXME: + 1 is an IE bugfix.
				}, 'slow', function() {
					location.hash = hash;
				});
			}
		});

		// Trigger a resize event to recompute on DOM ready and onload.
		$window.resize();
		$window.load(function() { $window.resize(); });
	});
}(jQuery, document, this));
