var refreshIntervalMinutes = 30;

var xmlHttp;
var IE = false;
var sessionID = "";
var myPhoneNo = "";
var myVerificationCode = null;
var contactList = new Hashtable();
var sortedContacts;
var reconnecting = false;

var boundsList;
var timeoutUpdate;
var timeoutPoll;
var fullscreenstate = false;
var accurencyAreas;
var map = null;
var processCreatingMap = false;
var gettingContactsFirstTime = true;

var currentSettingPinType = 'P';        // P = show pins in contact positions, I = show the avatar icon
var currentSettingShowPos = false;  // false = don't show position in list, true = show it
var currentSettingShowAllContacts = false; // false = don't show contacts that currently hava no position
var currentSettingAccurency = 'S';  // S = sqare, O = octagone, C = circle
var currentSettingShapeBorder = 1;  // size of the border of the accurency area
var xCoor;
var yCoor;

var circleColours = new Array( "#F62529", "#FEF223", "#67B368", "#F99427", "#46FEFE", "#878787", "#291CFF", "#4AFF1E", "#8E00FF", "#911618" );

function handleError( err ) {
	alert( "The page throws the error '"+err.message+"'.\n\nYou may have to reload the page" );
	throw( err );
} // handleError

function Contact( id, phone, name, avatar ) {
	this.id       = id;
	this.phone    = phone;
	this.name     = name;
	this.show     = false;
	this.avatar   = avatar;

	this.status   = 0;
	this.presence = "";
	this.marker   = undefined;
	this.pos      = "";
	this.lat      = "";
	this.lon      = "";
	this.acc      = "";
	this.group    = 0;
	this.zindex   = 0;
	this.accbounds= null;
} // Contact


function init() {
//	ajaxFunction( "init", "" );
	getAllSettings();

	// Create coorinates to make cirkles
	var incr = Math.PI / 10.0;
	var pi2  = 2*Math.PI;
	xCoor = new Array();
	yCoor = new Array();
	var i = 0;
	for (var angle = 0; angle < pi2; angle = angle + incr) {
		xCoor[i] = Math.cos(angle) + 1;
		yCoor[i] = Math.sin(angle) + 1;
		i++;
	}

} // init

var redirectAfterDisconnect = null;

function disconnect( elem ) {
	removeRefresh();
	ajaxFunction( "exit", "" );
	if (elem != undefined)
		redirectAfterDisconnect = elem;
}


function update() {
	clearTimeout( timeoutPoll );
	ajaxFunction( "contacts", "" );
	document.getElementById("refreshTime").innerHTML = "Updated " + now();
}


function poll() {
	ajaxFunction( "check", "" );
}


function fullscreen() {
	fullscreenstate = ! fullscreenstate;

	var mapElement = document.getElementById("gmap");
	var toolbarElement = document.getElementById("toolbar");
	var serverErrorElement = document.getElementById("serverError");

	if (fullscreenstate) {
		window.resizeTo( screen.availWidth, screen.availHeight );
		window.moveTo( 0, 0 );

		mapElement.style.position = "fixed";
		mapElement.style.top = "0";
		mapElement.style.left = "0";
		mapElement.style.height = "100%";
		mapElement.style.width = "100%";

		map.checkResize();

		toolbarElement.style.top = "10px";
		toolbarElement.style.left = "90px";

		serverErrorElement.style.position = "fixed";
		serverErrorElement.style.top = "10px";
		serverErrorElement.style.left = "170px";

	} else {
		mapElement.style.position = "relative";
		mapElement.style.top = "0px";
		mapElement.style.left = "0px";
		mapElement.style.height = "560px";
		mapElement.style.width = "800px";

		map.checkResize();

		toolbarElement.style.top = "220px";
		toolbarElement.style.left = "765px";

		serverErrorElement.style.position = "relative";
		serverErrorElement.style.top = "-860px";
		serverErrorElement.style.left = "0";

	}
}


function saveData( key, value ) {
	var expiry = new Date();
	expiry.setFullYear( 2099, 0, 1 );

	document.cookie = key + "=" + value + "; expires="+expiry.toGMTString()+"; path=/";
}


function getData( key ) {
	var pairs = document.cookie.split(';');
	for (var i = 0; i < pairs.length; i++) {
		var pair = pairs[i].split("=");
		if (trim(pair[0]) == key) return trim(pair[1]);
	}
	return "";
}


