(function($) {
	var CONTENT_AND_READ_LESS_WRAP = "<span class='expandable-content-and-read-less-wrap' />";
	var CONTENT_WRAP = "<span class='expandable-content-wrap' />";
	var CONTAINER_WRAP = "<span class='expandable-container-wrap' />";
	var FADER_WRAP = "<span class='expandable-fader'></span>";
	var READ_MORE_WRAP = "<span class='expandable-read-more'><a href='/'>Read more</a></span>";
	var READ_LESS_WRAP = "<span class='expandable-read-less'><a href='/'>Read less</a></span>";

	$.fn.expandable = function() {
		return this.each(function() {
			var $this = $(this);
			var data = $this.data("expandable");
			$this.addClass("collapsed");
			$this.css({
				"overflow" : "hidden"
			});

			var originalHeight = $this.height();

			$this.data("expandable", {
				originalHeight : originalHeight
			});

			if (!data) {
				$this.wrapInner(CONTAINER_WRAP);
				var $containerWrap = $this.find(".expandable-container-wrap");
				$containerWrap.wrapInner(CONTENT_AND_READ_LESS_WRAP);
				$containerWrap.find(".expandable-content-and-read-less-wrap")
				        .wrapInner(CONTENT_WRAP);
				$containerWrap.height($this.height());
			}

			removeReadMore($this);
			removeReadLess($this);

			var scrollHeight = $this.attr("scrollHeight");
			if (scrollHeight > originalHeight) {
				addReadMoreAndFader($this);
				var $readMoreLink = $this.find(".expandable-read-more a");
				$readMoreLink.click(function(e) {
					onReadMore.apply($this, [ e ]);
				});
			}

		});
	};

	function addReadLess($container) {
		$container.find(".expandable-content-and-read-less-wrap").append(
		        READ_LESS_WRAP);
		var scrollHeight = $container.attr("scrollHeight");
		var $readLessLink = $container.find(".expandable-read-less a");
		$readLessLink.click($.proxy(onReadLess, $container));
	}

	function removeReadMore($container) {
		var $readMoreWrap = $container.find(".expandable-read-more");
		$readMoreWrap.remove();
		var $faderWrap = $container.find(".expandable-fader");
		$faderWrap.remove();
	}

	function removeReadLess($container) {
		var $readLessWrap = $container.find(".expandable-read-less");
		$readLessWrap.remove();
		var scrollHeight = $container.attr("scrollHeight");
	}

	function addReadMoreAndFader($container) {
		var $containerWrap = $container.find(".expandable-container-wrap");
		$containerWrap.append(FADER_WRAP);
		$containerWrap.append(READ_MORE_WRAP);

		var $readMoreWrap = $container.find(".expandable-read-more");
		var $faderWrap = $container.find(".expandable-fader");
		$faderWrap.css({
			bottom : $readMoreWrap.height()
		});
	}

	function onReadMore(e) {
		e.preventDefault();
		e.stopPropagation();

		var $container = this;
		removeReadMore($container);
		$container.data("expandable").originalHeight = $container.height();
		addReadLess($container);
		$container.removeClass("collapsed");
		$container.animate({
			height : $container.attr("scrollHeight")
		}, 400, function() {
			$container.addClass("expanded");
		});
		$container.find(".expandable-container-wrap").animate({
			height : $container.attr("scrollHeight")
		}, 400);

		return false;
	}

	function onReadLess(e) {
		e.preventDefault();
		e.stopPropagation();

		var $container = this;
		addReadMoreAndFader($container);
		removeReadLess($container);
		$container.animate({
			height : $container.data("expandable").originalHeight
		}, 400);

		var $readMoreLink = $container.find(".expandable-read-more a");
		$container.removeClass("expanded");
		$container.find(".expandable-container-wrap").animate({
			height : $container.data("expandable").originalHeight
		}, 400, function() {
			$container.addClass("collapsed");
			$readMoreLink.click(function(e) {
				onReadMore.apply($container, [ e ]);
			});
		});

		return false;
	}
}(jQuery));
