/* geowiki.js */

//mode is one of the main modes (view, edit, history, search) or a temporary one
//(pick, pick2, tempSearch, tempEdit)
var globalMode = "view";
var oldMode = "";

//--------------worldkit -> js------------------------
//called from worldkit when an item has been clicked
function itemClicked(args) {
	var argObject = parseArgs(args);
	var mode = getMode();

	if (mode == "pick") {
		setMode("pick2");
		askForItem(argObject["id"]);
	}
	else if (mode == "view") {
		var url = argObject["link"];
		setContentUrl(url, "true");
	}
	else if (mode == "search") {
		if (argObject["lat"] && argObject["long"])
			zoomMap(argObject["lat"], argObject["long"], 3);
	}		
}

//called from worldkit when the user clicked into the map or as a response to
//askForItem()
function pointClicked(args) {
	var mode = getMode();	
	if (mode == "edit") {
		var argObject = parseArgs(args);
		var lastPoint = getLastPoint();
		addPoint(argObject["lat"], argObject["long"], lastPoint);
		showTempItem();
	}
	else if (mode == "pick") {
		//ignore
	}
	else if (mode == "pick2") {
		var ao = parseItem(args);
		var title = ao["title"];
		if (title != "currentItem" && title.substring(0, 9) != "tempPoint")
			item2forms(title, ao["link"], ao["desc"], ao["type"], ao["coords"], ao["tags"], "");
		setMode("edit");
	}
	else if (mode == "search" || mode == "tempSearch") {
		var argObject = parseItem(args);
		//todo: sth. with zoom factor, e.g. maxzoom
		if (argObject["lat"] && argObject["long"])
			zoomMap(argObject["lat"], argObject["long"], 3);
		activateItem(getUid(argObject["title"]));
		var url = argObject["link"];
		if (mode == "tempSearch")
			setMode("");	//back to previous mode
	}
	else if (mode == "tempEdit") {
		var ao = parseItem(args);
		item2forms(ao["title"], ao["link"], ao["desc"], ao["type"], ao["coords"], ao["tags"], "");
		setMode("edit");	//back to previous mode
	}
}


//--------------forms -> js------------------------
//called from the web interface via buttons or links

//called to pan and zoom to this item
function searchItem(itemTitle) {
	var uid = getUid(itemTitle);
	searchUid(uid);
}

function searchUid(uid) {
	setMode("tempSearch");
	askForItem(uid);
}

function editUid(uid) {
	setMode("tempEdit");
	askForItem(uid);
}

function showVersion(v) {
	clearRSS();
	var file = "rss.php?v=" + v;
	loadRSS(file);
}

//called to delete the last point of the currently edited item
function delLastPoint(showTemp) {
	delPoint(getLastPoint());
	if (showTemp == "true")
		showTempItem();
}

//delete item which is currently being edited from rss-file
function delItem() {
	jsrsPost = true;
	
	var uid = getUid(document.forms.formEdit.title.value);
	var user = document.forms.formEdit.user.value;
	var item = "";
	var params = Array(uid, user, item);
	
	jsrsExecute("data.rs.php", addItemCallback, "annotate", params);
}

//called when cancel button is pressed in edit form 
function cancelItem() {
	clearForm();
	setMode("edit");
}

//read edit-form and return <item> string
function forms2rssItem() {
	var form = document.forms.formEdit;
	var title = form.title.value;
	var uid = getUid(title);

	var wikiUrl = getWikiUrl();
	var link = wikiUrl + title;
	if (!wikiUrl)
		link = form.url.value;
		
	var desc = form.description.value;
	var user = form.user.value;
	var geoType = getRadioName(form.geoType);
	var coords = form.coordinates.value;
	var newCoords = strip(coords.replace(/\s+/g, " "));
	var cats = form.tags.value;
	var img = "";
//	var img = form.image.value;
	
	return fields2rssItem(uid, title, link, desc, user, geoType, newCoords, cats,
		img);
}

