var Text = {};

Text.Formatter = Class.create({
	linkify: function(text, attribute) {
		var out = '';
		while (text.match(/((?:https?|ftp):\/\/\S+)|([\w\-\.]+\@[A-Za-z0-9\-\.]+\.[A-Za-z]{2,})|([a-z_]*[A-Z][a-z_]*[A-Z][A-Za-z_]*)/)) {
			var r = this.dupRE();
			out += r.leftContext;
			text = r.rightContext;
			if (out.match(/\\\\$/)) {
				out = RegExp.leftContext + r.lastMatch;
			} else if (r.$1) {
				out += this.buildLink(r.$1, r.$1, attribute);
			} else if (r.$2) {
				out += this.buildLink(r.$2, 'mailto:' + r.$2, attribute);
			} else {
				out += r.lastMatch;
			}
		}
		out += text;
		return out;
	},
	imageTag: function(text, attribute) {
		return text.replace(/\[\[([^\[\]]+)\]\]/g, this.buildImageTag('$1', attribute));
	},
	nl2br: function(text) {
		return text.escapeHTML().replace(/(\n|\r)+/g, '<br />');
	},
	dupRE: function() {
		var properties = [
			'$1', '$2', '$3', '$4', '$5', '$6', '$7', '$8', '$9',
			'lastMatch',
			'leftContext',
			'rightContext'
		];
		var o = {};
		for (var i = 0; i < properties.length; i++) {
			o[properties[i]] = RegExp[properties[i]];
		}
		return o;
	},
	buildLink: function(text, url, attribute) {
		return '<a href="' + url + '" ' + attribute + '>' + text + '</a>';
	},
	buildImageTag: function(url, attribute) {
		return '<img src="' + url + '" ' + attribute + ' />';
	}
});

/*
 * Usage: new Text.Counter($('myTextarea'), function(count){ console.log(count); });
 */
Text.Counter = Class.create({
	textBox: null,
	monitor: null,
	lastString: '',
	
	initialize: function(textBox, onChange) {
		this.textBox = textBox;
		this.onChange = onChange;
		this.lastString = this.textBox.getValue();
		this.monitor = new PeriodicalExecuter(function(){ this.doSomethingOnChange(); }.bind(this), 0.5);
	},
	doSomethingOnChange: function() {
		var string = this.textBox.getValue();
		if (this.lastString != string) {
			this.onChange(this.count(string));
			this.lastString = string;
		}
	},
	count: function(str) {
		var zenLength;// 全角の文字数(全角を1文字と数えるブラウザと2文字と数えるブラウザがある)
		var charType = 0;// 1文字前の文字種(0:半角英数字  1:半角カタカナ  2:全角)
		var bytes = 0;// バイト数
		var length = 0;// 文字数
		var codes = 0;// 制御コードで使用されるバイト数(TU-KA,J-PHONE)
		var unicode = ('｡'.charCodeAt(0) == 0xFF61);
		
		zenLength = 'あ'.length;

		for (var i = 0; i < str.length; i++, length++) {
			code = str.charCodeAt(i);
			if (code < 0) code += 0x0100;
			if (code <= 0x7E) {
				// 半角英数
				bytes++;
				if (charType == 1) codes++;// 半角カタカナ→半角英数
				else if (charType == 2) codes += 3;// 全角→半角英数
				charType = 0;
			} else if ((code >= 0xA1 && code <= 0xDF) || (unicode && code >= 0xFF61)) {
				// 半角カタカナ
				bytes++;
				if (charType == 0) codes++;// 半角英数→半角カタカナ
				else if (charType == 2) codes += 4;// 全角→半角カタカナ
				else if (i == 0) codes++;// 半角カタカナで始まる
				charType = 1;
			} else {
				// 全角
				bytes += 2;
				if (charType == 0) codes += 3;// 半角英数→全角
				else if (charType == 1) codes += 4;// 半角カタカナ→全角
				else if (i == 0) codes += 3;// 全角で始まる
				charType = 2;
				if (zenLength == 2) i++;
			}
		}
		
		if (charType == 1) codes++;// 半角カタカナで終わる
		else if (charType == 2) codes += 3;// 全角で終わる
		
		return length;
	}
});
