// planner.js: a basic web program to plan furniture arrangements in several rooms.
//
// The plan is stored in a file on the server in the JSON format
// (see json.org for the specfication).
// The plans share a directory with the planner code (JavaScript, CSS and HTML)
// and can only be in that directory.
//
// The plan is displayed on a web page as a collection of DIV elements, most of them
// with "position: absolute" so it is easy to move them around.
// The plan data structure is not updated as the HTML page is edited but it is updated
// (from the HTML) before it is stored or the page is reinitialized (say when the scale
// is changed).

// We need to connect DOM elements to data structure elements for updating.
// This is done by assigning IDs to them. domToDS maps from the DOM to the data structure.
var domToDS = {};

// The plan file is read into this variable.
var plan = [];

// User-defined settings.
var showDimensions = false; // Show dimensions in object titles.
// This is the number of pixels per foot.
var unitsPerFoot = 50;

// This function is called after the page loads.
function plannerInit() {
	//initCanvas();
	initHTML();
}

// Call this when the page loads.
$(document).ready(plannerInit);

// This initialized the HTML version of the room planner.
// Mostly it sets up event handlers.
function initHTML()
{
	$("#messages").hide();
	// Set up the slider move callback function.
	$("#scaleSlider").slider({min:10, max:80, startValue:unitsPerFoot, change:function(e,ui) {
		// Update the data structure from the HTML and reload it with the new scale.
		updatePositionsInRooms();
		unitsPerFoot = ui.value;
		createRooms();
	}});

	// Hide the controls and set up the buttons to show them.
	setUpShowHidePanel("plancommands");
	setUpShowHidePanel("loadsave");
	setUpShowHidePanel("help");
	setUpShowHidePanel("about");
	
	
	// Set checkbox and text entry fields
	$('#showdimensions').attr('checked',false);
	$('#loadfilename').attr('value','');
	$('#savefilename').attr('value','');
	
	// Attach event handlers to the buttons
	$("#loadbutton").click(loadbutton);
	$("#savebutton").click(savebutton);
	$("#rotatebutton").click(rotatebutton);
	$("#showdimensions").click(showdimensions);
	
	// Set up CR in text fields
	$("#loadfilename").keypress(function(e) {
		if(e.keyCode==13) $("#loadbutton").click();
	});
	$("#savefilename").keypress(function(e) {
		if(e.keyCode==13) $("#savebutton").click();
	});
	
	// Get the name of the last plan loaded.
	$.get("lastPlan", null, function(data) {
		$("#loadfilename").attr('value', data);
		$("#loadbutton").click();
	})
}

function setUpShowHidePanel(namePrefix) {
	var divSelector = "#" + namePrefix + "div";
	$(divSelector).hide();
	$("#"+namePrefix+"button").click(function(e) { $(divSelector).toggle("normal"); });
}

function createRooms()
{
	$htmlDiv = $("#htmlDiv");
	
	// Hode the room and empty it out before we refill it.
	$htmlDiv.hide();
	$htmlDiv.empty();
	
	var objectID = 1;
	
	// Create the rooms
	for(var i=0; i<plan.length; ++i)
	{
		var room = plan[i];
		room.id = objectID++;
		var title = room.title;
		var x1 = room.x * unitsPerFoot;
		var y1 = room.y * unitsPerFoot;
		var w1 = room.w * unitsPerFoot;
		var h1 = room.h * unitsPerFoot;
		
		// Compute a margin that will center the label verically.
		var margin = (h1-30)/2;
		if(margin < 0) margin = 0;
		
		// Add dimensions
		if(showDimensions) {
			title += ((margin==0)?" ":"<br/>") + "(" + room.w + "x" + room.h + ")";
		}
		
		// Prevent spaces from breaking the title
		if(margin==0) title = title.replace(/ /g, "&nbsp;");
		
		// Create the title
		var $titleDiv =
			$('<div></div>')
			.addClass('objectTitle')
			.css("padding-top", margin+"px")
			.html(title);

		// Create the room, set the styles and append the title.
		var $room = $("<div class='room'></div>")
			.css("position", "absolute")
			.css("left", x1+"px")
			.css("top", y1+"px")
			.css("width", w1+"px")
			.css("height", h1+"px")
			.css("text-align", "center")
			.css("background-color", room.color)
			.append($titleDiv);
			
		for(var j=0; j<room.objects.length; ++j) {
			var obj = room.objects[j];
			obj.id = objectID++;
			var $obj = addObject($room, obj.title, obj.color, obj.x, obj.y, obj.w, obj.h);
			// Associate the object in the data structure with the object in the DOM
			domToDS[obj.id] = $obj;
		}
		
		$htmlDiv.append($room);
	}
	
	$htmlDiv.fadeIn('normal')
}

