
// NOTE: This file assumes that the global var "sessionId" exists and is the current session ID.

var figureStack = new Stack();

////////////////////////////////////////////////////////////////////////////////

function FigurePreview() {
	this.containerElem = null;
}

FigurePreview.prototype.show = function(options) {
	var relativeElem = options.relativeElem;
	
	this.containerElem = $('<div class="figure-preview-container"></div>').appendTo('body');
	
	this.imgElem = $('<img />').appendTo(this.containerElem);
	this.imgElem.attr('src', options.url);
	
	// TODO: This should happen after imgElem has loaded.
	var offset = relativeElem.offset();
	var left = offset.left + relativeElem.outerWidth(true) / 2;
	var top = offset.top;
	top -= 10;
	x = left - this.containerElem.outerWidth(true) / 2;
	y = top - this.containerElem.height();
	
	if (x < 0) {
		x = 0;
	}
	if (y < 0) {
		y = 0;
	}
	
	var padding = 2;
	
	if (x + this.containerElem.outerWidth(true) + padding > $('body').width()) {
		x = $('body').outerWidth(true) - this.containerElem.width() - padding;
	}
	
	if (y + this.containerElem.outerHeight(true) + padding > $('body').height()) {
		y = $('body').outerHeight(true) - this.containerElem.height() - padding;
	}
	
	this.containerElem.css('left', x + 'px');
	this.containerElem.css('top', y + 'px');
	
	if ('number' in options) {
		this.figureElem = $('<div class="figure-number" />').appendTo(this.containerElem);
		this.figureElem.text(options.number);
	} else {
		this.figureElem = null;
	}
}

FigurePreview.prototype.hide = function() {
	if (this.containerElem != null) {
		this.containerElem.remove();
		this.containerElem = null;
	}
}

var figurePreview = new FigurePreview();

////////////////////////////////////////////////////////////////////////////////

// A figure popup in the main command window.
function FigurePopup(options) {
	log('FigurePopup()');
	
	var figurePopup = this;
	
	this.number = options.number;
	
	// NOTE: This will get set later in the init() function.
	this.state = null;
	this.initState = options.state;

	log('  number: ' + this.number);
	this.is_manually_positioned = options.is_manually_positioned;
	log('  is_manually_positioned: ' + this.is_manually_positioned);
	
	this.restored_position_left = options.restored_position_left;
	this.restored_position_top = options.restored_position_top;
	this.maximized_position_left = options.maximized_position_left;
	this.maximized_position_top = options.maximized_position_top;
	this.z_index = options.z_index;
	
	this.width = options.width;
	this.height = options.height;
	
	// Keeps track of popped-out window so we can auto-update it later.
	this.popoutWindow = null;
	
	/*
	
	this.containerElem = $('<div class="figure-popup"></div>').appendTo($('#command-output'));
	
	figureStack.add(this.containerElem[0], function(zindex) {
		figurePopup.onStackChange(zindex);
	});

	this.containerElem.draggable({
		start: function() {
			figureStack.top(figurePopup.containerElem[0]);
		},
		stop: function() {
			log('draggable.stop();');
			figurePopup.onStopDragging();
		}
	});
	
	this.containerElem.hide();
	this.containerElem.click(function(e) {
		return figurePopup.onClick(e);
	});
	
	this.title = $('<div class="figure-popup-title">Figure #' + this.number + '</div>').appendTo(this.containerElem);
	this.title.click(function() {
		figurePopup.onTitleClick();
	});
	
	this.buttonContainerElem = $('<div class="figure-popup-button-container"></div>').appendTo(this.containerElem);
	
	this.minimizeButtonElem = $('<img src="/media/images/figure_popup_minimize.png" />').appendTo(this.buttonContainerElem);
	this.minimizeButtonElem.hide();
	this.minimizeButtonElem.click(function(e) {
		figurePopup.onClickMinimizeButton(e);
	});
	
	this.restoreButtonElem = $('<img src="/media/images/figure_popup_restore.png" />').appendTo(this.buttonContainerElem);
	this.restoreButtonElem.hide();
	this.restoreButtonElem.click(function(e) {
		figurePopup.onClickRestoreButton(e);
	});
	
	this.maximizeButtonElem = $('<img src="/media/images/figure_popup_maximize.png" />').appendTo(this.buttonContainerElem);
	this.maximizeButtonElem.hide();
	this.maximizeButtonElem.click(function(e) {
		figurePopup.onClickMaximizeButton(e);
	});
	
	this.popoutButtonElem = $('<img src="/media/images/figure_popup_popout.png" />').appendTo(this.buttonContainerElem);
	this.popoutButtonElem.click(function(e) {
		figurePopup.onClickPopoutButton(e);
	});
	
	this.body = $('<div class="figure-popup-body"></div>').appendTo(this.containerElem);
	this.body.hide();
	this.img = $('<img />').appendTo(this.body);
	
	*/
}

