// ==UserScript==
// @name           GC-Vote
// @namespace      http://dosensuche.de
// @include        http*://www.geocaching.com/seek/cache_details.aspx?*
// @include        http*://www.geocaching.com/my/*
// @include        http*://www.geocaching.com/map*
// @include        http*://www.geocaching.com/seek/nearest.aspx*
// @include        http*://www.geocaching.com/seek/gmnearest.aspx*
// @include        http*://www.geocaching.com/seek/log.aspx?*
// @include        http*://www.geocaching.com/seek/cdpf.aspx?*
// @include        http*://www.geocaching.com/bookmarks/view.aspx?*
// @include        http://*dosensuche.de/GCVote*
// @description    displays average votes and lets users vote for the quality of caches on geocaching.com
// ==/UserScript==
//
// Author: guido.wegener@gmx.de
// Version 2.1a - czech traslate beta tested
//
//Czech Translation by sHpy00n

var version="2.1c";

var voteServerBase="http://dosensuche.de/GCVote"; // connection to server
var GETVOTES=voteServerBase+"/getVotes.php";
var SETVOTE=voteServerBase+"/setVote.php";
var LISTVOTES=voteServerBase+"/listUserVotes.php";
var CHANGEPASSWORD=voteServerBase+"/changePassword.php";
var GCVoteAdvertisementDefault = "\n(Rated %%% stars with [url=http://www.gcvote.com]GCVote[/url])";
// This string is just a default and is only used for the first install.
// "%%%" will be replaced by your selected vote and the resulting string is written to the log.

var LOGGING=getLogging();
var HALFSTARS=getHalfstars();
var SORTSIDEBAR=getSortSidebar();

var logInLink;
var userName;
var unescapedUserName;
var loggedIn;
var securityState;
var translations;

log("start");
init();
if(document.URL.search("dosensuche.de\/GCVote")>=0) displayVersionInfo();
else if(!document.getElementById("ctl00_SiteContent_lblSubmitErrorInfo")) {
	if(document.getElementById("ctl00_LoginUrl")) logInLink=document.getElementById("ctl00_LoginUrl");
	if(document.getElementById("Header1_urlLogin")) logInLink=document.getElementById("Header1_urlLogin");
//	if(!logInLink) displayMessage("Unexpected HTML, please update GCVote at http://userscripts.org/scripts/show/14849");
	if(!logInLink || !logInLink.parentNode.getElementsByTagName("a")[1]) userName=null;
	else {userName=logInLink.parentNode.getElementsByTagName("a")[0].firstChild.nodeValue;}
//if(!logInLink.previousSibling.previousSibling) userName=null;
//else {userName=logInLink.previousSibling.previousSibling.firstChild.nodeValue;}

	log("userName="+userName+"  escaped:"+encodeURIComponent(userName));
	unescapedUserName=userName;
	if(userName) userName=encodeURIComponent(userName);

	if(userName && document.URL.search("www\.geocaching\.com\/my\/")>=0) {insertGCVoteMenu();}
	if(document.URL=="http://www.geocaching.com/my/owned.aspx" || document.URL=="http://www.geocaching.com/seek/nearest.aspx?u="+userName) {userName=null;}
	if(document.URL.search("cache_details\.aspx")>=0) {pageType="details";initDetailsPage();}
	else if(document.URL.search("cdpf\.aspx")>=0) {pageType="print";initPrintPage();}
	else if(document.URL.search("logs\.aspx")>=0 || document.URL.search("owned\.aspx")>=0) {pageType="loglist";initListPage();}
	else if(document.URL.search("www.geocaching.com\/map")>=0) {pageType="gmnearestlist";initGMListPage();}
	else if(document.URL.search("nearest\.aspx")>=0) {pageType="nearestlist";initListPage();}
	else if(document.URL.search("\/my\/$")>=0 || document.URL.search("\/my\/#")>=0 || document.URL.search("\/my\/[dD]efault\.aspx")>=0) {pageType="overviewlist1";initListPage();}
	else if(document.URL.search("\/my\/geocaches\.aspx")>=0) {pageType="overviewlist2";initListPage();}
	else if(document.URL.search("\/log\.aspx")>=0) {pageType="logedit";initLogEditPage();}
	else if(document.URL.search("\/bookmarks\/view\.aspx")>=0) {pageType="bookmarks";initListPage();}
	else if(document.URL.search("\/my\/watchlist\.aspx")>=0) {pageType="watchlist";userName=null;initListPage();}
}

function init() {
	translations=[
	
"\n(Rated %%% stars with [url=http://www.gcvote.com]GCVote[/url])",["\n(%%% Sterne bei [url=http://www.gcvote.com]GCVote[/url])","\nJ'ai donné %%% à cette cache grâce à [url=http://www.gcvote.com]GCVote[/url]","\n (Uděleno %%% hvězdiček prostřednictvím [url=http://www.gcvote.com]GCVote[/url])"],

"Unable to get votes from server! Errorcode ",["Fehler bei der Server-Abfrage: ","Impossible de récupérer les cotes sur le serveur! Code d'erreur :","Chyba při získávání hodnocení ze serveru! ErrorCode:"],

"Your Account is password protected and you supplied no or the wrong password. If you did not register a password, please inform me: guido.wegener@gmx.de",["Dein Account ist mit einem Passwort geschützt und Du hast kein oder ein falsches Passwort angegeben.","Ce compte est protégé par mot de passe","Nevyplněné, nebo chybné heslo. V případě potíží mne kontaktujte: guido.wegener@gmx.de"],

"Unable to send vote to server! Errorcode",["Fehler beim Speichern der Bewertung: ","Impossible d'envoyer votre cote sur le serveur! Code d'erreur :","Chyba při ukládání hodnocení na server! ErrorCode:"],

"Average (mean) ",["Durchschnitt (Mittel) ","Moyenne ","Průměr (střední) "],

" your vote: ",[" Deine Bewertung: "," votre cote: ","mé hodnocení: "],

"no vote",["unbewertet","aucune cote","nehodnoceno"],

"1: poor",["1: schlecht","1: perte de temps","1: nevyhovující odpad!"],

"1.5: worthless",["1,5: lohnt nicht","1,5: sans intérêt","1,5: bezcenná"],

"2: not good",["2: unschön","2: sous la moyenne","2: dík za bod"],

"2.5: ok",["2,5: ok","2,5: pas si mal","2,5: OK"],

"3: average",["3: durchschnittlich","3: moyenne","3: stojí za návštěvu"],

"3.5: better",["3,5: besser","3,5: pas mal du tout","3,5: lepší průměr"],

"4: good",["4: gut","4: plus plaisante que la moyenne","4: velmi dobrá"],

"4.5: near perfect",["4,5: fast perfekt","4,5: vraiment intéressante","4,5: skvělá"],

"5: great",["5: großartig","5: à faire absolument","5: zlatý fond"],

"Insert GCVote Info",["GCVote-Info-Text einfügen","Ajouter signature GCVote", "Vložit notifikaci GCVote"],

"Distribution of votes:",["Verteilung der Bewertungen:","Distribution des votes","Rozdělení hodnocení :"],

"Couldn't find entry tag for inserting GCVote configuration window. Maybe the geocaching.com website has been changed. Please have a look on http://gcvote.com and check for possibly released GCVote updates.",["Unerwartetes HTML gefunden. Probiere mal aus, die Seite neu zu laden oder schau auf http://gcvote.com nach, ob es schon eine neue Version gibt.","Couldn't find entry tag for inserting GCVote configuration window. Maybe the geocaching.com website has been changed. Please have a look on http://gcvote.com and check for possibly released GCVote updates.","Nelze zobrazit okno nastavení GCVote. Možná že došlo ke změně  internetových stránek geocaching.com. Prosím zkontrolujte aktualizaci na http://gcvote.com."],

"hide config",["Menü verstecken","cacher config","skrýt nastavení"],

"show config",["Menü einblenden","voir config","zobrazit nastavení"],

"GCVote Configuration",["GCVote Konfiguration","Configuration GCVote","Nastavení GCVote"],

"Update GCVote",["Update GCVote","Mettre à jour GCVote","Aktualizace GCVote"],

"Homepage",["Homepage","Site web GCVote","Homepage GCVote"],

"List my votes",["meine Bewertungen","Voir mes votes","Seznam mých hodnocení"],

"Change password",["Passwort ändern","Changer mot de passe","Změna hesla"],

"Password:",["Passwort:","Mot de passe","Heslo"],

"passwords must be registered via GC.com-mail to BonnerGuido",["Passwörter müssen per GC.com-Mail an BonnerGuido registriert werden","Les mots de passe doivent être enregistrés auprèes de l'utilisateur BonnerGuido via le site geocaching.com","heslo musí být registrováno prostřednictvím e-mailu kačeru BonnerGuido z gc.com"],

"Template:",["Mustertext","Signature","Šablona"],

"GCVote info string to insert into logs",["GCVote-Informationstext, der bei Logs eingefügt werden soll","Texte à ajouter dans un log seulement lorsque vous appuyer sur le bouton prévu à cet effet","vloží do logu tuto informaci o hodnocení keše prostřednictvím GCVote"],

"Minimum vote count:",["Minimum Stimmenanzahl:","Compte minimum de cotes:","Minimální počet hlasů: "],

"display stars only for caches with more than X votes",["nur Sterne anzeigen, wenn mehr als X Bewertungen vorhanden sind","montrer les cotes seulement pour les caches qui ont plus de X cotes","zobrazit jen keše s počtem hodnocení vyšším než x"],

"Average calculation:",["Durchschnittsberechnung:","Méthode du calcul moyen:","Způsob půměrování: "],

"how the number of displayed stars should be calculated",["Berechnungsmethode für die Sterne","la façon dont les cotes sont calculées","způsob průměrování pro výpočet zobrazených hvězdiček"],

"Mean",["Durchschnitt","Moyenne","Aritm. průměr"],

"arithmetic mean of all votes for the cache",["arithmetisches Mittel der Bewertungen","calcul de la moyenne selon toutes les cotes","aritmetický průměr všech udělených hodnocení"],

"Median",["Median","Médiane","Střední hodn."],

"median ignores unusual votes",["Der Median ignoriert ungewöhnliche Bewertungen","valeur médiane ignore les cotes exagérées","pro výpočet střední hodnoty nebudou započítána krajní hodnocení"],

"save changes",["Änderungen speichern","Enregistrer","Uložit nastavení"],

"Language:",["Sprache:","Langage:","Jazyk: "],

"language for GCVote",["Sprache in GCVote","Langue d'affichage de ce module","jazyk pro GCVote"],

"English",["Englisch","Anglais","Anglicky"],

"German",["Deutsch","Allemand","Německy"],

"enable logging",["Fehler-Log","aide au déboguage","povolit protokolování"],

"write debugging information to the error console",["zusätzliche Meldungen in die Fehler-Konsole schreiben","écrit l'information de déboguage à la console","zaznamenává hlášení do chybové konzole"],

"sorted sidebar",["Karte sortieren","tri selon les cotes","řazení"],

"sort caches on the map page according to their ratings",["Caches in der Liste auf der Karte nach Bewertung sortieren","affiche les caches triées selon leur cote","seřadí keše na stránce mapy podle jejich ohodnocení"],

"half stars",["halbe Sterne","demie-étoile","povolit půlhvězdy"],

"enable ratings 1.5, 2.5, 3.5 and 4.5",["auch halbe Sternchen vergeben","permet de donner des cotes et demi","povolit hodnocení půlhvězdamii, tedy 1.5, 2.5, 3.5 a 4.5"],

"?",["?","?","?"],

" out of 5",[" von 5"," sur 5"," z 5"],

"password active",["Passwort aktiviert","mot de passe actif","heslo je aktivované"],

"Help",["Hilfe","Aide","Nápověda"],

"Quality",["Qualität","Appréciation","Hodnocení"],

"French",["Französisch","Français","Francouzsky"],

"Czech",["Czech","Czech","Česky"],

"compact layout",["kompaktes Layout","format compact","kompaktní zobrazení"],

"improve GCVote's layout for small screens",["kompakteres Layout für kleine Bildschirme","Format compact pour les petits écrans","kompaktní zobrazení pro monitory s nízkým rozlišením obrazovky"]
	];
	return;
}

