// AJAX is super cool!!!

/* display AJAX log, and toggle whether to display it or not */
var ajaxLog;
var verbose = true;
//verbose = false;

function prepareAJAXLog () {
	ajaxLog = document.getElementById('ajaxLog');
	if (!verbose)
		ajaxLog.style.display = 'none';
}

function loadImageGallery () {
	var request;
	var mySelectionMenu = document.getElementById('imageSelection');
	prepareAJAXLog(false);
	var ajaxOutput = ajaxLog.innerHTML;

	if (window.XMLHttpRequest) { // Object of the current windows
		request = new XMLHttpRequest(); // Firefox, Safari, ...
		ajaxOutput += "<p>Success - Created a Mozilla AJAX object</p>";
	} else if (window.ActiveXObject) { // ActiveX version
		request = new ActiveXObject("Microsoft.XMLHTTP"); // Internet Explorer
		ajaxOutput += "<p>Success - Created a Microsoft ActiveX (AJAX) object</p>";
	} else {
		ajaxOutput += "<p>Error - Unknown AJAX object support</p>";
	}

	request.onreadystatechange = function() { // instructions to process the response;
		if (request.readyState == 4) {
			if(request.status == 200) {
				ajaxOutput += "<p>-=-=-</p>";
				ajaxOutput += "<p>Open call Complete!</p>";
				ajaxOutput += "<p>Received:" + request.responseText + "</p>";
				/*
				newChoice = document.createElement("option");
				choiceContent = document.createTextNode(request.responseText);
				mySelectionMenu.appendChild(newChoice);
				newChoice.appendChild(choiceContent);
				*/
				mySelectionMenu.innerHTML = request.responseText;
				/* finds the first choice that AJAX loaded */
				var beginningOfFirst = request.responseText.indexOf(">") + 1;
				var endOfFirst = request.responseText.indexOf("</option");
				var firstOption = "error";
				ajaxOutput += "<p>found first to be starting at "+beginningOfFirst+" and ending at "+endOfFirst+" and total length to be "+request.responseText.length+"</p>";
				if (beginningOfFirst > 0 && endOfFirst > beginningOfFirst+1)
					firstOption = request.responseText.substring(beginningOfFirst, endOfFirst);
				ajaxOutput += "<p>found first to be: "+firstOption+"</p>";
				ajaxOutput += "<p>-=-=-</p>";
				changeImageSeries(firstOption);
			} else {
				ajaxOutput += "<p>-=-=-</p>";
				ajaxOutput += "<p>An error has occurred:</p>";
				ajaxOutput += "<p>AJAX Error code " + request.status + "</p>";
			}
		} else {
			ajaxOutput += "<p>-=-=-</p>";
			ajaxOutput += "<p>Status update:</p>";
			ajaxOutput += "<p>AJAX ReadyCode: " + request.readyState +"</p>";
		}
		ajaxLog.innerHTML = ajaxOutput;
	};

	request.open('GET', 'gallery.txt', true);
	request.send(null);
}

var filename = "";

function loadImageBackgroundInformation () {
	var request;
	var backgroundDescription = document.getElementById('imageBackground');
	var ajaxOutput = ajaxLog.innerHTML;

	if (window.XMLHttpRequest) { // Object of the current windows
		request = new XMLHttpRequest(); // Firefox, Safari, ...
		ajaxOutput += "<p>Background Information - Success - Created a Mozilla AJAX object</p>";
	} else if (window.ActiveXObject) { // ActiveX version
		request = new ActiveXObject("Microsoft.XMLHTTP"); // Internet Explorer
		ajaxOutput += "<p>Background Information - Success - Created a Microsoft ActiveX (AJAX) object</p>";
	} else {
		ajaxOutput += "<p>Background Information - Error - Unknown AJAX object support</p>";
	}

	request.onreadystatechange = function() { // instructions to process the response;
		if (request.readyState == 4) {
			if(request.status == 200) {
				ajaxOutput += "<p>Background Information - open call is complete!</p>";
				backgroundDescription.innerHTML = request.responseText;
			} else {
				ajaxOutput += "<p>An error has occurred retrieving image background information:</p>";
				ajaxOutput += "<p>AJAX Error code " + request.status + "</p>";
			}
		}
		ajaxLog.innerHTML = ajaxOutput;
	};

	request.open('GET', 'eyecandy/'+filename+'.txt', true);
	request.send(null);
}