FigurePopup.prototype.init = function() {
	if (this.initState == 'minimized') {
		this.minimize();
	} else if (this.initState == 'maximized') {
		this.maximize();
	} else if (this.initState == 'restored') {
		this.restore();
	} else if (this.initState == 'popout') {
		this.popout();
	} else {
		alert('FigurePopup(): Error, unrecognized this.initState "' + this.initState + '"');
		return;
	}
	this.initState = null;
}

FigurePopup.prototype.onTitleClick = function() {
}

FigurePopup.prototype.onClick = function() {
	if (this.state == 'restored' || this.state == 'maximized') {
		figureStack.top(this.containerElem[0]);
	}
}

FigurePopup.prototype.onStackChange = function(zindex) {
	this.z_index = zindex;
	this.saveState();
}

FigurePopup.prototype.onClickMinimizeButton = function(e) {
	this.minimize();
	this.saveState();
	e.stopPropagation();
}

FigurePopup.prototype.onClickRestoreButton = function(e) {
	this.restore();
	figureStack.top(this.containerElem[0]);
	e.stopPropagation();
}

FigurePopup.prototype.onClickMaximizeButton = function(e) {
	this.maximize();
	figureStack.top(this.containerElem[0]);
	e.stopPropagation();
}

FigurePopup.prototype.onClickPopoutButton = function(e) {
	this.popout();
	this.saveState();
	e.stopPropagation();
}

// Destroys any created DOM elements, hides the figure.  Does not use or modify this.state.
FigurePopup.prototype._hide = function() {
	if ('containerElem' in this && this.containerElem != null) {
		this.containerElem.remove();
		log('FigurePopup._hide(): this.containerElem = null');
		this.containerElem = null;
	}
	
	if ('iconElem' in this) {
		this.iconElem = null;
	}
	
	if ('numberElem' in this) {
		this.numberElem = null;
	}
	
	figurePreview.hide();
}

FigurePopup.prototype.minimize = function() {
	log('FigurePopup.minimize()');
	log('  this.state: ' + this.state);
	var figurePopup = this;
	if (this.state != 'minimized') {
		
		this._hide();
		
		log('Showing as minimized.');
		log('FigurePopup.minimize(): creating this.containerElem');
		this.containerElem = $('<div class="figurepopup-minimized-container"></div>').appendTo('#minimized-figures-bar');
		this.containerElem.click(function(e) {
			return figurePopup.onClick(e);
		});
		this.containerElem.hover(
			function() {
				figurePopup.onMouseOver();
			},
			function() {
				figurePopup.onMouseOut();
			}
		);
		this.containerElem.css('z-index', 0);

		var imgSrc = '/session/' + sessionId + '/figure/' + this.number + '?' + (new Date()).getTime();
		this.iconElem = $('<img class="figurepopup-minimized-icon" />').appendTo(this.containerElem);
		this.iconElem.attr('src', imgSrc);
		
		this.numberElem = $('<div class="figurepopup-minimized-number"></div>').appendTo(this.containerElem);
		this.numberElem.text(this.number);
		
		this.state = 'minimized';
		
		figures.reorderMinimizedFigures();
	}
}

FigurePopup.prototype.onClick = function(e) {
	if (this.state == 'minimized') {
		this.restore();
	}
}

FigurePopup.prototype.onMouseOver = function() {
	if (this.state == 'minimized') {
		this.showPreview();
	}
}

