/* ==> meGoogleTranslate <== / by Radosław Pycka / MIT licensed */

var meGT = (function (document, undefined) {
	
	var $ = {}; // <- nice, isn't it :)
	
	// State:
	
	$.ready = false;
	$.loaded = false;
	$.currentLanguage = undefined;
	$.onLoadCallback = null;
	$.template = 'Google Translate: <select id="meGT-switch"></select>';
	$.switcherParent = null;
	
	$.engine = null;
	$.locked = false;
	$.textNodes = [];
	$.textNodesCount = 0;
	$.textOriginals = [];
	$.fieldSeparator = '<sep>';

	// Behaviour:
	
	// private:
	function _init() {
		$.scan();
		$.loadSwitcher();
	}
	
	// public:
	$.init = function () {
		this.getCurrentLanguage();
		
		if (!this.loaded) {
			this.onLoadCallback = _init;
		}
		else {
			_init();
		}
	};


	// -- langauge related
	$.getCurrentLanguage = function () {
		var lang;
		
		if ((lang = this.currentLanguage)) {
			return lang;
		}
		else if ((lang = document.documentElement.getAttribute('lang'))){
			this.currentLanguage = lang;
			return lang;
		}
		// might add detection with google translate api
		else {
			throw new Error ('meGT: couldn\'t determine current language, please provide via .currentLanguage property or lang attribute on root element');
		}
	};
	$.setCurrentLanguage = function (lang) {
		$.currentLanguage = lang;
		document.documentElement.setAttribute('lang', lang);
	};
	$.getTranslationLanguages = function () {
		// user provided language map (i.e. object mapping printed name to BCP47 code)
		if (this.languages) {
			return;
		}
		else if (this.loaded) {
			this.languages = this.engine.Languages;
		}
		else {
			throw new Error('meGT: no translation languages provided, use .languages mapping property');
		}
	};
	
	
	// -- library related
	$.loadCallback = function () {
		var $ = meGT;
		
		$.engine = window.google.language;
		$.loaded = true;
		
		$.getTranslationLanguages();
		
		// run user supplied onload callback
		if ($.onLoadCallback) {
			$.onLoadCallback($);
		}
	};


	// -- DOM related
	$.loadSwitcher = function () {
		var switcher = document.createElement('div');
		switcher.setAttribute('id', 'meGT-wrapper');
		switcher.innerHTML = this.template;
		
		var select = switcher.getElementsByTagName('select')[0];
		var langs = this.languages;
		for (var lang in langs) {
			if (langs.hasOwnProperty(lang)) {
				var option = document.createElement('option');
				option.value = langs[lang];
				option.appendChild(document.createTextNode(lang));
				select.appendChild(option);
			}
		}
		
		this.select = select;
		if (select.addEventListener) {
			select.addEventListener('change', this.translateContent, false);
		}
		else {
			select.attachEvent('onchange', this.translateContent);
		}
		
		// insert into document
		if (!this.switcherParent) {
			this.switcherParent = document.body;
		}
		
		this.switcherParent.appendChild(switcher);
	};
	$.scan = function () {
		
		var textNodes = this.textNodes;
		var texts = this.textOriginals;
		var test = /[a-z]/ig;
		var omitTags = {
			SCRIPT : true
		};

		function walk (node) {
			var n = node.firstChild;
			while (n) {
				if (!omitTags.hasOwnProperty(n.nodeName)) {
					if (n.nodeType === 3) {
						var val = n.nodeValue;
						if (test.test(val)) {
							textNodes.push(n);
							texts.push(val);
						}
					}
					walk(n);
				}
				n = n.nextSibling;
			}
		}
		
		walk(document.body);		
		this.textNodesCount = textNodes.length;
	};
	
	$.loadTranslation = function (result) {
		if (result.translation) {
			var that = $;
			var textNodes = that.textNodes;
			var strs = result.translation.split(that.fieldSeparator);
			var index = parseInt(strs[0]);
			var intendedLength = parseInt(strs[1]);
			var pointer = 2;
			
			function escToUTF(str) {
				str = str.slice(2);
				return String.fromCharCode(parseInt(str));
			}
			
			if (intendedLength === strs.length - 2) {
				for (var i = index, len = index + strs.length - 2 ; i < len ; ++i) {
					var v = strs[pointer++];		
					if (v) {
						v = v.replace(/&#[0-9]+;/g, escToUTF);
						textNodes[i].nodeValue = v;
					}
				}				
			}
		}
	}
	$.buildRequestTab = function () {
		var MAX_LENGTH = 512;
		var reqs = [];
		var req = [];
		var clen = 0;
		var begIndex = 0;
		var textNodes = $.textNodes;
		var separator = $.fieldSeparator;
		var texts = $.textOriginals;
		
		for (var i = 0, len = textNodes.length ; i < len ; ++i) {
			var curr = texts[i];
						
			if (!clen || clen + curr.length < MAX_LENGTH) {
				clen += curr.length;
				req.push(curr);
			}
			else {
				req.unshift(req.length);
				req.unshift(begIndex);				
				reqs.push(req.join(separator));
				req.length = 0;
				clen = 0;
				
				// put next item
				req.push(curr);
				clen += curr.length;
				begIndex = i;
			}
			
			// 
			if (i === (len - 1) && clen) {
				req.unshift(req.length);
				req.unshift(begIndex);
				reqs.push(req.join(separator));
				req.length = 0;
			}
		}
		
		return reqs;		
	}	
	$.translateContent = function () {
		var that = $;
		var target = that.select.options[that.select.selectedIndex].getAttribute('value');
		if (target) {
			var requests = that.buildRequestTab();

			for (var i = 0, len = requests.length ; i < len ; ++i) {
				var toTranslate = requests[i];
				that.engine.translate(toTranslate, that.currentLanguage, target, that.loadTranslation);
			}		
		}
	}

	return $;	
})(document);

google.load('language', '1');
google.setOnLoadCallback(meGT.loadCallback);
