var ytTranslationCallbacks = {};

(function(){

var g_serviceUrlBase ='http://ajax.googleapis.com/ajax/services/language/';
var g_vlboxes = {};
var g_translateLinkCount = 0;
var g_showingCheckBox = false;
var g_showCheckBoxThreshold = 3;
var g_debug = true;
var g_logging = false;

// if the given text is too long GET call fails
var g_translateMaxLength = 512;

var entityRegex = /&[a-z]+;/g;
var brTagRegex = /<[bB][rR] ?\/?>/g;
var xmlTagRegex = /<[^>]*>/g;
var paragraphRegex = /..*?(\n|\u3002|\uff01|\uff1f|[\.\!\?](\s+|$))/g;
var wordRegex = /..*?(\s)/g;
var incompleteUrlEscapeRegex = /%[uA-Z0-9]{0,4}$/;

/**
 * @return a shortened string if its url-encoded-length is larger than the
 * given maxLength
 */
shortenStringInUrlEncodedLength = function(str, maxLength) {
	str = str.replace(brTagRegex, '\n');
	str = str.replace(xmlTagRegex, '');
	var escaped = escape(str);
	if (escaped.length < maxLength) {
		return str;
	}

	escaped = escaped.substring(0, maxLength);
	escaped = escaped.replace(incompleteUrlEscapeRegex, '');
	str = unescape(escaped);
	
	var newStringArray = str.match(paragraphRegex);
	if (newStringArray == null || newStringArray.length == 0) {
		newStringArray = str.match(wordRegex);
		if (newStringArray == null || newStringArray.length == 0) {
			return str;
		}
	}

	return newStringArray.join('') + '...';
}

jsonGetInternal = function(url, params) {
	var head = document.getElementsByTagName("head")[0];
	var script = document.createElement('script');
	script.type = 'text/javascript';
	script.charset = 'UTF-8'
	script.src = url + '?' + urlEncodeDict(params);
	head.appendChild(script);
}

jsonGetCall = function(url, params) {
	if (isIE()) {
		var make_ie_closure = function(object, method, opt) {
			return function() { method.apply(object, opt); };
		};
		var closure = make_ie_closure(this, jsonGetInternal, [url, params]);
		setTimeout(closure, 0);
	} else {
		jsonGetInternal(url, params);
	}
}

var g_cbid = 200;
createTranslationCallback = function(client_callback) {
	var id = 'id' + (g_cbid++);
	ytTranslationCallbacks[id] = function(context, jsonObject, statusCode) {
		var result = {};
		result.status = { 'code': statusCode };
		if (statusCode != 200) {
			result.error = result.status;
			result.language = '';
		} else {
			result.language = jsonObject.language;
			result.isReliable = jsonObject.isReliable;
			result.confidence = jsonObject.confidence;
			result.translation = jsonObject.translatedText;
		}
		client_callback(result);
		delete ytTranslationCallbacks[id];
	};
	return 'ytTranslationCallbacks.' + id;
}

translateIt = function(text, fromLang, toLang, callback) {
	// make sure the translating text is short enough
	text = shortenStringInUrlEncodedLength(text, g_translateMaxLength);
	if (g_debug)
		showDebugMessage("translating (" + fromLang + "->" + toLang + "): " + text);

	//google.language.translate(text, fromLang, toLang, callback);

	var callback_id = createTranslationCallback(callback);
	var param = new Array();
	param.push({name:'context', value:'yt'});
	param.push({name:'v', value:'1.0'});
	param.push({name:'q', value:text});
	param.push({name:'langpair', value:fromLang + '|' + toLang});
	param.push({name:'callback', value:callback_id});
	param.push({name:'key', value:'internal-youtube'});
	jsonGetCall(g_serviceUrlBase + 'translate', param);
}

detectLanguage = function(vid, text, callback) {
	text = shortenStringInUrlEncodedLength(text, g_translateMaxLength);

	// google.language.detect(text, callback);

	var callback_id = createTranslationCallback(callback);
	var param = new Array();
	param.push({name:'context', value:'yt'});
	param.push({name:'v', value:'1.0'});
	param.push({name:'q', value:text});
	param.push({name:'callback', value:callback_id});
	param.push({name:'key', value:'internal-youtube'});
	jsonGetCall(g_serviceUrlBase + 'detect', param);
}

/**
 * TranslationStatus - holds translation states
 */
TranslationStatus = function() {
	this.errorCount = 0;
	this.successCount = 0;
	this.translatingCount = 0;
}

TranslationStatus.prototype.resetTranslation = function() {
	this.errorCount = 0;
	this.successCount = 0;
	this.translatingCount = 0;
}

TranslationStatus.prototype.getTranslatedCount = function() {
	return this.errorCount + this.successCount;
}

TranslationStatus.prototype.isTranslating = function() {
	return this.translatingCount > 0;
}

TranslationStatus.prototype.startTranslation = function() {
	this.translatingCount += 1;
}

TranslationStatus.prototype.endTranslation = function(error) {
	if (error) {
		this.errorCount += 1;
	} else {
		this.successCount += 1;
	}
}

TranslationStatus.prototype.isFinished = function(error) {
	return this.getTranslatedCount() == this.translatingCount;
}

TranslationStatus.prototype.needDisable = function(error) {
	return this.errorCount == this.translatingCount;
}

/**
 * VlBox - holds bookkeeping info for vlbox elements
 */
VlBox = function(vid) {
	this.vid = vid;
	this.translationStatus = new TranslationStatus();
	this.savedHTML = {};
	this.strippedTexts = {};
	this.language = '';
	this.translatedElems = {};
	g_vlboxes[vid] = this;
}

VlBox.prototype.enableTranslation = function(primary_lang_differs) {
	this.translationStatus = new TranslationStatus();
	showDiv("translate_link_" + this.vid);
	if (primary_lang_differs) {
		g_translateLinkCount++;
		if (g_translateLinkCount > g_showCheckBoxThreshold) {
			showDiv("translate-checkbox-span");
			g_showingCheckBox = true;
		}
	}
	if (!g_showingCheckBox) {
		var chkbox = _gel("translate-checkbox");
		if (chkbox && chkbox.checked) {
			// Checkbox is on; we must show checkbox anyway!
			showDiv("translate-checkbox-span");
			g_showingCheckBox = true;
		}
	}
}

VlBox.prototype.disableTranslation = function() {
	hideDiv("translate_link_" + this.vid);
	hideDiv("untranslate_link_" + this.vid);
	g_vlboxes[this.vid] = null;
}

VlBox.prototype.getTranslationStatus = function() {
	return this.translationStatus;
}

VlBox.prototype.setLanguage = function(language) {
	this.language = language;
}

VlBox.prototype.endTranslation = function(error) {
	this.translationStatus.endTranslation(error);
	/* if (this.translationStatus.needDisable()) {
		showDiv("translate_disabled_" + this.vid);
		this.disableTranslation();
	} else */ if (this.translationStatus.isFinished()) {
		hideDiv("translate_link_" + this.vid);
		showDiv("untranslate_link_" + this.vid);
	}
}

VlBox.prototype.getElement = function() {
	return _gel("video-main-content-" + this.vid);
}

VlBox.prototype.translate = function(toLang) {
	if (this.translationStatus.isTranslating()) {
		return;
	}
	var boxElem = this.getElement();
	var elems = boxElem.getElementsByTagName('div');
	for (var i = 0; i < elems.length; ++i) {
		if (hasClass(elems[i], "video-description")) {
			this.translateVlDesc(elems[i], toLang);
		} else if (hasClass(elems[i], "video-title")) {
			this.translateVlTitle(elems[i], toLang);
		}
	}
}

VlBox.prototype.untranslate = function() {
	this.translationStatus.resetTranslation();
	var boxElem = this.getElement();
	var elems = boxElem.getElementsByTagName('div');
	var html;
	for (var i = 0; i < elems.length; ++i) {
		if (html = this.savedHTML[elems[i].className]) {
			elems[i].innerHTML = html;
		}
	}
	hideDiv("untranslate_link_" + this.vid);
	showDiv("translate_link_" + this.vid);
	hideDiv("translated_short_prefix_" + this.vid);
	hideDiv("translated_long_prefix_" + this.vid);
}

// get element to detect language
VlBox.prototype.getDetectLangElement = function() {
	var elem = _gel("RemainvidDesc" + this.vid);
	if (elem) {
		return elem;
	}
	elem = _gel("BeginvidDesc" + this.vid);
	if (elem) {
		return elem;
	}
	return _gel("video-main-content-" + this.vid);
}

// translate vltitle
VlBox.prototype.translateVlTitle = function(elem, toLang) {
	var vlbox = this;
	var shortTitle, longTitle;
	var elems = elem.getElementsByTagName('div');
	var handleTitleClass = function(elem) {
		if (! vlbox.savedHTML[elem.className]) {
			vlbox.savedHTML[elem.className] = elem.innerHTML;
		}
		var anchors = elem.getElementsByTagName('a');
		if (anchors.length > 0)
			return anchors[0];
		return elem;
	}
	for (var i = 0; i < elems.length; ++i) {
		if (elems[i].className == "video-short-title") {
			shortTitle = handleTitleClass(elems[i]);
		} else if (elems[i].className == "video-long-title") {
			longTitle = handleTitleClass(elems[i]);
		}
	}
	if (!longTitle) {
		return;
	}
	this.translationStatus.startTranslation();
	translateIt(longTitle.innerHTML, this.language, toLang, function(result) {
		if (!vlbox.getTranslationStatus().isTranslating()) {
			return;
		}
		if (!result.error) {
			longTitle.innerHTML = result.translation;
			longTitle.href += '&translated=1';
			if (shortTitle) {
				var length = shortTitle.innerHTML.length;
				shortTitle.innerHTML = result.translation.substring(0, length);
				shortTitle.href += '&translated=1';
			}
			showDiv("translated_short_prefix_" + vlbox.vid);
			showDiv("translated_long_prefix_" + vlbox.vid);
		}
		vlbox.endTranslation(result.error);
	});
}

// translate vldesc
VlBox.prototype.translateVlDesc = function(elem, toLang) {
	if (! this.savedHTML[elem.className]) {
		this.savedHTML[elem.className] = elem.innerHTML;
	}
	var text = '';
	var spans = elem.getElementsByTagName('span');
	var longDesc, shortDesc;
	var longToShortRatio = 1.0;
	if (spans.length == 0) {
		text = elem.innerHTML;
		shortDesc = elem;
	} else {
		for (var j = 0; j < spans.length; ++j) {
			span = spans[j];
			if (span.id == undefined) continue;
			if (span.id.match(/^BeginvidDesc/)) {
				// snippet
				text = span.innerHTML;
				shortDesc = span;
			} else if (span.id.match(/^RemainvidDesc/)) {
				// description
				// note: RemainvidDesc always comes after BeginvidDesc
				text = span.innerHTML;
				longDesc = span;
				longToShortRatio = escape(shortDesc.innerHTML).length / Math.min(escape(longDesc.innerHTML).length, g_translateMaxLength);
			}
		}
	}
	var vlbox = this;
	translateIt(text, this.language, toLang, function(result) {
		if (!vlbox.getTranslationStatus().isTranslating()) {
			return;
		}
		if (!result.error) {
			text = result.translation;
			if (longDesc) {
				// heuristic
				var shortLen = text.length * longToShortRatio;
				shortDesc.innerHTML = text.slice(0, shortLen).replace('<br>',' ');
				longDesc.innerHTML = text.replace('\n','<br>');
			} else {
				shortDesc.innerHTML = text;
			}
		} else if (g_debug) {
			showDebugMessage("*** translation (" + text + ") failed. (" + result.error + ")***");
		}
		vlbox.endTranslation(result.error);
	});
}

showVlboxDebugMessage = function(vid, message) {
	var _e = _gel("video-main-content-" + vid);
	if (_e) {
		_e.innerHTML += '<br/><span style="color:green">' + message + '</span>';
	}
}

showDebugMessage = function(message) {
	var _e = _gel("search-section-header");
	if (!_e) {
		return;
	}
	var debugElem = _gel("translation-debug");
	if (!debugElem) {
		debugElem = document.createElement('div');
		debugElem.id = 'translation-debug'
		debugElem.width = '100%';
		_e.parentNode.insertBefore(debugElem, _e);
	}
	debugElem.innerHTML = '<span style="color:red">' + message + '</span>';
}

//---------------------------------------------------------
translateVideoMainContent = function(vid, toLang, debugFlag) {
	g_debug = debugFlag;
	var vlbox;
	if ((vlbox = g_vlboxes[vid])) {
		vlbox.translate(toLang);
	}
}

untranslateVideoMainContent = function(vid) {
	var vlbox;
	if ((vlbox = g_vlboxes[vid])) {
		vlbox.untranslate();
	}
}

logTranslation = function() {
	if (g_logging && g_translateLinkCount > 0) {
		getUrlXMLResponse('/results_ajax?action_log_translation_shown=' + g_translateLinkCount, null);
	}
}

setResultCount = function(count) {
	if (count < g_showCheckBoxThreshold) {
		g_showCheckBoxThreshold = 0;
	} else if (count < g_showCheckBoxThreshold * 2) {
		g_showCheckBoxThreshold = Math.floor(count / 2);
	}
}

translateAll = function(toLang, xsrfPair) {
	var chkbox = _gel("translate-checkbox");

	var param = new Array();
	param.push({name:'translate', value:(chkbox && chkbox.checked)});
	postUrlXMLResponse('/results_ajax?action_set_translation=1', urlEncodeDict(param) + '&' + xsrfPair);

	for (var vid in g_vlboxes) {
		if (chkbox && chkbox.checked) {
			g_vlboxes[vid] && g_vlboxes[vid].translate(toLang);
		} else {
			g_vlboxes[vid] && g_vlboxes[vid].untranslate();
		}
	}
}

enableTranslateIfNecessary = function(vid, toLang, debug) {
	g_debug = debug;
	vlbox = new VlBox(vid);
	var elem = vlbox.getDetectLangElement();
	var chkbox = _gel("translate-checkbox")
	detectLanguage(vid, elem.innerHTML, function(result) {
		if (!result.error) {
			if (debug) {
				showVlboxDebugMessage(vid, result.language + ' -> ' + toLang + '(' + isTranslatable(toLang) + ')');
			}
			if (toLang == result.language || !isTranslatable(toLang)) {
				vlbox.disableTranslation();
			} else {
				vlbox.setLanguage(result.language);
				vlbox.enableTranslation(toLang != result.language);
				if (chkbox && chkbox.checked)
					vlbox.translate(toLang);
			}
		} else {
			vlbox.disableTranslation();
		}
	});
}

enableTranslate = function(vid, fromLang, toLang, primaryLang, debug) {
	g_debug = debug;
	if (g_debug) {
		showVlboxDebugMessage(vid, 'primary:' + primaryLang + ' ' + fromLang + '(' + isTranslatable(fromLang) + ') -> ' + toLang + '(' + isTranslatable(toLang) + ')');
	}
	if (fromLang != '' && isTranslatable(fromLang) != true) {
		return;
	}
	if (isTranslatable(toLang)) {
		vlbox = new VlBox(vid);
		vlbox.setLanguage(fromLang);
		vlbox.enableTranslation(toLang != primaryLang);
		var chkbox = _gel("translate-checkbox")
		if (chkbox && chkbox.checked) {
			vlbox.translate(toLang);
		}
	}
}

//--------------------------------------------------------------------------
// TODO: replace this with cacheable js file once it becomes ready
/**
 * Enum for languages supported
 * @type Object
 */
var lang = {

  'AFRIKAANS' : 'af',
  'ALBANIAN' : 'sq',
  'AMHARIC' : 'am',
  'ARABIC' : 'ar',
  'ARMENIAN' : 'hy',
  'AZERBAIJANI' : 'az',
  'BASQUE' : 'eu',
  'BELARUSIAN' : 'be',
  'BENGALI' : 'bn',
  'BIHARI' : 'bh',
  'BULGARIAN' : 'bg',
  'BURMESE' : 'my',
  'CATALAN' : 'ca',
  'CHEROKEE' : 'chr',
  'CHINESE' : 'zh',
  'CHINESE_SIMPLIFIED' : 'zh-CN',
  'CHINESE_TRADITIONAL' : 'zh-TW',
  'CROATIAN' : 'hr',
  'CZECH' : 'cs',
  'DANISH' : 'da',
  'DHIVEHI' : 'dv',
  'DUTCH': 'nl',
  'ENGLISH' : 'en',
  'ESPERANTO' : 'eo',
  'ESTONIAN' : 'et',
  'FILIPINO' : 'tl',
  'FINNISH' : 'fi',
  'FRENCH' : 'fr',
  'GALICIAN' : 'gl',
  'GEORGIAN' : 'ka',
  'GERMAN' : 'de',
  'GREEK' : 'el',
  'GUARANI' : 'gn',
  'GUJARATI' : 'gu',
  'HEBREW' : 'iw',
  'HINDI' : 'hi',
  'HUNGARIAN' : 'hu',
  'ICELANDIC' : 'is',
  'INDONESIAN' : 'id',
  'INUKTITUT' : 'iu',
  'ITALIAN' : 'it',
  'JAPANESE' : 'ja',
  'KANNADA' : 'kn',
  'KAZAKH' : 'kk',
  'KHMER' : 'km',
  'KOREAN' : 'ko',
  'KURDISH': 'ku',
  'KYRGYZ': 'ky',
  'LAOTHIAN': 'lo',
  'LATVIAN' : 'lv',
  'LITHUANIAN' : 'lt',
  'MACEDONIAN' : 'mk',
  'MALAY' : 'ms',
  'MALAYALAM' : 'ml',
  'MALTESE' : 'mt',
  'MARATHI' : 'mr',
  'MONGOLIAN' : 'mn',
  'NEPALI' : 'ne',
  'NORWEGIAN' : 'no',
  'ORIYA' : 'or',
  'PASHTO' : 'ps',
  'PERSIAN' : 'fa',
  'POLISH' : 'pl',
  'PORTUGUESE' : 'pt-PT',
  'PUNJABI' : 'pa',
  'ROMANIAN' : 'ro',
  'RUSSIAN' : 'ru',
  'SANSKRIT' : 'sa',
  'SERBIAN' : 'sr',
  'SINDHI' : 'sd',
  'SINHALESE' : 'si',
  'SLOVAK' : 'sk',
  'SLOVENIAN' : 'sl',
  'SPANISH' : 'es',
  'SWAHILI' : 'sw',
  'SWEDISH' : 'sv',
  'TAJIK' : 'tg',
  'TAMIL' : 'ta',
  'TAGALOG' : 'tl',
  'TELUGU' : 'te',
  'THAI' : 'th',
  'TIBETAN' : 'bo',
  'TURKISH' : 'tr',
  'UKRAINIAN' : 'uk',
  'URDU' : 'ur',
  'UZBEK' : 'uz',
  'UIGHUR' : 'ug',
  'VIETNAMESE' : 'vi',
  'UNKNOWN' : ''
};

/**
 * Enum for languages that are not translatable
 * @type Object
 */
var ntLang = {
  'AFRIKAANS' : 'af',
  'ALBANIAN' : 'sq',
  'AMHARIC' : 'am',
  'ARMENIAN' : 'hy',
  'AZERBAIJANI' : 'az',
  'BASQUE' : 'eu',
  'BELARUSIAN' : 'be',
  'BENGALI' : 'bn',
  'BIHARI' : 'bh',
  'BURMESE' : 'my',
  'CATALAN' : 'ca',
  'CHEROKEE' : 'chr',
  'DHIVEHI' : 'dv',
  'ESPERANTO' : 'eo',
  'ESTONIAN' : 'et',
  'FILIPINO' : 'tl',
  'GALICIAN' : 'gl',
  'GEORGIAN' : 'ka',
  'GUARANI' : 'gn',
  'GUJARATI' : 'gu',
  'HEBREW' : 'iw',
  'HUNGARIAN' : 'hu',
  'ICELANDIC' : 'is',
  'INDONESIAN' : 'id',
  'INUKTITUT' : 'iu',
  'KANNADA' : 'kn',
  'KAZAKH' : 'kk',
  'KHMER' : 'km',
  'KURDISH': 'ku',
  'KYRGYZ': 'ky',
  'LAOTHIAN': 'lo',
  'LATVIAN' : 'lv',
  'LITHUANIAN' : 'lt',
  'MACEDONIAN' : 'mk',
  'MALAY' : 'ms',
  'MALAYALAM' : 'ml',
  'MALTESE' : 'mt',
  'MARATHI' : 'mr',
  'MONGOLIAN' : 'mn',
  'NEPALI' : 'ne',
  'ORIYA' : 'or',
  'PASHTO' : 'ps',
  'PERSIAN' : 'fa',
  'PUNJABI' : 'pa',
  'SANSKRIT' : 'sa',
  'SERBIAN' : 'sr',
  'SINDHI' : 'sd',
  'SINHALESE' : 'si',
  'SLOVAK' : 'sk',
  'SLOVENIAN' : 'sl',
  'SWAHILI' : 'sw',
  'TAJIK' : 'tg',
  'TAMIL' : 'ta',
  'TAGALOG' : 'tl',
  'TELUGU' : 'te',
  'THAI' : 'th',
  'TIBETAN' : 'bo',
  'TURKISH' : 'tr',
  'UKRAINIAN' : 'uk',
  'URDU' : 'ur',
  'UZBEK' : 'uz',
  'UIGHUR' : 'ug',
  'VIETNAMESE' : 'vi'
};

/**
 * Map of language codes to booleans.
 * @type Object
 */
var li = {};

function buildLanguageTranslatableLookup() {
  var l;
  // All supported
  for (l in lang) {
    li[lang[l]] = true;
  }
  // Override for non-translatable.
  for (l in ntLang) {
    li[ntLang[l]] = false;
  }
}

/* our version of isTranslatable */
function isTranslatable(language) {
	// return google.language.isTranslatable(language);
  return li[language];
}

// Dynamically build the lookup.
buildLanguageTranslatableLookup();
//--------------------------------------------------------------------------

})();
