var UC_Actions = new Object ();
UC_Actions['LC'] = UC_ToLowerCase;
UC_Actions['UC'] = UC_ToUpperCase;
UC_Actions['REPL'] = UC_ReplaceText;
UC_Actions['SPACES'] = UC_RemoveSpaces;
UC_Actions['LINES'] = UC_RemoveLines;
UC_Actions['SORT'] = UC_Sort;
UC_Actions['HTML'] = UC_StripHTML;
UC_Actions['CSV'] = UC_ConvertCSV;

function	UC_Convert ()
{

	var src = document.forms[0].elements['SOURCE'];
	if	(src == null)	return;
	var text = src.value;
	var dest = document.forms[0].elements['DEST'];
	if	(dest == null)	return;
	var oper = document.forms[0].elements['OPER'];
	if	(oper == null)	return;

	// Get all oper2 flags
	var oper2_flags = new Object();
	var oper2 = document.forms[0].elements['OPER2'];
	var len, i, v;
	if	(oper2 != null)
	{
		len = oper2.length;
		for (i = 0; i < len; i++)
		{
			if	(oper2[i].checked)
				oper2_flags[oper2[i].value] = 1;
		}
	}

	len = oper.length;
	var n_opers = 0;
	for (i = 0; i < len; i++)
	{
		if	(oper[i].checked)
		{
			v = oper[i].value;
			if	(!UC_Actions[v])
			{
				alert ("Unsupported operation '" + v + "'!");
				continue;
			}
			text = UC_Actions[v](text, oper2_flags);
			n_opers++;
		}
	}
	if	(n_opers == 0)
	{
		alert ('Nothing to do');
		return;
	}

	dest.value = text;

	//	Show the destonation textarea
	var obj = document.getElementById ('DEST_DIV');
	if	((obj != null)&&(obj.style.display != 'block'))
		obj.style.display = 'block';
	//	Update the size of source window
	src.rows = 10;
}

function	UC_ToLowerCase (p_text, p_flags)
{
	p_text = p_text.toLowerCase();
	if	(p_flags['LC_W'])
		p_text = p_text.replace (/\b\w+\b/g, UC__ToCamelCase);
	if	(p_flags['LC_S'])
		p_text = p_text.replace (/(?:^|[\.\!\?]\s+)\w/g, UC__SmartCapitalization);

	return p_text;
}

function	UC__ToCamelCase (p_text)
{
	return p_text.substr(0, 1).toUpperCase() + p_text.substr(1);
}

function	UC__SmartCapitalization (p_text)
{
	var len = p_text.length - 1;
	return p_text.substr(0, len) + p_text.substr(len, 1).toUpperCase();
}

function	UC_ToUpperCase (p_text, p_flags)
{
	return p_text.toUpperCase();
}

function	UC_ReplaceText(p_text, p_flags)
{
	var fvalue = document.forms[0].elements['REPL_FROM'];
	if	(fvalue == null)	return p_text;
	fvalue = fvalue.value;
	if	(fvalue == '')		return p_text;

	var tvalue = document.forms[0].elements['REPL_TO'];
	if	(tvalue == null)	return p_text;
	tvalue = tvalue.value;

	var re;
	var flags = (p_flags['REPL_CASE'])? 'g': 'gi';
	if	(p_flags['REPL_RE'])
	{
		try { re = new RegExp (fvalue, flags); }
		catch (err)
		{
			alert ("Cannot create regular expression from:\n" +
				fvalue + "\nError:\n" + err.message);
		}
	}
	else
	{
		fvalue = fvalue.replace(/([^\w\s])/g, "\\$1");
		re = new RegExp (fvalue, flags);
	}
	return p_text.replace (re, tvalue);
}

function	UC_RemoveSpaces (p_text, p_flags)
{
	var a = p_text.split(/\n/);

	var len = a.length;
	var i;
	//	Remove heading spaces
	if	(p_flags['SPACES_H'])
	{
		for (i = 0; i < len; i++)
			a[i] = a[i].replace(/^\s+/, '');
	}
	// Remove traling spaces
	if	(p_flags['SPACES_T'])
	{
		for (i = 0; i < len; i++)
			a[i] = a[i].replace(/\s+$/, '');
	}
	//	Compact multiple spaces into one
	if	(p_flags['SPACES_C'])
	{
		for (i = 0; i < len; i++)
			a[i] = a[i].replace(/\s\s+/g, ' ');
	}

	return a.join("\n");
}