FigurePopup.prototype.onMouseOut = function() {
	if (this.state == 'minimized') {
		this.hidePreview();
	}
}

FigurePopup.prototype.showPreview = function(timeout) {
	var figurePopup = this;
	if (this.state == 'minimized') {
		var imgSrc = '/session/' + sessionId + '/figure/' + this.number + '?' + (new Date()).getTime();
		figurePreview.show({
			relativeElem: this.containerElem,
			url: imgSrc,
			number: this.number
		});
		
		if (timeout != undefined && timeout != null) {
			this.hidePreviewTimer = setTimeout(
				function() {
					figurePopup.hidePreview();
				},
				timeout
			);
		}
	}
}

FigurePopup.prototype.hidePreview = function() {
	if (this.hidePreviewTimer) {
		clearTimeout(this.hidePreviewTimer);
		this.hidePreviewTimer = null;
	}
	if (this.state == 'minimized') {
		figurePreview.hide();
	}
}

FigurePopup.prototype.maximize = function() {
	log('FigurePopup.maximize()');
	var figurePopup = this;
	if (this.state != 'maximized') {
		this._show_popup();
		
		this.img.addClass('figure-popup-image');
		this.img.removeClass('figure-popup-image-thumbnail');
		// Update the image.
		this.refresh();
		
		this.minimizeButtonElem.show();
		this.restoreButtonElem.show();
		this.maximizeButtonElem.hide();
		
		if (this.maximized_position_left == null || this.maximized_position_top == null) {
			
			if (this.restored_position_left != null && this.restored_position_top != null) {
				// Somehow use the restored position.
				this.maximized_position_left = this.restored_position_left;
				this.maximized_position_top = this.restored_position_top;
				
			} else {
				// Default to middle of screen.
				this.maximized_position_left = $('#command-output').attr('offsetWidth') / 2 - this.containerElem.attr('offsetWidth') / 2;
				this.maximized_position_top = $('#command-output').attr('offsetHeight') / 2 - this.containerElem.attr('offsetHeight') / 2;
			}
		}
		
		// Clear restored position.
		this.restored_position_left = null;
		this.restored_position_top = null;
		
		this.containerElem.css('left', this.maximized_position_left + 'px');
		this.containerElem.css('top', this.maximized_position_top + 'px');
		
		this.state = 'maximized';
		
		this.refresh();
	}
}

FigurePopup.prototype.restore = function() {
	log('FigurePopup.restore()');
	var figurePopup = this;
	if (this.state != 'restored') {
		this._show_popup();
		
		this.img.addClass('figure-popup-image-thumbnail');
		this.img.removeClass('figure-popup-image');

		this.minimizeButtonElem.show();
		this.restoreButtonElem.hide();
		this.maximizeButtonElem.show();

		if (this.restored_position_left == null || this.restored_position_top == null) {
			
			if (this.maximized_position_left != null && this.maximized_position_top != null) {
				// Somehow use the maximized position.
				this.restored_position_left = this.maximized_position_left;
				this.restored_position_top = this.maximized_position_top;
				
			} else {
				// Default to middle of screen.
				log('Default to middle of screen.');
				this.restored_position_left = $('#command-output').attr('offsetWidth') / 2 - this.containerElem.attr('offsetWidth') / 2;
				this.restored_position_top = $('#command-output').attr('offsetHeight') / 2 - this.containerElem.attr('offsetHeight') / 2;
			}
		}
		
		// Clear maximized position.
		this.maximized_position_left = null;
		this.maximized_position_top = null;
		
		this.containerElem.css('left', this.restored_position_left + 'px');
		this.containerElem.css('top', this.restored_position_top + 'px');
		
		this.state = 'restored';
		
		this.refresh();
	}
}

