// GMap2 - the google map
var map;

// Array - an array containing previous loaded data
var memoryComments = new Array();
var memoryAddComment = new Array();
var memoryPhotos = new Array();
var memoryAddPhoto = new Array();

// Array - an array of markers
var markers = new Array();

// GIcon - the icon of all markers at potholes
var icon_badroad = makeIcon("blue");

// GIcon - the icon of a marker visible when highlighting an pothole
var icon_highlight = makeIcon("green");

// GIcon - the icon of a marker visible when creating a new pothole
var icon_arrow = makeArrow("arrow");

// GMarker - a marker that overlays the currently selected marker
var highlight = new GMarker(new GLatLng(0,0), {icon: icon_highlight});

// GMarker - a marker that shows where a new marker will be placed
var arrow = new GMarker(new GLatLng(0,0), {icon: icon_arrow, draggable: true, dragCrossMove: false});

// int - the ID of the current marker
var highlight_id = 0;

// boolean - whether the arrow is visible
var arrow_visible = false;

// boolean - is the user in "insert" mode or "browse" mode?
var insert_mode = false;

// string - the piece of HTML that creates a form for a new pothole
var badroad_form = "";
badroad_form += '<div>Add a marker:</div>'+"\n";
badroad_form += '<form name="form1" id="form1" method="post" action="javascript:void(0);" >'+"\n";
badroad_form += '<div>*Name of Street/Intersection:</div>'+"\n";
badroad_form += '<input type="text" name="title" maxlength="45" />'+"\n";
badroad_form += '<div>Your Name:</div>'+"\n";
badroad_form += '<input type="text" name="name" maxlength="30" />'+"\n";
badroad_form += '<div>Age:</div>'+"\n";
badroad_form += '<input type="text" name="age" maxlength="2" size="5" />'+"\n";
badroad_form += '<div>City of Residence:</div>'+"\n";
badroad_form += '<input type="text" name="residence" maxlength="30" />'+"\n";
badroad_form += '<div>*Comments:</div>'+"\n";
badroad_form += '<textarea name="comments" rows="5" cols="20"></textarea>'+"\n";
badroad_form += '<input type="button" value="Add Marker" onClick="user_sendBadroad()" />'+"\n";
badroad_form += '</form>'+"\n";

// string - the piece of HTML that creates a form for a new comment
var comment_form = "";
comment_form += '<div>Add a comment:</div>'+"\n";
comment_form += '<form name="form2" id="form2" method="post" action="javascript:void(0);" >'+"\n";
comment_form += '<div>Your Name:</div>'+"\n";
comment_form += '<input type="text" name="name" maxlength="30" />'+"\n";
comment_form += '<div>Age:</div>'+"\n";
comment_form += '<input type="text" name="age" maxlength="2" size="5" />'+"\n";
comment_form += '<div>City of Residence:</div>'+"\n";
comment_form += '<input type="text" name="residence" maxlength="30" />'+"\n";
comment_form += '<div>*Comments:</div>'+"\n";
comment_form += '<textarea name="comments" rows="5" cols="20"></textarea>'+"\n";
comment_form += '<input type="button" value="Add Comment" onClick="user_sendComment()" />'+"\n";
comment_form += '</form>'+"\n";

var iframe_a = "";
var iframe_b = "";
iframe_a += '<iframe src="photo_upload.php?id=';
iframe_b += '" height="250" width="98%">'+"\n";
iframe_b += 'You cannot upload photos using the browser or security settings you are using.'+"\n";
iframe_b += '</iframe>'+"\n";

// int - default latitude/longitude/zoom
var HOME_LAT = 47.24730;
var HOME_LNG = -122.44400;
var HOME_ZOOM = 11;

var infoTabs;

// This function is triggered by <body onload="">
function initialize() {
	
	// Initialize the map
	map = new GMap2(document.getElementById("map"));
	map.setCenter(new GLatLng(HOME_LAT, HOME_LNG), HOME_ZOOM);
	
	// Add extras to map
	map.addControl(new GLargeMapControl());
	
	var mapControl = new GHierarchicalMapTypeControl();
	map.addControl(mapControl);
	
	// Add click behavior to map
	GEvent.addListener(map, "click", user_clickOnMap);
	GEvent.addListener(map, "dblclick", user_dblclickOnMap);
	GEvent.addListener(map, 'infowindowclose', removeHighlight);
	
	// Load the markers onto the map
	refreshMarkers();
}



// Ask the server to send information about all the markers on the map
function refreshMarkers() {
	memory = new Array();
	markers = new Array();
	removeArrow();
	removeHighlight();
	map.clearOverlays()
	GDownloadUrl("markers.php", outcome_refreshMarkers);
}



