
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// static
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

var urlPrefix		= ''

var users   		= new Array()
var userSel		= null

// demo user
var userDemo
var demoTrackIndex	= 0
var demoTrack		= new Array(new GLatLng(51.6795450,5.3458650), new GLatLng(51.6797654,5.3460640), new GLatLng(51.6799913,5.3462513), new GLatLng(51.6802217,5.3464268), new GLatLng(51.6804563,5.3465899), new GLatLng(51.6806948,5.3467409), new GLatLng(51.6809359,5.3468771), new GLatLng(51.6811790,5.3470030), new GLatLng(51.6814252,5.3471152), new GLatLng(51.6816737,5.3472135), new GLatLng(51.6819233,5.3473032), new GLatLng(51.6821738,5.3473852), new GLatLng(51.6824247,5.3474618), new GLatLng(51.6826761,5.3475289), new GLatLng(51.6829281,5.3475955), new GLatLng(51.6831780,5.3476690), new GLatLng(51.6834268,5.3477471), new GLatLng(51.6836749,5.3478260), new GLatLng(51.6839235,5.3479062), new GLatLng(51.6841751,5.3479831), new GLatLng(51.6844275,5.3480663), new GLatLng(51.6846745,5.3481430), new GLatLng(51.6849244,5.3482203), new GLatLng(51.6851735,5.3482971), new GLatLng(51.6854230,5.3483751), new GLatLng(51.6856730,5.3484581), new GLatLng(51.6859233,5.3485422), new GLatLng(51.6861733,5.3486290), new GLatLng(51.6864240,5.3487147), new GLatLng(51.6866763,5.3487924), new GLatLng(51.6869277,5.3488701), new GLatLng(51.6871791,5.3489466), new GLatLng(51.6874294,5.3490258), new GLatLng(51.6876791,5.3491059), new GLatLng(51.6879273,5.3491855), new GLatLng(51.6881756,5.3492643), new GLatLng(51.6884241,5.3493428), new GLatLng(51.6886723,5.3494204), new GLatLng(51.6889201,5.3494991), new GLatLng(51.6891674,5.3495767), new GLatLng(51.6894152,5.3496545), new GLatLng(51.6896627,5.3497310), new GLatLng(51.6899120,5.3498077), new GLatLng(51.6901609,5.3498851), new GLatLng(51.6904110,5.3499610), new GLatLng(51.6906616,5.3500339), new GLatLng(51.6909106,5.3501020), new GLatLng(51.6911629,5.3501657), new GLatLng(51.6914137,5.3502368), new GLatLng(51.6916633,5.3503172), new GLatLng(51.6919127,5.3503946), new GLatLng(51.6921628,5.3504667))

// update timeout
var updateTimer

// overlays for for active/inactive user, and tack
var markerMan		= 0
var usersOverlay	= new Array()
var trackOverlay	= 0

// icon constants
var iconPuppet0, iconPuppet, iconPuppetNo

var batch_size = 5
var timeout1 = 100

var loading_user_index
var busy
var userXML


function UsersGetById(id)
{
	var user
	user = null
	
	if (0 == id)
	{
		user = userDemo
	}
	else
	{
		var i
		for (i = 0; i < users.length; i++)
		{
			if (users[i].id == id)
			{
				user = users[i]
				break
			}
		}
	}
	
	return user
}

function UsersGetByNickname(nickname)
{
	var user
	user = null

	if ('demo' == nickname)
	{
		user = userDemo
	}
	else
	{
		var i
		for (i = 0; i < users.length; i++)
		{
			if (users[i].nickname == nickname)
			{
				user = users[i]
				break
			}
		}
	}

	return user
}

function UsersInit()
{
	// icons
	overlaysVisible = true
	iconPuppet0  = new GIcon(G_DEFAULT_ICON, 'pics/puppet0.gif')
	iconPuppet   = new GIcon(G_DEFAULT_ICON, 'pics/puppet.gif')
	iconPuppetNo = new GIcon(G_DEFAULT_ICON, 'pics/puppetNo.gif')

	// marker manager
	markerMan = new GMarkerFS(map, 200)
	// demo user
	userDemo = new CUser(0)
	userDemo.nickname	= 'demo'
	userDemo.pin 		= '0000'
	userDemo.age 		= 0
	userDemo.timeout 	= 1
	userDemo.pos		= new GLatLng(demoTrack[0].lat(),demoTrack[0].lng())
	userDemo.MarkerUpdate()
	
	// start updates
	UsersLatestListUpdate()
	UsersSelectedUpdate()
	UsersAllListUpdate()
}

