
function FIGfont() {
	this.initialize.apply(this, arguments);
}

FIGfont.load = function(url) {
	var req = window.XMLHttpRequest ? new XMLHttpRequest() : (function() {
		try {
			return new ActiveXObject("Msxml2.XMLHTTP");
		} catch(e) {
			try {
				return new ActiveXObject("Microsoft.XMLHTTP");
			} catch(e) { return null; }
		}
	})();
	req.open('GET', url, false);
	req.send(null);
	if (req.status == 200) {
		return new FIGfont(req.responseText);
	} else {
		return null;
	}
};

FIGfont.prototype = {
	initialize: function(font) {
		var lines  = font.split(/\r?\n/);
		var header = lines.shift().split(/ /);
		var sig    = header.shift();
		if (sig.substr(0, 5) != "flf2a")
			throw "Error: Unknown font format";

		this.hardblank = sig.charAt(sig.length-1);
		this.height    = parseInt(header.shift(), 10);
		this.baseline  = parseInt(header.shift(), 10);
		this.maxLength = parseInt(header.shift(), 10);
		this.oldLayout = parseInt(header.shift(), 10);
		lines.splice(0,  parseInt(header.shift(), 10));
		this.printDerection = parseInt(header.shift(), 10);

		var characters = [];
		for (var i = 32; i < 127; i++) {
			var character = [];
			for (var j = 0; j < this.height; j++) {
				character[j] = lines.shift().replace(/(.)\1?$/, '');
			}
			characters[i] = character;
			if (lines.length < this.height) break;
		}
		this.characters = characters;
	},
	charAt: function(code) {
		return (this.characters[code] || '').join("\r\n").replace(new RegExp("\\" + this.hardblank, 'g'), ' ');
	}
};

function FIGlet() {
	this.initialize.apply(this, arguments);
}

FIGlet.prototype = {
	initialize: function(font) {
		this.font  = font;
		this.smush = false;
	},
	figify: function(str) {
		var hardblank = this.font.hardblank;
		var layout = this.font.oldLayout;
		var height = this.font.height;
		var result = new Array(height);
		var s = "([^" + this.font.hardblank + "\\x00\\s])";
		var pattern = new RegExp(s + "\\x00" + s);
		var symbol = '|/\\[]{}()<>';
		var bracket = {};
		var brackets = [['[', ']'], ['{', '}'], ['(', ')']];
		for (var n = 0; n < brackets.length; n++) {
			bracket[brackets[n][1]] = brackets[n][0];
			bracket[brackets[n][0]] = brackets[n][1];
		}
		var table = {};
		table['/\\'] = '|';
		table['\\/'] = 'Y';
		table['><']  = 'X';

		for (var i = 0, length = str.length; i < length; i++) {
			var character = this.font.characters[str.charCodeAt(i)];
			if (!character) continue;

			for (var j = 0; j < height; j++) {
				result[j] = (result[j] || '') + character[j] + ((layout > -1 && i + 1 < length) ? '\0' : '');
			}

			if (layout == -1 || i == 0) continue;

			var match, len, diff = -1;
			for (j = 0; j < height; j++) {
				if (match = result[j].match(/\s*\x00\s*/)) {
					len = match[0].length - 1;
					diff = (diff == -1 ? len : Math.min(diff, len));
				}
			}
			if (diff > 0) for (j = 0; j < height; j++) {
				var re = new RegExp("\\x00\\s{0," + diff + "}");
				if (match = result[j].match(re)) {
					len = match[0].length - 1;
					re = new RegExp("\\s{0," + (diff - len) + "}\\x00\\s{" + len + "}");
					result[j] = result[j].replace(re, '\0');
				}
			}

			var flag = false;
			if (this.smush) for (j = 0; j < height; j++) {
				result[j] = result[j].replace(pattern, function(s, a, b) {
					var ab = a + b;
					var left, right;
					if ((layout & 1) && a == b) {
						flag = true;
						return a;
					} else if ((layout & 2) && (a == '_' && symbol.indexOf(b) != -1 || b == '_' && symbol.indexOf(a) != -1)) {
						flag = true;
						return a;
					} else if ((layout & 4) && ((left = symbol.indexOf(a)) != -1 && (right = symbol.indexOf(b)) != -1)) {
						flag = true;
						return right > left ? b : a;
					} else if ((layout & 8) && (bracket[b] && bracket[b] == a)) {
						flag = true;
						return '|';
					} else if ((layout & 16) && table[ab]) {
						flag = true;
						return table[ab];
					} else if ((layout & 32) && (a == b && hardblank == a)) {
						flag = true;
						return hardblank;
					} else {
						return s;
					}
				});
			}

			for (j = 0; j < height; j++) {
				if (flag) {
					result[j] = result[j].replace(/\s\x00(?!$)|\x00\s/, '').replace(/\x00(?!$)/, '');
				} else {
					result[j] = result[j].replace(/\x00(?!$)/, '');
				}
			}
		}

		return result.join("\r\n").replace(new RegExp("\\" + hardblank, 'g'), ' ');
	}
};