FigurePopup.prototype._show_popup = function() {
	log('_show_popup()');
	var figurePopup = this;
	if (this.state != 'restored' && this.state != 'maximized') {
		this._hide();
		
		var parent = $('#right-column');
		
		log('FigurePopup._show_popup(): creating this.containerElem');
		this.containerElem = $('<div class="figure-popup"></div>').appendTo(parent);
		this.containerElem.show();
		this.containerElem.css('z-index', this.z_index);
		
		/*
		left = parent.outerWidth(true) / 2;
		top = parent.outerHeight(true) / 2;
		
		left -= this.containerElem.outerWidth(true) / 2;
		top -= this.containerElem.outerHeight(true) / 2;
		
		// Add a bit of randomness so they don't overlap.
		var randomDistance = 20;
		left += Math.floor(Math.random() * randomDistance - randomDistance / 2);
		top += Math.floor(Math.random() * randomDistance - randomDistance / 2);
		
		this.containerElem.css('left', left);
		this.containerElem.css('top', top);
		*/
		
		log('FigurePopup._show_popup(): calling figureStack.add()');
		figureStack.add(this.containerElem[0], function(zindex) {
			figurePopup.onStackChange(zindex);
		});
		
		this.containerElem.click(function(e) {
			return figurePopup.onClick(e);
		});
		
		this.title = $('<div class="figure-popup-title">Figure #' + this.number + '</div>').appendTo(this.containerElem);
		this.title.click(function() {
			figurePopup.onTitleClick();
		});
		
		this.buttonContainerElem = $('<div class="figure-popup-button-container"></div>').appendTo(this.containerElem);
		
		this.minimizeButtonElem = $('<img src="/media/images/figure_popup_minimize.png" />').appendTo(this.buttonContainerElem);
		this.minimizeButtonElem.hide();
		this.minimizeButtonElem.click(function(e) {
			figurePopup.onClickMinimizeButton(e);
		});
		
		this.restoreButtonElem = $('<img src="/media/images/figure_popup_restore.png" />').appendTo(this.buttonContainerElem);
		this.restoreButtonElem.hide();
		this.restoreButtonElem.click(function(e) {
			figurePopup.onClickRestoreButton(e);
		});
		
		this.maximizeButtonElem = $('<img src="/media/images/figure_popup_maximize.png" />').appendTo(this.buttonContainerElem);
		this.maximizeButtonElem.hide();
		this.maximizeButtonElem.click(function(e) {
			figurePopup.onClickMaximizeButton(e);
		});
		
		this.popoutButtonElem = $('<img src="/media/images/figure_popup_popout.png" />').appendTo(this.buttonContainerElem);
		this.popoutButtonElem.click(function(e) {
			figurePopup.onClickPopoutButton(e);
		});
		
		this.body = $('<div class="figure-popup-body"></div>').appendTo(this.containerElem);
		this.img = $('<img />').appendTo(this.body);		
		
		// Update the image.
		this.refresh();
		
		// Set draggable.
		log('FigurePopup._show_popup(): Setting containerElem as draggable.');
		this.containerElem.draggable({
			start: function() {
				log('FigurePopup._show_popup(): calling figureStack.top()');
				figureStack.top(figurePopup.containerElem[0]);
			},
			stop: function() {
				log('draggable.stop();');
				figurePopup.onStopDragging();
			}
		});
		//this.containerElem.draggable('enable');
		log('FigurePopup._show_popup(): this.containerElem:');
		log(this.containerElem);
	}
}

FigurePopup.prototype.popout = function() {
	log('FigurePopup.popout()');
	log('  this.state: ' + this.state);
	if (this.state != 'popout') {
		this._hide();
		// Open a new window for this figure.
		var windowName = 'figure_popout_' + sessionId + '_' + this.number;
		this.popoutWindow = window.open('/session/' + sessionId + '/figure/' + this.number + '/popout', windowName, 'width=' + (this.width+20) + ',height=' + (this.height+20) + ',location=0');
		this.state = 'popout';
	}
}

FigurePopup.prototype.show = function() {
	log('show()');
	log('  this.state: ' + this.state);
	if (this.state == 'maximized' || this.state == 'restored') {
		figureStack.top(this.containerElem[0]);
	}
}

FigurePopup.prototype.onStopDragging = function() {
	log('onStopDragging()');
	
	if (this.state == 'restored') {
		this.restored_position_left = this.containerElem.attr('offsetLeft');
		this.restored_position_top = this.containerElem.attr('offsetTop');
	} else if (this.state == 'maximized') {
		this.maximized_position_left = this.containerElem.attr('offsetLeft');
		this.maximized_position_top = this.containerElem.attr('offsetTop');
	} else if (this.state == 'minimized') {
		// Can't drag while minimized
		alert('FigurePopup.onStopDragging(): Error, dragged figure while minimized.');
		return;
	} else {
		alert('FigurePopup.onStopDragging(): Error, unknown state "' + this.state + '"');
		return;
	}
	
	this.is_manually_positioned = true;
	
	this.saveState();
}

