// Saurian Translator 6.2 Backend
// Copyright (C) 2006-2008 Mr. Krystal
// New In This Version:
//     * Fixed glitch with Saurian to English translation of Y characters
//     * Created new visual theme with animated button
//     * Added debug information mode
// Warning: This code was designed with only one goal in mind: make it as fast as possible. Though there are comments, the code is significantly more tricky, if not more complicated, than the previous version. If the way I chose to do something seems inconsistent or strange, it's because it made the code run faster.
// Challenge: I know that I could at least redouble the speed of this code in some other language. The challenge is for you to find a way to make this code faster while still using pure Javascript. GO!


//********************************************************
// Tranlation
//********************************************************

// English (and Saurian equivalent) of most printable ASCII values relative to ASCII order
var englishChars = "        \b\t\n \f\r                   !\"#$%&\'()*+,-./0123456789:;<=>?@IKLNOPQRUSTVMWEXZBCDAFGHYJ[\\]^_`iklnopqrustvmwexzbcdafghyj{|}~";
var saurianChars = "        \b\t\n \f\r                   !\"#$%&\'()*+,-./0123456789:;<=>?@URSTOVWXAZBCMDEFGHJKILNP0Q[\\]^_`urstovwxazbcmdefghjkilnp0q{|}~";

// Regular expressions for dealing with specific sets of non-sequential characters (ranges can be tested faster via mathematical comparison)
var whiteSpaces = new RegExp(/\s/);
var sentenceEnd = new RegExp(/\.|\?|!/);
var quotes = new RegExp(/"|'/);

// Proper Noun Detection is default on
var properNounDetection = true;

// Assume first direction is English to Saurian (true)
var languageDirection = true;


// Translates English to Saurian
function EnglishToSaurian()
{
	// Timer start
	var startTime = new Date();
	
	languageDirection = true;
	
	// Get English input
	var english = document.getElementById("englishTextBox").value;
	
	var saurian = "";
	
	if (properNounDetection)
	{
		// Prevent first input word from being detected as proper
		var endOfSentence = true;
		
		// For every character...
		for (var i = 0; i < english.length; i++)
		{
			// Grab the ASCII value
			var currentCharacterCode = english.charCodeAt(i);
			
			if (sentenceEnd.test(english.charAt(i - 1)))
			{
				endOfSentence = true;
			}
			// Capital letters are not counted toward sentence-starting characters because the endOfSentence condition must be true to correctly choose whether or not to translate it in the code
			else if (endOfSentence && !(currentCharacterCode < 91 && currentCharacterCode > 64) && !whiteSpaces.test(english.charAt(i)) && !quotes.test(english.charAt(i)))
			{
				endOfSentence = false;
			}
			
			// If the character is beyond translation range (Unicode support)
			if (currentCharacterCode > 126)
			{
				// Save character without translation
				saurian += english.charAt(i);
			}
			// If the character is a '~'
			else if (currentCharacterCode == 126 && !whiteSpaces.test(english.charAt(i + 1)))
			{
				// Save word without translation
				while (i < english.length && !whiteSpaces.test(english.charAt(i)))
				{
					saurian += english.charAt(++i);
				}
			}
			// If the character is a 'I'
			else if (currentCharacterCode == 73)
			{
				var nextLetter = english.charAt(i + 1);
				
				// If any of these conditions are true, the I should get translated
				if (whiteSpaces.test(nextLetter) || nextLetter == '\'' || endOfSentence || sentenceEnd.test(nextLetter) || i == english.length - 1)
				{
					saurian += 'A';
					endOfSentence = false;
				}
				else
				{
					// Save word without translation
					while (i < english.length && !whiteSpaces.test(english.charAt(i)))
					{
						saurian += english.charAt(i++);
					}
					i--;
				}
			}
			// If the character is a capital letter
			else if (currentCharacterCode < 91 && currentCharacterCode > 64)
			{
				if (endOfSentence)
				{
					// Save character with translation
					saurian += saurianChars.charAt(currentCharacterCode);
					
					endOfSentence = false;
				}
				else
				{
					// Save word without translation
					while (i < english.length && !whiteSpaces.test(english.charAt(i)))
					{
						saurian += english.charAt(i++);
					}
					i--;
				}
			}
			else
			{
				// Save character with translation
				saurian += saurianChars.charAt(currentCharacterCode);
			}
		}
	}
	// Proper noun detection off
	else
	{
		// For every character...
		for (var i = 0; i < english.length; i++)
		{
			// Grab the ASCII value
			var currentCharacterCode = english.charCodeAt(i);
			
			// If the character is beyond translation range (Unicode support)
			if (currentCharacterCode > 126)
			{
				// Save character without translation
				saurian += english.charAt(i);
			}
			// If the character is a '~'
			else if (currentCharacterCode == 126 && !whiteSpaces.test(english.charAt(i + 1)))
			{
				// Save word without translation
				while (i < english.length && !whiteSpaces.test(english.charAt(i)))
				{
					saurian += english.charAt(++i);
				}
			}
			else
			{
				// Save character with translation
				saurian += saurianChars.charAt(currentCharacterCode);
			}
		}
	}
	
	// Set Saurian translation
	document.getElementById("saurianTextBox").value = saurian;
	
	// Timer end and report
	var endTime = new Date();
	WriteDebugMessage(endTime-startTime, english.length);
}

// Translates Saurian to English
function SaurianToEnglish()
{
	// Timer start
	var startTime = new Date();
	
	languageDirection = false;
	
	// Get Saurian input
	var saurian = document.getElementById("saurianTextBox").value;
	
	var english = "";
	
	if (properNounDetection)
	{
		// Prevent first input word from being detected as proper
		var endOfSentence = true;
		
		// For every character...
		for (var i = 0; i < saurian.length; i++)
		{
			// Grab the ASCII value
			var currentCharacterCode = saurian.charCodeAt(i);
			
			if (sentenceEnd.test(saurian.charAt(i - 1)))
			{
				endOfSentence = true;
			}
			// Capital letters are not counted toward sentence-starting characters because the endOfSentence condition must be true to correctly choose whether or not to translate it in the code
			else if (endOfSentence && currentCharacterCode != 48 && !(currentCharacterCode < 91 && currentCharacterCode > 64) && !whiteSpaces.test(saurian.charAt(i)) && !quotes.test(saurian.charAt(i)))
			{
				endOfSentence = false;
			}
			
			// If the character is beyond translation range (Unicode support)
			if (currentCharacterCode > 126)
			{
				// Save character without translation
				english += saurian.charAt(i);
			}
			// If the character is a '~'
			else if (currentCharacterCode == 126 && !whiteSpaces.test(saurian.charAt(i + 1)))
			{
				// Save word without translation
				while (i < saurian.length && !whiteSpaces.test(saurian.charAt(i)))
				{
					english += saurian.charAt(++i);
				}
			}
			// If the character is a '0', Saurian for 'y' or 'Y'
			else if (currentCharacterCode == 48)
			{
				var prevLetter = saurian.charCodeAt(i - 1);
				var nextLetter = saurian.charCodeAt(i + 1);
				
				// If these conditions are satisfied, it's a number
				if ((prevLetter < 58 && prevLetter > 47) || (nextLetter < 58 && nextLetter > 47) || prevLetter == 46 || (whiteSpaces.test(saurian.charAt(i - 1)) && whiteSpaces.test(saurian.charAt(i + 1))))
				{
					english += '0';
				}
				else if (endOfSentence)
				{
					english += 'Y';
				}
				else
				{
					english += 'y';
				}
			}
			// If the character is a 'A', Saurian for 'I'
			else if (currentCharacterCode == 65)
			{
				var nextLetter = saurian.charAt(i + 1);
				
				// If any of these conditions are true, the A should get translated
				if (whiteSpaces.test(nextLetter) || nextLetter == '\'' || endOfSentence || sentenceEnd.test(nextLetter) || i == saurian.length - 1)
				{
					english += 'I';
					endOfSentence = false;
				}
				else
				{
					// Save word without translation
					while (i < saurian.length && !whiteSpaces.test(saurian.charAt(i)))
					{
						english += saurian.charAt(i++);
					}
					i--;
				}
			}
			// If the character is a capital letter
			else if (currentCharacterCode < 91 && currentCharacterCode > 64)
			{
				if (endOfSentence)
				{
					// Save character with translation
					english += englishChars.charAt(currentCharacterCode);
					
					endOfSentence = false;
				}
				else
				{
					// Save word without translation
					while (i < saurian.length && !whiteSpaces.test(saurian.charAt(i)))
					{
						english += saurian.charAt(i++);
					}
					i--;
				}
			}
			else
			{
				// Save character with translation
				english += englishChars.charAt(currentCharacterCode);
			}
		}
	}
	// Proper noun detection off
	else
	{
		// For every character...
		for (var i = 0; i < saurian.length; i++)
		{
			// Grab the ASCII value
			var currentCharacterCode = saurian.charCodeAt(i);
			
			// If the character is beyond translation range (Unicode support)
			if (currentCharacterCode > 126)
			{
				// Save character without translation
				english += saurian.charAt(i);
			}
			// If the character is a '~'
			else if (currentCharacterCode == 126 && !whiteSpaces.test(saurian.charAt(i + 1)))
			{
				// Save word without translation
				while (i < saurian.length && !whiteSpaces.test(saurian.charAt(i)))
				{
					english += saurian.charAt(++i);
				}
			}
			// If the character is a '0', Saurian for 'y' or 'Y'
			else if (currentCharacterCode == 48)
			{
				var prevLetter = saurian.charCodeAt(i - 1);
				var nextLetter = saurian.charCodeAt(i + 1);
				
				// If these conditions are satisfied, it's a number
				if ((prevLetter < 58 && prevLetter > 47) || (nextLetter < 58 && nextLetter > 47) || prevLetter == 46 || (whiteSpaces.test(saurian.charAt(i - 1)) && whiteSpaces.test(saurian.charAt(i + 1))))
				{
					english += '0';
				}
				else
				{
					english += 'y';
				}
			}
			else
			{
				// Save character with translation
				english += englishChars.charAt(currentCharacterCode);
			}
		}
	}
	
	// Set English translation
	document.getElementById("englishTextBox").value = english;
	
	// Timer end and report
	var endTime = new Date();
	WriteDebugMessage(endTime-startTime, saurian.length);
}


//********************************************************
// Debug
//********************************************************

var debug = false;

// Tested to prevent multiple simultaneous animations
var db_toggleInProgress = false;

// Starts toggle and animation
function db_ToggleButton()
{
	if (db_toggleInProgress)
	{
		return;
	}
	
	db_toggleInProgress = true;
	
	db_AnimateButton();
}

// Used to stop animations
var db_interval = null;

// Animates the button left or right
function db_AnimateButton()
{
	if (debug)
	{
		db_interval = setInterval("db_OnToOff()", 10);
	}
	else
	{
		db_interval = setInterval("db_OffToOn()", 10);
	}
}

// The current frame of button toggle button
var db_frameNumber = 9;

// Animates on to off
function db_OnToOff()
{
	db_frameNumber++;
	
	db_SetToggleState(db_frameNumber * -25);
	
	if (db_frameNumber == 9)
	{
		clearInterval(db_interval);
		HideDebugInfo();
		db_toggleInProgress = false;
		debug = false;
	}
}

// Animates off to on
function db_OffToOn()
{
	db_frameNumber--;
	
	db_SetToggleState(db_frameNumber * -25);
	
	if (db_frameNumber == 0)
	{
		clearInterval(db_interval);
		ShowDebugInfo();
		db_toggleInProgress = false;
		debug = true;
	}
}

function ShowDebugInfo()
{
	document.getElementById("debugArea").style.display = "block";
}

function HideDebugInfo()
{
	document.getElementById("debugArea").style.display = "none";
}

// Writes the debug information
function WriteDebugMessage(timeInMilliseconds, length)
{
	document.getElementById("debugInfo").innerHTML = languageDirection ? "Translation Direction: English to Saurian<br />" : "Translation Direction: Saurian to English<br />";
	document.getElementById("debugInfo").innerHTML += properNounDetection ? "Proper Noun Detection: ON<br />" : "Proper Noun Detection: OFF<br />";
	document.getElementById("debugInfo").innerHTML += "String Length: " + length + "<br />";
	document.getElementById("debugInfo").innerHTML += "Time Required: ";
	document.getElementById("debugInfo").innerHTML += (timeInMilliseconds == 0) ? "Unmeasurable<br />" : timeInMilliseconds / 1000.0 + " seconds";
}

// Recreates the toggle image at the appropriate frame
function db_SetToggleState(position)
{
	document.getElementById("debugToggle").innerHTML = "<img src=\"images/transparent.gif\" alt=\"Click to toggle Debug Information\" onmouseup=\"db_ToggleButton()\" style=\"background:url(images/onOff.gif) 0 " + position + "px\" />";
}


//********************************************************
// Toggle Proper Noun Detection
//********************************************************

// Tested to prevent multiple simultaneous animations
var pn_toggleInProgress = false;

// Starts toggle and animation
function pn_ToggleButton()
{
	if (pn_toggleInProgress)
	{
		return;
	}
	
	pn_toggleInProgress = true;
	
	pn_AnimateButton();
}

// Used to stop animations
var pn_interval = null;

// Animates the button left or right
function pn_AnimateButton()
{
	properNounDetection ? pn_interval = setInterval("pn_OnToOff()", 10) : pn_interval = setInterval("pn_OffToOn()", 10);
}

// The current frame of button toggle button
var pn_frameNumber = 0;

// Animates on to off
function pn_OnToOff()
{
	pn_frameNumber++;
	
	pn_SetToggleState(pn_frameNumber * -25);
	
	if (pn_frameNumber == 9)
	{
		clearInterval(pn_interval);
		ProperNounToggle();
		pn_toggleInProgress = false;
	}
}

// Animates off to on
function pn_OffToOn()
{
	pn_frameNumber--;
	
	pn_SetToggleState(pn_frameNumber * -25);
	
	if (pn_frameNumber == 0)
	{
		clearInterval(pn_interval);
		ProperNounToggle();
		pn_toggleInProgress = false;
	}
}

// Actually toggles proper noun detection on and off and redoes translation
function ProperNounToggle()
{
	// Toggle proper noun detection
	properNounDetection = !properNounDetection;
	
	// Depending on the language direction, retranslate
	languageDirection ? EnglishToSaurian() : SaurianToEnglish();
}

// Recreates the toggle image at the appropriate frame
function pn_SetToggleState(position)
{
	document.getElementById("properNounToggle").innerHTML = "<img src=\"images/transparent.gif\" alt=\"Click to toggle Proper Noun Detection\" onmouseup=\"pn_ToggleButton()\" style=\"background:url(images/onOff.gif) 0 " + position + "px\" />";
}


//********************************************************
// Checking for Javascript
//********************************************************

// Remove the "Enable Javascript" message, if Javascript is indeed enabled
function JavascriptCheck()
{
	document.getElementById("javascriptMessage").style.display = "none";
}