function displayMessage(message) {
	// display message on page or as alert
	log("displayMessage "+message);
    var messageBox=document.getElementById("GCVoteMessage");
    if(!messageBox) {
		var cont;
		if(document.getElementById("CacheName")) cont=document.getElementById("CacheName").parentNode.parentNode.parentNode;
		else if(document.getElementById("ctl00_ContentBody_SearchResultText")) cont=document.getElementById("ctl00_ContentBody_SearchResultText").parentNode.parentNode;
		else if(document.getElementById("__VIEWSTATE")) cont=document.getElementById("__VIEWSTATE").parentNode.parentNode;
		else if(document.getElementById("ctl00_Breadcrumbs")) cont=document.getElementById("ctl00_Breadcrumbs").parentNode.parentNode;
		messageBox=document.createElement("div");
		messageBox.id=("GCVoteMessage");
		setStyle(messageBox,"border-width:2px;border-style:solid");
		messageBox.innerHTML="<b>GCVote</b>";
		if(!cont || !cont.firstChild) {
			GM_log("Unknown XML on page named "+document.title);
			if(document.title.substr(0,10)=="Geocaching")
				alert("GCVote: Please update at http://userscripts.org/scripts/show/14849 or http://gcvote.com");
		}
		cont.insertBefore(messageBox,cont.firstChild);
	}
	messageBox.innerHTML+="<p>"+message+"</p>";
	window.scrollTo(0,0);
}

function setVote(cacheId,vote) {
	// highlight user's vote
	log("setVote "+cacheId+" -> "+vote);
	for(var i=0;i<=5;i+=HALFSTARS?0.5:1) {
		var voteLink=document.getElementById("GCVoteLink"+cacheId+"="+i);
		var style;
		if(vote==i) {
			if(vote==0) {style="background-color:#00c800;font-weight:normal";}
			else {style="background-color:orange;font-weight:normal";}
		}
		else {style="font-weight:normal"};
		if(voteLink!=null) {setStyle(voteLink,style)}
	}
};

function initDetailsPage() {
	// on load of detail pages
	log("initDetails "+pageType);
	var ref=document.getElementById("ctl00_LoginUrl").getAttribute("href");
	var regexp=/%3fguid%3d([^%]*)/;
	regexp.exec(ref);
	cacheId=RegExp.$1;
	if(!cacheId) {
		ref=document.getElementById("ctl00_ContentBody_lnkPrintFriendly").getAttribute("href");
		regexp=/\?guid=(.*)/;
		regexp.exec(ref);
		cacheId=RegExp.$1;
	}
	var wp=document.getElementById("ctl00_cacheCodeWidget").getElementsByTagName("p")[0].firstChild.data.replace(/\s/g,"");
	requestVote(cacheId,wp);
}

function initPrintPage() {
	// on load of printer friendly pages
	log("initPrintPage "+pageType);
	var ref=document.getElementById("Form1").getAttribute("action");
	var regexp=/guid=([^%]*)/;
	regexp.exec(ref);
	cacheId=RegExp.$1;
	log("ref="+ref+"   id="+cacheId);
	requestVote(cacheId);
}

function initLogEditPage() {
	// on load of "edit log"  pages
	log("initEdit "+pageType);
	var ref=document.getElementById("ctl00_ContentBody_LogBookPanel1_WaypointLink").getAttribute("href");
	var regexp=/\?guid=([^%]*)/;
	regexp.exec(ref);
	cacheId=RegExp.$1;
	requestVote(cacheId);
}

function myUpdateSideBarList() {
	log("updatesidebar");
	unsafeWindow.GCVoteOriginalUpdateSideBarList();
	simClick();
}

function updateSideBarListListener() {
	log("updatesidebarlistener");
	var waypoints=new Array();
	var sidebar = document.getElementById('cacheListBody');
	var lis=sidebar.getElementsByTagName("a");
	for (var i=0, l=lis.length; i<l; i++) {
		var li=lis[i];
		var link=li.getAttribute("href");
		var regexp=/wp=(\w*)/;
		regexp.exec(link);
		waypoint=RegExp.$1;
		waypoints[i]=waypoint;
		var span=document.createElement("span");
		span.id="td"+waypoint;
		var target=li.parentNode.parentNode.nextSibling;
		target.appendChild(span);
	}
	requestVotesForWaypoints(waypoints);
}

function simClick() {
	var input=document.getElementById("hiddenTriggerInput");
	var event=document.createEvent("MouseEvents");
	event.initEvent("click", true, false);
	input.dispatchEvent(event);
}