function changeImageSeries (choice) {
	var backgroundDescription = document.getElementById('imageBackground');
	var ajaxOutput = ajaxLog.innerHTML;
	var eyeCandyChoices = document.getElementById('eyecandyExample');
	ajaxOutput += "<p>You have chosen " + choice + "</p>";
	ajaxLog.innerHTML = ajaxOutput;
	filename = choice;
	loadImageBackgroundInformation();
	eyeCandyChoices.style.visibility = 'hidden';
	preloadImages(filename);
	changeImageSrc(1);
}

/**
 * Image manipulation functions for the eyecandy example
 * this is where all the eyecandy magic is! woo!
 **/

var picture = new Array(12);

function toggleLightingCorrectionDisplay (hasLighting) {
	var eyeCandyChoices = document.getElementById('eyecandyExample');

	var i = 1;
	var listing = "<ol>"
	listing += "  <li><a href='#' onmouseover='changeImageSrc("+i+")' onclick='createImagePopup("+i+"); return false;'>Original Image</a></li>";
	if (hasLighting) {		
		i++;
		listing += "  <li><a href='#' onmouseover='changeImageSrc("+i+")' onclick='createImagePopup("+i+"); return false;'>Lighting Correction Surface (blue)</a></li>";
	}
	i++;
	listing += "  <li><a href='#' onmouseover='changeImageSrc("+i+")' onclick='createImagePopup("+i+"); return false;'>Segmentation (red) 50% opacity</a></li>";
	i++;
	listing += "  <li><a href='#' onmouseover='changeImageSrc("+i+")' onclick='createImagePopup("+i+"); return false;'>Segmentation (red) solid</a></li>";
	i++;
	listing += "  <li><a href='#' onmouseover='changeImageSrc("+i+")' onclick='createImagePopup("+i+"); return false;'>Original Skeleton (green) / Outline (red)</a></li>";
	i++;
	listing += "  <li><a href='#' onmouseover='changeImageSrc("+i+")' onclick='createImagePopup("+i+"); return false;'>Enclosed Meshes (cyan)</a></li>";
	i++;
	listing += "  <li><a href='#' onmouseover='changeImageSrc("+i+")' onclick='createImagePopup("+i+"); return false;'>Pruned Skeleton(green) / Outline(red)</a></li>";
	i++;
	listing += "  <li><a href='#' onmouseover='changeImageSrc("+i+")' onclick='createImagePopup("+i+"); return false;'>Pruned Segmentation (red) solid</a></li>";
	i++;
	listing += "  <li><a href='#' onmouseover='changeImageSrc("+i+")' onclick='createImagePopup("+i+"); return false;'>Skeleton(green) / Nodes(yellow)</a></li>";
	i++;
	listing += "  <li><a href='#' onmouseover='changeImageSrc("+i+")' onclick='createImagePopup("+i+"); return false;'>Graph(yellow) Unmerged Nodes / Edges</a></li>";
	i++;
	listing += "  <li><a href='#' onmouseover='changeImageSrc("+i+")' onclick='createImagePopup("+i+"); return false;'>Graph(yellow) Merged Nodes / Edges</a></li>";
	listing += "</ol>";
	
	eyeCandyChoices.innerHTML = listing;
	
	eyeCandyChoices.style.visibility = 'visible';

}

var seriesWidth = 300;
var seriesHeight = 200;