function getAllSettings() {
	var oldPhone = getData( "lastPhone" );
	if (oldPhone != "") document.getElementById("PhoneNumber").value = oldPhone;

	currentSettingPinType = getData( "pinSetting" );
	if (currentSettingPinType != "")
		document.getElementById("pinSetting"+currentSettingPinType).checked = true;
	else
		document.getElementById("pinSettingP").checked = true;

	currentSettingShowPos = getData( "showPosSetting" ) == "true";
	document.getElementById("showPosSetting").checked = currentSettingShowPos;

	currentSettingShowAllContacts = getData( "showAllContactsSetting" ) == "true";
	document.getElementById("showAllContactsSetting").checked = currentSettingShowAllContacts;

	currentSettingAccurency = getData( "shapeSetting" );
	if (currentSettingAccurency != "")
		document.getElementById("shapeSetting"+currentSettingAccurency).checked = true;
	else
		document.getElementById("shapeSettingS").checked = true;

	currentSettingShapeBorder = getData( "shapeBorder" );
	if (currentSettingShapeBorder == "") currentSettingShapeBorder = 1;
	document.getElementById("shapeBorder").value = currentSettingShapeBorder;

	refreshIntervalMinutes = parseInt( getData( "refreshInterval" ) );
	if (isNaN(refreshIntervalMinutes) || refreshIntervalMinutes < 0 || refreshIntervalMinutes > 999) refreshIntervalMinutes = 0;
	document.getElementById("refreshInterval").value = refreshIntervalMinutes;
}


function getAndSaveAllSettings() {
	currentSettingPinType = 'P';
	if (document.getElementById("pinSettingI").checked) currentSettingPinType = 'I';
	saveData( "pinSetting", currentSettingPinType );

	currentSettingShowPos = document.getElementById("showPosSetting").checked;
	saveData( "showPosSetting", ""+currentSettingShowPos );

	currentSettingShowAllContacts = document.getElementById("showAllContactsSetting").checked;
	saveData( "showAllContactsSetting", ""+currentSettingShowAllContacts );

	currentSettingAccurency = 'S';
	if (document.getElementById("shapeSettingO").checked) currentSettingAccurency = 'O';
	if (document.getElementById("shapeSettingC").checked) currentSettingAccurency = 'C';
	saveData( "shapeSetting", currentSettingAccurency );

	currentSettingShapeBorder = parseInt( document.getElementById("shapeBorder").value );
	saveData( "shapeBorder", currentSettingShapeBorder );

	refreshIntervalMinutes = parseInt( document.getElementById("refreshInterval").value );
	if (refreshIntervalMinutes == Number.NaN || refreshIntervalMinutes < 0) refreshIntervalMinutes = 0;
	saveData( "refreshInterval", refreshIntervalMinutes );
}


function trim( text ) {
	while (text.length > 0 && text.charAt(0) == " ")
		text = text.substr(1);
	while (text.length > 0 && text.charAt(text.length-1) == " ")
		text = text.substr(0,text.length-1);
	return text;
}


function now()
{
	var today = new Date();
	var h = today.getHours();
	var m = today.getMinutes();
	var s = today.getSeconds();

	return (h<10?"0"+h:h)+"."+(m<10?"0"+m:m)+"."+(s<10?"0"+s:s);
}


function findPos( obj ) {
	var curleft = curtop = 0;
	if (obj.offsetParent) {
		do {
			curleft += obj.offsetLeft;
			curtop  += obj.offsetTop;
		} while (obj = obj.offsetParent);
	}
	return [curleft,curtop];
} // findPos


function ajaxFunction( operation, param ) {
	var params, url;
	params = param.split( '\t' );

	try {
		// Firefox, Opera 8.0+, Safari
		xmlHttp=new XMLHttpRequest();
	} catch (e) {
		// Internet Explorer
		try {
			xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {
				alert( "Your browser does not support AJAX!" );
				return false;
			}
		}

		IE = true;
	}

	xmlHttp.onreadystatechange = serverResponse;

	if (operation == "init") {
		accessServer( server+"?comm=lang" );

	} else if (operation == "search") {
		accessServer( server+"?comm=search&phone="+params[0]+"&pin="+params[1]+"&ver="+params[2] );

	} else if (operation == "contacts") {
		accessServer( server+"?comm=contacts&sid="+sessionID );

	} else if (operation == "check") {
		accessServer( server+"?comm=check&sid="+sessionID );

	} else if (operation == "mess") {
		accessServer( server+"?comm=mess&sid="+sessionID+"&phone="+params[0]+"&text="+params[1] );

	} else if (operation == "exit") {
		accessServer( server+"?comm=exit&sid="+sessionID );

	}
} // ajaxFunction


function accessServer( url ) {
	log( "accessing "+url );
	xmlHttp.open( "GET", url, true );
	xmlHttp.send( null );
} // accessServer


