/*
 * jQuery Translate plugin 
 *
 * Version: 1.1.0
 *  
 * 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
 * 
 * The copyEvents plugin is needed for rebinding some element's event handlers:
 * http://plugins.jquery.com/project/copyEvents
 * 
 */
 

;(function($){

var translate=function(){
	return new translate.prototype.init()
}

translate.prototype={
	init: function(){ return this; },
	
	process: 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);
				var hasChildNode=false;
				omit ? omit=omit.firstChild : omit=null;
					while(omit){
						if(omit.nodeType==1){
							hasChildNode=true;
							break;
						}
						omit=omit.nextSibling;
					}
				if(hasChildNode){ this.jq=this.jq.not($(opt.not).find('*')) }
			}
		}
		
		var jql=this.jq.length;
		//------------loop through elements-------------
		
		for (var n=0; n<jql; n++){
			var trtext=''; var hasTextNode=false; var hasChildNode=false;
			var el=this.jq[n];//current dom element
			if(!el){ continue; }
			var e=$(el);

			if(typeof opt.subject=='string'){	
				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{
					var cont=el.firstChild;
					//---check childNodes
						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{
						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();
							this.jq=this.jq.not(e.find('*'));
						}else{
							trtext='';
						}
					}
				}
			}

			if(!trtext){ continue; }
			this.jqt.push(el);
			if(opt.comments===false){ trtext=this.strip(trtext) }
			this.txtorig.push(trtext)
		}//loop end
		
		if(opt.translate!==false){ this.translateInit() }
		
		if(opt.walk===false){ return this.jqo; } 
		if(opt.returnAll===true){ return $(this.jqt); }else{ return this.jqo; } 
	},
	
	
	translateInit: function(){
		if(typeof this.txtorig=='string'){
			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.start=0;
		this.tt='';
		this.divs=0;
		this.finalarr=[];
		this.num=0;
		
		return this.translate()
	},
	
	
	translate: function(){
		if(this.stopped===true){ return }
		var _this=this;
		this.end=this.start*1+this.opt.limit;
		this.ts=this.tc.substring(this.start,this.end);
	
		//----------break on end of sentence or tag----------
		var mymatch0=/<(?![^<]*>)/.exec(this.ts);
		if(!mymatch0){//if no broken tag present
			var mymatch2=/>\s*$/.exec(this.ts);
			if(!mymatch2){//if doesn't end with '>'
				var mymatch3=/[\.\?\!;:](?![^\.\?\!;:]*[\.\?\!;:])/.exec(this.ts); 
				if(mymatch3){//if broken sentence present
					var mymatch4=/>(?![^>]*<)/.exec(this.ts);
					if(mymatch4){
						if(mymatch3.index > mymatch4.index){
							this.tt=this.ts.substring(0, (mymatch3.index+1));
						}else{ this.tt=this.ts.substring(0, (mymatch4.index+1)); }
					}else{ this.tt=this.ts.substring(0, (mymatch3.index+1)); }
				}else{ this.tt=this.ts; }
			}else{ this.tt=this.ts; }
		}else{ this.tt=this.ts.substring(0, (mymatch0.index)); }
		
		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);
			
			if(subst.match(/<div(>|( style=";))/gi)){ var divst=subst.match(/<div(>|( style=";))/gi).length; }
			//google adds additional markup to divs for right-to left languages
			if(subst.match(/<\/div>/gi)){ var divcl=subst.match(/<\/div>/gi).length; }
			if(typeof divst=='undefined'){divst=0;}
			if(typeof divcl=='undefined'){divcl=0;}
	
			if(divst==divcl+1){
				var divscompl=$(this.tf.substr(0,(i+7)));
				var divlen=divscompl.length;
				if(this.divs!=divlen){//if new elements have been translated
					var each=divscompl.slice(this.divs,divlen);
					each.each(function(i, e){
						(function(){											 
							if(this.stopped!==true){
								var k=this.divs+i;//generate index
								
								var txteach=$.trim($(e).html());
								this.finalarr[k]=txteach;//create an array for complete callback
								if(this.from.length<2 && this.detlang){ var from=this.detlang; }else{ var from=this.from; }//set det.source lang, if wasn't set
			
								if(this.fn){//called from function
									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);
								}
							}
						}).call(_this)
					})
					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){ 
						//this.warn('google.lang.transl error: '+result.error.code+' '+result.error.message); 
						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;
					var mm=/[\.\?\!;:]$/.exec(this.tf); if(mm){ this.tf=this.tf+' '}
						
					this.translate();
				}).call(_this)
			});
			this.num=this.num+1;
		}else{
		
		//------------translation complete------------
			if(!this.tf){ return; }
	
			this.tf=this.tf.replace(/\s*$/,'')
			if(this.from.length<2 && this.detlang){ var from=this.detlang; }else{ var from=this.from; }
			
			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 _this=this;
		this.fn=false;
		this.stopped=false;
		this.jq=jq;
		this.jqo=jq;
		var opt={};
		if(typeof a!='string'){return  this.warn("Destination language is not set");}
		if(!b && !c){this.from=''; this.to=a; }
		if(!c && b){ if(typeof b=='object'){ this.from=''; this.to=a; opt=b; }else{ this.from=a; this.to=b; } }
		if(typeof a=='string' && b && c){ this.from=a; this.to=b; opt=c;}
		var from=this.from; var to=this.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,
			start: function(){},
			error: function(){},
			each: function(){},
			complete: function(){},
			onTimeout: function(){},
			timeout: 0
		}, $.fn.translate.defaults, opt)
		
		if(opt.rebind===true && opt.replace===true && !$.isFunction($.event.copy)){
			this.warn("You have to include the copyEvents plugin to enable rebinding events on all elements: http://plugins.jquery.com/project/copyEvents");
			this.opt.rebind=opt.rebind=false;
		}
		if(opt.timeout>0){
			this.timeout=setTimeout(function(){
				opt.onTimeout.call(_this, jq, from, to, opt)
			}, opt.timeout);
		}
		
		opt.start.call(this, this.jqo, from, to, opt);
		return this.process()
	},


	translateMethodEach: function(i, el, tff, orig, from, to, opt, num){
		var _this=this;
		var e=$(el)
		//--------------set data--------------
		if(opt.data===true){
			if(typeof opt.subject=='string'){
				$.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{
						var type=e.attr('type') || ''; type=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--------------
		opt.setLangAttr===true ? e.attr('lang',to) : '';
		typeof opt.setLangAttr=='string' ? e.attr(opt.setLangAttr,to) : '';
		
		//---------------replace----------------
		if(opt.replace===true){
			if(typeof opt.subject=='string'){
				e.attr(opt.subject, tff)
			}else{
					
				from=='ar' ? e.css('direction','ltr') : '';
				to=='ar' ? e.css('direction','rtl') : '';
				if(e.css('text-align')==('right' || 'left')){
					from=='ar' ? e.css('text-align','right') : '';
					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{
						var type=e.attr('type') || ''; type=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); var kl=k.length;//clone original html
						e.html(tff);//set new html
						var h=e.find('*').not('script');//get new html
						for (var m=0; m<kl; m++){//each
							h.eq(m).copyEvents(k.get(m))
						}
					}else{
						e.html(tff);
					}
				}
			}
		}
				
		opt.each.call(_this, i, el, tff, orig, from, to, opt, num);
	},
	
	
	translateFunction:function(t, a, b, c){
		var _this=this;
		this.fn=true;
		this.stopped=false;
		var opt={};
		if(typeof a!='string'){	return  this.warn("Destination language is not set");}
		if(!b && !c){this.from=''; this.to=a; }
		if(!c && b){ if(typeof b=='object'){ this.from=''; this.to=a; opt=b; }else{ this.from=a; this.to=b; } }
		if(typeof a=='string' && b && c){ this.from=a; this.to=b; opt=c;}
		var from=this.from; var to=this.to;

		this.opt=opt=$.extend({
			limit: 500,
			comments: false,
			start: function(){},
			error: function(){},
			each: function(){},
			complete: function(){},
			onTimeout: function(){},
			timeout: 0
		}, $.translate.defaults, opt)
		
		if(opt.timeout>0){
			this.timeout=setTimeout(function(){
				opt.onTimeout.call(_this, t, from, to, opt)
			}, opt.timeout);
		}
		opt.start.call(this, t, from, to, opt);

		if(typeof t=='string'){	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;
		
		this.translateInit();
	},
	

	
	detectInit: function(){
		this.k=0;
		this.arr_langCode=[];
		this.arr_lang=[];
		this.arr_result=[];
		this.stopped=false;
		
		this.detect()
	},
	
	detect: function(){
		if(this.stopped===true){ return }
		var _this=this;
		google.language.detect(this.t[this.k].substring(0, this.opt.limit*1), function(result){
			(function(){
				if(!result.error){
					var language = 'unknown';
					for (l in google.language.Languages){
						if (google.language.Languages[l] == result.language){language = l; break;}
					}
						
					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]
						this.opt.setLangAttr===true ? $(e).attr('lang', result.language) : '';
						typeof this.opt.setLangAttr=='string' ? $(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(_this)
		});
	
	},
	
	
	detectMethod: function(jq, opt){
		var _this=this;
		this.jq=this.jqo=jq;
		this.fn=false;
		this.string=false;
		this.t=[]
		this.arr_e=[];
		
		opt=$.extend({
			start: function(){},
			each: function(){},
			complete: function(){},
			error: function(){},
			setLangAttr: true,
			subject: true,
			limit: 500,
			walk: false,
			not: '',
			altAndVal:false
		}, $.fn.language.defaults, opt)
		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.process().each(function(i, e){
			var subject;
			if(opt.subject===true){ $(e).is(':input') ? subject=$(e).val() : subject=$(e).text() 
			}else if(typeof opt.subject=='string'){ subject=$(e).attr(opt.subject); }
			_this.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){
		this.opt=opt=$.extend({
			start: function(){},
			each: function(){},
			complete: function(){},
			error: function(){},
			limit: 500
		}, $.language.defaults, opt)
	
		opt.start.call(this, t, opt);
		
		if(typeof t=='string'){ t=[t]; this.string=true; }

		this.t=t;
		this.len=t.length;
		this.fn=true;
		
		this.detectInit();
	},
	
	strip: function(t){ return t.replace(/<![ \r\n\t]*(--([^\-]|[\r\n]|-[^\-])*--[ \r\n\t]*)>/g,''); },
	warn: function(m){ if(typeof console!='undefined'){  console.warn(m) } },
	stop: function(){
		this.stopped=true;
		return this;
	}
}


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: ''}, $.fn.nodesContainingText.defaults, opt ,{
		subject: true,
		not: '',
		altAndVal:false,
		walk: true,
		returnAll: true,
		translate:false
	})
	return this.translate('en', opt)
}
$.fn.nodesContainingText.defaults={}



$.translate.langLoaded=function(){}
$.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()
	}
	key ? key='key='+key : key='';
	var script = document.createElement("script");
	script.src = "http://www.google.com/jsapi?"+key;
	script.type = "text/javascript";
	document.getElementsByTagName("head")[0].appendChild(script);
	script.onload=$.translate.loadLang
}

$.translate.initLoader()

})(jQuery);