function initGMListPage() {
	log("initMap "+pageType);
	if(typeof(unsafeWindow)=="undefined") return;
	unsafeWindow.GCVoteOriginalUpdateSideBarList=unsafeWindow.updateSideBarList;
	unsafeWindow.updateSideBarList=myUpdateSideBarList;
	var input=document.createElement("input");
	input.id="hiddenTriggerInput";
	addEvent(input,"click",function() {setTimeout(function() {updateSideBarListListener();},0)});
	input.setAttribute("type","hidden");
	document.getElementById("aspnetForm").appendChild(input);
//	document.getElementById("aspnetForm").appendChild(document.createElement('script')).innerHTML=
//		"GCVoteOriginalUpdateSideBarList=updateSideBarList;updateSideBarList=function() {GCVoteOriginalUpdateSideBarList();simClick();};";
//	document.body.appendChild(document.createElement('script')).innerHTML=simClick.toString();
}

function initListPage() {
	// on load of pages containing lists of caches
	log("initList "+pageType);
	var anchors=document.getElementsByTagName('a');
	var reg=/cache_details\.aspx\?guid=([^&]*)/;
	var regTrack=/track\/details\.aspx\?guid=/;
	var cacheIds=new Array();
	var cacheDone=new Object();
	var ignoreNextLink=false;

   // create table header entry "QUALITY"
    {
        if(pageType=="bookmarks") {
            var tableHeaderRow=document.getElementById("ctl00_ContentBody_ListInfo_cboItemsPerPage").parentNode.parentNode;
            var qualityHeader=document.createElement("th");
            qualityHeader.appendChild(document.createTextNode(tl("Quality")));
            tableHeaderRow.appendChild(qualityHeader);
        }
        else if(pageType=="nearestlist") {
            var headers=document.getElementsByTagName("th");
            var tableHeaderRow=headers[0].parentNode;
            var qualityHeader=document.createElement("th");
            qualityHeader.setAttribute("scope","col");
            qualityHeader.appendChild(document.createTextNode(tl("Quality")));
            tableHeaderRow.appendChild(qualityHeader);
        }
        else if(pageType=="loglist") {
            var headers=document.getElementsByTagName("th");
            // logs.aspx has no table headers!
            if(headers.length!=0)
            {
                var tableHeaderRow=headers[0].parentNode;
                var qualityHeader=document.createElement("th");
                qualityHeader.setAttribute("scope","col");
                qualityHeader.appendChild(document.createTextNode(tl("Quality")));
                tableHeaderRow.appendChild(qualityHeader);
            }
        }
    }
        
	for(var i=0;i<anchors.length;i++) { // check all links
		var a=anchors[i];
		if(ignoreNextLink) {ignoreNextLink=false;continue;}
		if(reg.exec(a.href)) { // anchor is a link to a cache
			var cacheId=RegExp.$1;
			if(cacheDone[cacheId]>0) continue; // only one control per cache
			if(pageType=="overviewlist1" && (a.parentNode.tagName=="LI")) {
				continue; // cache is part of list of unpublished caches
			}
			cacheDone[cacheId]=1;
			cacheIds.push(cacheId);
			log("found cache "+cacheId);
			var target=document.createElement("td"); // create container for control
			target.id="td"+cacheId;
			setStyle(target,"text-align:left");
			if(pageType=="overviewlist1")
				a.parentNode.parentNode.appendChild(target);
			if(pageType=="loglist" || pageType=="nearestlist") {
				var tr=a.parentNode.parentNode;
				if(tr.tagName!="TR") {tr=tr.parentNode;}
				tr.appendChild(target);
			}
			if(pageType=="watchlist") {
				var tr=a.parentNode.parentNode;
				if(tr.tagName!="TR") {tr=tr.parentNode;}
				tr.appendChild(target);
			}
			if(pageType=="bookmarks") {
                // One bookmark list entry spans two rows!
                target.setAttribute("rowspan", "2");
                a.parentNode.parentNode.appendChild(target);
            }
			if(pageType=="overviewlist2" && a.parentNode.parentNode.tagName=="TR") {
				a.parentNode.parentNode.replaceChild(target,a.parentNode.parentNode.getElementsByTagName("td")[2]);
			}
		}
		else if(regTrack.exec(a.href)) {ignoreNextLink=true;}
	}
	requestVotes(cacheIds);
}

function parseXML(xmlString) {
	// callback for XML containing the requested votes
	log("parseXML: "+xmlString);
	xmlDoc = getXmlDoc(xmlString);
	var messages=xmlDoc.getElementsByTagName("message");
	for(var i=0;i<messages.length;i++) {
		var message=messages[i].firstChild.nodeValue;
		displayMessage(message);
	}
	var rootNodes=xmlDoc.getElementsByTagName("votes");
	if(rootNodes) {
		var rootNode=rootNodes[0];
		var currentVersion=rootNode.getAttribute("currentVersion");
		if(currentVersion!=version) {
			var upd=document.getElementById("GC-Vote-update");
			
			// changed by Odilbert for better style
			if(upd) {setStyle(upd,"padding:5px; background-color:#ffe0c8");showConfig();}
		}
		securityState=rootNode.getAttribute("securityState");
		loggedIn=rootNode.getAttribute("loggedIn")=="true";
		log("cv="+currentVersion+" ss="+securityState+" li="+loggedIn);
		if(securityState=="locked") {
			var pwd=document.getElementById("GCVotePasswordActive");
			
			// changed by Odilbert for better style
			if(pwd) setStyle(pwd,"vertical-align:middle");
		}
		if(securityState=="locked" && !loggedIn) {showConfig();}
	}
	var votes=xmlDoc.getElementsByTagName("vote");
	var mapdivs=new Array();
	if(pageType=="gmnearestlist") {
		var divs=document.getElementsByTagName("DIV");
		var mapdiv;
		for(var i=0;i<divs.length;i++) {
			if(divs[i].className=="LabeledMarker_markerLabel") {mapdiv=divs[i];break;}
		}
		if(mapdiv) {
			var divs=mapdiv.parentNode.childNodes;
			var re=/\((\w+)\)\s*$/;
			for(var i=0;i<divs.length-1;i+=2) {
				if(divs[i].getElementsByTagName("span").length>0) {
					divs[i].removeChild(divs[i].getElementsByTagName("span")[0]);
				}
				re.exec(divs[i+1].title);
				var wp=RegExp.$1;
				mapdivs[wp]=divs[i];
			}
		}
	}
	for(var i=0;i<votes.length;i++) {
		var vote=votes[i];
		var userName=vote.getAttribute("userName");
		var cacheId=vote.getAttribute("cacheId");
		var voteAvg=vote.getAttribute("voteAvg");
		var voteStars=vote.getAttribute(getStarAttributeName());
		var voteCnt=vote.getAttribute("voteCnt");
		var voteUser=vote.getAttribute("voteUser");
		var waypoint=vote.getAttribute("waypoint");
        var vote1=vote.getAttribute("vote1");
        var vote2=vote.getAttribute("vote2");
        var vote3=vote.getAttribute("vote3");
        var vote4=vote.getAttribute("vote4");
        var vote5=vote.getAttribute("vote5");
		var span;
		if(pageType=="gmnearestlist") {
			if(waypoint && Number(voteCnt)>=getThreshold()) {
				var td=document.getElementById("td"+waypoint);
				if(td.getElementsByTagName("span").length>0) {
					td.removeChild(td.getElementsByTagName("span")[0]);
				}
				span=getSmallVoteSpan(cacheId,voteStars,voteAvg,voteCnt,voteUser);
				td.appendChild(span);
				td.parentNode.parentNode.setAttribute("GCVote_stars",voteStars);
				if(!mapdivs || !mapdivs[waypoint]) continue;
				mapdivs[waypoint].appendChild(getSmallVoteSpan(cacheId,voteStars,voteAvg,-voteCnt,voteUser));
			}
			continue;
		}
		else span=getNewSpan(cacheId,voteStars,voteAvg,voteCnt,voteUser, vote1, vote2, vote3, vote4, vote5);
		var replace=false; // replace existing control or generate new one
		if(document.getElementById("GCVoteLink"+cacheId+"=1") && document.getElementById("GCVoteLink"+cacheId+"=1").firstChild) {replace=true;}
		if(pageType=="details") {
			var hidden=document.getElementById("ctl00_ContentBody_DateHidden");
			if(!hidden) hidden=document.getElementById("ctl00_ContentBody_Difficulty");
//			if(replace) hidden.parentNode.replaceChild(span,hidden.parentNode.childNodes[3]);
//			else hidden.parentNode.insertBefore(span,hidden.parentNode.childNodes[3]);
			if(replace) {log("replace");hidden.parentNode.replaceChild(span,hidden.parentNode.getElementsByTagName("div")[0]);}
			else hidden.parentNode.insertBefore(span,hidden.parentNode.getElementsByTagName("br")[0]);
		}
        else if(pageType=="logedit") {
        	var oldtr=document.getElementById("GCVote-logedit");
        	if(oldtr) {oldtr.parentNode.removeChild(oldtr);}
            var comment=document.getElementById("divComment");
            var newdiv=document.createElement("div");
            comment.parentNode.insertBefore(newdiv,comment);
            fillLogEditTR(newdiv,span,voteUser);
        }           
        else if(pageType=="print") {
        	var bd=document.getElementById("bd");
        	setStyle(span,"display:inline;float:right");
	       	setStyle(span.firstChild,"display:inline");
        	bd.getElementsByTagName("p")[7].appendChild(span);
        }           
		else {
			var td=document.getElementById("td"+cacheId);
			if(!td) {log("parseXML could not find td"+cacheId);continue;}
			if(replace) td.replaceChild(span,td.lastChild);
			else td.appendChild(span);
		}
		setVote(cacheId,voteUser);
	}
	if(pageType=="gmnearestlist" && SORTSIDEBAR) {
		var cacheList=document.getElementById("cacheListBody");
		var list=cacheList.getElementsByTagName("TR");
		var arr=new Array();
		log("Sidebar length: "+list.length);
		for(var i=0;list.length;i++) {
			arr[i]=list[0];
			cacheList.removeChild(list[0]);
		}
		arr.sort(function (a,b) {return b.getAttribute("GCVote_stars")-a.getAttribute("GCVote_stars");});
		for(var i=0;i<arr.length;i++) {
			cacheList.appendChild(arr[i]);
		}
		log("sorted");
	}
}