function serverResponse() {
	try{

	if(xmlHttp.readyState != 4) {
		return;
	}

	var r, rader, data, typ, titel, gammal, aux2, titel, html, mapp;

	r = xmlHttp.responseText.indexOf("HTTP Status");
	if (xmlHttp.status != 200) {
		log( "error "+xmlHttp.status );
		if (xmlHttp.status == 401) {
			if (myVerificationCode != null) {
				document.getElementById("serverError").innerHTML = "Lost connection to the phone session. Trying to reconnect...";
				reconnecting = true;
				connectToPhone();
			} else {
				document.getElementById("serverError").innerHTML = "Lost connection to the phone session. Please reload the page";
			}
		} else {
			document.getElementById("serverError").innerHTML = "Unexpected error from server "+xmlHttp.status + ". Please reload the page";
		}
		removeRefresh();
		return;
	}

	log( "response "+xmlHttp.responseText );

	response = xmlHttp.responseText.replace(/\015/g,"").replace(/\012/g,"");
	data = response.split("\t");

	if (data[0] == "LANG") {
		var lang = data[1].substr( 0, 2 );
		setLanguage( lang );
		document.getElementById("header1").innerHTML = getText( "Where are my contacts" );
		document.getElementById("header2").innerHTML = getText( "Show all your contacts on a map" );
		document.getElementById("header3").innerHTML = getText( "Contact list" );
		document.getElementById("header4").innerHTML = getText( "Here is my contacts" );
		document.getElementById("tabContact").innerHTML = getText( "Contacts" );
		document.getElementById("tabMap").innerHTML = getText( "Map" );
		document.getElementById("phonecomment").innerHTML = getText( "(international format)" );
		document.getElementById("PhoneNumber").value = getText( "PhoneNumber" );
		document.getElementById("Submit").value = getText( "Connect" );
		document.getElementById("waitbox").innerHTML = getText( "Please wait" );

		if (navigator.appName.indexOf("Microsoft") >= 0) {
			document.getElementById("contentdiv").className = "contenttext";
			document.getElementById("contentdiv").innerHTML = getText( "Not supported", navigator.appName );
			return;
		}

		getAllSettings();
	} // if - LANG

	else if (data[0] == "SEARCH") {
		if (data[1] == "OK") {
			document.getElementById("pin").innerHTML = getText( "Please wait" );

			saveData( "phone", myPhoneNo );
			saveData( "ver" + myPhoneNo, myVerificationCode );

			sessionID = data[2];
			update();

		} else {
			if (reconnecting)
				document.getElementById("serverError").innerHTML = getText( "Error reconnecting to the phone" );
			else
				document.getElementById("pin").innerHTML = getText( "Error connecting to the phone" );
		}

		reconnecting = false;
	} // if - SEARCH

	else if (data[0] == "CONTACTS") {
		if (data[1] == "ERROR") {
			if (myVerificationCode != null) {
				document.getElementById("serverError").innerHTML = "Error getting the contacts, phone is not responing. Trying to reconnect...";
				reconnecting = true;
				connectToPhone();
			} else {
				document.getElementById("serverError").innerHTML = "Error getting the contacts, phone is not responing - please reload the page";
			}
		} else {

			// Update the contact list. First mark all old contacts
			for (var id in contactList.hash) {
				var contact = contactList.get(id);
				contact.old = true;
			}

			var savedContacts = getData( "contacts" );

			// Add all new contacts to the list
			if (data[1] != "") {
				var contacts = data[1].split("[^]");

				if (contacts.length > 0) {
					sortedContacts = new Array( contacts.length );
					var i = 0;

					for (var c in contacts) {
						var newcontact = contacts[c].split("[|]");
						var id = newcontact[0];
						if (id.indexOf("+") == 0)
							id = id.substring(1);
						var avatar = newcontact[2]; if (avatar == undefined) avatar = "1";
						var avatarURL = "http://hanashi.nu/im/Avatars?id="+avatar+"&w=30&h=40";
						if (avatar < 10) avatarURL = "_imgmap/defAvatar"+avatar+".gif";

						sortedContacts[i++] = id;

 						var isChecked = (savedContacts.indexOf("/"+id+"/") >= 0);

						var contact = contactList.get(id);
						if (contact == undefined || contact == null) {
							contact = new Contact( id, newcontact[0], newcontact[1], avatarURL );
							contact.old = false;
							contact.show = isChecked || !gettingContactsFirstTime; // Always show new contacts automatically   !!problem om första gg!!
							contactList.put( id, contact );
							if (newcontact.length >= 4)
								contact.presence = newcontact[3];
							if (newcontact.length >= 5)
								contact.status = newcontact[4];
						} else {
							contact.old = false;
						}
					}
				}
			}

			// Now remove all old contacts
			for (var id in contactList.hash) {
				var contact = contactList.get(id);
				if (contact.old) contactList.remove( id );
			}

			// Finally, recreate the checkbox table
			var table = document.getElementById( "contacttable" );
			while (table.rows.length > 0) {
				table.deleteRow( 0 );
			}

			createNewContactRow( "selectall", getText("Select all"), false, "selectAll()", -1 );
			for (var i in sortedContacts) {
				var contact = contactList.get(sortedContacts[i]);
				if (contact != undefined && contact != null)
					createNewContactRow( contact.id, contact.name, contact.show, "checkSelected()", contact.status );
			}

			checkSelected();

			if (gettingContactsFirstTime) {
				document.getElementById("waitbox").style.display = "none";
				showContacts();
			} else {
				getContactPositions();
			}
		}
	} // if - CONTACTS

	else if (data[0] == "CHECK") {
		if (data[1] == "1") {
			var contacts = data[2].split("[^]");

			if (contacts.length > 0) {
				var phoneList = "";
				for (var c in contacts) {
					var updatedcontact = contacts[c].split("[|]");
					var id = updatedcontact[0];
					if (id.indexOf("+") == 0)
						id = id.substring(1);
					var avatar = updatedcontact[2]; if (avatar == undefined) avatar = "1";
					var avatarURL = "http://hanashi.nu/im/Avatars?id="+avatar+"&w=30&h=40";
					if (avatar < 10) avatarURL = "_imgmap/defAvatar"+avatar+".gif";

					var contact = contactList.get(id);
					if (contact != undefined && contact != null) {
						contact.avatarURL = avatarURL;
						contact.presence = updatedcontact[3];
						contact.status = updatedcontact[4];

						if (contact.show) {
							if (phoneList != "") phoneList += ",";
							phoneList += contact.id;
						}
					}
				}
				getContactPositions( phoneList );
			}

		} else if (data[1] == "0") {
			timeoutPoll = setTimeout( "poll()", 10000 );

		} else {
			if (myVerificationCode != null) {
				document.getElementById("serverError").innerHTML = "Lost connection to the phone session. Trying to reconnect...";
				reconnecting = true;
				connectToPhone();
			} else {
				document.getElementById("serverError").innerHTML = "Lost connection to the phone session. Please reload the page";
			}
		}
	} // if - CHECK

	else if (data[0] == "MESS") {
	} // if - MESS

	else if (data[0] == "EXIT") {
		if (redirectAfterDisconnect != null)
			window.location = redirectAfterDisconnect;
		else
			window.location = ".";
	} // if - EXIT

	else if (data[0] == "ERROR") {
		document.getElementById("pin").innerHTML = getText("Error connecting to the phone") + document.phoneform.PhoneNumber.value + " ("+data[1] + ")";
	} // if - ERROR

	else {
		document.getElementById("serverError").innerHTML = "Unexpected response from server - retrying i a minute";
		setRefresh( 1 );
	}

	} catch (err) {
		handleError( err );
	}
} // serverResponse