function preloadImages(filename) {
	/* create image objects, all my images are the exact same size */
	/* begin loading them! this function is called when the website is loaded */
	var i;
	i = 1;
	for (i=1; i<=11; i++) {
		picture[i] = new Image();
		if (i < 10)
			picture[i].src = "eyecandy/"+filename+"000"+i+".jpg";
		else 
			picture[i].src = "eyecandy/"+filename+"00"+i+".jpg";
	}
	// used to store the width and height information of the series
	picture[1].onload = function () {
		var ajaxOutput = ajaxLog.innerHTML;
		if (picture[1].width > 0) {
			seriesWidth = picture[1].width;
			seriesHeight = picture[1].height;
			ajaxOutput += "<p>series onload: width=" + seriesWidth + " and height=" + seriesHeight + "</p>";
			changeImageSize();
		} else {
			ajaxOutput += "<p>series onload: unknown width and height</p>";
		}
		// alert("there was an error for image '" + picture11.src + "'.. was it complete?" + picture11.complete + " and its width is" + picture11.width);
		ajaxLog.innerHTML = ajaxOutput;
	}
	
	// used to manipulate the gallery listing for this image series
	picture[11].onerror = function () {
		var ajaxOutput = ajaxLog.innerHTML;
		if (picture[11].width > 0) {
			ajaxOutput += "<p>onerror: attempting to turn the lighting correction list item on</p>";
			toggleLightingCorrectionDisplay(true);
		} else {
			ajaxOutput += "<p>onerror: attempting to turn the lighting correction list item OFF</p>";
			toggleLightingCorrectionDisplay(false);
		}
		// alert("there was an error for image '" + picture11.src + "'.. was it complete?" + picture11.complete + " and its width is" + picture11.width);
		ajaxLog.innerHTML = ajaxOutput;
	}
	picture[11].onload = function () {
		var ajaxOutput = ajaxLog.innerHTML;
		if (picture[11].width > 0) {
			ajaxOutput += "<p>onload: attempting to turn the lighting correction list item on</p>";
			toggleLightingCorrectionDisplay(true);
		} else {
			ajaxOutput += "<p>onload: attempting to turn the lighting correction list item OFF</p>";
			toggleLightingCorrectionDisplay(false);
		}
		// alert("there was an error for image '" + picture11.src + "'.. was it complete?" + picture11.complete + " and its width is" + picture11.width);
		ajaxLog.innerHTML = ajaxOutput;
	}
	return;
}


/**
 * This function is large but not very complex.
 * It essentially gets the image and the <p> by ID
 * and modifies them based off of the imageNumber.
 *
 * There's really no point in putting these strings
 * in an array, because.. well.. they're only used here
 * and just this one time.
 **/
var imageDescription = Array(12);
var imageCaption = Array(12);