function requestVote(cacheId) {
	// request vote for a single cache
	requestVote(cacheId,null);
}

function requestVote(cacheId,waypoint) {
	// request vote for a single cache
	log("requestVote "+cacheId);
	var cacheIds=new Array(cacheId);
	requestVotes(cacheIds,waypoint);
}

function requestVotes(cacheIds) {
	// request votes for a number of caches
	requestVotes(cacheIds,null);
}

function requestVotes(cacheIds,waypoint) {
	// request votes for a number of caches
	log("requestVotes");
	var user=userName;
	if(!user) user="uglyDUMMYusernamesolution";
	var dataString="version="+version+"&userName="+user+"&cacheIds="+cacheIds+"&password="+encodeURIComponent(getPassword());
	if(waypoint) {
		dataString+="&waypoint="+waypoint;
		log(waypoint);
	}
	GM_xmlhttpRequest({
	method: 'POST',
	headers: {'Content-type':'application/x-www-form-urlencoded; charset=UTF-8'},
	data: dataString,
	url: GETVOTES,
	onload: function(responseDetails) {
		parseXML(responseDetails.responseText);
	},
	onerror: function(responseDetails) {
		alert(tl("Unable to get votes from server! Errorcode ")+responseDetails.status);
	}
	});
}

function requestVotesForWaypoints(waypoints) {
	// request votes for a number of caches identified by waypoints
	log("requestVotesForWaypoints");
	var user=userName;
	if(!user) user="uglyDUMMYusernamesolution";
	GM_xmlhttpRequest({
	method: 'POST',
	headers: {'Content-type':'application/x-www-form-urlencoded; charset=UTF-8'},
	data: "version="+version+"&userName="+user+"&waypoints="+waypoints+"&password="+encodeURIComponent(getPassword()),
	url: GETVOTES,
	onload: function(responseDetails) {
		parseXML(responseDetails.responseText);
	},
	onerror: function(responseDetails) {
		alert(tl("Unable to get votes from server! Errorcode ")+responseDetails.status);
	}
	});
}

function sendVote(cacheId,voteUser) {
	// send vote for cache with unknown waypoint to server
	log("sendVote "+cacheId+" -> "+voteUser);
sendVoteWaypoint(cacheId,null,voteUser);
/*	var url="http://www.geocaching.com/seek/cache_details.aspx?guid="+cacheId;
	GM_xmlhttpRequest({
	method: 'GET',
	headers: {'Content-type':'application/x-www-form-urlencoded; charset=UTF-8'},
	url: url,
	onload: function(responseDetails) {
		var lines=responseDetails.responseText.split("\n");
		var foundtitle=false;
		for(var i=0;i<lines.length;i++) {
			var line=lines[i];
			if(!foundtitle) {
				if(line.search("<title>")!=-1) {
					foundtitle=true;
				}
			}
			else {
				var regexp=/\s*(\w*)/;
				regexp.exec(line);
				var wp=RegExp.$1;
				if(wp=="Geocaching" || wp=="Error") {sendVoteWaypoint(cacheId,null,voteUser);}
				else {sendVoteWaypoint(cacheId,wp,voteUser);}
				return;
			}
		}
		sendVoteWaypoint(cacheId,wp,voteUser);
	},
	onerror: function(responseDetails) {
		sendVoteWaypoint(cacheId,null,voteUser);
	}
	});
*/
}

function sendVoteWaypoint(cacheId,waypoint,voteUser) {
	// send the user's new vote including waypoint to server
	log("sendVoteWaypoint "+cacheId+" ("+waypoint+") -> "+voteUser);
	var seturl=SETVOTE+"?cacheId="+cacheId+"&userName="+userName+"&voteUser="+voteUser+"&password="+encodeURIComponent(getPassword());
	if(waypoint) {seturl+="&waypoint="+waypoint;}
	log(seturl);
	GM_xmlhttpRequest({
	method: 'GET',
	url: seturl,
	onload: function(responseDetails) {
	if(responseDetails.responseText=="OK") {
		voteLink=document.getElementById("GCVoteLink"+cacheId+"="+voteUser)
		setStyle(voteLink,"background-color:orange;font-weight:bolder;color:black"); // highlight confirmed vote
		requestVote(cacheId); // request reload of displayed score
	}
	else if(responseDetails.responseText.indexOf("wrong password")>=0) {
		log(responseDetails.responseText);
		displayMessage(tl("Your Account is password protected and you supplied no or the wrong password. "
			+"If you did not register a password, please inform me: guido.wegener@gmx.de"));
		window.location=voteServerBase+"/passwordwrong.php";
		return;
	}
	else {
		displayMessage(tl("Error while sending vote: ")+responseDetails.status+"; '"+responseDetails.responseText)+"'";
	}
	},
	onerror: function(responseDetails) {
	alert(tl("Unable to send vote to server! Errorcode ")+responseDetails.status);
	}
	});
}

function GCVote_voteClick() {
	// user clicked a link to change his vote
	log("voteClick");
	if(securityState!="locked") {
		log("voteClick wrong");
		window.location=voteServerBase+"/passworderror.php";
		return;
	}
	log("voteClick ok");
	var reg=/#([^=]*)=([0-9\.]*)/;
	reg.exec(this);  // "this" contains the clicked URL
	var cacheId=RegExp.$1;
	var voted=RegExp.$2;
	setVote(cacheId,voted); // display user's choice
	var imgWait=document.getElementById("GCVoteWait"+cacheId);
	setStyle(imgWait,"position:relative;top:3px");
	sendVote(cacheId,voted); // send new vote to server
}

function avg2suffix(avg,voteCnt) {
	log("avg2suffix "+avg+", "+voteCnt+" - "+Math.abs(Number(voteCnt))+" - "+getThreshold());
	if(Math.abs(Number(voteCnt))<getThreshold()) {return "0";}
	var avg2=Math.round(avg*2)/2;
	var favg2=Math.floor(avg2);
	var s=favg2;
	if(avg2-favg2>.25) {s+="_5";}
	return s;
}

function getSmallVoteSpan(cacheId,voteStars,voteAvg,voteCnt,voteUser) {
	log("getsmallvote");
	var span=document.createElement("span");
	var em=document.createElement("em");
	em.setAttribute("style","font-size:xx-small;color:"+colorCodeForVoteCount(voteCnt)); //#909090")
	em.appendChild(document.createTextNode(" ("+voteCnt+")"));
	var img=document.createElement("img");
	var opacity=Math.min(0.4+Math.abs(Number(voteCnt))/6,1);
	if(voteCnt<0) {img.setAttribute("width","34px");img.setAttribute("height","8px");setStyle(img,"opacity:"+opacity+";position:relative;left:-7px;top:-1px");}
	else {img.setAttribute("width","36px");img.setAttribute("height","9px");}
	var s=avg2suffix(voteStars,voteCnt);
	var voteAvg1=new Number(voteAvg);
	img.src="http://www.geocaching.com/images/stars/stars"+s+".gif";
	span.appendChild(img);
	if(Number(voteCnt)>=getThreshold()) span.appendChild(em);
	return span;
}

