window.$Iwml = { };

$Iwml.PATH_TO_DOWNLOAD_SCRIPT = 'system/application/http-documents/download.php';
$Iwml.LIST_CODE = { '-': 'u', '+': 'o' },
$Iwml.LT_RE  = (/</g);
$Iwml.AMP_RE = (/&/g);
$Iwml.DIAERESIS = (/¨/g);

$Iwml.CLASS_NAMES_RS = '((\\.\\w+)+)?\\s*';
$Iwml.BLOCK_SEPARATOR_RS = '\\s*[\\r\\n]\\s*';
$Iwml.DIFFERED_RS = '\\x01([^\\x01]+)\\x01';

$Iwml.H_BLOCK_TYPE_RS = '#{1,6}';
$Iwml.L_BLOCK_TYPE_RS = '[+-]+';
$Iwml.R_BLOCK_TYPE_RS = '_+';
$Iwml.P_BLOCK_TYPE_RS = '';

$Iwml.H_BLOCK_HEAD_RE = new RegExp('^(' + $Iwml.H_BLOCK_TYPE_RS + ')' + $Iwml.CLASS_NAMES_RS);
$Iwml.L_BLOCK_HEAD_RE = new RegExp('^(' + $Iwml.L_BLOCK_TYPE_RS + ')' + $Iwml.CLASS_NAMES_RS);
$Iwml.R_BLOCK_HEAD_RE = new RegExp('^(' + $Iwml.R_BLOCK_TYPE_RS + ')' + $Iwml.CLASS_NAMES_RS);
$Iwml.P_BLOCK_HEAD_RE = new RegExp('^(' + $Iwml.P_BLOCK_TYPE_RS + ')' + $Iwml.CLASS_NAMES_RS);