function createNewContactRow( id, name, checked, callback, statusID ) {
	var table, lastRow, row, col, checktxt;

	var status = "";
	if (statusID == 0) status = "Not recently active";
	if (statusID == 1) status = "Offline or sleeping";
	if (statusID == 2) status = "Online";

	checktxt = "";
	if (checked) checktxt = "checked=\"checked\"";

	table = document.getElementById( "contacttable" );
	lastRow = table.rows.length;

	row = table.insertRow( lastRow );

	col = row.insertCell(0);
	col.id  = id+"Box";
	col.align  = "left";
	col.vAlign = "middle";
	col.width  = 30;
	col.height = 22;
	col.className = "contactCell";
	col.innerHTML = "<input type=\"checkbox\" id=\""+id+"\" value=\""+id+"\" "+checktxt+" onChange=\""+callback+"\">";

	col = row.insertCell(1);
	col.id  = id+"Text";
	col.align  = "left";
	col.vAlign = "middle";
	col.width  = 175;
	col.height = 22;
	col.className = "contactCell";
	col.innerHTML = "<span onClick=\"sendWakeUp('"+id+"');\">" + name + "</span>" + "<br>" +
	                "<span class=\"contactStatusClass\">" + status + "</span>";
} // createNewContactRow


function clickContact( id ) {
	document.getElementById(id).click();
}


function checkSelected() {
	var contactExists = false;
	var selectedContacts = "";
	for (var id in contactList.hash) {
		var contact = contactList.get(id);
		contact.show = document.getElementById(contact.id).checked;
		if (contact.show) {
			contactExists = true;
			selectedContacts += contact.id + "/";
		}
	}

	if (contactExists) {
		if (document.getElementById("maplayer").style.display == "none")
			document.getElementById("tabMap").className = "topNavTabUnselected";
		else
			document.getElementById("tabMap").className = "topNavTabSelected";
	} else {
		document.getElementById("tabMap").className = "topNavTabUnclickable";
	}

	saveData( "contacts", "/" + selectedContacts );
}


function selectAll() {
	document.getElementById("selectallText").innerHTML = "<span onClick=\"unSelectAll();\">" + getText( "Unselect all" ) + "</span>";
	document.getElementById("selectallBox").innerHTML = "<input type=\"checkbox\" id=\"selectall\" value=\"selectall\" checked=\"checked\" onChange=\"unSelectAll()\">";

	for (var id in contactList.hash) {
		var contact = contactList.get(id);
		document.getElementById(contact.id).checked = true;
	}

	checkSelected();
}


function unSelectAll() {
	document.getElementById("selectallText").innerHTML = "<span onClick=\"selectAll();\">" + getText( "Select all" ) + "</span>";
	document.getElementById("selectallBox").innerHTML = "<input type=\"checkbox\" id=\"selectall\" value=\"selectall\" onChange=\"selectAll()\">";

	for (var id in contactList.hash) {
		var contact = contactList.get(id);
		document.getElementById(contact.id).checked = false;
	}

	checkSelected();
}