function colorCodeForVoteCount(voteCnt) {
	var voteColor=Math.log(Math.abs(voteCnt))/Math.log(50);
	if(voteColor>1) voteColor=1;
	if(voteColor<0) voteColor=0;
	voteColor=Math.floor(voteColor*180);
	voteColor=voteColor.toString(16);
	while(voteColor.length<2) {voteColor="0"+voteColor;}
//	log("voteCnt="+voteCnt+"  voteColor="+voteColor);
	return "#00"+voteColor+"00";
}

function getNewSpan(cacheId,voteStars, voteAvg, voteCnt, voteUser, vote1, vote2, vote3, vote4, vote5) {
	// generate HTML node containing average and user's vote
//	log("getspan cacheid="+cacheId);
	function getVoteLink(cacheId,vote,text) {
		// generate single link for a user's vote
		var voteLink=document.createElement("a");
		addEvent(voteLink,"click",GCVote_voteClick);
		voteLink.setAttribute("href","#"+cacheId+"="+vote);
		setStyle(voteLink,"text-decoration:none!important");
		voteLink.id="GCVoteLink"+cacheId+"="+vote;
		voteLink.title=text;
		var voteText=(vote==0?"?":Math.floor(vote));
		if(Math.floor(vote)<vote) {
			var halfVote=document.createElement("span");
			setStyle(halfVote,"color:grey;font-size:1.4ex");
			halfVote.appendChild(voteLink);
			voteLink.appendChild(document.createTextNode("\u00bd"));
			return halfVote;
		}
		voteLink.appendChild(document.createTextNode(voteText));
		return voteLink;
	}
	var div=document.createElement("div");
	if(pageType=="details") {setStyle(div,"float:right");}
	if(pageType=="loglist") {setStyle(div,"float:left");}
	if(pageType=="nearestlist") {setStyle(div,"float:left");}
	var span=document.createElement("div");
	setStyle(span,"white-space:nowrap;font-size:small;padding:0px;margin:0px;line-height:80%");
//	if(voteUser>0) {span.setAttribute("style","white-space:nowrap");}
//	else {span.setAttribute("style","white-space:nowrap;background-color:#FFF0FF");}

    // skip "Quality:"-string for all tables containing a table header
    if(pageType!="nearestlist" && pageType!="bookmarks" && pageType!="loglist" && (!getCompactCurrentPage())) {
        var bold=document.createElement("b");
        bold.appendChild(document.createTextNode(" "+tl("Quality")+": "));
        span.appendChild(bold);
    }

	var img=document.createElement("img");
	var s=avg2suffix(voteStars,voteCnt);
	var voteAvg1=new Number(voteAvg);
	img.src="http://www.geocaching.com/images/stars/stars"+s+".gif";
    var tooltip = tl("Average (mean) ")+voteAvg1.toFixed(1)+tl(" out of 5");
    img.setAttribute("alt",tooltip);
	img.setAttribute("title",tooltip);
	img.setAttribute("align","absmiddle");
    // set image id
    img.id = "gcvoteStars"+cacheId;
    // add onclick event listener
    addEvent(img,"click", toggleGCVoteDetails(cacheId));
    // modify img's cursor
    img.style.cursor = 'pointer';
    span.appendChild(img);
    createGCVoteDetails( span, cacheId, voteCnt, vote1, vote2, vote3, vote4, vote5 );
	span.appendChild(img);
	var small=document.createElement("small");
	var em=document.createElement("em");
	setStyle(em,"color:"+colorCodeForVoteCount(voteCnt)+";font-weight:normal");
	em.appendChild(document.createTextNode(" ("+translateVoteCount(voteCnt)+")"));
	small.appendChild(em);
	span.appendChild(small);
	if(userName) {
		var span2=document.createElement("div");
		setStyle(span2,"white-space:nowrap");
		var small2=document.createElement("small");
		if(!getCompactCurrentPage()) {
			var em2=document.createElement("em");
			em2.appendChild(document.createTextNode(tl(" your vote: ")));
			small2.appendChild(em2);
		}
		span2.appendChild(small2);
		span2.appendChild(getVoteLink(cacheId,0,tl("no vote")));
		span2.appendChild(getVoteLink(cacheId,1,tl("1: poor")));
		if(HALFSTARS) span2.appendChild(getVoteLink(cacheId,1.5,tl("1.5: worthless")));
		span2.appendChild(getVoteLink(cacheId,2,tl("2: not good")));
		if(HALFSTARS) span2.appendChild(getVoteLink(cacheId,2.5,tl("2.5: ok")));
		span2.appendChild(getVoteLink(cacheId,3,tl("3: average")));
		if(HALFSTARS) span2.appendChild(getVoteLink(cacheId,3.5,tl("3.5: better")));
		span2.appendChild(getVoteLink(cacheId,4,tl("4: good")));
		if(HALFSTARS) span2.appendChild(getVoteLink(cacheId,4.5,tl("4.5: near perfect")));
		span2.appendChild(getVoteLink(cacheId,5,tl("5: great")));
		var imgWait=document.createElement("img");
		imgWait.setAttribute("width","14px");imgWait.setAttribute("height","14px");
		imgWait.src="http://www.geocaching.com/images/loading.gif";
		setStyle(imgWait,"display:none");
		imgWait.id="GCVoteWait"+cacheId;
		span2.appendChild(imgWait);
	}
	div.appendChild(span);
	if(userName) div.appendChild(span2);
	return div;
}

function fillLogEditTR(tr,span,voteUser) {
	log("filltr");
	var td = document.createElement("span");
	td.appendChild(span);
	tr.appendChild(td);

	var td2 = document.createElement("span");
	var button = document.createElement("input");
	button.setAttribute( "type", "button" );
		button.setAttribute( "value", tl("Insert GCVote Info") );
	addEvent(button,"click", function(event) {
		var template=getAdvertisementTemplate();
//		var string = template.replace("%%%",voteUser);
		var vu=voteUser;
		if(Math.round(voteUser)==vu) vu=Math.round(voteUser);
		var string = template.replace("%%%",vu);
		var logbox = document.getElementById("ctl00_ContentBody_LogBookPanel1_tbLogInfo");
		logbox.value=logbox.value.substring(0, logbox.selectionStart) + string + logbox.value.substring(logbox.selectionEnd, logbox.value.length);    
	});        
	td2.appendChild(button);
	td2.appendChild(document.createElement("br"));
/*	var buttonChange = document.createElement("input");
	buttonChange.setAttribute( "type", "button" );
	buttonChange.setAttribute( "value", "Edit Info Text" );
	buttonChange.id="editAdvertisementButton";
	buttonChange.addEvent("click", function(event) {
		document.getElementById("editAdvertisement").setAttribute("style","");
		document.getElementById("editAdvertisementButton").setAttribute("style","display:none");
	}, false);        
	td2.appendChild(buttonChange);
	var hiddenSpan=document.createElement("span");
	hiddenSpan.setAttribute("style","display:none");
	hiddenSpan.id="editAdvertisement";
	var inputChange = document.createElement("input");
	inputChange.setAttribute( "type", "text" );
	inputChange.setAttribute( "size", "40" );
	inputChange.setAttribute( "value", getAdvertisementTemplate() );
	inputChange.id="AdvertisementText";
	var buttonSave = document.createElement("input");
	buttonSave.setAttribute( "type", "button" );
	buttonSave.setAttribute( "value", "Save Changes" );
	buttonSave.addEvent("click", function(event) {
		log("new ad text: "+document.getElementById("AdvertisementText").value);
		GM_setValue("advertisementTemplate",document.getElementById("AdvertisementText").value);
		document.getElementById("editAdvertisement").setAttribute("style","display:none");
		document.getElementById("editAdvertisementButton").setAttribute("style","");
	}, false);
	hiddenSpan.appendChild(inputChange);
	hiddenSpan.appendChild(buttonSave);
	td2.appendChild(hiddenSpan);
*/
	tr.appendChild(td2);
	tr.id="GCVote-logedit";
}