FigurePopup.prototype.saveState = function() {
	//log('saveState()');
	//log('  fig num: ' + this.number);
	//log('  number: ' + this.number);
	//log('  pos: ' + this.containerElem.attr('offsetLeft') + ', ' + this.containerElem.attr('offsetTop'));
	//log('  state: ' + this.state);
	//log('  is_manually_positioned: ' + this.is_manually_positioned);
	
	var restored_position_left = this.restored_position_left ? parseInt(this.restored_position_left) : null;
	var restored_position_top = this.restored_position_top ? parseInt(this.restored_position_top) : null;
	var maximized_position_left = this.maximized_position_left ? parseInt(this.maximized_position_left) : null;
	var maximized_position_top = this.maximized_position_top ? parseInt(this.maximized_position_top) : null;
	
	if ('containerElem' in this && this.containerElem != null) {
		z_index = this.containerElem.css('z-index');
	} else {
		z_index = null;
	}
	
	$.ajax({
		url: '/ajax/save_figure_state',
		type: 'post',
		data: {
			session_id: sessionId,
			figure_number: this.number,
			state: this.state,
			restored_position_left: restored_position_left,
			restored_position_top: restored_position_top,
			maximized_position_left: maximized_position_left,
			maximized_position_top: maximized_position_top,
			z_index: z_index,
			is_manually_positioned: this.is_manually_positioned
		},
		success: function() {
			//log('  successfully saved state.');
		}
	});
}

FigurePopup.prototype.refresh = function() {
	if (this.state == 'maximized' || this.state == 'restored') {
		// Force a refresh of the image.
		var imgSrc = '/session/' + sessionId + '/figure/' + this.number + '?' + (new Date()).getTime();
		this.img.attr('src', imgSrc);
	}
	
	// Force all popouts to refresh too.
	if (this.popoutWindow) {
		this.popoutWindow.location.reload(true);
	}
}

FigurePopup.prototype.onUnload = function() {
	log('FigurePopup.onUnload()');
	// Page is unloading, close all popups.
	if (this.popoutWindow) {
		this.popoutWindow.close();
	}
}

FigurePopup.prototype.checkPopouts = function() {
	if (this.popoutWindow) {
		if (this.popoutWindow.closed && this.state == 'popout') {
			// Popout was closed by the user, minimize it.
			this.minimize();
			this.saveState();
		}
	}
}

////////////////////////////////////////////////////////////////////////////////

// Searches a list of objects in 'array' for an attribute 'attributeName' == value.
// ie. findInArray(objects, id, 1) - looks for an object in objects where object.id == 1.
// Returns the index of the matching item, or -1 if none found.
function findInArray(array, attributeName, value) {
	for (var i=0; i<array.length; i++) {
		if (array[i][attributeName] == value) {
			return i;
		}
	}
	return -1;
}

// Singleton (figures) - maintains a list of open figures, and also handles positioning.
function Figures() {
	log('Figures()');
	var figures = this;
	this.figures = [];
	this.minimizedFigures = [];
	this.firstLoadImages = true;
	
	this.oldWindowWidth = null;
	$(window).resize(function() {
		figures.onResize();
	});
	
	setTimeout(
		function() {
			figures.checkPopouts();
		},
		1000
	);
}

Figures.prototype.onResize = function() {
	var windowWidth = $(window).width();
	if (windowWidth != this.oldWindowWidth) {
		log('Repositioning after resize');
		this.oldWindowWidth = windowWidth;
	}
}