function checkPhoneNumber( phoneNo ) {
	var patt = /^\+?[\d ]+$/;
	if (patt.test( phoneNo )) {
		return true;
	} else {
		alert( getText( "Illegal format of phone number", phoneNo ) );
		return false;
	}
}


function connectToPhone() {
	myPhoneNo = document.phoneform.PhoneNumber.value.replace(/ /g,"");
	var pinCode = generatePin( 4 );

	myVerificationCode = getData( "ver" + getShortPhone(myPhoneNo) );
	if (myVerificationCode == "")
		myVerificationCode = generatePin( 12 );

	document.getElementById("pin").innerHTML = getText("Enter #1 in your phone", pinCode );

	document.phoneform.PhoneNumber.blur();
	ajaxFunction( "search", myPhoneNo + "\t" + pinCode + "\t" + myVerificationCode );

	return false;
} // connectToPhone


function generatePin( digits ) {
	var pin = "" + Math.floor( Math.random() * Math.pow(10,digits) );
	while (pin.length < digits)
		pin = "0"	 + pin;
	return pin;
} // generatePin


function getQueryString( name ) {
	var paramExpressions, param, parts;
	paramExpressions = window.location.search.substr(1).split("&");
	for (var param in paramExpressions) {
		parts = paramExpressions[param].split("=");
		if (parts.length >= 2) {
			if (parts[0] == name)
				return unescape( parts[1] );
		}
	}
	return "";
}


function showMap() {
	if (sessionID != "") {
		getAndSaveAllSettings();

		if (document.getElementById("tabMap").className != "topNavTabUnclickable") {
			document.getElementById("tabContact").className = "topNavTabUnselected";
			document.getElementById("tabMap").className = "topNavTabSelected";

			document.getElementById("phonelayer").style.display = "none";
			document.getElementById("contactlayer").style.display = "none";
			document.getElementById("maplayer").style.display = "block";

			if (map == null)
				initializeMap();
			else
				update();
		}
	}

	return false;
}

function showContacts() {
	removeRefresh();

	if (sessionID != "") {
		checkSelected();
		gettingContactsFirstTime = false;

		document.getElementById("tabContact").className = "topNavTabSelected";
		document.getElementById("tabMap").className = "topNavTabUnselected";

		document.getElementById("phonelayer").style.display = "none";
		document.getElementById("contactlayer").style.display = "block";
		document.getElementById("maplayer").style.display = "none";
	}

	return false;
}

function setRefresh( interval ) {
	removeRefresh();
	if (interval > 0) {
		timeoutUpdate = setTimeout( "update()", interval*60000 );
		timeoutPoll = setTimeout( "poll()", 10000 );
	}
}

function removeRefresh() {
	if (timeoutUpdate != undefined && timeoutUpdate != null) {
		clearTimeout( timeoutUpdate );
	}
	timeoutUpdate = null;
}


// ------------------------------
//	 Functions for GoogleMap
// ------------------------------

function getContactPositions( phoneList ) {
	if (phoneList == undefined) {
		phoneList = "";
		for (var id in contactList.hash) {
			var contact = contactList.get(id);
			if (contact.show) {
				if (phoneList != "") phoneList += ",";
				phoneList += contact.id;
			}
		}
	}

	log( "accessing "+server+"?comm=pos&sid=" + sessionID + "&phones=" + phoneList );
	GDownloadUrl(server+"?comm=pos&sid=" + sessionID + "&phones=" + phoneList, function(data) {
		log( "response " + data );

		var response = eval('(' + data + ')');
		// response.contacts contains number, pos, lat, lon, acc

		// Update the contactList with all positions
		var positions = response.contacts;
		for (var i = 0; i < positions.length; i++) {
			var contact = contactList.get( positions[i].number );
			if (contact != undefined) {
				contact.pos = positions[i].pos;
				if (contact.pos == "NA") {
					contact.pos = "";
					contact.lat = "";
					contact.lon = "";
				} else {
					contact.lat = positions[i].lat;
					contact.lon = positions[i].lon;
					contact.acc = positions[i].acc;
				}
			}
		}

		document.getElementById("waitbox").style.display = "block";
		removeAllPins();
		document.getElementById("contactPosTable").innerHTML = "";

		putContactsOnMap();

		document.getElementById("serverError").innerHTML = "";
	 	document.getElementById("waitbox").style.display = "none";

		setRefresh( refreshIntervalMinutes );
	});
}


function removeAllPins() {
	for (var id in contactList.hash) {
		var contact = contactList.get(id);
		if (contact.marker != undefined && contact.marker != null) {
			map.removeOverlay( contact.marker );
		}
	}
	if (accurencyAreas != undefined) {
		for (var area in accurencyAreas) {
			if (accurencyAreas[area] != undefined && accurencyAreas[area] != null) {
				map.removeOverlay( accurencyAreas[area] );
			}
			accurencyAreas[area] = null;
		}
	}
}


