/* 
 * jQuery Translate plugin 
 * 
 * Version: 1.2.2
 * 
 * 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
 * 
 */
 
//NodesContainingText
;(function($){

function is(el, name){ return el.nodeName && el.nodeName.toUpperCase()==name.toUpperCase(); }

function isInput(e){
	if(!is(e[0],'input'))
		return false;
	var t=e.attr('type');
	return t=='text' || t=='button' || t=='submit';
}

function Nct(){}

Nct.prototype={
	init: function(jq, o){
		this.textArray=[];
		this.elements=[];
		this.options=o;
		this.jquery=jq;
		this.n=-1;
		if(o.async===true) o.async=2;
		
		jq=jq.not('script, ' + o.not);
		jq=jq.add( jq.find('*').not('script, ' + o.not) );//add all contents to jq
		if(o.not)
			jq=jq.not( $(o.not).find('*') );
		
		this.jq=jq;
		this.jql=this.jq.length;
		return this.process();

	},

	process: function(){
		this.n++;
		var that=this, o=this.options, text='', hasTextNode=false, hasChildNode=false, el=this.jq[this.n], e, c, ret;
		
		if(this.n==this.jql){
			ret=this.jquery.pushStack(this.elements);
			o.complete.call(ret, ret, this.textArray);
			
			if(o.returnAll===false && o.walk===false)
				return this.jquery;
			return ret;
		}
		
		if(!el)
			return this.process();
		e=$(el);

		if(typeof o.subject=='string')
			text=e.attr(o.subject);
		else{
			
			if(o.altAndVal && is(el,'img'))
				text=e.attr('alt');
			else if(o.altAndVal && isInput(e))
				text=e.val();
			else if(is(el,'textarea'))
				text=e.val();
			else{
				//check childNodes:
				c=el.firstChild;
				if(o.walk!==true)
					hasChildNode=true;
				else{
					while(c){
						if(c.nodeType==1){
							hasChildNode=true;
							break;
						}
						c=c.nextSibling;
					}
				}

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

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

		if(!text)
			return this.process();
		this.elements.push(el);
		if(o.comments===false)
			text=this.stripComments(text);
		this.textArray.push(text);

		o.each.call(el, this.elements.length-1, el, text);
		
		if(o.async){
			setTimeout(function(){ that.process(); }, o.async);
			return this.jquery;
		}else
			return this.process();
		
	},

	stripComments: function(t){ return t.replace(/<![ \r\n\t]*(--([^\-]|[\r\n]|-[^\-])*--[ \r\n\t]*)>/g,''); }

}

$.fn.nodesContainingText=function(o){
	o=$.extend({}, defaults, $.fn.nodesContainingText.defaults, o);
	return new Nct().init(this, o);
}

var defaults={
	not: '',
	async: false,
	each: function(){},
	complete: function(){},
	comments: false,
	returnAll: true,
	walk: true,
	altAndVal:false,
	subject:true
}
	
$.fn.nodesContainingText.defaults=defaults;

})(jQuery);




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

function is(el, name){ return el.nodeName && el.nodeName.toUpperCase()==name.toUpperCase(); }

function isInput(e){
	if(!is(e[0],'input'))
		return false;
	var t=e.attr('type');
	return t=='text' || t=='button' || t=='submit';
}

function args(a, b, c, method){
	var from='', to, o={};
	if(typeof a=='object'){o=a;}else{
		if(!b && !c) to=a;
		if(!c && b){ if(typeof b=='object'){ to=a; o=b; }else{ from=a; to=b; } }
		if(a && b && c){ from=a; to=b; o=c;}
		o.from=T.fn.toLanguageCode(from)||''; o.to=T.fn.toLanguageCode(to)||'';
	}
	if(o.toggle) o.data=true;
	if(o.async===true) o.async=2;
	
	return $.extend({}, defaults, (isSet(method) ? $.fn.translate.defaults : $.translate.defaults), o);
}

function T(){}

T.fn=T.prototype={
	
	translateInit: function(t, a, b, c){
		var that=this, from, to, o;
		
		this.options=o=args(a, b, c);
		
		if(isString(t)){
			if(o.comments===false)
				t=this.stripComments(t);
			this.rawSource='<div>'+t+'</div>';
			this.isString=true;
		}else{
			if(o.comments===false)
				for(var i=0, l=t.length; i<l; i++)
					t[i]=this.stripComments(t[i]);
			this.rawSource='<div>'+t.join('</div><div>')+'</div>';
			this.isString=false;
		}

		this.from=o.from;
		this.to=o.to;
		this.source=t;
		this.elements=o.nodes;
		this.rawTranslation='';
		this.translation=[];
		this.startPos=0;
		this.i=0;
		this.numberOfCalls=0;
		this.stopped=false;
		
		if(o.timeout>0){
			this.timeout=setTimeout(function(){
				o.onTimeout.call(that, o.nodes[0] ? o.nodes : t, o.from, o.to, o);
			}, o.timeout);
		}
		
		o.start.call(this, o.nodes[0] ? o.nodes : t , o.from, o.to, o);
		if(o.toggle && o.nodes[0])
			this.toggle()
		return this.translate();
	},
	
	translate: function(){
		if(this.stopped)
			return;
		var that=this, o=this.options;
	
		this.rawSourceSub=this.truncate( this.rawSource.substring(this.startPos, this.startPos+o.limit) );
		this.startPos+=this.rawSourceSub.length;//set next start position
		
		//---------handle each callbacks as transl arrived----------
		var i=this.rawTranslation.length;
		while(this.rawTranslation.lastIndexOf('</div>',i)>-1){
			i=this.rawTranslation.lastIndexOf('</div>',i)-1;
			var subst=this.rawTranslation.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.rawTranslation.substr(0,(i+7))), divlen=divscompl.length;
				if(this.i!=divlen){//if new elements have been translated
					divscompl.slice(this.i, divlen).each(function(i, e){
						(function(){
							if(this.stopped)
								return false;
							var from, tr=$(e).html(), j=this.i+i;//generate index
							
							this.translation[j]=tr;//create an array for complete callback
							
							from=this.from.length<2 && this.detectedSourceLanguage || this.from;//set det.source lang, if unset
		
							if(!o.nodes[0]){//called from function
								if(this.isString)
									this.source=[this.source];
								o.each.call(this, j, tr, this.source[j], from, this.to, o, this.numberOfCalls);
							}else{//called from method
								this.each(j, this.elements[j], tr, this.source[j], from, this.to, o);
								o.each.call(this, j, this.elements[j], tr, this.source[j], from, this.to, o, this.numberOfCalls);
							}
						}).call(that);
					});
					this.i=divlen;
				}
				break;
			}
		}

		//---------translate one part of text-----------
		if(this.rawSourceSub.length>0){
			GL.translate(this.rawSourceSub, this.from, this.to, function(result){  
				(function(){											 
					if(result.error)
						return o.error.call(this, result.error, this.rawSourceSub, this.from, this.to, o, this.numberOfCalls);
			
					this.rawTranslation+=result.translation;
					this.detectedSourceLanguage=result.detectedSourceLanguage;
					if( /[\.\?\!;:]$/.exec(this.rawTranslation) )
						this.rawTranslation+=' ';
						
					this.translate();
				}).call(that);
			});
			this.numberOfCalls++;
			
			if(!o.nodes[0])
				return this;
		}else{
		
		//------------translation complete------------
			
			if(!this.rawTranslation)
				return;
	
			this.rawTranslation=this.rawTranslation.replace(/\s*$/,'');
			var from=this.from.length<2 && this.detectedSourceLanguage || this.from;
			
			if(this.timeout)
				clearTimeout(this.timeout);
	
			if(!o.nodes[0]){//called from function
				if(this.isString){ this.translation=this.translation[0]; this.source=this.source[0]; }
				o.complete.call(this, this.translation, this.source, from, this.to, o, this.numberOfCalls);
			}else
				o.complete.call(this, this.elements.end(), this.elements, this.translation, this.source, from, this.to, o, this.numberOfCalls);
		}
	},

	
	
	each: function(i, el, t, s, from, to, o){
		var that=this, e=$(el), d;
		
		if(o.data===true){
			if(isString(o.subject))
				d=o.subject;
			else{
				if(o.altAndVal && is(el,'img'))
					d='alt';
				else if(o.altAndVal && isInput(e))
					d='value';
				else if(is(el,'textarea'))
					d='value';
				else
					d='html';
			}
			//alert(e.attr("class"));
			//alert('translation.'+to+'.'+d);
			$.data(el, 'translation.'+from+'.'+d, s);
			$.data(el, 'translation.'+to+'.'+d, t);
		}
		
		this.setLangAttr(e, to, o);
		this.replace(e, t, o);
	},
	
	toggle: function(){
		var that=this, translation=[], o=this.options, el=o.nodes, to=o.to, stop=false;
		
		el.each(function(i){
			var e=$(this),
				a=o.subject===true && $.data(this, 'translation.'+to+'.html'),
				b=isString(o.subject) && $.data(this, 'translation.'+to+'.'+o.subject),			
				c=o.altAndVal && $.data(this, 'translation.'+to+'.value'),
				d=o.altAndVal && $.data(this, 'translation.'+to+'.alt'),
				tr=(a||b||c||d);
		
			if(isSet(tr))
				that.stop();
			else{
				stop=true;
				return false;
			}
			that.setLangAttr(e, to, o);
			that.replace(e, tr, o);

			translation.push(tr);
			o.each.call(that, i, that.elements[i], tr, that.source[i], that.from, to, o);
			//'from' will be undefined, if it wasn't set
		})
		
		if(!stop)
			o.complete.call(this, el.end(), el, translation, this.source, this.from, this.to, o);
	},
	
	replace: function(e, t, o){
		if(o.replace===true){
			if(isString(o.subject))
				e.attr(o.subject, t);
			else{
				if(o.from=='ar' || o.to=='ar'){
					if(o.from=='ar')	e.css('direction','ltr');
					if(o.to=='ar')	e.css('direction','rtl');
					if(e.css('text-align')=='right')	e.css('text-align','left');
					if(e.css('text-align')=='left')		e.css('text-align','right');
				}
				
				if(o.altAndVal && is(e[0],'img'))
					e.attr('alt', t);
				else if(o.altAndVal && isInput(e))
					e.val(t);
				else if(is(e[0],'textarea'))
					e.val(t);
				else{
					if(o.rebind===true){
						var k=e.find('*').not('script').clone(true);
						e.html(t);
						this.copyEvents(k, e.find('*'));
					}else
						e.html(t);
				}
			}
		}
	},
	
	setLangAttr: function(e, l, o){
		if(o.setLangAttr===true)
			e.attr('lang', l);
		if(isString(o.setLangAttr))
			e.attr(o.setLangAttr, l);
	},
	
	stripComments: function(t){ return t.replace(/<![ \r\n\t]*(--([^\-]|[\r\n]|-[^\-])*--[ \r\n\t]*)>/g,''); },
	
	truncate: function(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;
	},

	copyEvents: function(from, to){
		to.each(function(i){
			var events=$.data(from[i], 'events');
			if(!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);
		});
	},
	
	stop: function(){
		if(this.stopped)
			return this;
		this.stopped=true;
		this.options.error.call(this, {message:'stopped'});
		return this;
	},
	
	ready: function(fn, that){//sth like $(document).ready()
		if(isReady)//if the API is loaaded
			return fn();
		readyList.push(fn);//else execute it later
		if(isSet(that))//and return the object provided for chaining
			return that;
	},
	
	getLanguages: function(translatable){
		if(!isSet(translatable))
			return GLL;
		translatable={};
		for (var l in GLL)
			if(GL.isTranslatable(GLL[l]))
				translatable[l]=GLL[l];
		return translatable;
	},
	
	toLanguage: function(langCode, format){//accepts both full language and language code
		var lang='UNKNOWN';
		langCode=langCode.toLowerCase();
		for(l in GLL)
			if(GLL[l]==langCode || l==langCode ){lang=l; break;}
		if(format=='lowercase')
			lang=lang.toLowerCase();
		if(format=='capitalize')
			lang=lang.charAt(0).toUpperCase()+lang.substring(1).toLowerCase();
		return lang;
	},
	
	toLanguageCode: function(a){//accepts both full language and language code
		a=a.toLowerCase();
		for(l in GLL)
			if( GLL[l]==a || l==a.toUpperCase() )
				return GLL[l];
	},
		
	isTranslatable: function(l){//accepts both full language and language code
		return GL.isTranslatable(this.toLanguageCode(l));
	},
	
	getBranding: function(a, b){ return $( GL.getBranding(a, b) ); }
	
}