function	UC_RemoveLines (p_text, p_flags)
{
	var a = p_text.split(/\n/);

	var len = a.length;
	var i;
	if	(p_flags['LINES_DUP'])
	{
		var uniq = new Object ();
		for (i = 0; i < len; i++)
		{
			if	(uniq[a[i]])
			{
				a.splice(i, 1);
				len--;
				i--;
			}
			else
				uniq[a[i]] = 1;
		}
	}

	if	(p_flags['LINES_L'])
	{
		for (i = 0; i < len; i++)
		{
			if	(a[i].match(/^\s*$/))
			{
				a.splice(i, 1);
				len--;
				i--;
			}
		}
	}

	return a.join("\n");
}

function	UC_Sort (p_text, p_flags)
{

	var a = p_text.split(/\n/).sort();
	if	(p_flags['SORT_R'])
		a = a.reverse();

	return a.join("\n");
}

function	UC_StripHTML (p_text, p_flags)
{
	if	(p_flags['HTML_T'])
	{
		p_text = p_text.replace(/\n/g, ' ');
//		p_text = p_text.replace(/^.*?(<table(?:\s+[^>]+)?>)/i, "$1");
//		p_text = p_text.replace(/<\/table>.*?$/i, '');
		p_text = p_text.replace(/<(script|style)(?:\s+[^>]+)?>.*?<\/\1\s*>/gi, '');
		p_text = p_text.replace(/<\!\-\-(.*?)\-\->/g, '');
		p_text = p_text.replace(/<\/?(?!br\s|br>|table\s|table>|t[dh]\s|t[dh]>|tr\s|tr>)\w+(?:\s+[^>]+)?>/gi, '');
		p_text = p_text.replace(/<table(?:\s+[^>]+)?>\s*<tr(?:\s+[^>]+)?>\s*<t[dh](?:\s+[^>]+)?>\s*(.*?)\s*(?:<\/t[dh]>\s*)?<\/tr>\s*<\/table>/gi, "$1");
		p_text = p_text.replace(/<tr(?:\s+[^>]+)?>\s*<t[dh](?:\s+[^>]+)?>/gi, '');
		p_text = p_text.replace(/\s*<table(?:\s+[^>]+)?>\s*/gi, "<br>");
		p_text = p_text.replace(/\s*<\/tr>\s*/gi, "<br>");
		p_text = p_text.replace(/\s*<t[dh](?:\s+[^>]+)?>\s*/gi, "~~~");
		p_text = p_text.replace(/<\/table>/gi, "\n");
		p_text = p_text.replace(/\s*<(?!br\s|br>)[^>]*>\s*/g, ' ');
		p_text = p_text.replace(/\s*<(?:br|br\s+\/)>\s*/gi, "\n");
		p_text = p_text.replace(/&nbsp;/g, ' ');
		p_text = p_text.replace(/&quot;/g, '"');
		p_text = p_text.replace(/&lt;/g, '<');
		p_text = p_text.replace(/&gt;/g, '>');
		p_text = p_text.replace(/&amp;/g, '&');
		p_text = p_text.replace(/&(reg|trade|copy);/g, '');
		var rows = p_text.split(/\s*\n\s*/);
		var result = new Array ();
		var rlen = rows.length;
		var i, j, s, columns, clen;
		for (i = 0; i < rlen; i++)
		{
			s = rows[i].replace(/\s+$/, '').replace(/^\s+/, '');
			if	(s == '')	continue;
			columns = s.split(/\s*~~~\s*/);
			clen = columns.length;
			for (j = 0; j < clen; j++)
			{
				s = columns[j];
				if	((s == '')||(s.match(/[,"]/)))
				{
					s = s.replace(/"/g, '""');
					columns[j] = '"' + s + '"';
				}
			}
			result.push(columns.join(', '));
		}
		p_text = result.join ("\n");
	}
	else
	{
		p_text = p_text.replace(/\n/g, '<br>');
		p_text = p_text.replace(/<(script|style)(?:\s+[^>]+)?>.*?<\/\1\s*>/gi, '');
		p_text = p_text.replace(/<(?:br|br\s+\/)>/gi, "\n");
		p_text = p_text.replace(/<[^>]*>/g, '');
		p_text = p_text.replace(/&nbsp;/g, ' ');
		p_text = p_text.replace(/&quot;/g, '"');
		p_text = p_text.replace(/&lt;/g, '<');
		p_text = p_text.replace(/&gt;/g, '>');
		p_text = p_text.replace(/&amp;/g, '&');
	}

	return p_text;
}

function	UC_ConvertCSV (p_text, p_flags)
{
	// Generate an array of array with CSV data
	var rows = p_text.split(/\s*\n\s*/);
	var rlen = rows.length;
	var csv_data = new Array ();
	var max_clen = 0;
	var i, j, s, v, columns, a, b, len, col, sep;
	s = UC_GetFieldValue ('CSV_FROM');
	if	(s == null)		return p_text;
	if	(s == 'CSV_FROMCSV')
	{
		var re = /(?:^\s*|,\s*)(?:"((?:[^"]*"")*[^"]*)"(?=\s*,|$)|([^,"]*?)(?=\s*,|$))/g;
		for (i = 0; i < rlen; i++)
		{
			columns = new Array ();
			s = ' ' + rows[i];
			if	(s == ' ')	continue;
			re.lastIndex = 0;
			while ((a = re.exec(s)) != null)
			{
				col = (a[2] == null)? '': a[2];
				if	((a[1] != null)&&(col == ''))
					col = a[1].replace(/""/g, '"')
				//	Code below doesn't work in IE
				//	col = (a[2] != null)? a[2]: a[1].replace(/""/g, '"');
//				if	(col.match(/[,"]/))
//					col = '"' + col.replace(/"/g, '""') + '"';
				columns.push(col);
			}
			csv_data.push(columns);
			len = columns.length;
			if	(len > max_clen)	max_clen = len;
		}
	}
	else
	{
		if	(s == 'CSV_FROMTAB')
			sep = "\t";
		else
		{
			sep = UC_GetFieldValue ('CSV_FROMCUSTOM');
			if	(sep == null)		return p_text;
//			sep = sep.replace(/([^\w\s])/g, "\\$1");
		}
		for (i = 0; i < rlen; i++)
		{
			columns = new Array ();
			s = rows[i];
			if	(s == '')	continue;
			a = s.split(sep);
			csv_data.push(a);
			len = a.length;
			if	(len > max_clen)	max_clen = len;
		}
	}
	rlen = csv_data.length;

	if	(p_flags['CSV_MISSING'])
	{
		for (i = 0; i < rlen; i++)
		{
			a = csv_data[i];
			for (j = a.length; j < max_clen; j++)
				a.push ('');
		}
	}

	if	(p_flags['CSV_MERGE'])
	{
		var numbers = UC_GetNumbers ('CSV_MERGE');
		if	(numbers == null)	return p_text;
		len = numbers.length;
		//	Merge column data together
		a = new Array ();
		var first = numbers[0];
		for (i = 0; i < max_clen; i++)
		{
			a.length = 0;
			for (j = 0; j < len; j++)
			{
				b = csv_data[numbers[j]];
				if	(b == null)	continue;
				s = b[i];
				if	(s == null)		continue;
				if	(s.match(/"/))
				{
					s = s.replace(/^"(.*)"$/, "$1");
					s = s.replace(/""/g, '"');
					
				}
				if	(s == '')		continue;
				a.push (s);
			}
			if	(a.length == 0)	continue;
			if	(csv_data[first] == null)
				csv_data[first] = new Array ();
			s = a.join(' ');
			if	(s.match(/[,"]/))
				s = '"' + s.replace(/"/g, '""') + '"';
			csv_data[first][i] = s;
		}

		//	Remove all merged lines except the first one
		for (i = len - 1; i > 0; i--)
		{
			j = numbers[i];
			if	(j >= rlen)	continue;
			csv_data.splice(j, 1);
			rlen--;
		}
	}

	if	(p_flags['CSV_ADDC'])
	{
		var numbers = UC_GetNumbers ('CSV_ADDC_NUM');
		if	(numbers == null)	return p_text;
		var num_len = numbers.length;

		s = UC_GetFieldValue ('CSV_ADDC_TEXT');
		if	(s == null)		return p_text;
		if	(s.match(/[,"]/))
			s = '"' + s.replace(/"/g, '""') + '"';
		for (i = 0; i < rlen; i++)
		{
			a = csv_data[i];
			len = a.length;
			var k;
			for (j = 0; j < num_len; j++)
			{
				k = numbers[j];
				while (k > len)
				{
					a.push('');
					len++;
				}
				if	(k >= len)
					a.push(s);
				else
				{
					a.splice(k, 0, s);
					len++;
				}
			}
		}
	}

	if	((p_flags['CSV_EXPAND'])&&(rlen > 1))
	{
		var numbers = UC_GetNumbers ('CSV_EXPAND');
		if	(numbers == null)	return p_text;
		var num_len = numbers.length;
		var exp_col = new Object ();
		for (i = 0; i < num_len; i++)
			exp_col[numbers[i]] = 1;

		var k, col_n, repl_flag;
		var row_0 = csv_data[0];
		var len_0 = row_0.length;
		for (i = 1; i < rlen; i++)
		{
			a = csv_data[i];
			len = a.length;
			repl_flag = 1;
			for (j = 0; j < num_len; j++)
			{
				col_n = numbers[j];
				if	(col_n >= len_0)		continue;
				b = new Array ();
				for (k = 0; k < len; k++)
				{
					if	(exp_col[k])	continue;
					b.push (a[k]);
				}
				b.push (row_0[col_n], a[col_n]);
				if	(!repl_flag)
				{
					rlen++;
					i++;
				}
				csv_data.splice(i, repl_flag, b);
				repl_flag = 0;
			}
		}
	}

	if	(p_flags['CSV_SPLIT'])
	{
		var col_1 = UC_GetFieldValue ('CSV_SPLIT_COL', 1);
		if	(col_1 == null)	return p_text;
		sep = UC_GetFieldValue ('CSV_SPLIT_SEP');

		var k, b_len, copy;
		for (i = 0; i < rlen; i++)
		{
			a = csv_data[i];
			len = a.length;
			if	(col_1 >= len)	continue;
			b = a[col_1].split(sep);
			b_len = b.length;
			if	(b_len < 2)		continue;
			a[col_1] = b[0];
			for (j = 1; j < b_len; j++)
				a.splice(col_1 + j, 0, b[j]);
		}
	}

	if	(p_flags['CSV_BREAK'])
	{
		var col_1 = UC_GetFieldValue ('CSV_BREAK_COL', 1);
		if	(col_1 == null)	return p_text;
		sep = UC_GetFieldValue ('CSV_BREAK_SEP');

		var b_len, copy;
		for (i = 0; i < rlen; i++)
		{
			a = csv_data[i];
			len = a.length;
			if	(col_1 >= len)	continue;
			b = a[col_1].split(sep);
			b_len = b.length;
			if	(b_len < 2)		continue;
			a[col_1] = b[0];
			for (j = 1; j < b_len; j++)
			{
				copy = a.slice();
				copy[col_1] = b[j];
				csv_data.splice(i + 1, 0, copy);
				i++;
				rlen++;
			}
		}
	}

	if	(p_flags['CSV_SWAP'])
	{
		var col_1 = UC_GetFieldValue ('CSV_SWAP1', 1);
		if	(col_1 == null)		return p_text;
		var col_2 = UC_GetFieldValue ('CSV_SWAP2', 1);
		if	(col_2 == null)		return p_text;
		if	(col_1 == col_2)
		{
			alert ("Please specify different column numbers");
			return p_text;
		}
		if	(col_1 > col_2)
		{
			i = col_2;
			col_2 = col_1;
			col_1 = i;
		}

		for (i = 0; i < rlen; i++)
		{
			a = csv_data[i];
			len = a.length;
			if	((col_1 >= len)&&(col_2 >= len))	continue;
			s = (col_1 < len)? a[col_1]: '';
			while (col_2 > len)
			{
				a.push ('');
				len++;
			}
			if	(col_2 == len)
			{
				v = '';
				a.push (s);
			}
			else
			{
				v = a[col_2];
				a[col_2] = s;
			}
			a[col_1] = v;
		}
	}

	if	(p_flags['CSV_MOVE'])
	{
		var col_s = UC_GetFieldValue ('CSV_MOVS', 1);
		if	(col_s == null)		return p_text;
		var col_d = UC_GetFieldValue ('CSV_MOVD', 1);
		if	(col_d == null)		return p_text;
		if	(col_s == col_d)
		{
			alert ("Please specify different column numbers");
			return p_text;
		}

		for (i = 0; i < rlen; i++)
		{
			a = csv_data[i];
			len = a.length;
			if	((col_s >= len)&&(col_d >= len))	continue;
			if	(col_s < len)
			{
				s = a[col_s];
				a.splice(col_s, 1);
				len--;
			}
			else
				s = '';
			
			while (col_d > len)
			{
				a.push ('');
				len++;
			}
			if	(col_d == len)
				a.push (s);
			else
				a.splice (col_d, 0, s);
		}
	}

	if	(p_flags['CSV_RM'])
	{
		var numbers = UC_GetNumbers ('CSV_RM');
		if	(numbers == null)	return p_text;
		var num_len = numbers.length;

		var k, offset;
		for (i = 0; i < rlen; i++)
		{
			a = csv_data[i];
			len = a.length;
			offset = 0;
			for (j = 0; j < num_len; j++)
			{
				k = numbers[j] - offset;
				if	(k >= len)	continue;
				a.splice(k, 1);
				offset++;
				len--;
			}
		}
	}

	var align = 0;
	s = UC_GetFieldValue ('CSV_TO');
	if	(s == null)		return p_text;
	var to_other = (s == 'CSV_TOTAB')? 1: ((s == 'CSV_TOCUSTOM')? 2: 0);
	var spaces, clen, col_len;
	if	((p_flags['CSV_LALIGN'])||(p_flags['CSV_RALIGN']))
	{
		var quotes;
		var max_len = 0;
		//	Determine maximum length for each column
		col_len = new Array ();
		for (i = 0; i < rlen; i++)
		{
			a = csv_data[i];
			clen = a.length;
			for (j = 0; j < clen; j++)
			{
				s = a[j];
				len = s.length;
				if	((!to_other)&&(s.match(/[,"]/)))
				{
					s = s.replace(/"/g, '""');
					len = 2 + s.length;
				}
				if	((col_len[j] == null)||(col_len[j] < len))
				{
					col_len[j] = len;
					if	(len > max_len)		max_len = len;
				}
			}
		}

		align = (p_flags['CSV_LALIGN'])? 2: 1;
		b = new Array ();
		while (max_len--)
			b.push (' ');
		spaces = b.join('');
	}

	var result = new Array ();
	if	(to_other)
	{
		if	(to_other == 2)
		{
			sep = UC_GetFieldValue ('CSV_TOCUSTOM');
			if	(sep == null)		return p_text;
		}
		else
			sep = "\t";

		if	(align)
		{
			align--;
			b = new Array ();
			for (i = 0; i < rlen; i++)
			{
				a = csv_data[i];
				clen = a.length;
				b.length = 0;
				for (j = 0; j < clen; j++)
				{
					s = a[j];
					len = col_len[j] - s.length;
					b.push ((len)? ((align)? s + spaces.substr(0, len):
						spaces.substr(0, len) + s): s);
				}
				result.push (b.join (sep));
			}
			return result.join("\n");
		}
		else
		{
			for (i = 0; i < rlen; i++)
				result.push (csv_data[i].join (sep));
		}
		return result.join("\n");
	}

	if	(align)
	{
		align--;
		for (i = 0; i < rlen; i++)
		{
			a = csv_data[i];
			clen = a.length;
			b.length = 0;
			for (j = 0; j < clen; j++)
			{
				s = a[j];
				if	(s.match(/[,"]/))
					s = '"' + a[j].replace(/"/g, '""') + '"';
				len = col_len[j] - s.length;
				b.push ((len > 0)? ((align)? s + spaces.substr(0, len):
					spaces.substr(0, len) + s): s);
			}
			result.push (b.join (', '));
		}
	}
	else
	{
		for (i = 0; i < rlen; i++)
		{
			a = csv_data[i];
			len = a.length;
			for (j = 0; j < len; j++)
			{
				if	(a[j].match(/[,"]/))
					a[j] = '"' + a[j].replace(/"/g, '""') + '"';
			}
			result.push (a.join (', '));
		}
	}

	return result.join("\n");
}

function	UC_GetNumbers (p_field)
{

	var s = document.forms[0].elements[p_field];
	if	(s == null)
	{
		alert ("Internal error: field with name '" + p_field + "' not found!");
		return null;
	}
	var field_value = s.value;
	s = field_value.replace(/,/g, ' ');
	var numbers = new Object ();
	var a = s.split (/ /);
	var len = a.length;
	var i, last;
	var range = 0;
	for (i = 0; i < len; i++)
	{
		s = a[i];
		if	(s == '')	continue;
		if	(s.match(/^\d+$/))
		{
			s = parseInt(s);
			if	(s == 0)
			{
				alert("'0' is not a valid column/row number.\nColumn/row numbering starts from 1");
				return null;
			}
			s--;
			if	(range)
			{
				while (s >= last)
					numbers[s--] = 1;
				range = 0;
			}
			else
				numbers[s] = 1;
			last = s;
		}
		else if (s == '-')
		{
			if	((last == null)||(range))
			{
				alert ("Invalid range in '" + field_value + "'");
				return null;
			}
			range = 1;
		}
		else
		{
			alert ("The list of numbers '" + field_value +
				"' should contain only numerical values!");
			return null;
		}
	}
	a.length = 0;
	for (s in numbers)
		a.push (s);

	return a.sort(UC_AscOrder);
}

function	UC_AscOrder (a, b)
{
	return a - b;
}

function	UC_GetFieldValue (p_field, p_num)
{

	var obj = document.forms[0].elements[p_field];
	if	(obj == null)
	{
		alert ("Internal error: field with name '" + p_field + "' not found!");
		return null;
	}
	var type = obj.type;
	if	(type == null)	type = obj[0].type;
	var s;
	if	(type == 'radio')
	{
		var i;
		var len = obj.length;
		for (i = 0; i < len; i++)
		{
			if	(obj[i].checked)
			{
				s = obj[i].value;
				break;
			}
		}
	}
	else
		s = obj.value;
	if	(p_num)
	{
		if	(!s.match(/^\d+$/))
		{
			alert ("Invalid value '" + s + "'. The value should be a number.");
			return null;
		}
		s = parseInt (s);
		if	(s == 0)
		{
			alert ("Invalid value '" + s + "'. The value should start from 1.");
			return null;
		}
		s--;
	}

	return s;
}

function	UC_Select(p_field)
{
	var obj = document.forms[0].elements[p_field];
	if	(obj == null)
	{
		alert ("Text area with name '" + p_field + "' not found!\n" +
			"Please select the code manually and press Ctrl-C to copy the code");
		return;
	}
	var text = obj.value;
	obj.select();
	if	(window.clipboardData)
	{
		window.clipboardData.setData("Text", text);
		alert ("The code was copied into the clipboard.\n");
	}
	else
	{
		alert("Your browser does not support copying data to the clipboard.\n" +
			"The code was selected for you. Click on the 'OK' button to close " +
			"this dialog box, and then press Ctrl-C to copy selected code.");
		obj.focus();
	}
}

function	UC_Clear(p_field)
{
	var obj = document.forms[0].elements[p_field];
	if	(obj == null)
	{
		alert ("Text area with name '" + p_field + "' not found!");
		return;
	}
	obj.value = '';
	obj.focus();
}

function	UC_Copy(p_from, p_to)
{
	var obj_from = document.forms[0].elements[p_from];
	if	(obj_from == null)
	{
		alert ("Text area with name '" + p_from + "' not found!");
		return;
	}
	var obj_to = document.forms[0].elements[p_to];
	if	(obj_to == null)
	{
		alert ("Text area with name '" + p_to + "' not found!");
		return;
	}
	obj_to.value = obj_from.value;
}

function showSubOption (p_obj)
{
	var obj;
	if	(p_obj.type == 'checkbox')
	{
		obj = document.getElementById ('DIV_' + p_obj.value);
		if	(obj == null)	return;
		obj.style.display = (p_obj.checked)? 'block': 'none';
	}
	//	radio
	else
	{
		var radio_obj = document.forms[0].elements[p_obj.name];
		var i;
		var len = radio_obj.length;
		for (i = 0; i < len; i++)
		{
			obj = document.getElementById ('DIV_' + radio_obj[i].value);
			if	(obj != null)
				obj.style.display = (radio_obj[i].checked)? 'block': 'none';
		}
	}
}