function putContactsOnMap() {
	processCreatingMap = true;

	// Find all coordinates to calculate the bounds for the map so it can be zoomed
	var bounds = createContactMarkers();

	createContactAccBounds( bounds );

	// Set the center of the map and a nice zoom level
	map.setCenter( bounds.getCenter(), map.getBoundsZoomLevel(bounds)-1 );

	// Calculate the z-coordinates and pin groups
	calculateAvatarPositions();

	// Create all accurence cirkles as GPolygon and set the accurencyAreas with them all
	createContactAccCircles();

	// Now put the markers on the map
	for (var id in contactList.hash) {
		var contact = contactList.get(id);
		if (contact.show && contact.pos != "") {
			// Create a pin on the map and the accurency cirkle around it
			if (currentSettingPinType == 'I' || contact.zindex == 0) {
				contact.marker.setLatLng( contact.accbounds.getCenter() );
				map.addOverlay( contact.marker );
			}
		}
	}
	for (var area in accurencyAreas) {
		map.addOverlay( accurencyAreas[area] );
	}

	// Create the content of the floating contact list
	createFloatingContactList();

	processCreatingMap = false;
}


// Create all markers for the contacts and put it in contacts.marker.
// Returns a GLatLngBounds with all contacts.
function createContactMarkers() {
	var bounds = new GLatLngBounds();

	for (var id in contactList.hash) {
		var contact = contactList.get(id);
		if (contact.show && contact.pos != "") {
			var latlng = new GLatLng( contact.lat, contact.lon );
			bounds.extend( latlng );

			var avatarIcon = new GIcon(G_DEFAULT_ICON);
			var avatarTitle = "";
			if (currentSettingPinType == 'P') {
				avatarIcon.image = "_imgmap/pin0.png";
				avatarIcon.iconSize = new GSize( 32, 32 );

				avatarIcon.iconAnchor = new GPoint( 0, 32 );
			} else {
				avatarIcon.image = contact.avatar;
				avatarIcon.iconSize = new GSize( 30, 40 );
				avatarIcon.shadow = "_imgmap/avatarShadow.png";
				avatarIcon.shadowSize = new GSize( 31, 41 );

				avatarIcon.iconAnchor = new GPoint( 15, 20 );
				avatarTitle = contact.name;
			}

			contact.marker = new GMarker( latlng, {icon:avatarIcon, title:avatarTitle} );
		}
	}

	return bounds;
}


// Create the boundsList hashtable with one GLatLngBounds for each group of contacts.
// If totalbounds is sent in, it's extended with all bounds created
function createContactAccBounds( totalbounds ) {
	// Create the bounds array
	boundsList = new Hashtable();
	for (var id in contactList.hash) {
		var contact = contactList.get(id);
		if (contact.show && contact.pos != "") {
			var posLeft   = contact.lon - contact.acc / 62876.0;
			var posRight  = contact.lon + contact.acc / 62876.0;
			var posBottom = contact.lat - contact.acc / 111319.0;
			var posTop    = contact.lat + contact.acc / 111319.0;

			var bounds = boundsList.get( contact.group );
			if (bounds == undefined) {
				bounds = new GLatLngBounds();
				boundsList.put( contact.group, bounds );
			}
			var temp = new GLatLng( posBottom, posLeft );
			bounds.extend( temp );
			if (totalbounds != null) totalbounds.extend( temp );
			temp = new GLatLng( posTop,    posRight );
			bounds.extend( temp );
			if (totalbounds != null) totalbounds.extend( temp );

			contact.accbounds = bounds;
		}
	}
}