//assign functions to jquery and delay execution if necessary (r=T.fn.ready)
$.fn.translate=function(a, b, c){
	var o=args(a, b, c, true), 
		ncto=$.extend({}, defaults, $.fn.translate.defaults, o,
		{complete:function(e,t){ o.nodes=e; $.translate(t, o); }, each:$fn } );
	
	if(isSet($.fn.nodesContainingText))
		return this.nodesContainingText(ncto);
	o.nodes=this.get();
	return $.translate(o);
}

$.translate=function(t, a, b, c){
	if($.isFunction(t))
		return r(t);
	var that=new T;
	if(!isSet(t))
		return that;
	return r(function(){ return that.translateInit(t, a, b, c); }, that);
}

var defaults={
	limit: 500,
	comments: false,
	start: $fn,
	error: $fn,
	each: $fn,
	complete: $fn,
	onTimeout: $fn,
	timeout: 0,
	from: '',
	to: '',
	nodes: [],
	walk: true,
	returnAll: false,
	replace: true,
	rebind: true,
	data: false,
	setLangAttr: false,
	subject: true,
	not: '',
	altAndVal:true,
	async: false,
	toggle: false
}, GL, GLL, isReady=false, readyList=[], r=T.fn.ready;

$.translate.defaults=$.fn.translate.defaults=defaults;