function UsersSelectedSet(nickname,pin)
{
	// select existing user?
	this.marker = null
	if (userSel)
	{
		if (userSel.nickname == nickname)
		{
			// user again chooses this user
		}
		else
		{
			userSel = UsersGetByNickname(nickname)
		}
	}
	else
	{
		userSel = UsersGetByNickname(nickname)
	}
	
	// create and select new user (if not yet selected)
	if (!userSel)
	{
		userSel = new CUser(-1)
		userSel.nickname = nickname
		userSel.pin = pin
	}
	
	// overwrite pin
	if ('' != pin)
	{
		userSel.pin = pin
	}

	// clear error
	userSel.Deinit()
	
	// force immediate update
	UsersSelectedUpdate()
}

function UsersSelectedUpdate()
{
	if (userSel)
	{
		if (active == true)
		{
			// update user
			userSel.Update()
	
			// clear any previous timeout
			if (updateTimer)
			{
				clearTimeout(updateTimer)
			}
		}
		
		// set new timeout
		updateTimer = setTimeout("UsersSelectedUpdate()", userSel.timeout * 1000)
	}
}

function UsersLatestListUpdate() 
{
		try 
	{
    		netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
    		netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   		} 
   		catch (e) 
   		{
   		}

	// postfix URL with current date/time so prevent cached results for this request
	GDownloadUrl(urlPrefix + "/online/os.asp?a=lu&q=" + escape(Date()),
		function (data, responseCode)
		{
			var xmlDoc = GXml.parse(data);
			// alert('[' + data + ']')
			
			var usersTemp = new Array()
			usersTemp.push(userDemo)
			
			var userXML = xmlDoc.documentElement.getElementsByTagName("user")			
			var nn = userXML.length
			for (var u = 0; u < nn; u++)
			{
				//document.getElementById('divDebug').innerHTML = 'loading users ' + u + '/' + nn
				// get if of user
				var id			
				id = parseInt(userXML[u].getAttribute('id'))
				
				// search if this user already exists
				var user = UsersGetById(id)
				if (!user)
				{
					// create new user
					user = new CUser(id)
				}
				
				// update user
				var lon,lat
				for (i = 0; i < userXML[u].childNodes.length; i++)
				{
					if (userXML[u].childNodes[i].firstChild)
					{
						var name = userXML[u].childNodes[i].nodeName					
						var val  = userXML[u].childNodes[i].firstChild.nodeValue
		
						if ("nickname" == name)
						{
							user.nickname = val
						}
						else if ("pincode" == name)
						{
							user.pin = val
						}
						else if ("age" == name)
						{
							user.age = parseInt(val)
						}
						else if ("t" == name)
						{
							user.timeout = parseInt(val)
						}
						else if ("x" == name)
						{
							lon = parseFloat(val)
						}
						else if ("y" == name)
						{
							lat = parseFloat(val)
						}
					}
				}
				user.pos = new GLatLng(lat,lon)
				
				// push user in new users array
				usersTemp.push(user)
			}
			
			// activate new users array
			users = usersTemp
			
			// format divUsers object
			var scratch = ''
			scratch += '<table CELLSPACING=1 CELLPADDING=0 bgcolor=#F8F8FF>'
			scratch += '<tr><th></th><th align=left>nickname</th><th align=left>updated</th></tr>'
			for (i = 0; i < Math.min(15,users.length); i++)
			{
				// get last update
				var lastUpdate
				if (users[i].OnlineGet())
				{
					lastUpdate = '<blink><b><font color=blue>online</font></b></blink>'
				}
				else
				{
					lastUpdate = users[i].LastUpdateGet()
				}
			
				scratch += '<tr>'		
				scratch += '<td><div style="overflow: hidden; width: 23; white-space : nowrap;">' + users[i].IconSmallGet() + '</div></td>'
				scratch += '<td><div style="overflow: hidden; width: 70; white-space : nowrap;">' + users[i].NicknameGet() + '</div></td>'
				scratch += '<td><div style="overflow: hidden; width: 93; white-space : nowrap;">' + lastUpdate + '</div></td>'
				
				scratch += '</tr>'
			}
			scratch += '</table>'
			document.getElementById('divUsers').innerHTML = scratch
			
			// refresh twice per minute
			setTimeout("UsersLatestListUpdate()", 30000)
		}
	)
}

