var urlbase = '/logictree/';

/**
* Make an object appear with an animation
*/
function appearThis(obj)
{
	new Effect.Appear(obj, {duration: 0.2});
}

/**
* Make an object disappear with an animation
*/
function fadeThis(obj)
{
	new Effect.Fade(obj, {duration: 0.5});
}

/**
* Redirect to the server's response page to adding a sentence (for debugging purposes only)
*/
function viewValidationResponse(system, sentence)
{
	var url = urlbase + 'validatesentence?system=' + escape(system) + '&sentence=' + escape(sentence);
	window.location = url;
}

/**
* Add a sentence to the set and update the interface accordingly
*/
function addSentence(system, sentence, set, addbutton, generatebutton)
{
	if(sentence.value != '')
	{
		addbutton.disabled = true;
		sentence.disabled = true;
		try
		{
			var url = urlbase + 'validatesentence?system=' + escape(system) + '&sentence=' + escape(sentence.value);
			
			new Ajax.Request(url,
							 {
								 method: 'get',
							 onSuccess: function(transport)
							 {
								 var response = transport.responseText.split("\n");
								 if(response.length > 1 && response[0] == 'ok')
								 {
									 Sortable.destroy(set.id);
									 var i = 0;
									 while($('Sentence' + i))
										 i++;
									 
									 set.insert('<li id="Sentence' + i + '"><span class="sentence">' + response[1] + '</span>&nbsp;&nbsp;<img id="remove' + i + '" src="' + urlbase + 'tts/images/remove.png" onclick="removeSentence($(\'' + set.id + '\'), \'' + i + '\', $(\'' + generatebutton.id + '\'));"/></li>');
									 sentence.value = '';
									 Sortable.create(set.id, { format: /(.*)/, onUpdate: function() { generatebutton.show(); } });
									 generatebutton.show();
								 }
								 else
								 {
									 sentence.className = 'rejected';
									 
								 }
							 },
							 onComplete: function(transport)
							 {
								 // Reenable the add button and the text field
								 addbutton.disabled = false;
								 sentence.disabled = false;
							 },
							 onFailure: function(transport)
							 {
								 var response = transport.responseText || "no response text";
								 alert("Ajax request failed.\n\n" + response);
							 }
							 });
		}
		catch(e)
		{
			// Reenable the add button and the text field
			addbutton.disabled = false;
			sentence.disabled = false;
			alert('Server unavailable.');
		}
	}
}

/**
* Add a sentence if the user pressed enter
*/
function addIfEnter(system, chr, sentence, set, addbutton, generatebutton)
{
	if(chr == 13)
	{
		addSentence(system, sentence, set, addbutton, generatebutton);
		
		if(navigator.userAgent.indexOf('Firefox') != -1)
		{
			// The next two lines are a fix for Firefox to prevent the caret to disapear
			sentence.blur();
			setTimeout("$('" + sentence.id + "').focus();", 0);
		}
	}
}

/**
* Remove the sentence with the given index
*/
function removeSentence(set, index, generatebutton)
{
	$('Sentence' + index).className = 'removing';
	
	updateGenerateButton(set, generatebutton);
	
	Effect.SwitchOff('Sentence' + index, {
		afterFinish: function()
		{
			setTimeout("$('Sentence" + index + "').remove();", 1000);
		}
	});
}

/**
* Remove all sentences of the set and the generated tree if any
*/
function resetSet(system, set, generatebutton)
{
	var sentences = set.descendants();
	var removed = new Array();
	
	// Mark all sentences to be deleted
	sentences.each(
	function(sentence)
	{
		if(sentence.nodeName == 'LI' && sentence.className != 'removing')
		{
			sentence.className = 'removing';
			removed[removed.length] = sentence;
		}
	});
	
	// Hide the Generate button
	updateGenerateButton(set, generatebutton);
	
	// Animate the removal of all sentences
	removed.each(
	function(sentence)
	{
		Effect.Fade(sentence.id, {
			afterFinish: function()
			{
				setTimeout("$('" + sentence.id + "').remove();", 1000);
			}
		});
	});
	
	// Remove the generated tree if any
	var treecontainerid = system + 'container';
	var loadingimgid = system + 'loadingimage';
	var treeimgid = system + 'treeimage';
	
	if(isImageOk($(treeimgid)))
	{
		$(loadingimgid).hide();
		Effect.BlindUp(treecontainerid);
		Effect.Fade(treecontainerid);
	}
}

/**
* Determine whether the "Generate the tree!" button should show or hide and update the status respectively
* @return string
*/
function updateGenerateButton(set, generatebutton)
{
	if(!isSetEmpty(set))
		generatebutton.show();
	else
		generatebutton.hide();
}

/**
* Returns whether the user's set is empty of not
* @return boolean
*/
function isSetEmpty(set)
{
	var sentences = set.childElements();
	var numSentences = 0;
	
	sentences.each(function(sentence)
	{
		if(sentence.nodeName == 'LI' && sentence.className != 'removing')
			numSentences++;
	});
	
	return numSentences == 0;
}