function addObject($parent, title, color, x, y, w, h)
{
	var x1 = x * unitsPerFoot;
	var y1 = y * unitsPerFoot;
	var w1 = w * unitsPerFoot;
	var h1 = h * unitsPerFoot;
	
	// Compute a margin that will center the label verically.
	var margin = (h1-30)/2;
	if(margin < 0) margin = 0;

	// Add dimensions
	if(showDimensions) {
		title += ((margin==0)?" ":"<br/>") + "(" + w + "x" + h + ")";
	}
	
	// Prevent spaces from breaking the title
	if(margin==0) title = title.replace(/ /g, "&nbsp;");

	// Create the title and set the class and styles.
	var $titleDiv =
		$('<div></div>')
		.addClass('objectTitle')
		.css("padding-top", margin+"px")
		.html(title);

	// Create the object, set the styles, add the event handler and append the title.
	$object = $('<div></div>')
		.addClass('object')
		.css("background-color", color)
		.css("position", "absolute")
		.css("left", x1+"px")
		.css("top", y1+"px")
		.css('width', w1+"px")
		.css('height', h1+"px")
		.dblclick(function() {
			$this = $(this);
			var w = $this.css('width');
			var h = $this.css('height');
			$this.css('width',h).css('height',w);
		})
		.append($titleDiv);
			
	$parent.append($object);
	$object.draggable({containment:'parent', zIndex:10});
	return $object;
}

// Make sure the data structure reflects the current position so the objects in the rooms.
function updatePositionsInRooms()
{
	for(var i=0; i<plan.length; ++i) {
		var room = plan[i];
		for(var j=0; j<room.objects.length; ++j) {
			// Get the object and the corresponding DOM element.
			var obj = room.objects[j];
			var $obj = domToDS[obj.id];
			// Get the pixel values and convert them back to feet and update the data structure.
			// Round everything off to one decimal place.
			obj.x = (parseInt($obj.css('left'),10)/unitsPerFoot).toFixed(2);
			obj.y = (parseInt($obj.css('top'),10)/unitsPerFoot).toFixed(2);
			obj.w = (parseInt($obj.css('width'),10)/unitsPerFoot).toFixed(2);
			obj.h = (parseInt($obj.css('height'),10)/unitsPerFoot).toFixed(2);
		}
	}
}

function showdimensions(e) {
	showDimensions = this.checked;
	updatePositionsInRooms();
	createRooms();
	showMessage('Dimensions '+(showDimensions?'visible':'hidden'));
}

function rotatebutton(e) {
	updatePositionsInRooms();
	
	var t;
	for(var i=0; i<plan.length; ++i) {
		var room = plan[i];
		t = room.x; room.x = room.y; room.y = t;
		t = room.w; room.w = room.h; room.h = t;
		for(var j=0; j<room.objects.length; ++j) {
			var obj = room.objects[j];
			t = obj.x; obj.x = obj.y; obj.y = t;
			t = obj.w; obj.w = obj.h; obj.h = t;
		}
	}
	createRooms();
	showMessage('Plan rotated');
}

var hideTimeout = null;
function showMessage(msg, interval) {
	if(hideTimeout) window.clearTimeout(hideTimeout);
	$("#messages").text(msg);
	$("#messages").fadeIn('normal');
	if(interval==null) interval = 10;
	if(interval > 0) {
		hideTimeout = window.setTimeout(function(){
			$("#messages").fadeOut('normal')
		}, interval*1000)
	}
}

function savebutton(e) {
	var filename = $("#savefilename").attr('value');
	if(filename.length == 0) {
		showMessage("No save file name specified")
		return;
	}
	updatePositionsInRooms();
	var json = JSON.stringify(plan, null, 4);
	$.post('saveplan.php', {'filename':filename, 'json':json}, function(){
		showMessage('Plan saved in file "'+filename+'"');
	});
}

function loadbutton(e) {
	// Get the filename from the text entry field and check for an empty name.
	var filename = $("#loadfilename").attr('value');
	if(filename.length == 0) {
		showMessage("No load file name specified")
		return;
	}
	// Start the AJAX request to get the plan file from the server.
	$.getJSON(filename, function(data) {
		// Save the retrieved plan and reload the page.
		plan = data;
		createRooms();
		// Remember the last file that loaded successfully.
		$.post('saveplan.php', {'filename':'lastPlan', 'json':filename});
		$("#savefilename").attr('value', filename);
		showMessage('Plan loaded from file "'+filename+'"');
	});
}

function addNewRoom($parent, w, h) {
	var w1 = w * unitsPerFoot;
	var h1 = h * unitsPerFoot;
	var $room = $('<div class="room"></div>').css('width', w1+"px").css('height', h1+"px");
	$parent.append($room);
	return $room;
}

// Available colors names:
// "black", "red", "green", "blue", "yellow", "fuchsia", "aqua", "maroon", "purple"
// "silver", "lime", "olive", "navy", "teal", "gray", "darkgray", "lightgray", "white"
// plus "rgb(125, 78, 198)" and "rgba(125, 78, 198, 0.5)" (last is transparency (0 to 1.0))