function toggleGCVoteDetails(cacheId) 
{
    return function() 
    {
        GM_log( "toggleGCVoteDetails " + cacheId );
        
        var detailsDiv = document.getElementById("gcvoteDetails"+cacheId);
        var p = document.getElementById("gcvoteStars"+cacheId);
        
        if( !detailsDiv )
        {
            GM_log( "detailsDiv is 0" );
            return false;
        }
        if( !p )
        {
            GM_log( "parent is 0" );
            return false;
        }
        
        if (detailsDiv.style.visibility != "visible")
        {
            // compute position of popup
            var top  = p.offsetHeight+2;
            var left = 0;
            
            for (; p ; p = p.offsetParent)
            {
                top  += p.offsetTop;
                left += p.offsetLeft;
            }
            
            detailsDiv.style.position   = "absolute";
            detailsDiv.style.top        = top +'px';
            detailsDiv.style.left       = left+'px';
            detailsDiv.style.visibility = "visible";
        }
        else detailsDiv.style.visibility = "hidden";
        
        return false;
    }
}

function createGCVoteDetailsRow( table, vote, votecount )
{
    var row = document.createElement( "tr" );
    table.appendChild( row );
    
    var td1 = document.createElement( "td" );
    row.appendChild( td1 );

    var img = document.createElement("img");
    img.src="http://www.geocaching.com/images/stars/stars" + vote + ".gif";
    td1.appendChild( img );
    
    var td2 = document.createElement( "td" );
    if( votecount != 0 )
    {
        td2.style.fontWeight = "bold";
    }
    td2.appendChild( document.createTextNode( translateVoteCount(votecount)) );
    row.appendChild( td2 );
}

function createGCVoteDetails( parent, cacheId, votes, vote1, vote2, vote3, vote4, vote5 ) 
{
    var div = document.createElement('div');
    div.id = "gcvoteDetails"+cacheId;
    div.style.position   = "absolute";
    div.style.visibility = "hidden";   
    div.style.backgroundColor = "#eff4f9";
    div.style.border = "solid 1px #c0cee3";
    addEvent(div,"click", toggleGCVoteDetails(cacheId));
    parent.appendChild( div );

    var header = document.createElement( "div" );
    header.style.fontWeight = "bold";
    header.appendChild( document.createTextNode( tl("Distribution of votes:") ) );
    div.appendChild( header );
    
    var table = document.createElement( "table" );
    
    div.appendChild( table );

    createGCVoteDetailsRow( table, "1", vote1 );
    createGCVoteDetailsRow( table, "2", vote2 );
    createGCVoteDetailsRow( table, "3", vote3 );
    createGCVoteDetailsRow( table, "4", vote4 );
    createGCVoteDetailsRow( table, "5", vote5 );
}

function log(str) {
	if(LOGGING) {GM_log(str);}
}

function displayVersionInfo() {
	log("versionInfo");
	var vit=document.getElementById("VersionInfoText");
	log("vit="+vit);
	var vin=document.getElementById("VersionInfoNumber");
	log("vin="+vin);
	if(!vit || !vin) return;
	var currentversion=document.getElementById("currentversion").firstChild.data;
	log("versioninfo found: -"+currentversion+"-  installed: -"+version+"-");
	vin.appendChild(document.createTextNode(version));
	setStyle(vit,"");
	if(currentversion==version) {
		setStyle(document.getElementById("updatelink"),"display:none");
	}
}

function getTooltipSpan(text,tooltip) {
	var span=document.createElement("span");
	span.appendChild(document.createTextNode(tl(text)));
	span.setAttribute("title",tl(tooltip));
	return span;
}

function getAdvertisementTemplate() {
	var str=GM_getValue("advertisementTemplate");
	if(!str) {
		log("no ad text in GM, using "+GCVoteAdvertisementDefault);
		GM_setValue("advertisementTemplate",GCVoteAdvertisementDefault);
		str=GCVoteAdvertisementDefault;
	}
	return str;
}

function getStarAttributeName() {
	var str=GM_getValue("starAttributeName");
	if(!str) {
		GM_setValue("starAttributeName","voteAvg");
		str="voteAvg";
	}
	return str;
}

function getPassword() {
	var str=GM_getValue("password["+userName+"]");
	if(!str) {
		GM_setValue("password["+userName+"]","");
		str="";
	}
	return str;
}

function getThreshold() {
	var threshold=GM_getValue("threshold");
	if(!threshold) {
		GM_setValue("threshold",1);
		threshold=1;
	}
	return Number(threshold);
}

function getSortSidebar() {
	var sortSidebar=GM_getValue("sortSidebar");
	if(!sortSidebar) {
		GM_setValue("sortSidebar",1);
		sortSidebar=1;
	}
	return Number(sortSidebar);
}

function getHalfstars() {
	var halfstars=GM_getValue("halfstars");
	if(!halfstars) {
		GM_setValue("halfstars",0);
		halfstars=0;
	}
	return Number(halfstars);
}

function getLogging() {
	var logging=GM_getValue("logging");
	if(!logging) {
		GM_setValue("logging",0);
		logging=0;
	}
	return Number(logging);
}

function getCompact() {
	var compact=GM_getValue("compact");
	if(!compact) {
		GM_setValue("compact",0);
		compact=0;
	}
	return Number(compact);
}

function getLanguage() {
	var language=GM_getValue("language");
	if(!language) {
		language = (navigator.language) ? navigator.language : navigator.userLanguage;
		log("detected language "+language);
		language=language.substr(0,2);
//		if(language!="de" && language!="fr") language="en";
		GM_setValue("language",language);
	}
	return language;
}

function getCompactCurrentPage() {
	if(!getCompact()) return false;
	switch(pageType) {
		case "details": return false;
		case "loglist": return true;
		case "gmnearestlist": return true;
		case "nearestlist": return true;
		case "overviewlist1": return true;
		case "overviewlist2": return true;
		case "logedit": return false;
		case "bookmarks": return true;
		case "watchlist": return true;
		case "print": return false;
		default: return false;
	}
}

function saveConfig(Event) {
	var newPwd=document.getElementById("GC-Vote-Password").value;
	var oldPwd=getPassword();
	var reload=false;
	if(newPwd!=oldPwd) {reload=true;}
	GM_setValue("password["+userName+"]",newPwd);
	GM_setValue("advertisementTemplate",document.getElementById("GC-Vote-Template").value);
	GM_setValue("threshold",document.getElementById("GC-Vote-threshold").value);
	if(document.getElementById("GC-Vote-Stars-Average").checked) {GM_setValue("starAttributeName","voteAvg");log("avg");}
	else if(document.getElementById("GC-Vote-Stars-Median").checked) {GM_setValue("starAttributeName","voteMedian");log("med");}
	var options=document.getElementById("GC-Vote-language").options;
	for(i=0;i<options.length;i++) {
		if(options[i].selected) {GM_setValue("language",options[i].value);log("language="+options[i].value);}
	}
	log("logging="+document.getElementById("GC-Vote-logging").checked);
	log("halfstars="+document.getElementById("GC-Vote-half").checked);
	log("sortSidebar="+document.getElementById("GC-Vote-sort").checked);
	GM_setValue("logging",document.getElementById("GC-Vote-logging").checked);
	GM_setValue("halfstars",document.getElementById("GC-Vote-half").checked);
	GM_setValue("sortSidebar",document.getElementById("GC-Vote-sort").checked);
	GM_setValue("compact",document.getElementById("GC-Vote-compact").checked);
	if(reload || true) {window.location.reload();}
}

function showConfig() {
	if(!document.getElementById("GCVote-Config")) return;
	setStyle(document.getElementById("GCVote-Config"),"");
	setStyle(document.getElementById("show GCVote-Config"),"display:none");
	setStyle(document.getElementById("hide GCVote-Config"),"");
	setStyle(document.getElementById("GC-Vote-Div-Dummy"),"display:none");
}

function hideConfig() {
	if(!document.getElementById("GCVote-Config")) return;
	setStyle(document.getElementById("GCVote-Config"),"display:none");
	setStyle(document.getElementById("show GCVote-Config"),"");
	setStyle(document.getElementById("hide GCVote-Config"),"display:none");
	setStyle(document.getElementById("GC-Vote-Div-Dummy"),"");
}