/**
* Converts the user's set into a string of the format "{A,B,...}" without the quotes
* @return string
*/
function formatSet(set)
{
	var setstr = '{';
	var sentences = set.descendants();
	
	first = true;
	
	sentences.each(function(sentence)
	{
		if(sentence.nodeName == 'LI' && sentence.className != 'removing')
		{
			var removing = sentence.descendants();
			
			removing.each(
			function(toberemoved)
			{
				if(toberemoved.nodeName == 'SPAN')
				{
					if(!first)
						setstr += ',';
					else
						first = false;
					setstr += toberemoved.innerHTML;
				}
			});
		}
	});
	
	setstr += '}';
	
	return setstr;
}

/**
* Add the link to the dynamic image that will trigger the generation of the tree
*/
function generateTree(system, generatebutton, set, dest, timeout)
{
	var setstr = formatSet(set);
	
	if(setstr != '' && setstr != '{}')
	{
		var treecontainerid = system + 'container';
		var loadingimgid = system + 'loadingimage';
		var treeimgid = system + 'treeimage';
		
		dest.innerHTML = '<p><img id="' + loadingimgid + '" src="/images/logictree/loading.gif"/></p>';
		generatebutton.hide();
		
		dest.insert('<div id="' + treecontainerid + '"><p><img id="' + treeimgid + '" src="/logictree/image?system=' + escape(system) + '&set=' + escape(setstr) + '"/></p></div>');
		$(treecontainerid).hide();
		isTreeLoaded(treeimgid, loadingimgid, treecontainerid, timeout);
	}
}

/**
* Test if a tree is loaded
* @return boolean
*/
function isTreeLoaded(treeimgid, loadingimgid, treecontainerid, timeout)
{
	isTreeLoadedRec(treeimgid, loadingimgid, treecontainerid, 0, timeout);
}

function isTreeLoadedRec(treeimgid, loadingimgid, treecontainerid, index, timeout)
{
	if(index > timeout)
	{
		$(loadingimgid).hide();
		$(treecontainerid).innerHTML = '<p class="error">The application timed out.</p>';
		$(treecontainerid).show();
	}
	else if(isImageOk($(treeimgid)))
	{
		$(loadingimgid).hide();
		Effect.BlindDown(treecontainerid);
		Effect.Appear(treecontainerid);
	}
	else
	{
		index++;
		setTimeout('isTreeLoadedRec("' + treeimgid + '", "' + loadingimgid + '", "' + treecontainerid + '", ' + index + ', ' + timeout + ')', 1000);
	}
}

/**
* Test if an image is fully loaded
* @return boolean
*/
function isImageOk(img) {
	// During the onload event, IE correctly identifies any images
	// that weren't downloaded as not complete. Others should too.
	// Gecko-based browsers act like NS4 in that they report this
	// incorrectly: they always return true.
	if (img == null || !img.complete)
		return false;
	
	// However, they do have two very useful properties: naturalWidth
	// and naturalHeight. These give the true size of the image. If
	// it failed to load, either of these should be zero.
	if (typeof img.naturalWidth != "undefined" && img.naturalWidth == 0)
		return false;
	
	// No other way of checking: assume it's ok.
	return true;
}

/**
* Add a character to a text input where its caret is given that the text input is enabled
*/
function addchar(inputtext, chr)
{
	if(!inputtext.disabled)
	{
		insertAtCaret(inputtext, chr);
		inputtext.className = 'accepted';
	}
}

/**
* Add a character to a text input where its caret is
*/
function insertAtCaret(obj, text) {
	if(document.selection) {
		obj.focus();
		var orig = obj.value.replace(/\r\n/g, "\n");
		var range = document.selection.createRange();
		
		if(range.parentElement() != obj) {
			return false;
		}
		
		range.text = text;
		
		var actual = tmp = obj.value.replace(/\r\n/g, "\n");
		
		for(var diff = 0; diff < orig.length; diff++) {
			if(orig.charAt(diff) != actual.charAt(diff)) break;
		}
		
		for(var index = 0, start = 0; 
		tmp.match(text) 
		&& (tmp = tmp.replace(text, "")) 
		&& index <= diff; 
		index = start + text.length
		) {
			start = actual.indexOf(text, index);
		}
	} else if(obj.selectionStart >= 0) {
		var start = obj.selectionStart;
		var end   = obj.selectionEnd;
		
		obj.value = obj.value.substr(0, start) 
		+ text 
		+ obj.value.substr(end, obj.value.length);
	}
	
	if(start != null) {
		setCaretTo(obj, start + text.length);
	} else {
		obj.value += text;
	}
}

/**
* Set the position of the caret in a text input
*/
function setCaretTo(obj, position)
{
	if(obj.createTextRange)
	{
		var range = obj.createTextRange();
		range.move('character', position);
		range.select();
	}
	else if(obj.selectionStart)
	{
		obj.focus();
		obj.setSelectionRange(position, position);
	}
}

