/* Copyright (c) 2008 James.Huang 
 * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * Copyright notice and license must remain intact for legal use
 * Version: 1.0 (Jun 15, 2009)
 * Requires: jQuery 1.2+
 */
(function($){

	var descid = 0;
	var oldesc = [];
	
	$.truncate = function (ele, options) {
		return $.truncate.impl.init(ele, options);
	};
	
	$.fn.truncate = function (options) {
		return $.truncate.impl.init(this, options);
	};
	
	$.truncate.defaults = {
		maxlength: 120,
		moreString: 'more',
		hideString: 'hide',
		beforeTruncate: null,
		afterTruncate: null,
		truncateBack: true
	};
	
	$.truncate.impl = {
		opts: null,
		desc: null,
		init: function(ele, options){
			this.opts = $.extend({}, $.truncate.defaults, options);
			if (typeof ele == 'object') {
				ele = ele instanceof jQuery ? ele : $(ele);
				oldesc[descid] = ele.find("p").html();
				this.folderInfo(ele, descid);
				descid++;
			}
		},
		truncateBack: function(str, pos){
			while (pos < str.length) {
				var w = str.slice(pos-1, pos);
				if (w == ' ') break;
				pos--;
			}
			return pos;
		},
		truncateForward: function(str, pos){
			while (pos < str.length) {
				var w = str.slice(pos, pos+1);
				if (w == ' ') break;
				pos++;
			}
			return pos;
		},
		folderInfo: function(containor, descid){
			var self = this; // be used for instance
			var word_length = this.opts.maxlength;
			var desc_string = containor.find("p").html();
			// handle desc before truncate
			if ($.isFunction(this.opts.beforeTruncate)) {
				this.opts.beforeTruncate.apply(this, [desc_string]);
				desc_string = this.desc;
			}
			// trim and strip html tags
			var string = this.stripTags(this.trim(desc_string));
			if (word_length > string.length) return;
			// truncate back or forward when encounter whole word
			var pos = word_length;
			if (this.opts.truncateBack) {
				pos = this.truncateBack(string, word_length);
			} else {
				pos = this.truncateForward(string, word_length);
			}
			// handle desc before truncate
			if ($.isFunction(this.opts.afterTruncate)) {
				this.opts.afterTruncate.apply(this, [string]);
				string = this.desc;
			}
			var descDiv = $('<p>' + string.slice(0, pos) + ' ... </p>');
			var moreBtn = $('<a href="javascript:;">' + this.opts.moreString + '</a>')
			.click(function(e){
				self.unfolderInfo(containor, descid);
			});
			containor.empty();
			moreBtn.appendTo(descDiv);
			descDiv.appendTo(containor);
		},
		unfolderInfo: function (containor, descid) {
			var self = this; // be used for instance
			var word_length = this.opts.maxlength;
			var descDiv = $('<p>' + oldesc[descid] + ' </p>');
			var hideBtn = $('<a href="javascript:;">' + this.opts.hideString + '</a>')
			.click(function(e){
				self.folderInfo(containor, descid);
			});
			containor.empty();
			hideBtn.appendTo(descDiv);
			descDiv.appendTo(containor);
		},
		stripTags: function (str) {
			if (typeof str == 'string') {
				return str.replace(/<\/?[^>]+>/gi, '');
			}
			return '';
		},
		trim: function (str) {
			if (typeof str == 'string') {
				return str.replace(/(^\s*)|(\s*$)/g, '');
			}
			return '';
		}
	}

})(jQuery);