/* 
 * jQuery Translate plugin 
 * 
 * Version: 1.1.6
 * 
 * http://code.google.com/p/jquery-translate/
 * 
 * Copyright (c) 2008 Balázs Endrész (balazs.endresz@gmail.com)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 * 
 * This plugin uses the 'Google AJAX Language API' (http://code.google.com/apis/ajaxlanguage/)
 * You can read the terms of use at http://code.google.com/apis/ajaxlanguage/terms.html
 * 
 */

;(function($){

function $fn(){}
function $isSet(a){	return typeof a!='undefined'; }
function $isString(a){ return typeof a=='string'; }

function copyEvents(from, to){
	var events;
	to.each(function(i){
		if(!(events=$.data(from[i], 'events')))
			return false;
		for(var type in events)
			for(var handler in events[type])
				$.event.add(this, type, events[type][handler], events[type][handler].data);
	});
}

function cut(t){
	var m1=/<(?![^<]*>)/.exec(t);
	if(!m1){//if no broken tag present
		var m2=/>\s*$/.exec(t);
		if(!m2){//if doesn't end with '>'
			var m3=/[\.\?\!;:](?![^\.\?\!;:]*[\.\?\!;:])/.exec(t); 
			if(m3){//if broken sentence present
				var m4=/>(?![^>]*<)/.exec(t);
				if(m4){
					if(m3.index > m4.index){
						t=t.substring(0, m3.index+1);
					}else t=t.substring(0, m4.index+1);
				}else t=t.substring(0, m3.index+1);
			}else t=t;
		}else t=t;
	}else t=t.substring(0, m1.index);
	
	return t;
}

function translate(){ return new translate.prototype.init(); }

translate.prototype={
	init: function(){ return this; },
	
	processInit: function(){
		this.txtorig=[];
		this.jqt=[];
		this.tc='';
		var opt=this.opt;

		this.jq=this.jq.not('script, '+opt.not);

		if(opt.walk===true){
			this.jq=this.jq.add(this.jq.find('*').not('script, '+opt.not));//add all contents to jq
			if(opt.not.length){//filter out childnodes if has any:
				var omit=$(opt.not).get(0), hasChildNode=false;
				omit=omit ? omit.firstChild : null;
				while (omit){
					if(omit.nodeType==1){
						hasChildNode=true;
						break;
					}
					omit=omit.nextSibling;
				}
				if(hasChildNode)
					this.jq=this.jq.not($(opt.not).find('*'));
			}
		}
		
		this.split.jqt=[];
		this.split.txtorig=[];
		this.split.finalarr=[];
		this.split.num=0;
		this.nct={};
		this.nct.jqt=[];
		this.nct.txtorig=[];
		
		this.jql=this.jq.length;
		this.n=-1;
		return this.process();

	},

	process: function(){
		this.n++;
		var that=this, opt=this.opt, trtext='', hasTextNode=false, hasChildNode=false, el=this.jq[this.n], e, cont;
		
		if(this.n==this.jql){
			if(opt.translate!==false && (!opt.split || this.nn===true))
				this.translateInit();
			if(opt.split){//complete callback if split was set
				this.jqt=this.split.jqt; this.num=this.split.num;
				this.finalarr=this.split.finalarr; this.txtorig=this.split.txtorig;
				var from=(this.from.length<2 && this.detlang) ? this.detlang : this.from;
				this.opt.complete.call(this, this.jqo, $(this.jqt), this.finalarr, this.txtorig, from, this.to, this.opt, this.num);
			}
			if($isSet(opt.nct))//complete callback for nodesContText
				this.opt.complete.call(this, $(this.nct.jqt), this.nct.txtorig);
			if(opt.walk===false)
				return this.jqo;
			if(opt.returnAll===true)
				return $(this.jqt);
			else
				return this.jqo;
		}
		
		if(!el)
			return this.process();
		e=$(el);

		if($isString(opt.subject))
			trtext=e.attr(opt.subject) || '';
		else{
			if(opt.altAndVal && (el.tagName.toLowerCase()=='img' || el.tagName.toLowerCase()=='input')){
				if(el.tagName.toLowerCase()=='img')
					trtext=e.attr('alt') || '';
				else{
					var type=e.attr('type') || ''; type=type.toLowerCase();
					if(type=='text' || type=='button' || type=='submit')
						trtext=e.val() || '';
				}
			}else if(el.tagName.toLowerCase()=='textarea')
				trtext=e.val();
			else{
				cont=el.firstChild;
				//---check childNodes
				if(opt.walk!==true)
					hasChildNode=true;

				while(cont){
					if(cont.nodeType==1){
						hasChildNode=true;
						break;
					}
					cont=cont.nextSibling;
				}
				//----------------

				if(!hasChildNode)//if doesn't have any children (not text)
					trtext=e.text();
				else{
					if(opt.walk!==true)
						hasTextNode=true;
					cont=el.firstChild;

					//---check textNodes
					while (cont){
						if(cont.nodeType==3 && cont.nodeValue.match(/\S/) !== null){//textnodes with text
							if(cont.nodeValue.match(/<![ \r\n\t]*(--([^\-]|[\r\n]|-[^\-])*--[ \r\n\t]*)>/) !== null){
								if(cont.nodeValue.match(/(\S+(?=.*<))|(>(?=.*\S+))/) !== null){
									hasTextNode=true;
									break;
								}
							}else{
								hasTextNode=true;
								break;
							}
						}
						cont=cont.nextSibling;
					}
					//---------------

					if(hasTextNode){//remove child nodes from jq
						trtext=e.html().replace(/<script[^<]+<[^<]+>/,'');//removes scripts
						this.jq=this.jq.not(e.find('*'));
					}else
						trtext='';
				}
			}
		}

		if(!trtext)
			return this.process();
		this.nn=true;
		this.jqt.push(el);
		if(opt.comments===false)
			trtext=this.strip(trtext);
		this.txtorig.push(trtext);

		if(!opt.split || !(this.n%opt.split==0)){
			if($isSet(opt.nct)){ 
				this.nct.jqt.push(el);
				this.nct.txtorig.push(trtext);
				opt.each.call(this, this.jqt.length-1, el, trtext);
			}
			if(opt.async)
				setTimeout(function(){ that.process(); }, opt.async);
			else
				return this.process();
		}else{
			this.nn=false;
			if(opt.translate!==false)
				return this.translateInit();
		}

	},
	
	
	translateInit: function(){
		if($isString(this.txtorig)){
			this.tc='<div>'+this.txtorig+'</div>';
			this.string=true;
		}else{
			this.tc='<div>'+this.txtorig.join('</div><div>')+'</div>';
			this.string=false;
		}

		this.tf='';
		this.l=this.tc.length;
		this.tt='';
		this.start=0;
		this.divs=0;
		this.finalarr=[];
		this.num=0;
		
		return this.translate();
	},
	
	
	translate: function(){
		if(this.stopped===true)
			return;
		var that=this;
	
		this.tt=cut( this.tc.substring(this.start, this.start*1+this.opt.limit) )
		this.start=this.start+this.tt.length;//set next start position
		
		//---------handle each callbacks as transl arrived----------
		var i=this.tf.length;
		while(this.tf.lastIndexOf('</div>',i)>-1){
			i=this.tf.lastIndexOf('</div>',i)-1;
			var subst=this.tf.substr(0,i),			
				divst=subst.match(/<div(>|( style=";))/gi),
				divcl=subst.match(/<\/div>/gi);
			
			divst=divst ? divst.length : 0;
			divcl=divcl ? divcl.length : 0;
				
			if(divst==divcl+1){
				var divscompl=$(this.tf.substr(0,(i+7))), divlen=divscompl.length;
				if(this.divs!=divlen){//if new elements have been translated
					divscompl.slice(this.divs,divlen).each(function(i, e){
						(function(){											 
							if(this.stopped!==true){
								var k=this.divs+i,//generate index
									txteach=$.trim($(e).html()), from;
								this.finalarr[k]=txteach;//create an array for complete callback
								
								from=(this.from.length<2 && this.detlang) ? this.detlang : this.from;//set det.source lang, if unset
			
								if(this.fn){//called from function
									if(this.string)
										this.txtorig=[this.txtorig];
									this.opt.each.call(this, k, txteach, this.txtorig[k], from, this.to, this.opt, this.num);
								}else{//called from method
									this.translateMethodEach(k, this.jqt[k], txteach, this.txtorig[k], from, this.to, this.opt, this.num);
									this.opt.each.call(this, k, this.jqt[k], txteach, this.txtorig[k], from, this.to, this.opt, this.num);
									this.split.jqt.push(this.jqt[k]);
									this.split.txtorig.push(this.txtorig[k]);
									this.split.finalarr.push(txteach);
								}
							}
						}).call(that);
					})
					this.divs=divlen;
				}
				break;
			}
		}

		//---------translate one part of text-----------
		if(this.tt.length>0){
			google.language.translate(this.tt, this.from, this.to, function(result){  
				(function(){											 
					if(result.error)
						return this.opt.error.call(this, result.error, this.tt, this.from, this.to, this.opt, this.num);
			
					this.tf=this.tf+result.translation;
					this.detlang=result.detectedSourceLanguage;
					if( /[\.\?\!;:]$/.exec(this.tf) )
						this.tf=this.tf+' ';
						
					this.translate();
				}).call(that);
			});
			this.num++;
			this.split.num++;
			
			if(this.fn)
				return this;
		}else{
		
		//------------translation complete------------
            if(this.opt.split && (this.n < this.jq.length)){//process remaining elements
				var n=this.n;
				this.jq=$($.grep(this.jq, function(e, i){
					return (i>n);
				}));
				this.jqt=[];
				this.txtorig=[];
				this.n=-1;
				return this.process();
			}
			
			if(!this.tf)
				return;
	
			this.tf=this.tf.replace(/\s*$/,'');
			var from=(this.from.length<2 && this.detlang) ? this.detlang : this.from;
			
			if(this.timeout)
				clearTimeout(this.timeout);
	
			if(this.fn){//called from function
				if(this.string){ this.finalarr=this.finalarr[0]; this.txtorig=this.txtorig[0]; }
				this.opt.complete.call(this, this.finalarr, this.txtorig, from, this.to, this.opt, this.num);
			}else
				this.opt.complete.call(this, this.jqo, $(this.jqt), this.finalarr, this.txtorig, from, this.to, this.opt, this.num);
		}
	},
	

	translateMethod: function(jq, a, b, c){
		var that=this, opt={}, from, to;
		this.fn=false;
		this.stopped=false;
		this.jq=jq;
		this.jqo=jq;
		
		if(!$isString(a))
			return this.jqo;
		if(!b && !c){from=''; to=a; }
		if(!c && b){ if(typeof b=='object'){ from=''; to=a; opt=b; }else{ from=a; to=b; } }
		if(a && b && c){ from=a; to=b; opt=c;}
		this.from=from; this.to=to;
		
		this.opt=opt=$.extend({
			walk: true,
			returnAll: false,
			replace: true,
			translate:true,
			limit: 500,
			rebind: true,
			data: false,
			setLangAttr: false,
			subject: true,
			not: '',
			comments: false,
			altAndVal:true,
			split: false,
			async: false,
			start: $fn,
			error: $fn,
			each: $fn,
			complete: $fn,
			onTimeout: $fn,
			timeout: 0
		}, $.fn.translate.defaults, opt);
		
		if(opt.timeout>0){
			this.timeout=setTimeout(function(){
				opt.onTimeout.call(that, jq, from, to, opt);
			}, opt.timeout);
		}
		
		this.split={};
		if(opt.async===true)
			opt.async=2;
		opt.start.call(this, this.jqo, from, to, opt);
		
		if(opt.async || opt.split){
			this.processInit();
			return this.jqo;
		}else
			return this.processInit();
	},


	translateMethodEach: function(i, el, tff, orig, from, to, opt, num){
		var that=this, e=$(el), type;
		//--------------set data--------------
		if(opt.data===true){
			if($isString(opt.subject)){
				$.data(el,'translation.'+from+'.'+opt.subject, orig);
				$.data(el,'translation.'+ to +'.'+opt.subject, tff);
			}else{
				
				if(opt.altAndVal && (el.tagName.toLowerCase()=='img' || el.tagName.toLowerCase()=='input')){
					if(el.tagName.toLowerCase()=='img'){
						$.data(el,'translation.'+from+'.'+'alt', orig);
						$.data(el,'translation.'+ to +'.'+'alt', tff);
					}else{
						type=(e.attr('type') || '').toLowerCase();
						if(type=='text' || type=='button' || type=='submit'){
							$.data(el,'translation.'+from+'.'+'value', orig);
							$.data(el,'translation.'+ to +'.'+'value', tff);
						}
					}
				}else if(el.tagName.toLowerCase()=='textarea'){
					$.data(el,'translation.'+from+'.'+'value', orig);
					$.data(el,'translation.'+ to +'.'+'value', tff);
				}else{
					$.data(el,'translation.'+from+'.'+'html', orig);
					$.data(el,'translation.'+ to +'.'+'html', tff);
				}
			}
		}
		
		//------------set html attr--------------
		if(opt.setLangAttr===true)
			e.attr('lang',to);
		if($isString(opt.setLangAttr))
			e.attr(opt.setLangAttr,to);
		
		//---------------replace----------------
		if(opt.replace===true){
			if($isString(opt.subject))
				e.attr(opt.subject, tff);
			else{
					
				if(from=='ar')
					e.css('direction','ltr');
				if(to=='ar')
					e.css('direction','rtl');
				if(e.css('text-align')==('right' || 'left')){
					if(from=='ar')
						e.css('text-align','right');
					if(to=='ar')
						e.css('text-align','right');
				}

				if(opt.altAndVal && (el.tagName.toLowerCase()=='img' || el.tagName.toLowerCase()=='input')){
					if(el.tagName.toLowerCase()=='img')
						e.attr('alt', tff);
					else{
						type=(e.attr('type') || '').toLowerCase();
						if(type=='text' || type=='button' || type=='submit')
							e.val(tff);
					}
				}else if(el.tagName.toLowerCase()=='textarea')
					e.val(tff);
				else{
					if(opt.rebind===true){//rebind event handlers when html was translated
						var k=e.find('*').not('script').clone(true);
						e.html(tff);
						copyEvents(k, e.find('*'));
					}else
						e.html(tff);
				}
			}
		}
	},
	
	
	translateFunction:function(t, a, b, c){
		var that=this, opt={}, from, to;
		this.fn=true;
		this.stopped=false;
		if(!$isSet(t))
			return this;
		if(!b && !c){from=''; to=a; }
		if(!c && b){ if(typeof b=='object'){ from=''; to=a; opt=b; }else{ from=a; to=b; } }
		if(a && b && c){ from=a; to=b; opt=c;}
		this.from=from; this.to=to;

		this.opt=opt=$.extend({
			limit: 500,
			comments: false,
			start: $fn,
			error: $fn,
			each: $fn,
			complete: $fn,
			onTimeout: $fn,
			timeout: 0
		}, $.translate.defaults, opt, {split:false, async:false});
		
		if(opt.timeout>0){
			this.timeout=setTimeout(function(){
				opt.onTimeout.call(that, t, from, to, opt);
			}, opt.timeout);
		}
		this.split={};
		opt.start.call(this, t, from, to, opt);

		if($isString(t))
			if(this.opt.comments===false)
				t=this.strip(t);
		else{
			if(this.opt.comments===false)
				for(var i=0; i<t.length; i++)
					t[i]=this.strip(t[i]);
		}
		
		this.txtorig=t;
		
		return this.translateInit();
	},
	

	
	detectInit: function(){
		this.k=0;
		this.arr_langCode=[];
		this.arr_lang=[];
		this.arr_result=[];
		this.stopped=false;
		
		return this.detect();
	},
	
	detect: function(){
		if(this.stopped===true)
			return;
		var that=this;
		google.language.detect(this.t[this.k].substring(0, this.opt.limit*1), function(result){
			(function(){
				if(!result.error){
					var language=this.getLanguage(result.language);
					this.arr_langCode.push(result.language);
					this.arr_lang.push(language);
					this.arr_result.push(result);
					
					//each:
					if(this.fn===false){
						var e=this.jqt[this.k];
						if(this.opt.setLangAttr===true)
							$(e).attr('lang', result.language);
						if($isString(this.opt.setLangAttr))
							$(e).attr(this.opt.setLangAttr, result.language);
						this.opt.each.call(this, this.k, e, this.t[this.k], result.language, language, result, this.opt);
					}else
						this.opt.each.call(this, this.k, this.t[this.k], result.language, language, result, this.opt);
					
					//complete:
					if(this.k==this.len-1){
						if(this.string===true)
							return this.opt.complete.call(this, this.t[0], this.arr_langCode[0], this.arr_lang[0],  this.arr_result[0], this.opt);
						else if(this.fn===true)
							return this.opt.complete.call(this, this.t, this.arr_langCode, this.arr_lang,  this.arr_result, this.opt);
						else
							return this.opt.complete.call(this, this.jqt, this.t, this.arr_langCode, this.arr_lang, this.arr_result, this.opt);
					}else{
						this.k++;
						return this.detect();
					}
				//error:		
				}else{
					if(this.fn===false)
						return this.opt.error.call(this, result.error, this.jqt[this.k], this.t[this.k], this.k, this.opt);
					else
						return this.opt.error.call(this, result.error, this.t[this.k], this.k, this.opt);
				}
			}).call(that);
		});
		
		return this;
	},
	
	
	detectMethod: function(jq, opt){
		var that=this;
		this.jq=this.jqo=jq;
		this.fn=false;
		this.string=false;
		this.t=[];
		this.arr_e=[];
		this.split={};
		
		opt=$.extend({
			start: $fn,
			each: $fn,
			complete: $fn,
			error: $fn,
			setLangAttr: true,
			subject: true,
			limit: 500,
			walk: false,
			returnAll: false,
			not: '',
			altAndVal:false
		}, $.fn.language.defaults, opt, {
			//internal:
			async:false,
			split:false
		});
		
		if(opt.walk===true && opt.returnAll===false)
			opt.returnAllInt=false;
		this.opt=opt=$.extend(opt, {translate:false, returnAll:true});

		opt.start.call(this, jq, opt);
		
		this.jqt=this.processInit().each(function(i, e){
			var subject;
			e=$(e);
			if(opt.subject===true)
				subject=e.is(':input') ? e.val() : e.text();
			else if($isString(opt.subject))
				subject=e.attr(opt.subject);
			
			that.t.push(subject);
		})
		this.len=this.jqt.length;
		
		this.detectInit();
		
		if(opt.returnAllInt===false)
			return  this.jqo;
		else
			return this.jqt;
	},
	
	
	detectFunction: function(t, opt){
		if(!$isSet(t))
			return this;
		this.opt=opt=$.extend({
			start: $fn,
			each: $fn,
			complete: $fn,
			error: $fn,
			limit: 500
		}, $.language.defaults, opt);
	
		opt.start.call(this, t, opt);
		
		if($isString(t)){ t=[t]; this.string=true; }

		this.t=t;
		this.len=t.length;
		this.fn=true;
		
		return this.detectInit();
	},
	
	strip: function(t){ return t.replace(/<![ \r\n\t]*(--([^\-]|[\r\n]|-[^\-])*--[ \r\n\t]*)>/g,''); },
	
	stop: function(){ this.stopped=true; return this; },
	
	getLanguage: function(langCode, format){
		var lang='unknown';
		for(l in google.language.Languages)
			if(google.language.Languages[l]==langCode){lang=l; break;}
		if(!$isSet(format))
			format='uppercase';
		switch(format){
			case 'lowercase': lang=lang.toLowerCase(); break;
			case 'uppercase': lang=lang; break;
			case 'capitalize': lang=lang.substring(0,1).toUpperCase()+lang.substring(1).toLowerCase(); break;
		}
		return lang;
	},
	
	getLanguages: function(translatable){
		if(!$isSet(translatable))
			return google.language.Languages;
		var langobj=google.language.Languages;
		translatable={};
		for (var i in langobj)
			if(google.language.isTranslatable(langobj[i]))
				translatable[i]=langobj[i];
		return translatable;
	}
}


translate.prototype.init.prototype=translate.prototype;



$.fn.translate=function(a, b, c){ return translate().translateMethod(this, a, b, c) }
$.fn.translate.defaults={}

$.translate=function(t, a, b, c){ return translate().translateFunction(t, a, b, c) }
$.translate.defaults={}

$.fn.language=function(opt){ return translate().detectMethod(this, opt) }
$.fn.language.defaults={}

$.language=function(t, opt){ return translate().detectFunction(t, opt) }
$.language.defaults={}

$.fn.nodesContainingText=function(opt){
	var opt=$.extend({
		not: '',
		async: false,
		altAndVal:false,
		each: $fn,
		complete: $fn
		}, $.fn.nodesContainingText.defaults, opt, {
		//internal:
		nct: true,
		subject: true,
		walk: true,
		returnAll: true,
		translate:false
	})
	return this.translate('en', opt)
}
$.fn.nodesContainingText.defaults={}



var interval, intervalCount=0,
	//you can modify these values for checking the $.translate.ready function:
	intervalCountLimit=60,
	intervalDelay=500;

function checkReadyFn(){
	if(typeof $.translate.ready=='function'){
		clearInterval(interval);
		return $.translate.ready();
	}
	if(++intervalCount>intervalCountLimit)
		clearInterval(interval);
}

$.translate.langLoaded=function(){ interval=setInterval(checkReadyFn, intervalDelay); }

$.translate.loadLang=function(){ google.load('language', '1', {'callback' : $.translate.langLoaded}); }

$.translate.initLoader=function(key){
	if(typeof google!='undefined' && typeof google.load!='undefined')
		return $.translate.loadLang();
	$.getScript('http://www.google.com/jsapi?'+(key ? 'key='+key : ''), $.translate.loadLang);
}

$.translate.initLoader()

})(jQuery);