function insertGCVoteMenu() {
	log("insertGCVoteMenu");
	var sidebar=document.getElementById("ctl00_ContentBody_WidgetMiniProfile1_LoggedInPanel");
	if(!sidebar) 
	{
		if(document.URL=="http://www.geocaching.com/my/"
		  && !document.getElementById("ctl00_ContentBody_WidgetMiniProfile1_LoggedOutPanel")) {
			// Added by Odilbert for better error handling
			displayMessage(tl("Couldn't find entry tag for inserting GCVote configuration window. Maybe the geocaching.com website has been changed. "+
				"Please have a look on http://gcvote.com and check for possibly released GCVote updates."));
		}
		
		return;
	}
	var header=document.createElement("h3");
	header.setAttribute("class","widget-header");
	var imgMinus=document.createElement("img");
	imgMinus.setAttribute("src","http://www.geocaching.com/images/minus.gif");
	imgMinus.setAttribute("alt",tl("hide config"));
	var linkMinus=document.createElement("a");
	addEvent(linkMinus,"click",hideConfig);
	linkMinus.id="hide GCVote-Config"
	setStyle(linkMinus,"display:none");
	linkMinus.appendChild(imgMinus);
	header.appendChild(linkMinus);
	var imgPlus=document.createElement("img");
	imgPlus.setAttribute("src","http://www.geocaching.com/images/plus.gif");
	imgPlus.setAttribute("alt",tl("show config"));
	var linkPlus=document.createElement("a");
	addEvent(linkPlus,"click",showConfig);
	linkPlus.id="show GCVote-Config"
	linkPlus.appendChild(imgPlus);
	header.appendChild(linkPlus);
	header.appendChild(document.createTextNode(" "+tl("GCVote Configuration")));
	var divDummy=document.createElement("div");
	divDummy.appendChild(document.createTextNode("\u00A0"));
	divDummy.id="GC-Vote-Div-Dummy";
	var div=document.createElement("div");
	setStyle(div,"display:none");
	div.id="GCVote-Config";
	var p1=document.createElement("p");
	p1.id="GC-Vote-update";
	setStyle(p1,"display:none");
	var updateLink=document.createElement("a");
	updateLink.setAttribute("href",voteServerBase);
	updateLink.appendChild(document.createTextNode(tl("Update GCVote")));
	p1.appendChild(updateLink);
	div.appendChild(p1);
	var p2=document.createElement("p");
	setStyle(p2,"margin:5px");
	
	var linkHome=document.createElement("a");
	linkHome.setAttribute("href","http://www.gcvote.com");
	linkHome.appendChild(document.createTextNode(tl("Homepage")));
	var linkHelp=document.createElement("a");
	linkHelp.setAttribute("href",voteServerBase+"/help.html");
	setStyle(linkHelp,"position:relative;right:3px;float:right;font-size:larger;font-weight:bold");
	linkHelp.appendChild(getTooltipSpan("?","Help"));
	p2.appendChild(linkHelp);
	p2.appendChild(linkHome);
	p2.appendChild(document.createElement("br"));
	var linkListVotes=document.createElement("a");
	addEvent(linkListVotes,"click",listVotes);
	linkListVotes.setAttribute("href","#");
//	linkListVotes.setAttribute("style","cursor:pointer");
	linkListVotes.appendChild(document.createTextNode(tl("List my votes")));
	p2.appendChild(linkListVotes);
	p2.appendChild(document.createElement("br"));
	var linkChangePassword=document.createElement("a");
	addEvent(linkChangePassword,"click",changePassword);
	linkChangePassword.setAttribute("href","#");
	linkChangePassword.appendChild(document.createTextNode(tl("Change password")));
	p2.appendChild(linkChangePassword);
	p2.appendChild(document.createElement("br"));

	var textBoxesTable=document.createElement("table");
	textBoxesTable.id="GCVoteTextBoxesTable";
	textBoxesTable.setAttribute("cellpadding", "0");
	textBoxesTable.setAttribute("cellspacing", "0");
	textBoxesTable.setAttribute("cellborder", "0");
	setStyle(textBoxesTable, "margin-top:10px");
	
	var passwordRow=document.createElement("tr");
	
	var spanPwd=document.createElement("span");
	spanPwd.id="GCVotePasswordSpan";
	spanPwd.appendChild(getTooltipSpan("Password:","passwords must be registered via GC.com-mail to BonnerGuido"));
	
	var inputPassword=document.createElement("input");
	inputPassword.setAttribute("type","password");
	setStyle(inputPassword,"margin:1px 0px 1px 3px");
	inputPassword.id="GC-Vote-Password";
	inputPassword.value=getPassword();
	
	var imgPadlock=document.createElement("img");
	imgPadlock.id="GCVotePasswordActive";
	setStyle(imgPadlock,"display:none");
	imgPadlock.setAttribute("src",voteServerBase+"/padlock.gif");
	imgPadlock.setAttribute("alt",tl("password active"));
	
	var newtd = document.createElement("td");
	newtd.appendChild(spanPwd);
	passwordRow.appendChild(newtd);
	
	newtd = document.createElement("td");
	newtd.appendChild(inputPassword);
	passwordRow.appendChild(newtd);
	
	newtd = document.createElement("td");
	newtd.appendChild(imgPadlock);
	passwordRow.appendChild(newtd);
	
	var templateRow=document.createElement("tr");
	
	var inputTemplate=document.createElement("input");
	inputTemplate.setAttribute("type","text");
	setStyle(inputTemplate,"margin:1px 0px 1px 3px");
	inputTemplate.id="GC-Vote-Template";
	inputTemplate.value=getAdvertisementTemplate();

	newtd = document.createElement("td");
	newtd.appendChild(getTooltipSpan("Template:","GCVote info string to insert into logs"));
	templateRow.appendChild(newtd);
	
	newtd = document.createElement("td");
	newtd.appendChild(inputTemplate);
	templateRow.appendChild(newtd);
	
	newtd = document.createElement("td");
	newtd.appendChild(document.createTextNode(" "));
	templateRow.appendChild(newtd);

	var textBoxesTBody=document.createElement("tbody");
	textBoxesTable.appendChild(textBoxesTBody);
	
	textBoxesTBody.appendChild(passwordRow);
	textBoxesTBody.appendChild(templateRow);
	
	var averageTable=document.createElement("table");
	averageTable.id="GCVoteAverageTable";
	averageTable.setAttribute("cellpadding", "0");
	averageTable.setAttribute("cellspacing", "0");
	averageTable.setAttribute("cellborder", "0");

	var voteCountRow=document.createElement("tr");

	var inputThreshold=document.createElement("input");
	inputThreshold.setAttribute("type","text");
	setStyle(inputThreshold,"margin:1px 0px 1px 3px");
	inputThreshold.setAttribute("size","2");
	inputThreshold.id="GC-Vote-threshold";
	inputThreshold.value=getThreshold();

	newtd = document.createElement("td");
	newtd.appendChild(getTooltipSpan("Minimum vote count:","display stars only for caches with more than X votes"));
	voteCountRow.appendChild(newtd);

	newtd = document.createElement("td");
	newtd.setAttribute("colspan", "2");
	newtd.appendChild(inputThreshold);
	voteCountRow.appendChild(newtd);

	var meanRow=document.createElement("tr");

	var inputStarsAvg=document.createElement("input");
	inputStarsAvg.setAttribute("type","radio");
	inputStarsAvg.setAttribute("name","GC-Vote-Stars");
	inputStarsAvg.id="GC-Vote-Stars-Average";
	inputStarsAvg.value="voteAvg";
	if("voteAvg"==getStarAttributeName()) {inputStarsAvg.checked="checked";}
	
	newtd = document.createElement("td");
	setStyle(newtd, "padding-top:3px");
	newtd.appendChild(getTooltipSpan("Average calculation:","how the number of displayed stars should be calculated"));
	meanRow.appendChild(newtd);

	newtd = document.createElement("td");
	newtd.appendChild(inputStarsAvg);
	meanRow.appendChild(newtd);

	newtd = document.createElement("td");
	setStyle(newtd, "padding-top:3px");
	newtd.appendChild(getTooltipSpan("Mean","arithmetic mean of all votes for the cache"));
	meanRow.appendChild(newtd);
	
	var medianRow=document.createElement("tr");

	var inputStarsMedian=document.createElement("input");
	inputStarsMedian.setAttribute("type","radio");
	inputStarsMedian.setAttribute("name","GC-Vote-Stars");
	inputStarsMedian.id="GC-Vote-Stars-Median";
	inputStarsMedian.value="voteMedian";
	if("voteMedian"==getStarAttributeName()) {inputStarsMedian.checked="checked";}
	
	newtd = document.createElement("td");
	newtd.appendChild(document.createTextNode(" "));
	medianRow.appendChild(newtd);

	newtd = document.createElement("td");
	newtd.appendChild(inputStarsMedian);
	medianRow.appendChild(newtd);

	newtd = document.createElement("td");
	setStyle(newtd, "padding-top:3px");
	newtd.appendChild(getTooltipSpan("Median","median ignores unusual votes"));
	medianRow.appendChild(newtd);

	var checkTable=document.createElement("table");
	checkTable.id="GCVoteCheckTable";
	checkTable.setAttribute("cellpadding", "0");
	checkTable.setAttribute("cellspacing", "0");
	checkTable.setAttribute("cellborder", "0");
	
	var selectTable=document.createElement("table");
	selectTable.id="GCVoteSelectTable";
	selectTable.setAttribute("cellpadding", "0");
	selectTable.setAttribute("cellspacing", "0");
	selectTable.setAttribute("cellborder", "0");
	
	var languageRow=document.createElement("tr");

	var inputLanguage=document.createElement("select");
//	setStyle(inputLanguage,"margin:1px 0px 1px 3px");
//	inputLanguage.setAttribute("size","2");
	inputLanguage.id="GC-Vote-language";
	var option=document.createElement("option");
	option.setAttribute("value","en");option.appendChild(document.createTextNode(tl("English")));
	if(getLanguage()=="en") option.setAttribute("selected","selected");
	inputLanguage.appendChild(option);
	option=document.createElement("option");
	option.setAttribute("value","de");option.appendChild(document.createTextNode(tl("German")));
	if(getLanguage()=="de") option.setAttribute("selected","selected");
	inputLanguage.appendChild(option);
	option=document.createElement("option");
	option.setAttribute("value","fr");option.appendChild(document.createTextNode(tl("French")));
	if(getLanguage()=="fr") option.setAttribute("selected","selected");
	inputLanguage.appendChild(option);
	option=document.createElement("option")
	option.setAttribute("value","cz");option.appendChild(document.createTextNode(tl("Czech")));
	if(getLanguage()=="cz") option.setAttribute("selected","selected");
	inputLanguage.appendChild(option);
	option=document.createElement("option")

	newtd = document.createElement("td");
	newtd.appendChild(getTooltipSpan("Language:","language for GCVote"));
	languageRow.appendChild(newtd);

	newtd = document.createElement("td");
//	newtd.setAttribute("colspan", "2");
	newtd.appendChild(inputLanguage);
	languageRow.appendChild(newtd);

	var loggingRow=document.createElement("tr");

	var inputLogging=document.createElement("input");
	inputLogging.setAttribute("type","checkbox");
//	setStyle(inputLogging,"margin:1px 0px 1px 3px");
//	inputLogging.setAttribute("size","2");
	inputLogging.id="GC-Vote-logging";
	if(LOGGING) inputLogging.setAttribute("checked","checked");

	newtd = document.createElement("td");
//	newtd.setAttribute("colspan", "2");
	newtd.appendChild(inputLogging);
	loggingRow.appendChild(newtd);

	newtd = document.createElement("td");
	newtd.appendChild(getTooltipSpan("enable logging","write debugging information to the error console"));
	loggingRow.appendChild(newtd);

	var sortRow=document.createElement("tr");

	var inputSort=document.createElement("input");
	inputSort.setAttribute("type","checkbox");
	inputSort.id="GC-Vote-sort";
	if(SORTSIDEBAR) inputSort.setAttribute("checked","checked");

	newtd = document.createElement("td");
	newtd.appendChild(inputSort);
	sortRow.appendChild(newtd);

	newtd = document.createElement("td");
	newtd.appendChild(getTooltipSpan("sorted sidebar","sort caches on the map page according to their ratings"));
	sortRow.appendChild(newtd);

	var halfstarsRow=document.createElement("tr");

	var inputHalfstars=document.createElement("input");
	inputHalfstars.setAttribute("type","checkbox");
	inputHalfstars.id="GC-Vote-half";
	if(HALFSTARS) inputHalfstars.setAttribute("checked","checked");

	newtd = document.createElement("td");
	newtd.appendChild(inputHalfstars);
	halfstarsRow.appendChild(newtd);

	newtd = document.createElement("td");
	newtd.appendChild(getTooltipSpan("half stars","enable ratings 1.5, 2.5, 3.5 and 4.5"));
	halfstarsRow.appendChild(newtd);

	var compactRow=document.createElement("tr");

	var inputCompact=document.createElement("input");
	inputCompact.setAttribute("type","checkbox");
	inputCompact.id="GC-Vote-compact";
	if(getCompact()) inputCompact.setAttribute("checked","checked");

	newtd = document.createElement("td");
	newtd.appendChild(inputCompact);
	compactRow.appendChild(newtd);

	newtd = document.createElement("td");
	newtd.appendChild(getTooltipSpan("compact layout","improve GCVote's layout for small screens"));
	compactRow.appendChild(newtd);

	averageTable.appendChild(voteCountRow);
	averageTable.appendChild(meanRow);
	averageTable.appendChild(medianRow);
	selectTable.appendChild(languageRow);
	checkTable.appendChild(sortRow);
	checkTable.appendChild(halfstarsRow);
	checkTable.appendChild(compactRow);
	checkTable.appendChild(loggingRow);
	
	p2.appendChild(textBoxesTable);
	p2.appendChild(averageTable);
	p2.appendChild(selectTable);
	p2.appendChild(checkTable);

	var buttonSave=document.createElement("input");
	buttonSave.setAttribute("type","button");
	buttonSave.setAttribute("value",tl("save changes"));
	setStyle(buttonSave,"margin-top:5px");
	
	addEvent(buttonSave,"click",saveConfig);
	p2.appendChild(buttonSave);
	div.appendChild(p2);
	sidebar.appendChild(header);
	sidebar.appendChild(div);
	sidebar.appendChild(divDummy);
	log("insertGCVoteMenu done");
}