// This function is triggered when the server responses to the client's request for markers
function outcome_refreshMarkers(data, responseCode) {
	
	// To ensure against HTTP errors that result in null or bad data,
	// always check status code is equal to 200 before processing the data
	if (responseCode == 200) {
		
		// Split up the data
		var rows = data.split("\n");
		
		// Read each row
		for (var i=0; i<rows.length-1; i++) {
			var record = rows[i];
			var data = record.split("\t");
			
			// If the correct number of variables are found
			if (data.length == 5) {
				
				// Create a marker
				var point = new GLatLng(data[2],data[3]);
				var marker = new GMarker(point, {icon: icon_badroad})
				marker.id = data[0];
				marker.name = data[1];
				marker.isCommented = (data[4] > 0);
				
				// Add the marker to the map
				map.addOverlay(marker);
				
				// Add the marker to the array
				markers[data[0]] = marker;
			}
			
		} // End of "for (var i=0; i<rows.length-1; i++)"
	} else { 
		alert("Cannot access list of markers.");
	}
}


// If the user double clicks while in insert mode, reload the marker onto that spot
function user_dblclickOnMap(marker, point) {
	if (insert_mode) {
		removeArrow();
		addArrowAt(point);
	}
}


// This function is triggered when the user clicks on the map
function user_clickOnMap(marker, point) {
	if (insert_mode) {
		
		// If the user clicked on a marker
		if (marker && marker != arrow) {
			var question = 'You have selected the marker: "'+marker.name+'".' +"\n"+ 'Do you want to comment on this marker?';
			if (confirm(question)) {
				changeToViewMode();
				user_clickOnMap(marker, marker.getPoint());
			}
		} else {
			// User clicked on the map itself
			if (!arrow_visible) {
				addArrowAt(point);
			}
		}
		
	} else {
		if (marker) {
			// If the user clicked on a marker, and that marker is not the highlight...
			if (marker instanceof GMarker) {
				// User clicked on a marker
				if (marker && marker != highlight) {
					removeHighlight();
					if (!infoTabs) {
						infoTabs = new Array();
						infoTabs[0] = new GInfoWindowTab("Remarks",    '<div id="ajax_tab_comments"   style="height: 300px; width: 400px; padding: 3px; overflow: auto"></div>');
						infoTabs[1] = new GInfoWindowTab("Add Remark", '<div id="ajax_tab_addcomment" style="height: 300px; width: 400px; padding: 3px; overflow: auto"></div>');
						infoTabs[2] = new GInfoWindowTab("Photos",     '<div id="ajax_tab_photos"     style="height: 300px; width: 400px; padding: 3px; overflow: auto"></div>');
						infoTabs[3] = new GInfoWindowTab("Add Photo",  '<div id="ajax_tab_addphoto"   style="height: 300px; width: 400px; padding: 3px; overflow: auto"></div>');
					}
					map.openInfoWindowTabsHtml(marker.getPoint(), infoTabs);
					addHighlightOnto(marker);
				}
			} else {
				// User clicked on the info window, do nothing
			}
		} else {
			// Nothing selected
			removeHighlight();
		}
	}
}


// Display text on the browser
function display(data, add_comment) {
	// Display the information about the marker
	/*
	if (document.getElementById("ajax_comments")) {
		
	}
	*/
}


function displaySingle() {
	document.getElementById("ajax_comments").innerHTML = badroad_form;
}

// Fill the DIV fields with the data of a specific marker
function displayData(id) {
	if (document.getElementById("ajax_tab_comments")) {
		if (memoryComments[id]) {
			document.getElementById("ajax_tab_comments").innerHTML = memoryComments[id];
		} else {
			document.getElementById("ajax_tab_comments").innerHTML = "";
		}
	}
	if (document.getElementById("ajax_tab_addcomment")) {
		if (memoryComments[id]) {
			document.getElementById("ajax_tab_addcomment").innerHTML = memoryAddComment[id];
		} else {
			document.getElementById("ajax_tab_addcomment").innerHTML = "";
		}
	}
	if (document.getElementById("ajax_tab_photos")) {
		if (memoryComments[id]) {
			document.getElementById("ajax_tab_photos").innerHTML = memoryPhotos[id];
		} else {
			document.getElementById("ajax_tab_photos").innerHTML = "";
		}
	}
	if (document.getElementById("ajax_tab_addphoto")) {
		if (memoryComments[id]) {
			document.getElementById("ajax_tab_addphoto").innerHTML = memoryAddPhoto[id];
		} else {
			document.getElementById("ajax_tab_addphoto").innerHTML = "";
		}
	}
}


