// HTML Truncator for jQuery
// by Henrik Nyh <http://henrik.nyh.se> 2008-02-28.
// Free to modify and redistribute with credit.

;(function($) {

  var trailing_whitespace = true;

  $.fn.readmore = function(options) {
  
    var opts = $.extend({}, $.fn.readmore.defaults, options);
    
    $(this).each(function() {

		var $more = "<span id='read_more' style='display: none;'>" + opts.more + "</span>";
		
		$(this).html( [ $more, $(this).html() ].join( "" ) );
		$(this).parent().addClass("read_more");
		$(this).width($(this).parent().innerWidth());
				
		if ( $(this).innerHeight() > opts.max_height )
		{
			var $more_visible = '<span id="read_more" style="">' + opts.more + '</span>';
			var $more_text = $(this).children("span#read_more:first").text();
			$(this).children("span#read_more:first").remove();
						
			var more_length = $more_text.length;
			var content_length = $.trim(squeeze($(this).text())).length;
			var height = $(this).innerHeight();
			var truncated_node = null;
			
			while ( height > opts.max_height && (content_length - more_length) > 0)
			{
				content_length -= 1;				
				if (truncated_node != null)
					truncated_node.remove();
							
				truncated_node = recursivelyTruncate(this, content_length - more_length);

				var node = findNodeForMore(truncated_node);				
				findNodeForMore(truncated_node).append($more_visible);
				truncated_node.insertAfter($(this));
				
				height = truncated_node.innerHeight();
			}
			
			if (truncated_node != null)
			{
				truncated_node.parent().removeClass("read_more");
				truncated_node.css("visibility", "visible");
				$(this).css("display", "none");
			}
		}
		else
		{
			$(this).parent().removeClass("read_more");
			$(this).css("visibility", "visible");
		}
		
    });
  }

  // Note that the " (...more)" bit counts towards the max length – so a max
  // length of 10 would truncate "1234567890" to "12 (...more)".
  $.fn.readmore.defaults = {
    max_length: 90,
    more: '...more',
	html: '',
    less: 'less',
	max_height: 42
  };

  function recursivelyTruncate(node, max_length) {
    return (node.nodeType == 3) ? truncateText(node, max_length) : truncateNode(node, max_length);
  }

	function truncateNode(node, max_length) {
		var node = $(node);
		var new_node = node.clone().empty();
		var truncatedChild;
		node.contents().each(function() {
			var remaining_length = max_length - new_node.text().length;
			if (remaining_length == 0) return;  // breaks the loop
			truncatedChild = recursivelyTruncate(this, remaining_length);
			if (typeof(truncatedChild) == 'object' || (typeof(truncatedChild) == 'string' && $.trim(truncatedChild).length > 0 )) 
			//if (typeof(truncatedChild) != 'undefined') 
			{				
				new_node.append(truncatedChild);
			}
		});
		return new_node;
	}

  function truncateText(node, max_length) {
    var text = squeeze(node.data);
    if (trailing_whitespace)  // remove initial whitespace if last text
      text = text.replace(/^ /, '');  // node had trailing whitespace.
    trailing_whitespace = !!text.match(/ $/);
    var text = text.slice(0, max_length);
    // Ensure HTML entities are encoded
    // http://debuggable.com/posts/encode-html-entities-with-jquery:480f4dd6-13cc-4ce9-8071-4710cbdd56cb
    text = $('<div/>').text(text).html();
    return text;
  }

  // Collapses a sequence of whitespace into a single space.
  function squeeze(string) {
    return string.replace(/\s+/g, ' ');
  }
  
  // Finds the last, innermost block-level element
  function findNodeForMore(node) {
	debugger;
    var $node = $(node);
	   var last_child = $node.children(":last");
	if (!last_child) return node;
    var display = last_child.css('display');
	
    if (!display || display=='inline') 
	{
		return $node;
	}
    return findNodeForMore(last_child);
  };

  // Finds the last child if it's a p; otherwise the parent
  function findNodeForLess(node) {
    var $node = $(node);
    var last_child = $node.children(":last");
    if (last_child && last_child.is('p')) return last_child;
    return node;
  };

})(jQuery);