function UsersAllListUpdate() 
{
	if (busy)
	{
		setTimeOut(UsersAllListUpdate, 300)
		return
	}
	
	busy = true
		try 
		{
    		netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
    		netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   		} 
   		catch (e) 
   		{
   		}
	// postfix URL with current date/time so prevent cached results for this request
	GDownloadUrl(urlPrefix + "/online/os.asp?a=au&q=" + escape(Date()),
		function (data, responseCode)
		{
			var xmlDoc = GXml.parse(data);
			
			userXML = xmlDoc.documentElement.getElementsByTagName("user")		
			loading_user_index = 0;
			processListXML()
		}
		)
}

function processListXML()
{	
	var u
	var bc = 0
	for (u = loading_user_index; u < userXML.length && bc < batch_size; u++)
	{
		bc++
		// get if of user
		var id			
		id = parseInt(userXML[u].getAttribute('id'))
		
		// search if this user already exists
		var user = UsersGetById(id)
		if (!user)
		{
			// create new user
			user = new CUser(id)
		}
		
		// update user
		var lon,lat
		for (i = 0; i < userXML[u].childNodes.length; i++)
		{
			if (userXML[u].childNodes[i].firstChild)
			{
				var name = userXML[u].childNodes[i].nodeName					
				var val  = userXML[u].childNodes[i].firstChild.nodeValue

				if ("nickname" == name)
				{
					user.nickname = val
				}
				else if ("pincode" == name)
				{
					user.pin = val
				}
				else if ("age" == name)
				{
					user.age = parseInt(val)
				}
				else if ("t" == name)
				{
					user.timeout = parseInt(val)
				}
				else if ("x" == name)
				{
					lon = parseFloat(val)
				}
				else if ("y" == name)
				{
					lat = parseFloat(val)
				}
			}
		}
		user.pos = new GLatLng(lat,lon)
		
		// user overlay
		user.MarkerUpdate()
	}
	loading_user_index = u;
	if (loading_user_index >= userXML.length)
	{
		document.getElementById('divDebug2').innerHTML = ''
		markerMan.refresh()
		busy = false
		userXML = 0
	}
	else
	{
		document.getElementById('divDebug2').innerHTML = 'Loading users: ' + loading_user_index + '/' + userXML.length
		setTimeout(processListXML, timeout1)
	}
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// class
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

function CUser(id)
{
	this.id			= id
	this.nickname   	= 'unknown'
	this.pin		= ''	
	this.age		= 0
	this.timeout		= 1
	this.pos		= new GLatLng(0,0)
	this.speed		= 0
	this.heading		= 0
	this.marker		= 0
	this.track		= new Array()
	this.state		= 0			// 0: uninitialized, 1: initializing, 2: initialized, 3: error
	
	this.ZeroGet		= CUser_ZeroGet
	this.OnlineGet		= CUser_OnlineGet
	this.PrivateGet		= CUser_PrivateGet
	this.LastUpdateGet	= CUser_LastUpdateGet
	this.IconGet		= CUser_IconGet
	this.IconSmallGet	= CUser_IconSmallGet
	this.NicknameGet	= CUser_NicknameGet
	this.InfoGet		= CUser_InfoGet
	this.MarkerUpdate	= CUser_MarkerUpdate
	
	this.Init		= CUser_Init
	this.Deinit		= CUser_Deinit
	this.Update		= CUser_Update
	this.Redraw		= CUser_Redraw
}

function CUser_ZeroGet()
{
	if (this.pos)
	{
		return  0 == this.pos.lat()  &&  0 == this.pos.lng()
	}
	else
	{
		return true;
	}
}

function CUser_OnlineGet()
{
	return  this.age <= this.timeout+5
}

function CUser_PrivateGet()
{
	return  '0000' != this.pin
}

function CUser_LastUpdateGet()
{
	var luDate
	luDate = new Date()
	luDate.setTime(luDate.getTime() - 1000 * users[i].age)
	return luDate.format('hh:nn:ss mm/dd/yyyy')
}

function CUser_IconGet()
{
	var icon
	if (this.ZeroGet())
	{
		icon = iconPuppet0
	}
	else if (this.OnlineGet())
	{
		icon = iconPuppet
	}
	else
	{
		icon = iconPuppetNo
	}

	return icon
}

function CUser_IconSmallGet()
{
	var icon
	icon = '<img src="'
	if (this.ZeroGet())
	{
		icon += 'pics/puppet0S.bmp'
	}
	else if (this.OnlineGet())
	{
		icon += 'pics/puppetS.bmp'
	}
	else
	{
		icon += 'pics/puppetNoS.bmp'
	}
	icon += '" ALIGN="LEFT" border="0" VSPACE="0" HSPACE="0">'
	
	if (this.PrivateGet())
	{
		icon += '<img src="Pics\\lockS.bmp" ALIGN="LEFT" border="0" VSPACE="0" HSPACE="0">'
	}
	
	return icon
}

function CUser_NicknameGet()
{
	return '<a href="#" onClick="OnTrackUser(\'' + this.nickname + '\',\'' + this.pin + '\')">' + this.nickname + '</a>'
}

function CUser_InfoGet()
{
	// compute when last update happened (current time minus age)
	var msg, lastUpdate
	lastUpdate = new Date()
	lastUpdate.setTime(lastUpdate.getTime() - 1000 * this.age)
	msg  = this.IconSmallGet()
	msg += "&nbsp" + this.NicknameGet()
	msg += "&nbsp(speed: " + this.speed + "kmh"
	msg += ", updated: " + lastUpdate.format('mm/dd/yyyy hh:nn:ss')
	msg += ", interval: " + this.timeout + "s)"
	
	return msg
}

function CUser_MarkerUpdate()
{
	var marker = 0
	if (!this.marker)
	{
		marker = this.marker = new GMarker(this.pos,{icon: this.IconGet(), clickable: true, title: this.nickname});

		var html = this.InfoGet()
		GEvent.addListener(marker, "click", function()
			{
				marker.openInfoWindowHtml(html);
			});
			
		usersOverlay.push(marker)
		markerMan.addMarker(marker,0,17)
	}
	else
	{
		// search for this marker in array of markers
		for (m in usersOverlay)
		{
			if (this.marker == usersOverlay[m]) { marker=this.marker; break; } // found!
		}
		if (marker)
		{
			marker.setPoint(this.pos)
			
			if (this.IconGet() != marker.getIcon())
			{
				markerMan.delMarker(marker)
				
				marker = this.marker = new GMarker(this.pos,{icon: this.IconGet(), clickable: true, title: this.nickname});
				
				var html = this.InfoGet() 	
				GEvent.addListener(marker, "click", function()
					{
						marker.openInfoWindowHtml(html);
					});
				usersOverlay[m] = marker
				markerMan.addMarkerForced(marker)
			}
		}
		else
		{
			alert('?')
		}
	}
	
	return marker;
}

function CUser_Init()
{
	// do not initialize if already done or error
	if (0 != this.state) return
	
	this.track.clear()
	if (0 == this.id)
	{
		demoTrackIndex = 0
		this.state = 2
	}
	else
	{
		this.state = 1
		// postfix URL with current date/time so prevent cached results for this request
		var user = this
		try 
		{
    		netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
    		netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   		} 
   		catch (e) 
   		{
   		}
		GDownloadUrl(urlPrefix + "/online/os.asp?a=bt&n=" + escape(this.nickname) + "&c=" + escape(this.pin)+ "&q=" + escape(Date()),
			function(data, responseCode)
			{

				// stop on error
				if (3 == user.state) return
				
				var xmlDoc = GXml.parse(data);
				// alert('[' + data + ']')

				var wpXML = xmlDoc.documentElement.getElementsByTagName("waypoint")
				if (wpXML.length <= 0)
				{
					// set error state
					user.state = 3
					if ("result" == xmlDoc.documentElement.nodeName)
					{
						// expected error codes: 5, 7, 8, or 9
						var tmLastError = parseInt(xmlDoc.documentElement.getAttribute("id"))
						switch (tmLastError)
						{
							case 5 : alert('The nickname you entered may not be empty.\n\nEnter exactly the same nickname as specified in Tracky.'); break;
							case 7 : alert('Nickname does not exist.\n\n1) enter exactly the same nickname as specified in Tracky\n2) make sure the client you try to track uses Tracky version 2.2 or higher'); break;
							case 8 : alert('Enter a valid PIN code.'); break;
							case 9 : alert('The PIN code you entered does not match the PIN code as specified in Tracky.'); break;
							default: alert('unknown error (' + tmLastError + ')'); break;
						}
					}
					else
					{
						alert('No position received from the given nickname.')
					}
				}
				else
				{
					for (var u = 0; u < wpXML.length; u++)
					{
						var lat,lon
						for (i = 0; i < wpXML[u].childNodes.length; i++)
						{
							if (wpXML[u].childNodes[i].firstChild)
							{
								var name = wpXML[u].childNodes[i].nodeName
								var val  = wpXML[u].childNodes[i].firstChild.nodeValue
		
								if ("x" == name)
								{
									lon = parseFloat(val)
								}
								else if ("y" == name)
								{
									lat = parseFloat(val)
								}
							}
						}
						// push in track of corresponding user
						//alert('lon= ' + lon + ' lat=' + lat)
						user.track.push(new GLatLng(lat,lon))
					}

					user.state = 2
					user.Update()
				}
			}
		);
	}
}

function CUser_Deinit()
{
	this.track.clear
	this.state = 0
}

function CUser_Update()
{
	// stop on error
	if (3 == this.state) return
	
	// make sure user is initialized
	if (this.state < 2)
	{
		this.Init()
	}
	
	if (0 == this.id)
	{
		demoTrackIndex++
		
		if (demoTrackIndex < demoTrack.length)
		{
			var pp = demoTrack[demoTrackIndex]
			
			this.age 	= 0
			this.timeout	= 1
			this.speed  	= 102.2
			this.heading	= 0
			
			this.pos = new GLatLng(pp.lat(),pp.lng())
			this.track.push(this.pos)
		}
		else
		{
			this.age	= demoTrackIndex - demoTrack.length
		}
		
		this.Redraw()
	}
	else
	{
		try 
		{
    		netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
    		netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   		} 
   		catch (e) 
   		{
   		}

		// postfix URL with current date/time so prevent cached results for this request
		var user = this
		GDownloadUrl(urlPrefix + "/online/os.asp?a=bg&n=" + escape(this.nickname) + "&c=" + escape(this.pin)+ "&q=" + escape(Date()),
			function(data, responseCode)
			{

				// stop on error
				if (3 == user.state) return
	
				var xmlDoc = GXml.parse(data);
				//alert('[' + data + ']')
									
				var buddyposition = xmlDoc.documentElement.getElementsByTagName("buddyposition");
				if (buddyposition.length <= 0)
				{
					// error, but error already signaled on init
					// so we should never come here
				}
				else
				{
					// store user ID
					user.id = parseInt(buddyposition[0].getAttribute('id'))
					
					// wait with pushing positions until initialized
					if (user.state == 2)
					{
						var lat,lon
						for (i = 0; i < buddyposition[0].childNodes.length; i++)
						{
							if (buddyposition[0].childNodes[i].firstChild)
							{
								var name = buddyposition[0].childNodes[i].nodeName
								var val  = buddyposition[0].childNodes[i].firstChild.nodeValue
		
								if ("age" == name)
								{
									user.age = parseInt(val)
								}
								else if ("t" == name)
								{
									user.timeout = parseInt(val)
								}
								else if ("x" == name)
								{
									lon = parseFloat(val)
								}
								else if ("y" == name)
								{
									lat = parseFloat(val)
								}
								else if ("s" == name)
								{
									user.speed = Math.round(10*val)/10
								}
								else if ("h" == name)
								{
									user.heading = parseInt(val)
								}
							}
						}
						// store latest position an push in track					
						user.pos = new GLatLng(lat,lon)
						user.track.push(user.pos)
						
						//alert('pushed (' + lat + ',' + lon + '), len is now ' + user.track.length)

						user.Redraw()
					}
					else
					{
						// user has not yet been initialized
						user.Init()
					}
				}
			}
		);
	}
}


function CUser_Redraw()
{
	// pan map if follow=true
	if (follow)
	{	
		map.panTo(this.pos)
	}
	
	//
	// show info in info textbox
	//
	document.getElementById('info').innerHTML = this.InfoGet()

	
	// draw puppet
	//if (usersOverlay) map.removeOverlay(usersOverlay)
	if (overlaysVisible)
	{
		this.MarkerUpdate()
	}
	
	// remove current track overlay
	if (trackOverlay) map.removeOverlay(trackOverlay)
	if (overlaysVisible)
	{
		// draw updated track
		trackOverlay = new GPolyline(this.track, "#0000FF", 5, 0.5);
		map.addOverlay(trackOverlay);
	}

	// update lat/lon
	if (!editLatLon)
	{
		myLat = new Number(map.getCenter().lat())
		myLon = new Number(map.getCenter().lng())
		document.frmJump.elements['InputLat'].value  = myLat.toFixed(8)
		document.frmJump.elements['InputLon'].value  = myLon.toFixed(8)
	}
}