// Ask the server for information about a specific marker
function getCommentsFor(marker) {
	var id = marker.id;
	var name = marker.name;
	var isCommented = marker.isCommented;
	
	// If this marker has comments...
	if (isCommented) {
		
		// Ask the server for the comments of this marker
		GDownloadUrl("data.php?id="+id, outcome_getCommentsFor);
		
	} else {
		
		displayData(id);
		
	}
}

// This function triggers when the server responds to the client's request about a specific marker
function outcome_getCommentsFor(data, responseCode) {
	
	// To ensure against HTTP errors that result in null or bad data,
	// always check status code is equal to 200 before processing the data
	if (responseCode == 200) {
		
		// Data comes in three parts: the ID, comments, and photos
		var chunks = data.split("<!-- Break -->");
		
		if (chunks.length == 3) {
			
			// Determine what the ID of the data is
			
			var id = ((trim(chunks[0]).match(/^\d+$/)) ? trim(chunks[0]) : 0);
			
			if (id > 0) {
				
				// Split up the data
				var rows = chunks[1].split("\n");
				
				// The formatted data to be saved
				var commentsHTML = "";
				
				for (var i=0; i<rows.length; i++) {
					var record = rows[i];
					var data = record.split("\t");
					
					// If the correct number of variables are found
					if (data.length == 5) {
						
						// If this is not the first comment, add a break
						if (commentsHTML != "") { commentsHTML += generateCommentBreak(); }
						
						// Add the comment
						commentsHTML += generateSingleComment(data);
					}
				}
				
				if (commentsHTML == "") {
					commentsHTML = "No comments yet.";
				}
				
				// Split up the data
				var rows = chunks[2].split("\n");
				
				// The formatted data to be saved
				var photosHTML = "";
				
				for (var i=0; i<rows.length; i++) {
					var record = rows[i];
					var data = record.split("\t");
					
					// If the correct number of variables are found
					if (data.length == 2) {
						
						// If this is not the first comment, add a break
						if (photosHTML != "") { photosHTML += generatePhotoBreak(); }
						
						// Add the comment
						photosHTML += generateSinglePhoto(data);
					}
				}
				
				if (photosHTML == "") {
					photosHTML = "No photos yet.";
				}
				
				memoryComments[id] = commentsHTML;
				memoryPhotos[id] = photosHTML;
				memoryAddComment[id] = comment_form;
				memoryAddPhoto[id] = iframe_a + id + iframe_b;
				
				
				if (id == highlight_id) {
					displayData(id);
				}
				
				
				
			} else {
				alert("Invalid ID.");
			}
			
		} else {
			alert("Problem reading file.");
		}
		
		/*
		// If the ID is valid...
		if (id > 0) {
			
			var marker = markers[id];
			
			// Add a title to the top of the result
			result = generateBadroadTitle(marker.name) + result;
			
			// If this marker is still being highlighted, display the data
				display(memory[id], true);
			}
			
		} // End of "if (id > 0)"
		*/
	} else { 
		alert("Cannot access comments.");
	}
	
}



///////////////////////////////////////////////////
////  JavaScript functions that generate HTML  ////
function generateSingleComment(data) {
	var result = "";
	
	var x = 0;
	x += (data[0] != "") ? 4 : 0; // Name
	x += (data[1] != "") ? 2 : 0; // Age
	x += (data[2] != "") ? 1 : 0; // Residence
	
	switch(x) {
		case 0: result += '<em>Anonymous</em> writes:'+"\n"; break;
		case 1: result += '<em>A resident of</em> '+data[2]+' writes:'+"\n"; break;
		case 2: result += '<em>Anonymous</em> writes:'+"\n"; break;
		case 3: result += '<em>A resident of</em> '+data[2]+' writes:'+"\n"; break;
		case 4: result += '<div class="head">'+data[0]+'  writes:</div>'+"\n"; break;
		case 5: result += '<div class="head">'+data[0]+' of '+data[2]+' writes:</div>'+"\n"; break;
		case 6: result += '<div class="head">'+data[0]+' ('+data[1]+') writes:</div>'+"\n"; break;
		case 7: result += '<div class="head">'+data[0]+' ('+data[1]+') of '+data[2]+' writes:</div>'+"\n"; break;
	}
	
	result += "\n";
	result += '<div class="body">'+data[3]+'</div>'+"\n";
	result += '<div class="date">'+data[4]+'</div>'+"\n";
	return result;
}

function generateCommentBreak() {
	return '<hr />'+"\n";
}