$Iwml.PASS_THROUGH_RE = (/(^|[^\\]){%(}|((.|\n|\r)*?)[^\\]})/g);
$Iwml.CELLS_RE = (/\|(\d+\\*\d+)?!?(\\\||[^|])*/g);
$Iwml.CELL_RE = new RegExp('^\\|((\\d+)\\*(\\d+))?(!)?' + $Iwml.CLASS_NAMES_RS + '(.*)');
$Iwml.CHUNK_RE = new RegExp('(^|[^\\\\]){(\\w*)' + $Iwml.CLASS_NAMES_RS + '(}|((\\\\\\{|[^{])*?[^\\\\])})');
$Iwml.ESCAPED_CHUNK_RE = (/\\({|})/g);
$Iwml.ESCAPED_VERTICAL_BAR_RE = (/\\\|/g);
$Iwml.ESCAPED_BLOCK_TYPE_RE = (/^\\+[-+#_|:;&/]/);
$Iwml.ESCAPED_BLOCK_SEPARATOR_RE = new RegExp('\\\\' + $Iwml.BLOCK_SEPARATOR_RS, 'g');
$Iwml.BLOCK_SEPARATOR_RE = new RegExp($Iwml.BLOCK_SEPARATOR_RS);
$Iwml.JOINED_BLOCKS_RE = new RegExp($Iwml.BLOCK_SEPARATOR_RS + ';', 'g');
$Iwml.DIFFERED_RE = new RegExp($Iwml.DIFFERED_RS, 'g');
$Iwml.DIFFEREDS_ALONE_RE = new RegExp('^(' + $Iwml.DIFFERED_RS + '\\s*)+$');
$Iwml.DEFINITION_RE = (/\x02([^\x02]+)\x02/g);
$Iwml.BR_RE = (/\x03/g);


$Iwml.GetHTML = function(IWML, PUBLIC) {
//----=======-------------------------

	var
		DIFFERED = [ ],
		DEFINITIONS = { },
		PREV_BLOCK_TYPE,
		BLOCKS,
		I,
		J,
		TYPE,
		CELLS,
		BLOCK,
		MATCHES,
		LEVEL,
		RULES,
		TAG_NAME,
		SUPER_CLASSES,
		SUPER_IDX;
	function GET_CLASS_ATTRIBUTE(CLASS_NAMES) {
	//-------===================-------------
	
	/*
		CLASS_NAMES est vide (ou null) ou de la forme:
		
			[.:]\w+(\.\w+)*
	*/
		return (CLASS_NAMES ? ' class="' + $TextTrim(CLASS_NAMES.replace(/\W+/g, ' _')) + '"' : '');
	}

	
	function PROCESS_BLOCK_TRANSITION(I, BLOCK_TYPE) {
	//-------========================----------------

		var
			CLASS_NAMES,
			J;
		BLOCKS[I] = '';
		if (BLOCK_TYPE != PREV_BLOCK_TYPE) {
			if (PREV_BLOCK_TYPE)
				switch (PREV_BLOCK_TYPE.charAt(0)) {
					case '-':
					case '+':
						for (
							J = 0;
							J < Math.max(0, PREV_BLOCK_TYPE.length - (BLOCK_TYPE && BLOCK_TYPE.charAt(0) == PREV_BLOCK_TYPE.charAt(0) ? BLOCK_TYPE.length : 0));
							J++
						)
							BLOCKS[I - 1] += '<' + '/' + $Iwml.LIST_CODE[PREV_BLOCK_TYPE.charAt(0)] + 'l>';
						break;
					case 't':
						BLOCKS[I - 1] += '<' + '/table>';
						break;
				}
			if (BLOCK_TYPE) {
				CLASS_NAMES = (I == SUPER_IDX ? GET_CLASS_ATTRIBUTE(SUPER_CLASSES) : '');
				switch (BLOCK_TYPE.charAt(0)) {
					case '-':
					case '+':
						if (! PREV_BLOCK_TYPE || PREV_BLOCK_TYPE.charAt(0) != BLOCK_TYPE.charAt(0) || PREV_BLOCK_TYPE.length < BLOCK_TYPE.length)
							BLOCKS[I] = '<' + $Iwml.LIST_CODE[BLOCK_TYPE.charAt(0)] + 'l' + CLASS_NAMES + '>';
						break;
					case 't':
						BLOCKS[I] = '<table' + CLASS_NAMES + '>';
						break;
				}
			}
			PREV_BLOCK_TYPE = BLOCK_TYPE;
		}
	}
	
	
	function PROCESS_CHUNK(UNUSED1, LEADING, TYPE, CLASS_NAMES, UNUSED2, UNUSED3, CHUNK_CONTENTS) {
	//-------=============-----------------------------------------------------------------------
	
		var
			T = (TYPE.length == 0 ? '' : (TYPE = TYPE.toLowerCase()).charAt(0)),
			MATCHES = CHUNK_CONTENTS.match(/(\S+)(\s+(.*\S))?/),
			MIX,
			PLUGIN,
			F;
			
		if (T == 'x') {
			if (MATCHES) {
				try {
					PLUGIN = eval(MATCHES[1])(MATCHES[3]);
				}
				catch (e) {
					return LEADING + '\\{ Plugin "' + MATCHES[1] + '" FAILED: ' + e.message + ' \\}';
				}
				
				return LEADING + PLUGIN;
			}
		}
		else if (T && 'lgy'.search(T) >= 0)
			if (MATCHES && MATCHES[3]) {
				if (T == 'y') {
					DEFINITIONS[MATCHES[3]] = MATCHES[1];
					return LEADING;
				}
			}
			else
				TYPE = '';
		else if (T && 'dm'.search(T) >= 0)
			if (MATCHES)
				MATCHES[3] = MATCHES[3] || MATCHES[1];
			else
				TYPE = '';
		switch (TYPE) {
			case 'l':
			case 'lw':
				return LEADING + '<a href="\x02' + MATCHES[1] + '\x02"' + (TYPE.toLowerCase() == 'lw' ? ' target="EXT"' : '') + GET_CLASS_ATTRIBUTE(CLASS_NAMES) + '>' + MATCHES[3] + '<' + '/a>';
			case 'd':
				return LEADING +
					'<a' +
						' href="' + $Iwml.PATH_TO_DOWNLOAD_SCRIPT +
						'?ID=' + MATCHES[1] + '&' +
						'PATH_TO_SYSTEM=' + $PathToSystem + '&' +
						'PATH_TO_SPACE=' + $PathToSpace + '&' +
						'PATH_TO_CWD=' + $PathToCWD + '"' +
						GET_CLASS_ATTRIBUTE(CLASS_NAMES) +
					'>' + MATCHES[3] + '<' + '/a>';
			case 'g':
				return LEADING + '<img' + GET_CLASS_ATTRIBUTE(CLASS_NAMES) + ' src="\x02' + MATCHES[1] + '\x02" alt="' + MATCHES[3].replace(/"/g, '&quot;') + '">';
			case 'm':
				return LEADING + EMAIL(MATCHES[1] + ' ' + MATCHES[3], TYPE);
			case 'm_':
				return LEADING + EMAIL(CHUNK_CONTENTS, TYPE);
			default:
				switch (TYPE) {
					case 'st': TYPE = 'strong'; break;
					case 'ci': TYPE = 'cite'; break;
					case 'co': TYPE = 'code'; break;
				}
				TYPE = TYPE || 'span';
				return LEADING + '<' + TYPE + GET_CLASS_ATTRIBUTE(CLASS_NAMES) + '>' + CHUNK_CONTENTS + '<' + '/' + TYPE + '>';
		}
	}


	function EMAIL(ARG, CODE) {
	//-------=====-----------
	
		function UNOBFUSCATE(I) {var l=''; while (I.length-l.length) l+=String.fromCharCode(I.charCodeAt(l.length)^1); return l; }
		
		var
			MATCHES = (CODE.toLowerCase() == 'm' ? ARG : UNOBFUSCATE(ARG.replace(/\\({|})/g, '$1'))).match(/(\S+)(\s+(.*\S))?/),
			ADDR = MATCHES[1],
			LABEL = MATCHES[3] || ADDR;

		return '<a href="mailto:' + $TextPlain2html(ADDR) + '">' + $TextPlain2html(LABEL ? LABEL : ADDR) + '</a>';
	}

	
	function PROCESS_BLOCK(BLOCK) {
	//-------=============-------

		BLOCK = BLOCK.
			replace($Iwml.AMP_RE, '&amp;').
			replace($Iwml.LT_RE, '&lt;').
			replace($Iwml.DIAERESIS, '&nbsp;');
	
		while (BLOCK.search($Iwml.CHUNK_RE) > -1)
			BLOCK = BLOCK.replace($Iwml.CHUNK_RE, PROCESS_CHUNK);
		return BLOCK;//.replace($Iwml.ESCAPED_CHUNK_RE, '$1');
	}

	
	function GET_TAG_WITH_ATTRIBUTES(TAG_NAME, MATCHES) {
	//-------=======================-------------------

		var
			OFFSET;
		if (TAG_NAME.charAt(0) == 't') {
			TAG_NAME += (MATCHES[1] ? (' colspan="' + MATCHES[2] + '" rowspan="' + MATCHES[3] + '"') : '');
			OFFSET = 3;
		}
		else
			OFFSET = 0;
		return '<' + TAG_NAME + GET_CLASS_ATTRIBUTE(MATCHES[2 + OFFSET]) + '>';
	}
	
	
	PREV_BLOCK_TYPE = null;
	SUPER_IDX = -1;
	BLOCKS = IWML.
		replace(
			$Iwml.PASS_THROUGH_RE,
			function(UNUSED, LEADING, REMAINDER) {
				DIFFERED.push($TextTrim(REMAINDER.substr(0, REMAINDER.length - 1)));
				return LEADING + '\x01' + (DIFFERED.length - 1) + '\x01';
			}
		).
		replace($Iwml.ESCAPED_BLOCK_SEPARATOR_RE, '').
		replace($Iwml.JOINED_BLOCKS_RE, '\x03').
		split($Iwml.BLOCK_SEPARATOR_RE);
		
	for (I = 0; I < BLOCKS.length; I++) {
		BLOCK = BLOCKS[I];
		if (I == 0)
			BLOCK = $TextTrim(BLOCK, 1);
		if (I == BLOCKS.length - 1)
			BLOCK = $TextTrim(BLOCK, 2);
		switch (BLOCK.charAt(0)) {
			case '/':
				PROCESS_BLOCK_TRANSITION(I);
				break;
			case ':':
				PROCESS_BLOCK_TRANSITION(I);
				if ((MATCHES = BLOCK.match(/^:\w+(\.\w+)*/))) {
					SUPER_CLASSES = MATCHES[0];
					SUPER_IDX = I + 1;
				}
				else
					BLOCKS[I] = '<!-- ' + $Lt('ERROR in classes scheme') + ' -->';
				break;
			case '_':
				MATCHES = BLOCK.match($Iwml.R_BLOCK_HEAD_RE);
				PROCESS_BLOCK_TRANSITION(I);
				BLOCKS[I] += GET_TAG_WITH_ATTRIBUTES('hr', MATCHES);
				break;
			case '#':
				MATCHES = BLOCK.match($Iwml.H_BLOCK_HEAD_RE);
				PROCESS_BLOCK_TRANSITION(I);
				BLOCKS[I] +=
					GET_TAG_WITH_ATTRIBUTES('h' + (LEVEL = MATCHES[1].length), MATCHES) +
						PROCESS_BLOCK(BLOCK.substr(MATCHES[0].length)) +
					'<' + '/h' + LEVEL + '>';
				break;
			case '-':
			case '+':
				MATCHES = BLOCK.match($Iwml.L_BLOCK_HEAD_RE);
				PROCESS_BLOCK_TRANSITION(I, MATCHES[1]);
				BLOCKS[I] +=
					GET_TAG_WITH_ATTRIBUTES('li', MATCHES) +
						PROCESS_BLOCK(BLOCK.substr(MATCHES[0].length)) +
					'<' + '/li>';
				break;
			case '|':
				PROCESS_BLOCK_TRANSITION(I, 't');
				BLOCKS[I] += '<tr>';
				CELLS = BLOCK.match($Iwml.CELLS_RE);
				for (J = 0; J < CELLS.length; J++) {
					MATCHES = CELLS[J].match($Iwml.CELL_RE);
					TAG_NAME = (MATCHES[4] ? 'th' : 'td');
					BLOCKS[I] +=
						GET_TAG_WITH_ATTRIBUTES(TAG_NAME, MATCHES) +
							PROCESS_BLOCK($TextTrim(MATCHES[7], 2).replace($Iwml.ESCAPED_VERTICAL_BAR_RE, '|')) +
						'<' + '/' + TAG_NAME + '>';
				}
				BLOCKS[I] += '<' + '/tr>';
				break;
			default:
				if (BLOCK.match($Iwml.ESCAPED_BLOCK_TYPE_RE))
					MATCHES = [ '.', null, '' ];
				else
					MATCHES = BLOCK.match($Iwml.P_BLOCK_HEAD_RE);

				PROCESS_BLOCK_TRANSITION(I, 'p');
				var AUX = PROCESS_BLOCK(BLOCK.substr(MATCHES[0].length));
				if (AUX.match(/\S/))
					BLOCKS[I] += (AUX.match($Iwml.DIFFEREDS_ALONE_RE) ?
						AUX :
						GET_TAG_WITH_ATTRIBUTES('p', MATCHES) +
							AUX +
							'<' + '/p>'
					);
		}
	}
	PROCESS_BLOCK_TRANSITION(I);

	return BLOCKS.join('').
		replace(
			$Iwml.DEFINITION_RE,
			function(UNUSED, KEY) {
				return (DEFINITIONS[KEY] == undefined ? KEY : DEFINITIONS[KEY]);
			}
		).
		replace(
			$Iwml.DIFFERED_RE,
			function(UNUSED, IDX) {
				return DIFFERED[IDX];
			}
		).
		replace($Iwml.ESCAPED_CHUNK_RE, '$1').
		replace($Iwml.BR_RE, '<br>');
};
