/*
 * jQuery Textarea Characters Counter Plugin v 2.0
 * Examples and documentation at: http://roy-jin.appspot.com/jsp/textareaCounter.jsp
 * Copyright (c) 2010 Roy Jin
 * Version: 2.0 (11-JUN-2010)
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 * Requires: jQuery v1.4.2 or later
 */
(function($){
	var defaults = {  
		maxCharacterSize: -1,  
		originalStyle: 'originalTextareaInfo',
		warningStyle: 'warningTextareaInfo',  
		warningNumber: 20,
		displayFormat: '#input characters | #words words'
	};  


	$.fn.CharSizeLimit = function(p_sCharSizeLimit){
		defaults.maxCharacterSize = p_sCharSizeLimit;
		$.fn.textareaCount(defaults);
		return true;
	}

  
	$.fn.textareaCount = function(options, fn) {   
		var options = $.extend(defaults, options);
		
		var container = $(this);
		
		//$("<div class='charleft'>&nbsp;</div>").insertAfter(container);
		
		//create charleft css
		var charLeftCss = {
			'width' : container.width()
		};
		
		var charLeftInfo = getNextCharLeftInformation(container);
		/*
		var charLeftInfo = getNextCharLeftInformation(function(){
			return $('.charleft');
		});
		*/
		charLeftInfo.addClass(options.originalStyle);
		charLeftInfo.css("width", container.width());
		//charLeftInfo.css(charLeftCss);
		
		var numInput = 0;
		var maxCharacters = options.maxCharacterSize;
		var numLeft = 0;
		var numWords = 0;
				
		container.bind('keyup', function(event){limitTextAreaByCharacterCount();})
				 .bind('mouseover', function(event){setTimeout(function(){limitTextAreaByCharacterCount();}, 10);})
				 .bind('paste', function(event){setTimeout(function(){limitTextAreaByCharacterCount();}, 10);});
		
		
		function limitTextAreaByCharacterCount(){
			charLeftInfo.html(countByCharacters());
			//function call back
			if(typeof fn != 'undefined'){
				fn.call(this, getInfo());
			}
			return true;
		}
		
		function countByCharacters(){
			var content = container.val();
			var contentLength = content.length;
			
			//Start Cut
			if(options.maxCharacterSize > 0){
				//If copied content is already more than maxCharacterSize, chop it to maxCharacterSize.
				if(contentLength >= options.maxCharacterSize) {
					content = content.substring(0, options.maxCharacterSize); 				
				}
				
				var newlineCount = SpecialCharCounter(content);
				
				// newlineCount new line character. For windows, it occupies 2 characters
				var systemmaxCharacterSize = options.maxCharacterSize - newlineCount;
				if (!isWin()){
					 systemmaxCharacterSize = options.maxCharacterSize
				}
				if(contentLength > systemmaxCharacterSize){
					//avoid scroll bar moving
					var originalScrollTopPosition = this.scrollTop;
					container.val(content.substring(0, systemmaxCharacterSize));
					this.scrollTop = originalScrollTopPosition;
				}
				charLeftInfo.removeClass(options.warningStyle);
				if(systemmaxCharacterSize - contentLength <= options.warningNumber){
					charLeftInfo.addClass(options.warningStyle);
				}
				
				numInput = container.val().length + newlineCount;
				if(!isWin()){
					numInput = container.val().length;
				}
			
				numWords = countWord(getCleanedWordString(container.val()));
				
				numLeft = maxCharacters - numInput;
			} else {
				//normal count, no cut
				var newlineCount = SpecialCharCounter(content);
				numInput = container.val().length + newlineCount;
				if(!isWin()){
					numInput = container.val().length;
				}
				numWords = countWord(getCleanedWordString(container.val()));
			}
			
			return formatDisplayInfo(options.maxCharacterSize
									, numInput
									, numLeft
									, numWords);
		}

		function formatDisplayInfo(p_lMaxCharLength, p_lMessageCharLength, p_lMessageCharLeft, p_sMessageWordLength){
			var format = options.displayFormat;
			format = format.replace('#input', p_lMessageCharLength);
			format = format.replace('#words', p_sMessageWordLength);
			//When maxCharacters <= 0, #max, #left cannot be substituted.
			if(p_lMaxCharLength > 0){
				format = format.replace('#max', p_lMaxCharLength);
				format = format.replace('#left', p_lMessageCharLeft);
			}
			return format;
		}
		
		function formatDisplayInfo1(){
			var format = options.displayFormat;
			format = format.replace('#input', numInput);
			format = format.replace('#words', numWords);
			//When maxCharacters <= 0, #max, #left cannot be substituted.
			if(maxCharacters > 0){
				format = format.replace('#max', maxCharacters);
				format = format.replace('#left', numLeft);
			}
			return format;
		}
		
		function getInfo(){
			var info = {
				input: numInput,
				max: maxCharacters,
				left: numLeft,
				words: numWords
			};
			return info;
		}
		function getNextCharLeftInformation(container){
			//return container.next('.charleft');
			return $('.charleft');
				
		}
		function isWin(){
			var strOS = navigator.appVersion;
			if (strOS.toLowerCase().indexOf('win') != -1){
				return true;
			}
			return false;
		}
		
		
		function SpecialCharCounter(p_sText){
			var sSpecialChar = "\\{}[]|€^~";
			var lCharLength = 0;
			var sChar = "";
			for(var i=0; i < p_sText.length; i++){
				sChar = p_sText.charAt(i); //equivalent InStr() in Visual Basic
				if(sChar == '\n'){
					lCharLength++;
				}else if (sSpecialChar.indexOf(sChar) !=  "-1") {
					lCharLength++;
				}
			}
			return lCharLength;
		}
		
		function getNewlineCount(content){
			var newlineCount = 0;
			for(var i=0; i<content.length;i++){
				if(content.charAt(i) == '\n'){
					newlineCount++;
				}
			}
			return newlineCount;
		}
		
		function getCleanedWordString(content){
			var fullStr = content + " ";
			var initial_whitespace_rExp = /^[^A-Za-z0-9]+/gi;
			var left_trimmedStr = fullStr.replace(initial_whitespace_rExp, "");
			var non_alphanumerics_rExp = rExp = /[^A-Za-z0-9]+/gi;
			var cleanedStr = left_trimmedStr.replace(non_alphanumerics_rExp, " ");
			var splitString = cleanedStr.split(" ");
			return splitString;
		}
		
		function countWord(cleanedWordString){
			var word_count = cleanedWordString.length-1;
			return word_count;
		}
	};  
})(jQuery); 