$.translate.fn=$.translate.prototype=T.fn;

function loaded(){
	GL=T.prototype.GL=google.language;
	GLL=GL.Languages;
	isReady=true;
	$.each(readyList, function(i, fn){ fn(); });
}

function load(){ google.load('language', '1', {'callback' : loaded}); }

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

jsapi();//you can put your Google API key here as the argument, or load it manually before this file

})(jQuery);



//Extensions

///Language Detection
;(function($){

function $fn(){}

$.fn.language=function(o){
	o=o || {};
	var ncto=$.extend( {}, defaults, $.fn.language.defaults, o,
		{complete:function(e,t){ o.nodes=e; $.language(t, o); }, each:$fn, start:$fn, returnAll:true } );
	
	if(typeof $.fn.nodesContainingText!='undefined')
		return this.nodesContainingText(ncto);
	o.nodes=this;
	return $.language(that, o);

}

$.language=function(t, o){
	o=o || {};
	var that=new $.translate;
	if($.isFunction(t))
		return that.ready(t);
	if(typeof t=='undefined')
		return that;
	return that.ready(function(){ return that.detect(t, o); }, that);
}

var defaults={
	start: $fn,
	each: $fn,
	complete: $fn,
	error: $fn,
	setLangAttr: true,
	subject: true,
	limit: 500,
	walk: true,
	returnAll: false,
	not: '',
	altAndVal: false,
	async: false,
	nodes: []
}

$.language.defaults=$.fn.language.defaults=defaults;

$.language.fn=$.language.prototype=$.extend($.translate.fn, {
	detect: function(t, o){
		if(typeof t=='undefined')
			return this;
		this.options=o=$.extend({}, defaults, (o.nodes[0] ? $.fn.language.defaults : $.language.defaults), o);
		
		var that=this, i=0, languageCodes=[], languages=[], results=[], elements=this.elements=o.nodes, isString;
		if(typeof t=='string'){ t=[t]; isString=true; }
		var len=t.length;
		this.text=t;
		this.stopped=false;
		
		o.start.call(this, o.nodes[0] ? o.nodes : t , o);
		
		$.each(t, function(i, v){
			that.GL.detect(v.substring(0, o.limit*1), function(result){
				(function(){
					if(this.stopped)
						return;
					if(result.error){
						if(elements[0])
							return o.error.call(this, result.error, elements[i], v, i, o);
						else
							return o.error.call(this, result.error, v, i, o);
					}
					
					var languageCode=result.language, language=this.toLanguage(languageCode);
					
					this.languageCodes=languageCodes.push(languageCode);
					this.languages=languages.push(language);
					this.results=results.push(result);
					
					//each:
					if(elements[0]){
						var e=elements[i];
						this.setLangAttr($(e), languageCode, o);
												
						o.each.call(this, i, e, v, languageCode, language, result, o);
					}else
						o.each.call(this, i, v, languageCode, language, result, o);
					
					//complete:
					if(i==len-1){
						if(isString)
							return o.complete.call(this, t[0], languageCodes[0], languages[0],  results[0], o);
						else if(elements[0])
							return o.complete.call(this, elements, t, languageCodes, languages, results, o);
						else
							return o.complete.call(this, t, languageCodes, languages,  results, o);
					}
				}).call(that);
			});
		})
		
		return this;
	}
})

})(jQuery);



///Simple user interface
;(function($){
$.extend($.translate.fn, {
	ui: function(a, b, c){
		var str='', cs='', cl='';
		if(c){ cs='<'+c+'>'; cl='</'+c+'>'; }
		$.each( this.getLanguages(true), function(l, lc){
			str+=('<'+b+'>'+cs+l.charAt(0)+l.substring(1).toLowerCase()+cl+'</'+b+'>');
		});
		return $('<'+a+' id="jq-translate-ui">'+str+'</'+a+'>');
	}
});
})(jQuery);
