(function($, undefined){

		/**
		 * Main constructor
		 * @param o		options
		 * @param init	auto-init?
		 */
	var	CORE 		= $.textareaCharLimit = function(o, init){

			if(init === undefined || init){
				this.init(o);
			}

		},
		addMethod 	= CORE.prototype,
		templates	= {},
		instances	= {};


	addMethod.init = function(o){
		var self		= this;

		// CONFIGURE
		this.$			= '.textareaCharLimit';
		this.$c			= undefined;
		this.limit		= 255;
		this.delay		= 100;
		this.count		= 0;
		this.templates	= $.extend({}, templates);
		this.onCount	= function(){};
		this.onLimit	= function(){};
		this.navKeys	= {8:1,9:1,16:1,17:1,18:1,37:1,38:1,39:1,40:1,46:1,91:1};

		if(o!==undefined){$.extend(this, o);}

		// BUILD
		this.$			= $(this.$);
		this.$c 		= (this.$c===undefined)?$(this.templates.$c).insertAfter(this.$):$(this.$c);
		this.cInner 	= this.$c.html();
		this.r			= new RegExp('(.{0,'+this.limit+'}).*');
		this.countChars();
		this.log();


		// BIND
		this.$.bind('keyup.textareaCharLimit', function(e){
			if(!self.countChars() && self.navKeys[e.keyCode]===undefined){
				self.trim();
			}
			self.log();
		});


	};


	addMethod.log = function(){
		var c = Math.min(this.count, this.limit);
		this.$c.html(this.cInner.replace(/\{count\}/g,c));
		var cR = this.limit-this.count;
		cR = (cR<0)?0:cR;
		this.$c.html(this.cInner.replace(/\{countRemaining\}/g,cR) );
	};

	addMethod.countChars = function(){
		var nl		= this.$.val().length;
		this.onCount(this.count, nl);
		this.count = nl;

		if(this.checkLimit()){
			return true;
		} else {
			this.onLimit(nl);
			return false;
		}
	};

	addMethod.checkLimit = function(){
		return (this.count>this.limit)?false:true;
	};


	addMethod.trim = function(){
		this.$.val(this.$.val().replace(this.r, '$1'));
	};


	templates = {
		$c	: '<span class="counter">{countRemaining} characters remaining</span>'
	};


	$.fn.textareaCharLimit = function(opts){

		this.each(function(){
			// CONFIGURE
			var o	= $.extend({}, opts),
				$el	= $(this);

			o.$ 	= $el;

			// BUILD
			$el.textareaCharLimit = new CORE(o);
		});

	};

})(jQuery);