function generateSinglePhoto(data) {
	var result = "";
	result += '<a href="photos/'+data[0]+'" rel="lightbox" title="'+data[1]+'" onclick="showLightbox(this); return false;" class="head"><img src="photos/thumbnails/'+data[0]+'" ></div>'+"\n";
	return result;
}

function generatePhotoBreak() {
	return "\n";
	//return '<hr />'+"\n";
}

function generateBadroadTitle(name) {
	return '<div class="title">'+name+'</div>'+"\n";
}
////  JavaScript functions that generate HTML  ////
///////////////////////////////////////////////////





// This function triggers when the user wants to add a pothole
function user_sendBadroad() {
	
	// Get the information from the form
	var id        = highlight_id;
	var title     = trim(document.form1.title.value);
	var latitude  = arrow.getPoint().lat();
	var longitude = arrow.getPoint().lng();
	var name      = trim(document.form1.name.value);
	var age       = trim(document.form1.age.value);
	var residence = trim(document.form1.residence.value);
	var comments  = trim(document.form1.comments.value);
	
	// Validate the information
	var errors = "";
	if (title     == "") { errors += "\n- Include a title"; }
	if (!arrow_visible ) { errors += "\n- Place a marker on the map."; }
	if (comments  == "") { errors += "\n- Include your comments"; }
	
	// Stop if the data is incomplete
	if (errors) {
		errors = "Please make sure all the information is filled out:"+errors;
		alert(errors);
		return;
	}
	
	// Send the information
	var post = "";
	post += "title="     + URLEncode(title)     + "&";
	post += "latitude="  + URLEncode(latitude)  + "&";
	post += "longitude=" + URLEncode(longitude) + "&";
	post += "name="      + URLEncode(name)      + "&";
	post += "age="       + URLEncode(age)       + "&";
	post += "residence=" + URLEncode(residence) + "&";
	post += "comments="  + URLEncode(comments)  + "&";
	post += "id=" + "0";
	
	GDownloadUrl("add_badroad.php", outcome_sendItem, post, "application/x-www-form-urlencoded");
	// Set a process to update the form
}

// This function triggers when the user wants to add a comment
function user_sendComment() {
	
	// Get the information from the form
	var id        = highlight_id;
	var name      = trim(document.form2.name.value);
	var age       = trim(document.form2.age.value);
	var residence = trim(document.form2.residence.value);
	var comments  = trim(document.form2.comments.value);
	
	// Validate the information
	var errors = "";
	if (comments  == "") { errors += "\n- Include your comments"; }
	
	// Stop if the data is incomplete
	if (errors) {
		errors = "Please make sure all the information is filled out:"+errors;
		alert(errors);
		return;
	}
	
	// Send the information
	var post = "";
	post += "name="      + URLEncode(name)      + "&";
	post += "age="       + URLEncode(age)       + "&";
	post += "residence=" + URLEncode(residence) + "&";
	post += "comments="  + URLEncode(comments)  + "&";
	post += "id=" + id;
	
	GDownloadUrl("add_comment.php", outcome_sendItem, post, "application/x-www-form-urlencoded");
	// Set a process to update the form
}


function outcome_sendItem(data, responseCode) {
	// To ensure against HTTP errors that result in null or bad data,
	// always check status code is equal to 200 before processing the data
	if (responseCode == 200) {
		
		// Split up the data
		var rows = data.split("\n");
		
		// The first line should contains the ID of the marker, which is a whole number
		var id = ((rows[0].match(/^\d+$/)) ? rows[0] : 0);
		var outcome = (rows[1] && (rows[1].match(/^\w+$/)) ? rows[1] : "");
		
		switch(outcome) {
			case "i-incomplete":
				alert("The marker has not been added because the title or the location is missing.");
				break;
			case "c-database":
				alert("The marker has not been added because of a problem with the database.");
				break;
			case "c-incomplete":
				alert("The comment has not been added because one or more fields were incomplete.");
				break;
			case "c-invalid":
				alert("The marker you are commenting on is not in the database.");
				break;
			case "c-database":
				alert("The comment has not been added because of a problem with the database.");
				break;
			case "approval":
				alert("The information has been received, and is awaiting administrator approval.");
				// Continue onto success
			case "success":
				changeToViewMode();
				
				// Remove comment list from memory
				memory[id] = "";
				
				if (markers[id]) {
					// The marker is on the map
					var marker = markers[id];
					
					// Note there is now a new comment on this marker
					marker.isCommented = true;
					
					user_clickOnMap(marker, marker.getPoint());
				} else {
					// The marker is not on the map, so must be new
					refreshMarkers();
				}
				break;
			default:
				alert("Message could not be understood:" + outcome);
				break;
		}
		
	} else { 
		alert("A problem occurd while trying to add the comment.");
	}
}