// Create the accurencyAreas array with one GOverlay for each group of contacts.
// It depends on that createContactAccBounds has been called before, to create the boundsList.
// The overlays are created from all the bounds as square, octagone or circle
function createContactAccCircles() {
	// Create the bounds array
	var boundsList = new Hashtable();
	for (var id in contactList.hash) {
		var contact = contactList.get(id);
		if (contact.show && contact.pos != "") {
			var posLeft   = contact.lon - contact.acc / 62876.0;
			var posRight  = contact.lon + contact.acc / 62876.0;
			var posBottom = contact.lat - contact.acc / 111319.0;
			var posTop    = contact.lat + contact.acc / 111319.0;

			var bounds = boundsList.get( contact.group );
			if (bounds == undefined) {
				bounds = new GLatLngBounds();
				boundsList.put( contact.group, bounds );
			}
			bounds.extend( new GLatLng( posBottom, posLeft ) );
			bounds.extend( new GLatLng( posTop,    posRight ) );

			contact.accbounds = bounds;
		}
	}

 	// Create the overlays
	accurencyAreas = new Array();
	for (var id in boundsList.hash) {
		var bounds = boundsList.get(id);

		var poly = new Array();

         var sw = bounds.getSouthWest();             // South west corner
         var ne = bounds.getNorthEast();             // North east corner
         var se = new GLatLng( sw.lat(), ne.lng() ); // South east corner
         var nw = new GLatLng( ne.lat(), sw.lng() ); // North west corner

		switch(currentSettingAccurency) {
			case 'S': // Create square
			          poly[0] = sw;
			          poly[1] = nw;
			          poly[2] = ne;
			          poly[3] = se;
			          poly[4] = sw;
			          break;
			case 'O': // Create 8-sided polygone
			          var lgdCornerH = se.distanceFrom(sw) * 0.293 / 62876.0;
			          var lgdCornerV = ne.distanceFrom(se) * 0.293 / 111319.0;
			          poly[0] = new GLatLng( ne.lat(),              nw.lng() + lgdCornerH );
			          poly[1] = new GLatLng( ne.lat(),              ne.lng() - lgdCornerH );
			          poly[2] = new GLatLng( ne.lat() - lgdCornerV, ne.lng() );
			          poly[3] = new GLatLng( se.lat() + lgdCornerV, ne.lng() );
			          poly[4] = new GLatLng( se.lat(),              ne.lng() - lgdCornerH );
			          poly[5] = new GLatLng( se.lat(),              nw.lng() + lgdCornerH );
			          poly[6] = new GLatLng( se.lat() + lgdCornerV, nw.lng() );
			          poly[7] = new GLatLng( ne.lat() - lgdCornerV, nw.lng() );
			          poly[8] = new GLatLng( ne.lat(),              nw.lng() + lgdCornerH );
			          break;
			case 'C': // Create a circle
			          var radiusH = se.distanceFrom(sw) * 0.5 / 62876.0;
			          var radiusV = ne.distanceFrom(se) * 0.5 / 111319.0;
			          for (var i = 0; i < xCoor.length; i++) {
			          	poly[i] = new GLatLng( sw.lat() + radiusV * yCoor[i], sw.lng() + radiusH * xCoor[i] );
			          }
			          poly[xCoor.length] = new GLatLng( sw.lat() + radiusV * yCoor[0], sw.lng() + radiusH * xCoor[0] );
			          break;
		}

		accurencyAreas[id] = new GPolygon( poly, circleColours[id], currentSettingShapeBorder, 1.0, circleColours[id], 0.05 );
	}
}


// Create the groups and z-index for all contacts into contact.group and contact.zindex.
// The group is a number with all contacts close enough to each other are in the same group.
// Z-index is 0 = first contact in the group, 1 = second in same group etc.
function calculateAvatarPositions() {
	var temp = new Array();
	var  c = 0;
	for (var id in contactList.hash) {
		var contact = contactList.get(id);
		if (contact.show && contact.pos != "") {
			temp[c++] = contact;
		} else {
			contact.zindex = -1;
			contact.group  = -1;
		}
	}

	nextGroup = 0;
	for (var i = 0; i < temp.length; i++) {
		var oldZValue = temp[i].zindex;
		var oldGValue = temp[i].group;
		temp[i].zindex = 0;
		temp[i].group  = nextGroup;
		var pos1 = map.fromLatLngToContainerPixel( new GLatLng( temp[i].lat, temp[i].lon ) );

		for (var j = 0; j < i; j++) {
			var pos2 = map.fromLatLngToContainerPixel( new GLatLng( temp[j].lat, temp[j].lon ) );
			if (Math.abs(pos1.x-pos2.x) < 16 && Math.abs(pos1.y-pos2.y) < 16) {
				temp[i].zindex++;
				temp[i].group = temp[j].group;
			}
		}
		if (temp[i].group == nextGroup) nextGroup++;

		if (currentSettingPinType == 'P') {
			var pinNo = temp[i].group % 10;

			temp[i].marker.getIcon().iconAnchor = new GPoint( 0, 32 );
			temp[i].marker.getIcon().image = "_imgmap/pin"+pinNo+".png";
			var clpin = document.getElementById("clpin"+temp[i].id);
			if (clpin != undefined) clpin.src = "_imgmap/pin"+pinNo+".png";
		} else {
			temp[i].marker.getIcon().iconAnchor = new GPoint( 15 - temp[i].zindex*20, 20 - temp[i].zindex*5 );
		}
	}
}


function createFloatingContactList() {
	var imageSrc;
	var table = "<table>";
	for (var i in sortedContacts) {
		var contact = contactList.get(sortedContacts[i]);
		if (contact.show && (currentSettingShowAllContacts || contact.pos != "")) {
			// Create a line in the floating contact table
			table += "<tr valign=\"top\">";
			if (currentSettingPinType == 'P') {
				if (contact.pos != "")
					imageSrc = contact.marker.getIcon().image;
				else if (contact.status == 1)
					imageSrc = "_imgmap/wakeup.png\" onClick=\"sendWakeUp('"+contact.id+"');";
				else
					imageSrc = "_imgmap/pin_nopos.png";
				table += "<td><img id=\"clpin"+contact.id+"\" src=\""+imageSrc+"\"></td>";
			}
			table += "<td><div id=\"clava"+contact.id+"\"><img src=\""+contact.avatar+"\" onClick=\"showLargeAvatar('"+contact.id+"');\"></div></td>";
			table += "<td nowrap onClick=\"sendWakeUp('"+contact.id+"');\">" + contact.name;
			var status = "";
			if (contact.status == 0) status = "Not recently active";
			if (contact.status == 1) status = "Offline or sleeping";
			if (contact.status == 2) status = "Online";
			if (status != "")
				table += "<br><span class=\"contactStatusClass\">" + status + "</span>";
			if (contact.presence != "")
				table += "<br><span class=\"contactPresenceClass\">" + contact.presence + "</span>";
			if (currentSettingShowPos)
				table += "<br><span class=\"contactPosClass\">" + (contact.pos != "" ? contact.pos : "---") + "</span>";
			table += "</td></tr>";
		}
	}
	document.getElementById("contactPosTable").innerHTML = table;
}