//called each time, when the geotype is changed in edit mode (point/line/poly)
function changeGeoType() {
	reloadMap();
	setLastPoint(0);
	showTempItem();
}

//called each time, when the coordinate field is changed directly
function changeCoordinates() {
	setLastPoint(0);
	showTempItem();
}

//called after a click into the tag cloud
function tagClick(tag) {
	if (typeof prevtag != "undefined") {
		if (prevtag == tag) {
			activateCategory(prevtag);
			return;
		}
		else {
			activateCategoryColour(prevtag);
		}
	}
	prevtag = tag;
	activateCategoryColour(tag);
}

//switch between modes ("view", "edit", "pick", "search", ...)
function setMode(mode) {
	var currentMode = getMode();
	if (mode == "view" || mode == "history") {
		setInputMode("false");
		reloadMap();
		hideField("divEdit");
		hideField("divSearch");
		showField("divContent");
		if (mode == "history")
		{
			var url = "history.php#end"; 
			setContentUrl(url, "false");
		}
		else
			setContentUrl("", "false");	//show last document in content
	}
	else if (mode == "edit") {
		setInputMode("true");
		reloadMap();
		showTempItem();
		hideField("divContent");
		hideField("divSearch");
		showField("divEdit");
	}
	else if (mode == "pick")
		reloadMap();
	else if (mode == "search") {
		setInputMode("false");
		reloadMap();
		hideField("divEdit");
		hideField("divContent");
		showField("divSearch");
	}
	else if (mode == "tempSearch" || mode == "tempEdit") {
		if (currentMode != "tempSearch" && currentMode != "tempEdit")
			oldMode = currentMode;
	}
	else if (mode == "")
		mode = oldMode;
	globalMode = mode;
}

//--------------js -> worldkit------------------------
//Annotations categorized under the value of this variable will be activated
//currently has no effect, bug?
function activateCategory(cat) {
	document.worldkit.SetVariable("JSubComm", cat);
}

//Annotations categorized under the value of this variable will be switched from
//visible to invisible, or vice versa
function switchCategory(cat) {
	document.worldkit.SetVariable("JLayComm", cat);
}

//Annotations categorized under the value of this variable will be set to the
//color specified in <activatecolor>.
function activateCategoryColour(cat) {
	document.worldkit.SetVariable("JActComm", cat);
}

//Annotations assigned the id specified in the value of this variable will be
//activated
//currently has no effect, bug?
function activateItem(uid) {
	document.worldkit.SetVariable("JComm", uid);
}

//Set the value to trigger worldKit to load an RSS feed. Pass "dataurl" or
//"updateurl" to load feeds specified in the config.xml. Pass "clear" to remove
//all the current annotations. Or alternatively, pass a url to load an arbitrary
//RSS feed
function loadRSS(url) {
	document.worldkit.SetVariable("JLoadComm", url);
}

//show RSS data on map: Set the value to a string containing RSS. worldKit will
//parse this RSS string, and display any annotations.
function showRSS(rss) {
	document.worldkit.SetVariable("JRSSComm", rss);
}

//Set the value to a location and zoom level, and worldKit will zoom and pan to
//that location. The format is "lat,lon,zoomlevel"
function zoomMap(lat, lon, zoom) {
	args = lat + "," + lon + "," + zoom;
	document.worldkit.SetVariable("JZoomComm", args);
}

//switch between normal mode and inputonly mode: Set to "true" to turn on
//Input-Only Mode. Set to "false" to switch off.
function setInputMode(inputOnly) {
	document.worldkit.SetVariable("JInputComm", inputOnly);
}

//The annotation assigned the id specified in the value of this variable will
//pass its contents, each field separated by "||", through the URL or Javascript
//function specified in <annotateurl>.
function askForItem(uid) {
	document.worldkit.SetVariable("JGetItemComm", uid);
}

