/* vim:ts=4:sts=4:sw=2:noai:noexpandtab
 * Live JavaScript remoting fridge magnets.
 * Copyright (c) 2005 Steven McCoy <fnjordy@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/* format of constructor is overloaded:
 * Fridge(<id>, <magnets>)
 * Fridge(<id>)
 * Fridge()
 */

function Fridge() {
	this.fridgeid = (arguments.length > 0) ? arguments[0] : 'fridge';
	this.obj = document.getElementById(this.fridgeid);

/* size to page */
	upperX = document.body.clientWidth - lowerX;
	upperY = document.body.clientHeight - this.total_offset(this.obj,'offsetTop') - lowerY;
	this.obj.style.left = lowerX + "px";
	this.obj.style.top = lowerY + "px";
	this.obj.style.width = upperX - lowerX + "px";
	this.obj.style.height = upperY - lowerY + "px";

/* store fridge size */
	this.fridge_left = this.total_offset(this.obj,'offsetLeft');
	this.fridge_top = this.total_offset(this.obj,'offsetTop');
	this.fridge_right = this.fridge_left + this.obj.offsetWidth;
	this.fridge_bottom = this.fridge_top + this.obj.offsetHeight;

/* install remoting objects */
	this.setup_jsr();

/* add magnets to page */
	this.magnet_data = (arguments.length > 1) ? arguments[1] : magnets;
	this.magnets = Array();
	this.create_magnets(this.magnet_data);

/* newest magnet timestamp */
	this.last_date = 0;

/* zindex of highest magnet */
	this.top_z = 0;

/* object being dragged */
	this.selected = null;
	this.drag_start_x = null;
	this.drag_start_y = null;

/* magnets are traveling */
	this.traveling = false;
	this.traveling_handle = null;
	this.traveling_delay = 20;
	this.traveling_step = 5;

/* add to thunk table */
        this.id = _fridges.length;
        _fridges[this.id] = this;

/* install timer to update fridge */
	this.update_delay = 1000;
	this.timer_handle = setTimeout('_fridge('+this.id+')', this.update_delay);
}

var _fridges = Array();
var _fridge_active = null;

/* use to calculate left & top relative to page of an element */
Fridge.prototype.total_offset = function(element, property) {
        var total = 0;
        while (element) {
                total += element[property];
                element = element.offsetParent;
        }
        return total;
}

/* setup remoting system
 * configure status div in top right hand corner with count of requests
 */
Fridge.prototype.setup_jsr = function () {
	var div = document.createElement('DIV');
	div.id = 'jsr_status';
	div.className = 'jsr_status';
	document.body.appendChild(div);

	var status = new jsr_status();
	status.counter = 0;
	status.loading = function () {
		this.obj.style.display = 'block';
		this.obj.innerHTML = this.counter++;
	}

	this.jsr = new JSR(status);
}

/* create div elements representing magnets from an array of parameters */
Fridge.prototype.create_magnets = function(magnets) {
	for (i = 0; i < magnets.length; i++) {
		var x = this.fridge_left + Math.floor(magnets[i][2] * this.obj.offsetWidth);
		var y = this.fridge_top + Math.floor(magnets[i][3] * this.obj.offsetHeight);

		var div = document.createElement('DIV');
		div.fridge = this;

		div.data_index = i;

/* use server id to aid updating */
		div.serverid = magnets[i][0];
		this.magnets[div.serverid] = div;

		div.className = 'magnet';
		div.style.left = x + "px";
		div.style.top = y + "px";
		div.onmousedown = this.drag_start;
		div.innerHTML = magnets[i][1];
		div.zIndex = magnets[i][4];
//alert('moo:'+i+'@'+x+','+y+'('+magnets[i][2]+'*'+this.obj.offsetWidth+','+magnets[i][3]+'*'+this.obj.offsetHeight);

/* track highest magnet */
		if (div.zIndex > this.top_z)
			this.top_z = div.z_index;

/* animation parameters */
		div.traveling = null;
		div.to_left = null;
		div.to_top = null;

		document.body.appendChild(div);
	}
}