function listVotes() {
// fakig a POST-form to hide password while redirecting
  var myForm = document.createElement("form");
  setStyle(myForm,"display:none");
  myForm.method="POST" ;
  myForm.action = LISTVOTES;
  i1=document.createElement("input");
  i1.setAttribute("name","userName");
  i1.setAttribute("value",unescapedUserName);
  myForm.appendChild(i1);
  i2=document.createElement("input");
  i2.setAttribute("name","password");
  i2.setAttribute("value",getPassword());
  myForm.appendChild(i2);
  document.body.appendChild(myForm) ;
  myForm.submit() ;
  document.body.removeChild(myForm) ;
}

function changePassword() {
// fakig a POST-form to hide password while redirecting
  var myForm = document.createElement("form");
  setStyle(myForm,"display:none");
  myForm.method="POST" ;
  myForm.action = CHANGEPASSWORD;
  i1=document.createElement("input");
  i1.setAttribute("name","userName");
  i1.setAttribute("value",unescapedUserName);
  myForm.appendChild(i1);
  i2=document.createElement("input");
  i2.setAttribute("name","oldPassword");
  i2.setAttribute("value",getPassword());
  myForm.appendChild(i2);
  document.body.appendChild(myForm) ;
  myForm.submit() ;
  document.body.removeChild(myForm) ;
}

// IE-Mod (by qByter): Added funtion to provide alternative to addEventListener for Internet Explorer
function addEvent( obj, type, fn ) {
        if (obj.addEventListener)
                obj.addEventListener(type, fn, false);
        else if (obj.attachEvent)
                obj.attachEvent('on' + type, function() { return fn.apply(obj, new Array(window.event));});
}

function getXmlDoc(xmlString) {
	if(typeof(DOMParser) == 'undefined') {
		xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
		xmlDoc.async="false";
		xmlDoc.loadXML(xmlString);
	}
	else {
		var parser = new DOMParser();
		xmlDoc = parser.parseFromString(xmlString, "text/xml");
	}
	return xmlDoc;
}

function setStyle(obj,style) {
//	obj.setAttribute("style",style);
	obj.style.cssText=style;
}

function translateVoteCount(count) {
	if(getCompactCurrentPage()) return count;
	if(getLanguage()=="de") return count + " Stimme"+(count==1?"":"n");
	if(getLanguage()=="fr") return count + " cote"+(count>1?"s":"");
	if(getLanguage()=="cz") return count + " hodnocení"+(count>1?"s":"");
	return count + " vote"+(count==1?"":"s");
}

function tl(str) {
	var index=-1;
	switch(getLanguage()) {
		case "de":index=0;break;
		case "fr":index=1;break;
		case "cz":index=2;break;
	}
	if(index<0) return str;
	var p=translations.indexOf(str);
	if(p<0) {
		log("missing translation for '"+str+"'.");
		return str;
	}
	var trans=translations[p+1];
	return trans[index];
}

