var Hyphenator=(function(){
	//private properties
	/************ can be changed ************/
	var debug=false;
	var basepath='./scripts/';
	var bookmarklet=false;
	var languages={'de':true,'en':true,'fr':true};
	var prompterStrings={'de':'Die Sprache dieser Webseite konnte nicht automatisch bestimmt werden. Bitte Sprache angeben: \n\nDeutsch: de\tEnglisch: en\tFranz%F6sisch: fr',
						 'en':'The language of these website could not be determined automatically. Please indicate main language: \n\nEnglish: en\tGerman: de\tFrench: fr',
						 'fr':'La langue de cette site ne pouvait pas %EAtre d%E9termin%E9e automatiquement. Veuillez indiquer une langue: \n\nFran%E7ais: fr\tAnglais: en\tAllemand: de'};
	var hyphenateclass='silbentrennung';
	
	/************ don't change! ************/
	var patternsloaded={};
	var preparestate=0; //0: not initialized, 1: loading patterns, 2: ready
	var mainlanguage=null;
	var donthyphenate={'script':true,'code':true,'pre':true,'img':true,'br':true};

	
	/************ UA related ************/
	var zerowidthspace='';
	function _createZeroWidthSpace() {
		var ua=navigator.userAgent.toLowerCase();
		if(ua.indexOf('firefox')!=-1 || ua.indexOf('msie 7')!=-1) {
			zerowidthspace=String.fromCharCode(8203); //UTF zero width space
		}
		/*if(navigator.userAgent.toLowerCase().indexOf('msie 6')!=-1) {
			zerowidthspace='<span style="font-size:0px;"> </span>';
		}*/
	}
	
	function _checkIfBookmarklet() {
		var loc=null;
		var jsArray = document.getElementsByTagName('script');
		for(var i=0; i<jsArray.length; i++) {
			if(!jsArray[i].hasAttribute) {
				jsArray[i].hasAttribute=function(a) {
					return (this.getAttribute(a)!='' && this.getAttribute(a)!=null)?true:false;
				};
			}
			if(jsArray[i].hasAttribute('src')) {
				loc=jsArray[i].getAttribute('src');
			}
			if(!loc) {
				continue;
			} else if(loc.indexOf('Hyphenator.js?bm=true')!=-1) {
				bookmarklet=true;
			}
		}
	};
	
	function _updateState(state) {
		switch(state) {
			case 1:
				var myDiv=document.createElement('div');
				var myStyle=document.createAttribute('style');
				var myId=document.createAttribute('id');
				myStyle.nodeValue='background-color:#000000; opacity:0; position:absolute; top:0px; left:0px; width:100%; height:100%; z-index:10;';
				myId.nodeValue='HyphenatorStatus';
				myDiv.setAttributeNode(myStyle);
				myDiv.setAttributeNode(myId);
				document.getElementsByTagName('body')[0].appendChild(myDiv);
				myDiv=document.getElementById('HyphenatorStatus');
				var opac=0;
				var interval=window.setInterval(function() {
					if(opac>=0.8) {
						myDiv.style.opacity='0.8';
						window.clearInterval(interval);
					} else {
						myDiv.style.opacity=String(opac);
						opac=opac+0.2;
					}
					
				},10);
			break;
			case 2:
				var myDiv=document.createElement('div');
				var myStyle=document.createAttribute('style');
				var myId=document.createAttribute('id');
				var myText=document.createTextNode('loading hyphenation patterns');
				myStyle.nodeValue='background-color:#000000; opacity:1; position:absolute; top:50%; left:40%; text-align:center; font-size:larger; color:#FFFFFF; z-index:11; border:1px solid #FFFFFF; padding:4px;';
				myId.nodeValue='HyphenatorStatusText';
				myDiv.setAttributeNode(myStyle);
				myDiv.setAttributeNode(myId);
				myDiv.appendChild(myText);
				document.getElementById('HyphenatorStatus').appendChild(myDiv);
			break;
			case 3:
				var myText=document.createTextNode('hyphenating text');
				document.getElementById('HyphenatorStatusText').replaceChild(myText,document.getElementById('HyphenatorStatusText').firstChild);
			break;
			case 4:
				myDiv=document.getElementById('HyphenatorStatus');
				var opac=0.8;
				var interval=window.setInterval(function() {
					if(opac<=0.1) {
						myDiv.style.opacity=0;
						myDiv.style.display='none';
						window.clearInterval(interval);
					} else {
						myDiv.style.opacity=String(opac);
						opac=opac-0.2;
					}
				},10);
			break;
			default:
				return;
		}
		
	};
		
	//private methods	
	/************ Language related methods ************/
	function _autoSetMainLanguage() {
		var el=document.getElementsByTagName('html')[0];
		mainlanguage=_getLang(el);
		if(!mainlanguage) {
			var m=document.getElementsByTagName('meta');
			for(var i=0; i<m.length; i++) {
				if(!m[i].hasAttribute) {
					m[i].hasAttribute=function(a) {
						return (this.getAttribute(a)!='' && this.getAttribute(a)!=null)?true:false;
					};
				}
				//<meta http-equiv="content-language" content="xy">	
				if(m[i].hasAttribute('http-equiv') && (m[i].getAttribute('http-equiv')=='content-language')) {
					mainlanguage = m[i].getAttribute('content').substring(0,2);
				}
				//<meta name="DC.Language" content="xy">
				if(m[i].hasAttribute('name') && (m[i].getAttribute('name')=='DC.Language')) {
					mainlanguage = m[i].getAttribute('content').substring(0,2);
				}			
				//<meta name="language" content="xy">
				if(m[i].hasAttribute('name') && (m[i].getAttribute('name')=='language')) {
					mainlanguage = m[i].getAttribute('content').substring(0,2);
				}			
			}
		}
		if(!mainlanguage) {
			var text='';
			var ul=(navigator.language)?navigator.language:navigator.userLanguage;
			ul=ul.substring(0,2);
			if(languages[ul]) {
				text=prompterStrings[ul];
			} else {
				text=prompterStrings.en;
			}
			var lang=window.prompt(unescape(text), ul);
			if(languages[lang]) {
				mainlanguage = lang;
			}
		}
	};

	function _getLang(el) {
		if(!el.hasAttribute) {
			el.hasAttribute=function(a) {
				try {
					return (this.getAttribute(a)!='' && this.getAttribute(a)!=null)?true:false;
				} catch(e) {
					return false;
				}
			};
		}
		if(el.hasAttribute('lang')) {
			return el.getAttribute('lang').substring(0,2);
		}
		if(el.hasAttribute('xml:lang')) {
			return el.getAttribute('xml:lang').substring(0,2);
		}
		if(mainlanguage) {
			return mainlanguage;
		}
		return null;
	};

	/************ pattern (loading) related methods ************/
	function _loadPatterns(lang) {
		if(debug)
			window.console.log("load patterns "+lang);
		if(languages[lang] && !patternsloaded[lang]) {
			var url=basepath+'patterns/'+lang+'.js';
		} else {
			return;
		}
		if(document.createElement) {
			var head=document.getElementsByTagName('head').item(0);
			var script=document.createElement('script');
			script.src=url;
			script.type='text/javascript';
			head.appendChild(script);
		}
		if(debug)
			window.console.log('Loading '+url);
	};

	/************ init methods ************/
	function _autoinit() {
		for(var lang in languages) {
			patternsloaded[lang]=false;
		}
		_autoSetMainLanguage();
		_createZeroWidthSpace();
		_checkIfBookmarklet();
	};
	/************ hyphenate helper methods ************/
	function _runHyphenation(min,hyphen) {
//		_updateState(3);
		var body=document.getElementsByTagName('body')[0];
		if(Hyphenator.isBookmarklet()) {
			Hyphenator.hyphenateElement(body,min,hyphen);
		} else {
			var elements=body.getElementsByTagName('*');
			for(var i=0; i<elements.length; i++)
			{
//				SK: Abbruch wenn Benutzer Maus drueckt...
//				if (userabortedHyphenation!=true){
					if(elements[i].className==hyphenateclass) {
						Hyphenator.hyphenateElement(elements[i],min,hyphen);
					}
//				}
			}
		}
//		_updateState(4);
	};

	_autoinit();
	return {
		//public properties
		patterns:{},
		//public methods
		isPatternLoaded: function(lang) {
			return patternsloaded[lang];
		},
		updatePatternsLoadState:function(lang,bool) {
			patternsloaded[lang]=bool;
		},
		isBookmarklet: function() {
			return bookmarklet;
		},
		prepare: function() {
//			_updateState(1);
			if(debug)
				window.console.log("preparing-state: 1 (loading)");
			preparestate=1;
			var languages={};
			languages[mainlanguage]=true;
			var root=document.getElementsByTagName('body')[0];
			var elements=root.getElementsByTagName('*');
			var lang=null;
			for(var i=0; i<elements.length; i++) {
				if((lang=_getLang(elements[i])) && !languages[lang]) {
					languages[lang]=true;
				}
			}
			if(debug) {
				for(var l in languages) {
					window.console.log("language found: "+l);
				}
			}
			for(lang in languages) {
				_loadPatterns(lang);
			}
//			_updateState(2);
			interval=window.setInterval(function(){
				finishedLoading=false;
				for(lang in languages) {
					if(!patternsloaded[lang]) {
						finishedLoading=false;
						break;
					} else {
						finishedLoading=true;
					}
				}
				if(finishedLoading) {
					window.clearInterval(interval);
					preparestate=2;
					if(debug)
						window.console.log("preparing-state: 2 (loaded)");
				}
			},100);

		},
		hyphenateDocument: function(min,hyphen) {
			if(debug)
				window.console.log("hyphenateDocument");
			if(!min) {
				var min=7 ;								//kuerzere Woerter nicht trennen
			}
			if(!hyphen) {
				var hyphen=String.fromCharCode(173);	//Default-Trennzeichen ist '&shy;'
			}
			if(preparestate!=2) {
				if(preparestate==0) {
					Hyphenator.prepare();
				}
				var interval=window.setInterval(function(){
					if(preparestate==2) {
						window.clearInterval(interval);
						_runHyphenation(min,hyphen);
					}
				},10);
			} else {
				_runHyphenation(min,hyphen);
			}
		},
		hyphenateElement : function(el,min,hyphen,lang) {
			if(debug)
				window.console.log("hyphenateElement: "+el.tagName+" id: "+el.id);
			if(!min) {
				var min=6;								//kuerzere Woerter nicht trennen
			}
			if(!hyphen) {
				var hyphen=String.fromCharCode(173);	//Default-Trennzeichen ist '&shy;'
			}
			if(!lang) {
				if(debug)
					window.console.log("lang not set");
				var lang=_getLang(el);
				if(debug)
					window.console.log("set lang to "+lang);
			} else {
				if(debug)
					window.console.log("got lang from parent ("+lang+")");
				var newlang=_getLang(el);
				if(newlang!=lang) {
					var lang=newlang;
					if(debug)
						window.console.log("but element has own lang ("+lang+")");
				}
			}
			if(debug)
				window.console.log("language: "+lang);
			var cn=el.childNodes;
			for(var i=0; i<cn.length; i++) {
				if(cn[i].nodeType==3) {					//typ 3=#text -> Trennen
					var w=cn[i].data.split(' ');
					var reg=/((ftp|http|https):\/\/)+(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))+/i;
					//       |      protocol        |  [user:password@host:port]   |           path             |
					for(var j=0; j<w.length; j++) {
						if(reg.test(w[j])) {
							w[j]=Hyphenator.hyphenateURL(w[j]);
						} else if(w[j].indexOf('-')!=-1) {		//Komposita oder manuell getrennt
							var w2=w[j].split('-');
							for(var k=0; k<w2.length; k++) {
								w2[k]=Hyphenator.hyphenateWord(lang,w2[k],hyphen);
							}
							w[j]=w2.join('-'+zerowidthspace);
						} else if(w[j].length>=min && w[j].indexOf(String.fromCharCode(173))==-1) {	//UTF #173 ist &shy;
							w[j]=Hyphenator.hyphenateWord(lang,w[j],hyphen);
						}
					}
					cn[i].data=w.join(' ');
				} else if(cn[i].nodeType==1 && !donthyphenate[cn[i].nodeName.toLowerCase()]) {			//typ 1=Elementknoten -> Rekursion
					Hyphenator.hyphenateElement(cn[i],min,hyphen,lang);
				}
			}
		},
		hyphenateWord    : function(lang,word,hyphen,leftmin,rightmin) {
			if(debug)
				window.console.log("hyphenateWord: "+word);
			var positions = new Array(); 		//Trennstellen
			var result = new Array();			//Array mit Silben
			if(!leftmin) {
				var leftmin=2;					//minimale Silbengroesse am Wortanfang
			}
			if(!rightmin) {
				var rightmin=3;					//minimale Silbengroesse am Wortende
			}
			var w='_'+word.toLowerCase()+'_';	//Anfang und Ende markieren
			for(var i=0; i<w.length; i++) {
				positions[i]=0;
			}
			for(var s=0; s<w.length; s++) {		//Buchstabe um Buchstabe durch das Wort
				var maxl=w.length-s;
				for(var l=1; l<=maxl; l++) {	//Wortteil vergroessern
					var part=w.substring(s).substring(0,l);	//Wortteil ab Position s mit Laenge l
					var values=null;
					if((values=Hyphenator.patterns[lang][part])!=null) {		//Werte aus der Liste holen, falls vorhanden
						var i=s;
						for(var p=0; p<values.length; p++) {
							if(parseInt(values.charAt(p))>positions[i]) {
								positions[i]=parseInt(values.charAt(p)); //Werte eintragen
							}
							i++;
						}
					}
				}
			}
			//Die Markierungen (_) entfernen, weil wir jetzt mit 'word' arbeiten. 
			positions.pop();
			positions.shift();
			for(i=0; i<word.length; i++) {
				if(parseInt(positions[i])%2 != 0 && i!=0 && i>=leftmin && i<=word.length-rightmin) {
					result.push(word.substring(result.join('').length,i)); //Silben eintragen
				}
			}
			result.push(word.substring(result.join('').length,i)); //Letzte Silbe eintragen
			if(hyphen=='&shy;') {
				hyphen=String.fromCharCode(173);
			}
			return result.join(hyphen);
		},
		hyphenateURL: function(url){
			var parts=url.split('/');
			return parts.join('/'+String.fromCharCode(8203));
		}
		
	};
})();
if(Hyphenator.isBookmarklet()) {
	Hyphenator.hyphenateDocument(6);
}