function _fridge_resize() {
	for (i = 0; i < _fridges.length; i++) {
		_fridges[i].relocate_magnets();
	}
}

/* re-position magnets as fridge has changed size */
Fridge.prototype.relocate_magnets = function() {

/* messy :( */
	upperX = document.body.clientWidth - lowerX;
	upperY = document.body.clientHeight - this.total_offset(this.obj,'offsetTop') - lowerY;
	this.obj.style.left = lowerX + "px";
	this.obj.style.top = lowerY + "px";
	this.obj.style.width = upperX - lowerX + "px";
	this.obj.style.height = upperY - lowerY + "px";

/* store new fridge size */
	this.fridge_left = this.total_offset(this.obj,'offsetLeft');
	this.fridge_top = this.total_offset(this.obj,'offsetTop');
	this.fridge_right = this.fridge_left + this.obj.offsetWidth;
	this.fridge_bottom = this.fridge_top + this.obj.offsetHeight;

	for (i = 0; i < this.magnet_data.length; i++) {
		var x = this.fridge_left + Math.floor(this.magnet_data[i][2] * this.obj.offsetWidth);
		var y = this.fridge_top + Math.floor(this.magnet_data[i][3] * this.obj.offsetHeight);
		var div = this.magnets[this.magnet_data[i][0]];
		div.style.left = x + "px";
		div.style.top = y + "px";
	}
}

/* div.onmousedown() */
Fridge.prototype.drag_start = function(e) {
	if (!e) e = window.event;

	var x = e.clientX;
	x += window.scrollX ? window.scrollX : document.documentElement.scrollLeft;
	var y = e.clientY;
	y += window.scrollY ? window.scrollY : document.documentElement.scrollTop;

	this.fridge.selected = this;
	this.fridge.drag_start_x = this.offsetLeft - x;
	this.fridge.drag_start_y = this.offsetTop - y;

/* raise magnet to top */
	this.style.zIndex = ++this.fridge.top_z;

/* install event handlers to monitor drag */
	_fridge_active = this.fridge;
	document.onmousemove = this.fridge.drag_move;
	document.onmouseup = this.fridge.drag_stop;

/* prevent mouse selecting text */
	e.returnValue = false;
	if (e.preventDefault) e.preventDefault();
}

/* document.onmousemove() */
Fridge.prototype.drag_move = function(e) {
	if (_fridge_active == null) return;
	if (!e) e = window.event;

	var x = e.clientX;
	x += window.scrollX ? window.scrollX : document.documentElement.scrollLeft;
	var y = e.clientY;
	y += window.scrollY ? window.scrollY : document.documentElement.scrollTop;

document.getElementById('mon').innerHTML = 'ds: '+_fridge_active.drag_start_x+','+_fridge_active.drag_start_y+' m: '+x+','+y;

/* update div to new mouse position */
	_fridge_active.selected.style.left = _fridge_active.drag_start_x + x + "px";
	_fridge_active.selected.style.top  = _fridge_active.drag_start_y + y + "px";

/* prevent mouse selecting text */
	e.returnValue = false;
	if (e.preventDefault) e.preventDefault();
}

/* document.onmouseup() */
Fridge.prototype.drag_stop = function() {
	if (_fridge_active == null) return;

/* remove document event handlers */
	document.onmousemove = null;
	document.onmouseup = null;

/* move magnet back onto fridge */
	var x = Math.min(Math.max(_fridge_active.selected.offsetLeft,_fridge_active.fridge_left),_fridge_active.fridge_right - _fridge_active.selected.offsetWidth);
	_fridge_active.selected.style.left = x + "px";
	var y = Math.min(Math.max(_fridge_active.selected.offsetTop,_fridge_active.fridge_top),_fridge_active.fridge_bottom - _fridge_active.selected.offsetHeight);
	_fridge_active.selected.style.top = y + "px";

/* normalise position */
	var nx = (x - _fridge_active.fridge_left)/_fridge_active.obj.offsetWidth;
	var ny = (y - _fridge_active.fridge_top)/_fridge_active.obj.offsetHeight;

/* update server */
	_fridge_active.send_magnet(_fridge_active.selected.serverid, nx, ny);
}

