/////////////////////////////////////////////////////////////////////////
/// Copyright Eric Zavesky @ zavesky.org (c) 2009
/// 
/// This software was created exclusively by Eric Zavesky and not
/// for public release in any form.
/// 
/// Any commercial use of the materials, without the written permission 
/// of Eric Zavesky, is strictly prohibited. For permission to use 
/// specific materials, please contact Eric Zavesky (eric@zavesky.org).
/// 
/// Eric Zavesky is not, under any circumstances, responsible for 
/// the unauthorized use or redistribution of digital collections 
/// found on this Web site.
///
/////////////////////////////////////////////////////////////////////////

$(function () {
	var cssInit = {
		'font-weight': 'bold',
		'font-style': 'normal',
		'color': '#FEFEFE',
		'text-align': 'center',
		'background-color': '#4488FF',
		'background-image': 'none',
		'padding': '4px 8px 4px 8px',
		'border': '1px solid #336699',
		'display': 'inline',
		'cursor': 'pointer'
	};
	$('#btn_random, #btn_rerank, #btn_reset').css(cssInit)
		.hover(function() {
			$(this).css('background-color', '#FEFEFE')
				.css('color', '#336699');
		}, function() {
			$(this).css('background-color', '#4488FF')
				.css('color', '#FEFEFE');
		})
		.click(function() {
			var localObj= $(this);
			model_act(localObj.attr('id').replace(/btn_/, ''));
		});
	//walk to parent then appedn in parent
	$('#btn_random').parent().parent()
		.append('<div id="screen_info">(stats...)</div>')
		.append('<br />k-NN: <input id="screen_neighbor" type="text" size="2" />')
		.append('<br />View: <input id="screen_size" type="text" size="2" />');

	var cssResultInit = {
		'border': '1px dotted white',
		'overflow-y': 'scroll',
		'padding': '5px 5px 0px 5px'
	};
	var objResult = $('#screen_main').height(400).css(cssResultInit);

	//add simpel control for view length
	objResult.data('viewmax', 60);
	$('#screen_size').val(objResult.data('viewmax')).height('80%')
		.change(function() {
			objResult.data('viewmax', $(this).val());
			screen_insert($('#screen_main'));
		});

	//add simpel control for sim depth
	objResult.data('simdepth', 40);
	$('#screen_neighbor').val(objResult.data('simdepth')).height('80%')
		.change(function() {
			objResult.data('simdepth', Math.min(100, $(this).val()));
			model_act('rerank');
		});

	//init some data members
	objResult.data('scores', []);
	objResult.data('total', 0);
	model_clear(objResult);
	objResult.empty();
	model_reload('init');
});

//add counts
function stats_update(numPos, numNeg, numTotal) {
	var objStat = $('#screen_info');
	if (!objStat.length) return;

	objStat.html('<br />'
		+'Available: '+numTotal+'<br />'
		+'Positive: '+numPos+'<br />'
		+'Negative: '+numNeg+'<br />'
		+'All Labels: '+(numPos+numNeg));
}

//user performed some action
function model_act(actTarget, imgId) {
	var objResult = $('#screen_main');

	switch(actTarget) {
		case 'pos':
			objResult.data('pos', objResult.data('pos')+1);
			var labelV = objResult.data('labels');
			labelV[imgId] = 1;
			objResult.data('labels', labelV);
			break;
		case 'neg':
			objResult.data('pos', objResult.data('pos')-1);
			objResult.data('neg', objResult.data('neg')+1);
			var labelV = objResult.data('labels');
			labelV[imgId] = -1;
			objResult.data('labels', labelV);
			break;
		case 'clear':
			objResult.data('neg', objResult.data('neg')-1);
			var labelV = objResult.data('labels');
			delete labelV[imgId];
			objResult.data('labels', labelV);
			break;

		
		case 'reset':    //just reset labels
			model_clear(objResult);
			break;
			
		case 'random':
			objResult.empty();

			//randomize scores for all objects
			var dataScore = objResult.data('scores');
			$.each(dataScore, function(itemI, itemV) {
				itemV.score = Math.random();
			});
			objResult.data('scores', dataScore);
			screen_insert($('#screen_main'));
			break;

		case 'rerank':   //clear all results
			//make a label object out of the source data...
			var labelStr = [];
			$.each(objResult.data('labels'), function(imgId, imgLabel) {
				labelStr.push(imgId+'!'+imgLabel);
			});
			model_reload('rerank', labelStr.join(' '));
			break;
	}

	//reset all labels
	stats_update(objResult.data('pos'), objResult.data('neg'), 
				objResult.data('total'));
}

//custom sort operation
function model_sort(a, b) {
	return b.score - a.score;
}

//clear all data
function model_clear(objResult) {
	objResult.data('pos', 0);
	objResult.data('neg', 0);
	objResult.data('labels', {});
	var objChildren = objResult.children('.imgres');
	if (objChildren.length) {
		objChildren.removeClass('shotpos').removeClass('shotneg')
			.children().css('background-color', 'inherit');
	}
}