// User has pressed the "add marker" or "view marker" button
function user_viewAddToggle() {
	if (insert_mode) {
		changeToViewMode()
	} else {
		changeToInsertMode();
	}
}

// If not in insert mode, change to insert mode
function changeToInsertMode() {
	if (!insert_mode) {
		insert_mode = true;
		map.disableDoubleClickZoom();
		removeHighlight()
		document.getElementById("toggleViewInsert").value = "Cancel Adding Marker";
		document.getElementById("ajax_comments").innerHTML = "Click a point on the map to set a marker. You can drag the arrow to fine-tune the location of the marker.";
		document.getElementById("ajax_comments").style.visibility = "visible";
	}
}

// If not in view mode, change to view mode
function changeToViewMode() {
	if (insert_mode) {
		insert_mode = false;
		map.enableDoubleClickZoom();
		removeArrow()
		document.getElementById("toggleViewInsert").value = "Add a Marker";
		document.getElementById("ajax_comments").style.visibility = "hidden";
	}
}


// Put the highlight on the map atop the marker the user has clicked
function addHighlightOnto(marker) {
	
	highlight.setPoint(marker.getPoint());
	map.addOverlay(highlight);
	highlight_id = marker.id;
	
	// If this marker has been cached...
	if (memory[highlight_id]) {
		// Pull the information from the cache
		display(memory[highlight_id], true);
	} else {
		// Ask the server for data about the marker
		getCommentsFor(marker);
	}
}

// If the highlight is on the map, remove the highlight
function removeHighlight() {
	if (highlight_id != 0) {
		map.removeOverlay(highlight);
		highlight_id = 0;
	}
	
	// Clear the display as well
	display("", false);
}

// Put the arrow on the map where the user has clicked
function addArrowAt(point) {
	arrow.setPoint(point);
	map.addOverlay(arrow);
	arrow_visible = true;
	
	displaySingle();
}

// If the arrow is on the map, remove the arrow
function removeArrow() {
	if (arrow_visible) {
		map.removeOverlay(arrow);
		arrow_visible = false;
	}
	
	// Clear the display as well
	display("", false);
}







/* Make an icon based on the folder the icon information is in. */
function makeIcon(color) {
	var xMarker = new GIcon();
	xMarker = new GIcon();
	xMarker.image = "markers/"+color+"/marker.png";
	xMarker.iconSize = new GSize(11, 11);
	xMarker.printImage = "markers/"+color+"/markerie.gif";
	xMarker.mozPrintImage = "markers/"+color+"/markerff.gif";
	xMarker.iconAnchor = new GPoint(6, 6);
	return xMarker;
}

/* Make an icon based on the folder the icon information is in. */
function makeArrow(color) {
	var xMarker = new GIcon();
	xMarker = new GIcon();
	xMarker.image = "markers/"+color+"/marker.png";
	xMarker.iconSize = new GSize(20, 34);
	xMarker.shadow = "markers/"+color+"/shadow.png";
	xMarker.printImage = "markers/"+color+"/markerie.gif";
	xMarker.printShadow = "markers/"+color+"/shadowie.gif";
	xMarker.mozPrintImage = "markers/"+color+"/markerff.gif";
	xMarker.mozPrintShadow = "markers/"+color+"/shadowff.gif";
	xMarker.shadowSize = new GSize(37, 34);
	xMarker.iconAnchor = new GPoint(9, 34);
	return xMarker;
}



/* Trim whitespace before and after text. */
/*        Version December 3, 2006        */
function trim(sString) {
   
   if (sString == null)
      return "";
   
   return sString.replace(/^\s*|\s*$/g,"");
   
}

// Code borrowed from (2008-05-14):
//   http://cass-hacks.com/articles/code/js_url_encode_decode/
function URLEncode (clearString) {
  var output = '';
  var x = 0;
  clearString = clearString.toString();
  var regex = /(^[a-zA-Z0-9_.]*)/;
  while (x < clearString.length) {
    var match = regex.exec(clearString.substr(x));
    if (match != null && match.length > 1 && match[1] != '') {
    	output += match[1];
      x += match[1].length;
    } else {
      if (clearString[x] == ' ')
        output += '+';
      else {
        var charCode = clearString.charCodeAt(x);
        var hexVal = charCode.toString(16);
        output += '%' + ( hexVal.length < 2 ? '0' : '' ) + hexVal.toUpperCase();
      }
      x++;
    }
  }
  return output;
}