//--------------more js -> worldkit-------------------
//load the RSS feed specified in config.xml
function reloadRSS() {
	loadRSS("dataurl");
	getTags();
}

//load the update RSS feed specified in config.xml
function updateRSS() {
	loadRSS("updateurl");
	getTags();
}

//remove all items from map
function clearRSS() {
	loadRSS("clear");
}



//--------------private functions------------------------
//make an element of the homepage visible
function showField(id) {
	var e = document.getElementById(id);
	e.style.visibility = "visible";
	e.style.display = "block";
}

//hide an element of the homepage
function hideField(id) {
	var e = document.getElementById(id);
	e.style.visibility = "hidden";
	e.style.display = "none";
}

//called at the beginning, setting up initial stuff
function loadActions(startMode, startItem, startPage) {
	setMode(startMode);
	if (!startPage)
		startPage = "about.html";
	setContentUrl(startPage, "true");
	setInterval("intervalUpdate();", 300000);
	if (startItem) {
		//a hack to make the search function execute after the data is loaded
		//may take even more time than 1000 ms!
		//todo: find a better solution which also stops <maxzoom>
		setTimeout(function() {searchUid(startItem);}, 1000);
	}
}

//called regularly, started from setInterval in loadActions
function intervalUpdate() {
	updateRSS();
}

//set document in content iframe
//if remember is "true", this url will be stored and it's possible to return
//to the last remembered url by calling setContentUrl with url=""
function setContentUrl(url, remember) {
	var lastUrl = document.forms.formContent.lastUrl.value;
	if (url == "")
	{
		if (lastUrl != "")
			url = lastUrl;
		else
			return;
	}
	else if (remember == "true")
		document.forms.formContent.lastUrl.value = url;
	document.getElementById("content").src = url;
	document.getElementById("divContentUri").href = url;
}

function getMode() {
//	return document.forms.formVars.mode.value;
	return globalMode;
}

//create uid from the item's given title
//should deal with spaces and special chars like the wiki system used
function getUid(title) {
	//replace special characters by space
	title = title.replace(/[^a-zA-Z0-9-]+/g, " ");
	if (title == "")
		return "";

	//set first characters of words to upper case, (how to do it with js regexp?)
	var uid = title.charAt(0).toUpperCase();
	for (var i=1; i<title.length; i++) {
		if (title.charAt(i) == " ") {
			if (i < title.length-1)
				uid += title.charAt(++i).toUpperCase();
		}
		else
			uid += title.charAt(i);
	}
	return uid;
}

//decode args received from worldkit
//parseArgs and parseItem are both necessary for different types of messages
function parseArgs(args) {
	var AO = new Object();
	var AA = args.split("&");
	var TA = new Array();
	for (var i=0; i<AA.length; i++) {
	  TA = AA[ i ].split("=");
	  AO[ TA[0] ] = unescape( TA[1] );
	}
	return AO;
}

//parse return string from worldkit after a call of askForItem
//if item is line or poly then return starting point in lat and long
//parseArgs and parseItem are both necessary for different types of messages
function parseItem(args) {
	var AO = new Object();
	var AA = args.split("||");
	AO["title"] = AA[0];
	AO["link"] = AA[1];
	AO["desc"] = AA[2];

	var tags = AA[3];
	AO["tags"] = tags.replace(/,?_default_/, "");
	
	//convert coords from space-separated string to groupings of lat,lon lat,lon
	var orgCoords = AA[4].split(" ");
	var coordsLength = orgCoords.length;
	var newCoords = "";
	for (var i=0; i<coordsLength; i++) {
		newCoords += orgCoords[i];
		if (i == coordsLength-1)
			break;
		if (i % 2 == 0)
			newCoords += ",";
		else
			newCoords += " ";
	}
	AO["coords"] = newCoords;
	
	AO["type"] = AA[5];	
	var TA;
	if (AO["type"] == "") {
		AO["type"] = "point";
		TA = AA[4].split(",");
	}
	else
		TA = AA[4].split(" ");
	AO["lat"] = TA[0];
	AO["long"] = TA[1];
	return AO;
}