//update data on this selection
function model_reload(newMode, newData) {
	var objResult = $('#screen_main');
	var reqParam = {
		mode: newMode,
		depth: objResult.data('simdepth')
	};
	if (newData!=undefined)
		reqParam['data'] = newData;

	//put busy message...
	objResult.html('<h1>Your request is loading, please wait...</h1>');

	//process the json request
	$.getJSON( '/tools/matmult/demo.php',  reqParam, //demo url/data
    	function(jData) {  //process result
			if (jData.name != 'matmult') return;
			switch (jData.mode) {
				case 'init':
					objResult.data('scores', jData.output);
					screen_insert(objResult);
					model_act('reset');
					break;
				case 'rerank':
					if (!jData.output.length) {
						objResult.html('<h2>Sorry, an error occured during the reranking process.  Make sure that you labeled at least one positive and one negative sample before ranking can occur.</h2>');
						break;
					}

					//make a temporary map to deref
					var localDeref = {};
					$.each(jData.output, function(idxI, dataV) {
						localDeref[dataV.id_image] = idxI;
					});

					//otherise, resolve new scores against current images
					var dataScore = objResult.data('scores');
					$.each(dataScore, function(idxI, dataV) {
						//store new score
						if (localDeref[dataV.id_image] != undefined) {
							var dRef = jData.output[localDeref[dataV.id_image]];
							dataV.score = dRef.score;
						}
						//adjust old score below min
						else {
							if (dataV.score > jData.range[0])
								dataV.score -= jData.range[1];
						}
					});
					//save updated scores and proceed as usual
					objResult.data('scores', dataScore);
					screen_insert(objResult);
					break;
				default:
					break;
			}
		});
}

//reinsert all objects into screen
function screen_insert(objResult) {
	//fetch score data, update length, sort by scores
	var dataScore = objResult.data('scores');
	objResult.data('total', dataScore.length);
	dataScore.sort(model_sort);
	objResult.data('scores', dataScore);
	objResult.empty();

	//walk through top results to insert
	var maxVal = Math.min(dataScore.length, objResult.data('viewmax'));
	$.each(dataScore, function(idxI, dataV) {
		if (idxI >= maxVal) return false;
		screen_add(objResult, dataV.id_image, dataV.score, 
					dataV.path, dataV.url, dataV.name);
		//screen_add(objResult, dataV.idx, dataV.score, dataV.url);
	});
}

//add local object
function screen_add(objResult, imgId, imgScore, imgPath, imgUrl, imgText) {
	var imgHref = 'http://www.flickr.com/photos/'+imgUrl;
	var imgThumbHref = '/tools/matmult/thumb/'+imgPath;
	var imgWidth = Math.max(100, (objResult.width()-4*25)/4);
	if (imgText==undefined || !imgText.length) imgText='(none)';
	imgText = "i:"+imgId+', s:'+(Math.round(1000*imgScore)/1000)+',n:'+imgText;

	//create new object
	var objNew = $('<div class="imgres" id="shot_'+imgId+'">'
		+'<a title="'+imgText+'" >'
		+'<img alt="'+imgText+'" src="'+imgThumbHref+'" />'
		+'</a></div>').appendTo(objResult);
	objNew.css('margin', '4px').css('float', 'left').width(imgWidth+12);

	//now apply a class based on the label
	if (objResult.data('labels')[imgId]==1)
		objNew.addClass('shotpos');
	else if (objResult.data('labels')[imgId]==-1)
		objNew.addClass('shotneg');

	// configure hovering actions
	var objLink = objNew.children()
		.css('border', '1px solid gray').css('display', 'block')
		.hover(function() {
			$(this).css('background-color', '#4488FF');
		}, function() {
			screen_colorize(imgId);
		});

	//configure click and double-click
	var objImg = objLink.children().css('margin', '5px').width(imgWidth)
		.click(function(e) {
			//if shift is pressed, double-click
			if (e.shiftKey) {
				window.open(imgHref);
				return;
			}

			//load the local object
			var objLocal = $('#shot_'+imgId);
			if (objLocal.hasClass('shotpos')) {
				objLocal.removeClass('shotpos').addClass('shotneg');
				model_act('neg', imgId);
			}
			else if (objLocal.hasClass('shotneg')) {
				objLocal.removeClass('shotneg');
				model_act('clear', imgId);
			}
			else {
				objLocal.addClass('shotpos');
				model_act('pos', imgId);
			}
			screen_colorize(imgId);
		});

	screen_colorize(imgId);

}	//end add new object

//set the A hyperlink background color
function screen_colorize(imgId) {
	var newColor = 'inherit';
	var objImg = $('#shot_'+imgId);
	if (objImg.hasClass('shotpos')) newColor = '#00FF00';
	else if (objImg.hasClass('shotneg')) newColor = '#FF0000';
	objImg.children().css('background-color', newColor);
}