// Loads all figures for this session via AJAX.
Figures.prototype.loadFigures = function() {
	log('loadFigures()');
	var results;
	$.ajax({
		async: false,
		url: '/ajax/get_session_figures',
		type: 'post',
		data: {
			session_id: sessionId
		},
		dataType: 'json',
		success: function(data) {
			results = data;
		}
	});
	
	//log('  Got ' + results.figures.length + ' figure numbers.');
	
	var gotNewFigures = false;
	for (var i=0; i<results.figures.length; i++) {
		
		var figure = results.figures[i];
		
		//log('  Showing loaded figure #' + figure.number);
		//this.show(figure.number);
		
		var existingFigure = null;
		for (var j=0; j<this.figures.length; j++) {
			if (this.figures[j].number == figure.number) {
				existingFigure = this.figures[j];
				break;
			}
		}
		
		if (existingFigure == null) {
			log('Found new figure #' + figure.number);
			//log('  figure.number: ' + figure.number);
			//log('  figure.state: ' + figure.state);
			var figurePopup = new FigurePopup({
				number: figure.number,
				state: figure.state,
				is_manually_positioned: figure.is_manually_positioned,
				restored_position_left: figure.restored_position_left,
				restored_position_top: figure.restored_position_top,
				maximized_position_left: figure.maximized_position_left,
				maximized_position_top: figure.maximized_position_top,
				z_index: figure.z_index,
				width: figure.width,
				height: figure.height
			});
			this.figures.push(figurePopup);
			figurePopup.init();
			gotNewFigures = true;
			
			if (!this.firstLoadImages) {
				// This is a newly-created figure, highlight with animation.
				figurePopup.showPreview(3000);
			}
			
		} else {
			log('Found existing figure');
		}
		
	}
	
	if (!this.firstLoadImages && gotNewFigures) {
		// Got new figures, reload.
		//alert('Got new figures, reloading page.');
		//window.location.reload(true);
	} else {
		// First page load of figures, don't reload now.
		this.firstLoadImages = false;
	}
	log('~loadFigures()');
}

// Shows the figure.
Figures.prototype.show = function(figureNumber) {
	log('Figures.show()');
	log('  figureNumber: ' + figureNumber);
	
	var index = findInArray(this.figures, 'number', figureNumber);
	//log('  index: ' + index);
	
	var figure;
	if (index  != -1) {
		log('  figureNumber already exists.');
		figure = this.figures[index];
		figure.show();
		figure.refresh();
	} else {
		alert('ERROR: Figures.show(), figure #' + figureNumber + ' does not exist.');
	}
	log('~show()');
}

Figures.prototype.reorderMinimizedFigures = function() {
	log('reorderMinimizedFigures()');
	
	var minimizedFigures = [];
	for (var i=0; i<this.figures.length; i++) {
		if (this.figures[i].state == 'minimized') {
			log('  #' + this.figures[i].number);
			minimizedFigures.push(this.figures[i]);
		}
	}
	
	function sortFigures(a, b) {
		if (a.number < b.number) {
			return -1;
		} else if (a.number > b.number) {
			return 1;
		} else {
			return 0;
		}
	}
	
	minimizedFigures.sort(sortFigures);
	// NOTE: Need to reverse these, since they're "float:right" (right-to-left order)
	minimizedFigures.reverse();
	
	log('Sorting.');
	var previousFigure = null;
	for (var i=0; i<minimizedFigures.length; i++) {
		log( '  #' + minimizedFigures[i].number);
		if (previousFigure != null) {
			//log('  inserting #' + minimizedFigures[i].number + ' after #' + previousFigure.number);
			minimizedFigures[i].containerElem.insertAfter(previousFigure.containerElem);
			//log('  done inserting #' + minimizedFigures[i].number + ' after #' + previousFigure.number);
		}
		previousFigure = minimizedFigures[i];
	}
	
	log('~reorderMinimizedFigures()');
}

Figures.prototype.onUnload = function() {
	//log('Figures.onUnload()');
	// Page is unloading, notify all popups.
	for (var i=0; i<this.figures.length; i++) {
		this.figures[i].onUnload();
	}
}

Figures.prototype.checkPopouts = function() {
	//log('Figures.checkPopouts()');
	// Check if any popouts have closed.
	for (var i=0; i<this.figures.length; i++) {
		this.figures[i].checkPopouts();
	}
		
	setTimeout(
		function() {
			figures.checkPopouts();
		},
		1000
	);
}

var figures;

////////////////////////////////////////////////////////////////////////////////