/* set the descriptions and captions for each eyecandy image */
function setDescriptions() {
	var i=1;
	imageDescription[i] = "The original image without any overlays or modifications.";
	imageCaption[i] = "The original image without any overlays or modifications. There may be some deformation due to JPEG compression (for web presentation). Images were originally provided in lossless TIF format.<br /><br />Here we see well-formed vasculature after approximately twelve hours of growth. The image quality is not perfect, and the vasculature we wish to identify for the computer is regularly the same color as the background.";
	i ++;
	imageDescription[i] = "The lighting correction surface (greyscale).";
	imageCaption[i]  = "The lighting correction surface is shown as computed. This is the polynomial surface approximation computed via sampling and least squares regression.<br /><br />Not all eyecandy examples have lighting correction surfaces.";
	i ++;
	imageDescription[i] = "The segmentation (red) has been blended with the original image at 50% opacity.";
	imageCaption[i]  = "The 50% opacity blend allows a lab technician to easily verify that all of the segmentated area was properly selected. Errors in over-aggressive segmentation are best caught in this image.<br /><br />A keen eye will notice that the segmentation algorithm used here was in fact 'too thick' as a result of its internal processes; clearly there is still room for improvement.";
	i ++;
	imageDescription[i] = "The segmentation (red) has been overlayed as solid.";
	imageCaption[i]  = "Now the technician can focus on any vasculature that was missed. All area that was segmented should be properly 'blotted out' leaving any remaining vasculature very apparent.<br /><br />While the automated tool did a reasonable job selecting vasculature, it did miss some area in the darker sections of the image due to what appears to be shadow. As you can therefore guess, lighting correction was not performed on these images before segmentation.";
	i ++;
	imageDescription[i] = "The original skeletonization (green) and outline (red) of the segmentation.";
	imageCaption[i]  = "The skeletonization is the ridge along the Euclidean Distance Map taken from the binary segmented image. This is essentially the Blum Medial Axis. This skeletonization preserves all information of the segmented image with minimal loss (if any, due to the shape of pixels).<br /><br />The problem with this approach is that the Blum Medial Axis is highly sensitive to noise, and a small surface perturbance can result in a branch extending from the main skeleton.<br /><br />As an excercise of verification, the outline of the segmentation is computed via the Blum skeleton. This is possible because the Euclidean Distance Map information is stored along every point of the skeletonization.<br /><br />The envolopes of the circles, whose radii are their distance map information at their center, along the skeleton forms the outline.<br /><br />At one point in the project, there was concern about the segmentation and skeletonization not being proper bijective operations. This image is generated to lay those concerns to rest. The image should demonstrate the skeleton is sufficiently centered along the segmentation. This is also a good demonstration of how the skeletonization can represent the shape of an object.";
	i ++;
	imageDescription[i] = "The enclosed meshes (cyan).";
	imageCaption[i]  = "Once the segmentation and skeleton are computed, information about the enclosed meshes is readily available. The latest series of experiments greatly benefit from 'filling' meshes below a certain specified area threshold judged by the technician to be artifiacts of an imperfect segmentation process. The remaining meshes above the area threshold are checked for complete enclosure.";
	i ++;
	imageDescription[i] = "The pruned skeletonization (green) and outline (red) generated from the pruned EDM Skeleton.";
	imageCaption[i]  = "The skeletonization is recursively pruned with a complicated ruleset until no further pruning operations occur. All endpoints shorter than a specified length are pruned, and all endpoints following certain EDM characteristics are also pruned. Pruning is a necessary part of representing a Biologically meaningful model when using the Blum Medial Axis, which is inherantly susceptible to noise.<br /><br />Depending on the image class, the difference can often be quite subtle, especially the visual comparison of the compressed JPEGs, but the process generally cuts hundreds of small artifact 'noise' branches from the skeleton.<br /><br />At one point in the project, there was concern about the segmentation and skeletonization not being proper bijective operations. This image is generated to lay those concerns to rest. The image should demonstrate the skeleton is sufficiently centered along the segmentation. This is also a good demonstration of how the skeletonization can represent the shape of an object.<br /><br />This step is configurable via the settings.txt file and the Create Settings plugin. Generally if important information is missing, pruning thresholds have been set too high. If this image looks too similar to the original segmented image and spurrious data remains, acceptable pruning limits should be increased.";
	i ++;
	imageDescription[i] = "The pruned segmentation (red) has been overlayed as solid.";
	imageCaption[i]  = "After pruning the skeleton, spurrious segmentation should be removed. The result hopefully allows the literal 'vascular network' to remain. Now the technician can focus on any vasculature that was missed. All vascular area that was segmented should be properly 'blotted out' leaving any remaining vasculature very apparent.<br /><br />This step is configurable via the settings.txt file and the Create Settings plugin. Generally if important information is missing, pruning thresholds have been set too high. If this image looks too similar to the original segmented image and spurrious data remains, acceptable pruning limits should be increased.";
	i ++;
	imageDescription[i] = "Nodes (yellow) and Skeleton (green) overlayed together.";
	imageCaption[i]  = "One part of researching these vascular networks is attempting to extract graph theoretic information from them. The skeletonization is a uniquely beneficial model which allows graph analysis.<br /><br />Nodes are initially placed blindly at every endpoint (a skeleton point with degree one) and branch point (a skeleton point with degree three or more). This process continues until the entire skeleton has been graphed.";
	i ++;
	imageDescription[i] = "Graph (yellow) with nodes and connections overlayed together.";
	imageCaption[i]  = "After all nodes have been labeled to the skeletonization, each node is then traced along the skeleton and adjacencies are computed. This information is then output as adjacency lists readable by Mathematics programs like Mathematica where Algorithms of Great Power can be performed.<br /><br />If there are any errors in node placement, it can be seen here as a result of the skeleton. Due to the extreme noise sensitivity of the EDM, nodes may be numerous. If they are not exactly centerred when compared to their biological equivalents, the skeletonization method is to blame.";
	i ++;
	imageDescription[i] = "Graph (yellow) with nodes and edges, before node merging.";
	imageCaption[i]  = "Here the graph of nodes and edges are shown without any skeleton overlay. The computed adjacency maps are used to display straight edges, and no effort to simulate the curve of the skelton is performed. While this may appear visually unusual, the graph theoretic meaning is unchanged, and the topology of the biological network is preserved.<br /><br />One interesting product of this process is every graph computed is planar.";
	i ++;
	imageDescription[i] = "Graph (yellow) with nodes and edges, after node merging.";
	imageCaption[i]  = "Overlapping nodes are merged in a greedy algorithm that (hopefully) better represents the Biology. Edges in the absorbed node are added to the larger node. At this point, all processing and analysis has completed, and the tool simply tabulates the results for statistical analysis.br /><br />This information is then output as adjacency lists readable by Mathematics programs like Mathematica where Algorithms of Great Power can be performed.";
return;
}