//show a message (for debugging)
function show(message) {
	alert(message);
}

//--------------private functions in edit mode-----------

//add currently edited item to the database
function addItemForm() {
	jsrsPost = true;
	
	var uid = getUid(document.forms.formEdit.title.value);
	var user = document.forms.formEdit.user.value;
	var item = forms2rssItem();
	var params = Array(uid, user, item);
	
	if (uid == "") {
//		uid = getDate();
		alert("Please insert a title for the item.");
		return;
	}
	jsrsExecute("data.rs.php", addItemCallback, "annotate", params);
}

//called after addItemForm has been executed
function addItemCallback(returnString) {
	if (returnString == "success") {
		clearForm();
		reloadMap();
	}
	else
		alert("addItemCallback: " + returnString);
}

//fill values into edit form
//coord pairs can be separated by spaces
function item2forms(title, link, desc, geoType, coords, tags, image) {
	var form = document.forms.formEdit;
	form.title.value = title;
	if (form.url)
		form.url.value = link;
	form.description.value = desc;
	if (geoType == "poly")
		geoType = "polygon";
	checkRadioName(form.elements.geoType, geoType);
	coords = coords.replace(/\s+/g, "\n");
	form.coordinates.value = coords;
	form.tags.value = tags;	
//	form.image.value = image;
}

//clear map and reload data
function reloadMap() {
	clearRSS();
	reloadRSS();
}

//show item which is currently being edited on map
function showTempItem() {
	var form = document.forms.formEdit;
	var geoType = getRadioName(form.geoType);
	var coords = form.coordinates.value;
	var newCoords = coords.replace(/\s+/g, " ");
	var items = fields2rssItem("currentItem", "currentItem", "", "", "",
		geoType, newCoords, "currentItem", "");
	var nrPoints = 1;
	if (geoType == "point") {
		if (newCoords == "")
			nrPoints = 0;
	}
	else {
		var coordArray = newCoords.split(" ");
		nrPoints = coordArray.length;
		var lastPoint = getLastPoint();
		//counting down to order points from oldest to newest
		for (var i=nrPoints-1; i >= 0; i--) {
			var point = coordArray[i];
			var cat = "tempPoint";
			if (lastPoint == i)
				cat = "lastTempPoint";
			var uid = "tempPoint"+i;
			var tempPoint = fields2rssItem(uid, uid, "", "", "",
				"point", point, cat, "");
			items += "\n" + tempPoint;
		}
	}
	var rssCode = items2rss(items);
	
	if (nrPoints < form.nrPoints.value) {
		form.nrPoints.value = nrPoints;
		reloadMap();
	}
	else if (nrPoints > form.nrPoints.value)
		form.nrPoints.value = nrPoints;

	showRSS(rssCode);
}

function getLastPoint() {
	return document.forms.formEdit.lastPoint.value;
}

//switch to point index of the currently edited line or poly to insert after
function setLastPoint(index) {
	document.forms.formEdit.lastPoint.value = index;
	//todo: mark corresponding line in edit form
}

function getWikiUrl() {
	var s = document.forms.formVars.wikiUrl.value;
	//todo: check if last character is /
	return s;
}

//clear entries of form, except user
function clearForm() {
	var form = document.forms.formEdit;
	form.title.value = '';
	if (form.url)
		form.url.value = '';
	form.description.value = '';
	form.tags.value = '';
	form.coordinates.value = '';
//	form.image.value = '';
}