/* send new magnet location to server via remoting */
Fridge.prototype.send_magnet = function(id,x,y) {
	var code = escape(id);
	if (code == null || code.length == 0)
		return;

	if (this.timer_handle) {
		clearTimeout(this.timer_handle);
		this.timer_handle = null;
	}

	var fridge = this;
	this.jsr.reply = function() { fridge.update_magnets.apply(fridge,arguments); }
	var date_tag = (this.last_date == 0) ? '' : "&d="+this.last_date;

/* z is generated on the server, we only send x,y */
//alert("index.php?id="+code+"&x="+x+"&y="+y+date_tag);
	this.jsr.send_request("index.php?id="+code+"&x="+x+"&y="+y+date_tag);
}

function _fridge_travel(id) {
	if (_fridges[id])
		_fridges[id].move_magnets();
}

Fridge.prototype.move_magnets = function() {
//alert('travel:'+this.magnet_data.length);
	this.traveling = false;
	for (i = 0; i < this.magnet_data.length; i++) {
		var div = this.magnets[this.magnet_data[i][0]];
		if (div.traveling == true) {
			var x = div.offsetLeft;
			if (div.to_left > x) {
				x += this.traveling_step;
				if (x > div.to_left) x = div.to_left;
			} else if (div.to_left < x) {
				x -= this.traveling_step;
				if (x < div.to_left) x = div.to_left;
			}

			var y = div.offsetTop;
			if (div.to_top > y) {
				y += this.traveling_step;
				if (y > div.to_top) y = div.to_top;
			} else if (div.to_top < y) {
				y -= this.traveling_step;
				if (y < div.to_top) y = div.to_top;
			}
			div.style.left = x + "px";
			div.style.top = y + "px";

			if (x == div.to_left && y == div.to_top) {
				div.style.opacity = 1;
				div.traveling = false;
			} else {
				this.traveling = true;
			}
		}
	}

	if (this.traveling)
		this.traveling_handle = setTimeout('_fridge_travel('+this.id+')', this.travel_delay);
	else
		this.traveling_handle = null;
}

/* process new magnet information from server */
Fridge.prototype.update_magnets = function() {
	this.last_date = arguments[0];
	for (i = 1; i < arguments.length; i += 4) {
		var div = this.magnets[arguments[i]];
		div.to_left = ((arguments[i+1] * this.obj.offsetWidth) + this.fridge_left);
		div.to_top = ((arguments[i+2] * this.obj.offsetHeight) + this.fridge_top);
		if (div.offsetLeft != div.to_left && div.offsetTop != div.to_top) {
			this.magnet_data[div.data_index][2] = arguments[i+1];
			this.magnet_data[div.data_index][3] = arguments[i+2];
			div.traveling = true;
			this.traveling = true;
			div.style.opacity = 0.5;
		}
		div.zIndex = arguments[i+3];
	}

	if (this.traveling && this.traveling_handle == null)
		this.traveling_handle = setTimeout('_fridge_travel('+this.id+')', this.travel_delay);

	if (this.timer_handle)
		clearTimeout(this.timer_handle);
	this.timer_handle = setTimeout('_fridge('+this.id+')', this.update_delay);
}

function _fridge(id) {
	if (_fridges[id])
		_fridges[id].check_magnets();
}

/* send request to server for new magnet information */
Fridge.prototype.check_magnets = function() {
	this.timer_handle = null;
	var fridge = this;
	this.jsr.reply = function() { fridge.update_magnets.apply(fridge,arguments); };
	this.jsr.send_request("index.php?d="+this.last_date);
}