/* now we only have to declare the desriptions and captions once */
setDescriptions();

function changeImageSrc(imageNumber) {
	/* get the image and the caption */
	var theImage = document.getElementById("eyecandy");
	var caption = document.getElementById("description");

	/* set them to whatever the user chose! */
	if (imageNumber >= 1 && imageNumber <= 9) {
		theImage.src = "eyecandy/"+filename+"000"+imageNumber+".jpg";
	} else if (imageNumber >= 10 && imageNumber <= 11) {
		theImage.src = "eyecandy/"+filename+"00"+imageNumber+".jpg";
	} 
	if (imageNumber >= 1 && imageNumber <= 11) {
		theImage.alt = imageDescription[imageNumber];
		theImage.title = imageDescription[imageNumber];
		caption.innerHTML = imageCaption[imageNumber];
	}

	return;
}

// let's try a popup window instead..
// I'll honestly be surprised if a popup is less annoying than a resize
// I hope this makes it persistant (ie static)
var windowHandle;

function createImagePopup(imageNumber) {
	// taken from the book page 197
	// var url = "http://www2.truman.edu/~mdm162/vnt/eyecandy/";
	var url = "http://www2.truman.edu/~mdm162/vnt/eyecandy/";
	if (imageNumber >= 1 && imageNumber <= 9) {
		url += filename+"000"+imageNumber+".jpg";
	} else if (imageNumber >= 10 && imageNumber <= 11) {
		url += filename+"00"+imageNumber+".jpg";
	} 
	changeImageSrc(imageNumber);
	windowHandle = window.open(url, "Eyecandy", "width=724, height=596");
	windowHandle.focus();
}

// this turned out to be far too annoying
var changeBig = false;
function changeImageSize() {
	var theImage = document.getElementById("eyecandy");
	var theDiv = document.getElementById("imageExample");
	// the user has selected to make the image large! get full size!
	if (changeBig) {
		theImage.width = seriesWidth;
		theImage.height = seriesHeight;
		theDiv.style.width = "" + (seriesWidth+20) + "px";
	// the user  has a teeny tiny wussy screen, make us half size!
	} else {
		theImage.width = seriesWidth/2;
		theImage.height = seriesHeight/2;
		theDiv.style.width = "" + (seriesWidth/2+20) + "px";
	}
	// the book said that the URL appears in the status bar if this returns true, in practice I haven't noticed this, but just to be safe
	return false;
}

// eye candy image size control
function toggleBigScreen(anEvent) {
	if (!anEvent) {
		// this may be different than null
		alert("anEvent was nonexistant");
		return;
	}
	if (anEvent == null) {
		alert("anEvent was null");
		return;
	}

	var myChecker = anEvent.currentTarget;

	if (myChecker.checked)
		changeBig = true;
	else
		changeBig = false;
	changeImageSize();
	return;
}