//if currently edited item is a point replace coordinates with lat, lon,
//else insert point with lat,lon before line index in coords-form
//todo: test with windows (splitting by \n)!!
function addPoint(lat, lon, index) {
	var coords = lat + "," + lon;
	var form = document.forms.formEdit;
	var geoType = getRadioName(form.geoType);
	var coordField = form.coordinates;
	if (geoType == "point") {
		coordField.value = coords;
		setLastPoint(0);
	}
	else
	{
		var oldCoords = coordField.value;
		var coordArray = oldCoords.split("\n");
		var first = coordArray.slice(0, index);
		var last = coordArray.slice(index);
		var newCoordArray = first.concat(Array(coords).concat(last));
		coordField.value = newCoordArray.join("\n");
	}
}

//removes line <index> (starting with 0) from coordinate form
function delPoint(index) {
	var form = document.forms.formEdit;
	var coordField = form.coordinates;
	
	var oldCoords = coordField.value;
	var coordArray = oldCoords.split("\n");
	var first = coordArray.slice(0, index);
	var last = coordArray.slice(index + 1);
	var newCoordArray = first.concat(last);
	coordField.value = newCoordArray.join("\n");
}

//return a string where element is surrounded by opening and closing tag
//return empty string if at least one of the params is empty
function wrapTag(element, tag) {
	if (element && tag)
		return "<" + tag + ">" + element + "</" + tag + ">";
	return "";
}

//strip whitespace at beginning and end of a string
function strip(s) {
	return s.replace(/^\s*(.*?)\s*$/, "$1");
}

//create rss-string from params
//type: point, line, polygon
//coords: each coord pair separated by commas, for line and poly the points have
//to be separated by spaces ("12.3,50.1 12.4,50.1 12.4,50.2")
//cats: categories, separated by commas ("music,roof terrace");
function fields2rssItem(uid, title, link, desc, user, geoType, coords, cats,
	img) {
	if (coords.indexOf(",") < 0)
		return "";

	var item = "";
	item += wrapTag(uid, "guid");
	item += wrapTag(title, "title");
	item += wrapTag(link, "link");
	if (desc)
		item += wrapTag("<![CDATA[" + desc + "]]>", "description");
	item += wrapTag(user, "author");
	
	if (geoType == "point") {
		var tmp = coords.split(",");
		var lat = tmp[0];
		var lon = tmp[1];
		
		//reduce to first point if more than one point given
		var space = lon.indexOf(" ");
		if (space > 0)
			lon = lon.substring(0, space);
		item += wrapTag(lat, "geo:lat") + wrapTag(lon, "geo:long");
	}
	else if (geoType == "line")
		item += wrapTag(coords, "geo:line");
	else if (geoType == "polygon")
		item += wrapTag(coords, "geo:polygon");
	
	var catsArray = cats.split(",");
	for (var i = 0, cat; cat = catsArray[i]; i++)
		item += wrapTag(strip(cat), "category");
	
	item += wrapTag(img, "photo:thumbnail");

	return wrapTag(item, "item");
}

//wrap xml code of items with the rss code needed to make it a valid feed
function items2rss(rssItems) {
	var header = "<?xml version=\"1.0\"?>\n";
	header += "<rss version=\"2.0\" ";
	header += "xmlns:geo=\"http://www.w3.org/2003/01/geo/wgs84_pos#\" ";
	header += "xmlns:photo=\"http://pheed.com/pheed/\">\n";
	header += "<channel>\n";
	
	var footer = "\n</channel>\n</rss>";
	
	return header + rssItems + footer;
}

//return the value of the active radio button or "" if none is active
function getRadioName(buttons) {
	var val = "";
	for (i=0; i<buttons.length; i++)
		if (buttons[i].checked)
			val = buttons[i].value;
	return val;
}

//activate the radio button <name>
function checkRadioName(buttons, name) {
	for (var i=0; i<buttons.length; i++)
		if (buttons[i].value == name) {
			buttons[i].checked = true;
			break;
		}
}

//ask for tags file
function getTags() {
	jsrsPost = true;
	jsrsExecute("gettags.rs.php", getTagsCallback, "gettags");
}

//called after execution of getTags, displays tag cloud
function getTagsCallback(tags) {
	document.getElementById('legend').innerHTML = tags;
}