function showLargeAvatar( id ) {
	var parentPos = findPos( document.getElementById("maplayer") );
	var avatarPos = findPos( document.getElementById("clava"+id) );

	var contact = contactList.get(id);
	if (contact != undefined && contact != null) {
		var largeAvatar = contact.avatar.replace("&w=30&h=40","&w=112&h=150");
		var element = document.getElementById("contactPosTableAvatar");
		element.innerHTML = "<img src=\""+largeAvatar+"\" onClick=\"document.getElementById('contactPosTableAvatar').style.display = 'none';\">";
		element.style.left = avatarPos[0] - parentPos[0] + 35;
		element.style.top  = avatarPos[1] - parentPos[1] + 10;
		element.style.display = "block";
	}
} // showLargeAvatar


function sendWakeUp( id ) {
	var contact = contactList.get(id);
	if (contact != undefined && contact != null) {
		var message = prompt( "Do you want to wake up "+contact.name+" with an SMS with text:", "I am asking for your position. Please choose Continue!" );
		if (message != null) {
			ajaxFunction( "mess", contact.phone + "\t" + message );
		}
	}
}


function clickContactOnMap( marker ) {

	if (marker) {
		var clickedContact = undefined;
		for (var id in contactList.hash) {
			var contact = contactList.get(id);
			if (contact.marker == marker) {
				clickedContact = contact;
				break;
			}
		}

		if (clickedContact == undefined) return;

		var html = "<div class=\"popup\"><table>";
		var moreLines = false;
		for (var i in sortedContacts) {
			var contact = contactList.get(sortedContacts[i]);
			if (contact == clickedContact || currentSettingPinType == 'P' && contact.group == clickedContact.group) {
				var tmp = "<img src=\""+contact.avatar+"\">";

				if (moreLines)
					html += "<tr><td colspan=\"3\"><img src=\"_imgmap/dot.png\" width=\"100%\" height=\"1\"></td></tr>";
				moreLines = true;

				html += "<tr><td rowspan=\"3\">"+tmp+"</td><td>Name:</td><td>" + contact.name + "</td></tr>" +
						"<tr><td>Phone:</td><td>" + contact.phone + "</td></tr>" +
						"<tr><td>Place:</td><td>" + contact.pos + "</td></tr>";
			}
		}
		html += "</table></div>";
		marker.openInfoWindowHtml( html );
	}
}


function mapIsZoomed( oldLevel, newLevel ) {
	if (processCreatingMap) return;

	removeAllPins();

	// Re-calculate the z-coordinates and pin groups
	calculateAvatarPositions();

	// Re-calculate the accurency circles
	createContactAccBounds( null );
	createContactAccCircles();

	// Now put the markers on the map
	for (var id in contactList.hash) {
		var contact = contactList.get(id);
		if (contact.show && contact.pos != "") {
			// Create a pin on the map and the accurency cirkle around it
			if (currentSettingPinType == 'I' || contact.zindex == 0) {
				if (contact.marker != undefined && contact.marker != null) {
					contact.marker.setLatLng( contact.accbounds.getCenter() );
					map.addOverlay( contact.marker );
				}
			}
		}
	}
	for (var area in accurencyAreas) {
		if (accurencyAreas[area] != undefined && accurencyAreas[area] != null) {
			map.addOverlay( accurencyAreas[area] );
		}
	}
}


function initializeMap() {
  if (GBrowserIsCompatible()) {
	document.getElementById("waitbox").style.display = "block";

	map = new GMap2( document.getElementById("gmap") );

	map.setCenter( new GLatLng(55.6516, 13.1018), 2 );
	map.setMapType( G_NORMAL_MAP ); // G_NORMAL_MAP, G_SATELLITE_MAP, G_HYBRID_MAP
	map.addControl( new GLargeMapControl() );
	map.addControl( new GScaleControl() );
	map.addControl( new GMapTypeControl() );

	GEvent.addListener(map, "click", clickContactOnMap);
	GEvent.addListener(map, "zoomend", mapIsZoomed);

	getContactPositions();
	new GDraggableObject( document.getElementById("contactPosTable"), {left:860,top:150} );
  }
}


function log( text ) {
	if (! IE) {
		var logelement = document.getElementById("debug");
		if (logelement != undefined) {
			logelement.innerHTML = logelement.innerHTML + text + "<br>";
		}
	}
} // log
