

/*********************************************
 *
 *	Slider: Singleton
 *
 *********************************************/
var Slider = {
	'boxes': new Array(), 
	
	'addBox': function(box) {
		Slider.boxes[box.id] = box;
	}, 
	
	'removeBox': function(box) {
		// This does not affect the length of the array or 
		// any of the other elements but changes the deleted 
		// element to undefined.
		delete Slider.boxes[box.id];
	}, 
	
	// Private function called from Box.move()
	'_slide': function(boxID) {
		var theBox = Slider.boxes[boxID];
		
		if (theBox) {
			theBox._slide();
		}
	}
	
};



/*********************************************
 *
 *	Box: Can exist in several instances
 *
 *	Note: The box must have "position: relative"
 *		  in order to slide
 *
 *	Note: The box must be within another 
 *		  DIV container in order to implement
 *		  the "overflow: hidden" property, i.e.
 *		  the box cannot appear outside of the 
 *		  surrounding DIV container.
 *
 *********************************************/
function Box(divID, stepSize, stepSpeed, onStopCall) {
	// ID of the container to be moved
	this.id = divID;
	
	// Maximum step size
	this.stepSize = stepSize;
	
	// Wait in stepSpeed miliseconds before moving again
	this.stepSpeed = stepSpeed; 
	
	// If defined, onStopCall is called when the sliding stops
	this.onStopCall = onStopCall;
	
	// If true, the sliding will stop and move the box to its final position
	this.doStop = false;
	
	// If true, the sliding will stop and the box won't move any further
	this.fullStop = false;
	
	// The zIndex of the element with this.id
	this.zIndex = 0;
	
	// Current x and y position
	this.x = 0;
	this.y = 0;
	
	// Get the x and y positions
	this.getPositions();

	// Destination coordinate
	this.endX = 0; 
	this.endY = 0;
	
	// Current distance
	this.distanceX = 0;
	this.distanceY = 0;
	
	// 1 means to the right and/or downwards
	// -1 means to the left and/or upwards
	this.directionX = 1;
	this.directionY = 1;
	
	// The step size in pixels in x and y direction
	this.stepX = 0;
	this.stepY = 0;

	Slider.addBox(this);
}

// startX and startY are the upper right start coordinates of the box
// endX and endY are the upper right end coordinates of the box
Box.prototype.slide = function(endX, endY, startX, startY) {
	// Make sure the box is not told to stop sliding
	this.doStop = false;

	// If neither startX nor startY is defined, get the current x,y position
	if (startX == null || startY == null) {
		this.getPositions();
	}

	if (startX) this.x = startX;
	if (startY) this.y = startY;
	
	// Update position of the box
	this.setPositions();
	
	// Update zIndex of box
	document.getElementById(this.id).style.zIndex = this.zIndex;

	this.endX = endX; 
	this.endY = endY;
	
	// Current distance
	this.distanceX = this.endX - this.x;
	this.distanceY = this.endY - this.y;
	
	// 1: moving to the right and/or downwards
	// -1: moving to the left and/or upwards
	this.directionX = (this.distanceX > 0 ? 1 : -1);
	this.directionY = (this.distanceY > 0 ? 1 : -1);
	
	// Reset the stop flags
	this.doStop = false;
	this.fullStop = false;
	
	// Move the box
	this._slide();
}

Box.prototype._slide = function() {
	this.getPositions();
	
	if (this.fullStop) {
		return;
	}
	if (this.doStop) { // If stop flag has been raised, do not continue moving the box
		// Force the box to move to its final x, 
		this.x = this.endX;
		this.y = this.endY;
		
		this.setPositions();
		
		return;
	}
	else if (this.x == this.endX && this.y == this.endY) { 	// Has the box reach its end destination?
		if(this.onStopCall) this.onStopCall();

		return;
	}
	
	// Current distance
	this.distanceX = this.endX - this.x;
	this.distanceY = this.endY - this.y;
	
	// proportion must be multiplied with stepX
	// proportion is an absolute value: 1 == |-1|
	var proportion = this.distanceX / this.distanceY;
	proportion = (proportion > 0 ? proportion : -1 * proportion);

	var stepX = stepY = this.stepSize;
	if (proportion > 1) { // divide y with proportion
		stepY = Math.ceil(stepY / proportion);
	} 
	else { // multiply x with proportion
		stepX = Math.ceil(stepX * proportion);
	}
	
	// Calculate delta x and delta y
	var deltaX = (this.directionX * this.distanceX > stepX ? this.directionX * stepX : this.distanceX);
	var deltaY = (this.directionY * this.distanceY > stepY ? this.directionY * stepY : this.distanceY);
	
	// Setting the new position
	this.x += deltaX;
	this.y += deltaY;
	
	this.setPositions();
	
	window.setTimeout("Slider._slide('" + this.id + "')", this.stepSpeed);
}

Box.prototype.move = function(x, y) {
	this.x = x;
	this.y = y; 
	
	this.setPositions();
}

Box.prototype.setZIndex = function(zIndex) {
	this.zIndex = zIndex;	
}

Box.prototype.getPositions = function () {
	if (document.all) { // IE
		this.x = parseInt(document.all[this.id].style.left);
		this.y = parseInt(document.all[this.id].style.top);
	}
	else if (document.layers) { // NS4
		this.x = document.layers[this.id].left;
		this.y = document.layers[this.id].top;
	}
	else if (document.getElementById) { // NS6 + Mozilla 1.2
		this.x = parseInt(document.getElementById(this.id).style.left);
		this.y = parseInt(document.getElementById(this.id).style.top);
	}
}

Box.prototype.setPositions = function () {
	if (document.all) { // IE
		document.all[this.id].style.left = this.x + 'px';
		document.all[this.id].style.top = this.y + 'px';
	}
	else if (document.layers) { // NS4
		document.layers[this.id].left = this.x + 'px';
		document.layers[this.id].top = this.y + 'px';
	}
	else if (document.getElementById) { // NS6 + Mozilla 1.2
		document.getElementById(this.id).style.left = this.x + 'px';
		document.getElementById(this.id).style.top = this.y + 'px';
	}
}

Box.prototype.getContainer = function() {
	return document.getElementById(this.id);
}

