/**
 * Royalfish Dropdown class.
 * TODO:		option to to the positioning of the box relative to the viewport or the document.
 * 2007-05-13	Added method calculateBoxPosition, so the calculation of the position of the box can be overruled in a subclass.
 * 2007-05-08	Partial debug system created;
 				Fixed bug which caused strange timedclose behaviour in IE.
 * 2007-04-16:	Fixed bug which prevented the for loops from working properly.
 *				Fixed the viewport detection to work also in Firefox 2.0 with the scrollbar either on and off
 * 2007-01-21:	Added option to use collections of items. So the close others before opening option only closes the items within the same collection.
 * 2007-01-18:	added royalfish centered layout support.
 *				added option to close all other dropdowns before showing the current
 *				added automatic initialisation
 *				added option to display the dropdown box on multiple places
 * 2007-01-17:	first initial version
 */
	
function jpxDropDown(in_name, in_heading, in_box, in_collection) {
	this.name = in_name;
	this.heading = in_heading;
	this.heading._super = this;
	this.box = in_box;
	this.box._super = this;
	this.collection = in_collection;
	
	if(in_collection != null) {
		this.collection.add(this);
	}
	else {
		jpxDropDown.add(this);
	}

	/**
	 * Variables needed for system use.
	 */
	this.toggle_open = false;
	this.drag_active = false;
	this.drag_old_onmousemove = null;
	this.drag_old_onmouseup = null;
	this.drag_old_ondrag = null;
	this.drag_old_onselectstart = null;
	this.drag_x_diff = 0;
	this.drag_y_diff = 0;
	this.active_timer = null;
		
	/**
	 * Initialize this dropdown combination
	 */
	this.initialize();
}

/**
 * Setting: int; delay for hiding a box.
 */
jpxDropDown.prototype.timeout = 500;

/**
 * Setting: bool; determines whether the normal timedClose feature is used or all other boxes are closed first.
 */
jpxDropDown.prototype.close_others_before_opening = true;

/**
 * Setting: int; Position of the box
 * Relative to the heading:
 * 0 = North
 * 1 = North East
 * 2 = East
 * 3 = South East
 * 4 = South
 * 5 = South West
 * 6 = West
 * 7 = North West
 * Relative to the document: 8
 * Relative to the viewport: 9
 */
jpxDropDown.prototype.box_position = 2;

/**
 * Setting: int; interpretation is depending on the value of the box position
 */
jpxDropDown.prototype.pos_x = 0;

/**
 * Setting: int; interpretation is depending on the value of the box position
 */
jpxDropDown.prototype.pos_y = 0;

/**
 * Setting: bool; determines whether to use toggling on the heading
 */
jpxDropDown.prototype.use_toggle = false;

/**
 * Setting: bool; determines whether the box can be moved by dragging and dropping
 */
jpxDropDown.prototype.use_drag = false;

/**
 * Setting: bool; determines whether the box is displayed when the mouse hovers the heading
 */
jpxDropDown.prototype.use_hover = true;

/**
 * Initializes the current dropdown instance
 */
jpxDropDown.prototype.initialize = function() {
	if(this.use_hover) {
		this.heading.onmouseover = function() { this._super.open(); };
		this.heading.onmouseout = function() { this._super.timedClose(); };
		this.box.onmouseover = function() { this._super.killTimer(); };
		this.box.onmouseout = function() { this._super.timedClose(); };
	}
	
	if(this.use_toggle) {
		this.heading.onclick = function() { this._super.toggle(); };
	}
	if(this.use_drag) {
		this.box.onmousedown = function(e) { this._super.startDrag(e); };
	}
}

jpxDropDown.prototype.open = function() {
	if(this.toggle_open) {
		return;
	}
	
	this.killTimer();
	
	if(this.close_others_before_opening && this.collection != null) {
		this.collection.closeAll();
	}

	this.box.style.visibility = 'hidden'; 
	this.box.style.display = 'block';
	
	var boxposition = this.calculateBoxPosition();
	
	/**
	 * Display the box on the right position
	 */
	this.box.style.top = boxposition.top + 'px';
	this.box.style.left = boxposition.left + 'px';
	this.box.style.visibility = 'visible';
}

jpxDropDown.prototype.close = function() {
	this.killTimer();
	this.box.style.display = 'none';
	this.toggle_open = false;
}

jpxDropDown.prototype.toggle = function() {
	this.killTimer();
	if(this.toggle_open) {
		this.close();
	}
	else {
		this.open();
		this.toggle_open = true;
	}
}

jpxDropDown.prototype.timedClose = function() {
	this.killTimer(); //solves a IE bug where multiple timedClose calls are generated while not necessary.
	if(this.toggle_open == false) {
		this.active_timer = setTimeout(this.name+'.close()', this.timeout);
	}
}

jpxDropDown.prototype.killTimer = function() {
	if(this.active_timer != null) {
		clearTimeout(this.active_timer);
		this.active_timer = null;
	}
}

jpxDropDown.prototype.startDrag = function(e) {
	this.drag_active = true;
	this.drag_old_onmousemove = document.onmousemove;
	this.drag_old_onmouseup = document.onmouseup;
	this.drag_old_ondrag = document.ondrag;
	this.drag_old_onselectstart = document.onselectstart;
	objpos = jpxLib.getObjectPosition(this.box);
	mousepos = jpxLib.getMousePosition(e);
	this.drag_x_diff = objpos.left - mousepos.left;
	this.drag_y_diff = objpos.top - mousepos.top;
	document.onselectstart = function() { return false; };
	document.ondrag = function() { return false; };
	jpxLib.addClassName(document.body, 'jpxNoSelect');
	
	document._super = this;
	document.onmousemove = function(e) { this._super.moveDrag(e); };
	document.onmouseup = function() { this._super.upDrag(); };
	
	return false;
}

jpxDropDown.prototype.moveDrag = function(e) {
	mousepos = jpxLib.getMousePosition(e);
	this.toggle_open = true;
	this.box.style.left = mousepos.left + this.drag_x_diff + 'px';
	this.box.style.top = mousepos.top + this.drag_y_diff + 'px';
	
	return false;
}

jpxDropDown.prototype.upDrag = function(e) {
	this.drag_active = false;
	document.onmousemove = this.drag_old_onmousemove;
	document.onmouseup = this.drag_old_onmouseup;
	document.ondrag = this.drag_old_ondrag;
	document.onselectstart = this.drag_old_onselectstart;
	jpxLib.removeClassName(document.body, 'jpxNoSelect');
}

jpxDropDown.prototype.calculateBoxPosition = function() {
	var pos_top = this.pos_y;
	var pos_left = this.pos_x;
	
	if(this.box_position <= 7) { //If positioned relative to the heading
		pos = jpxLib.getObjectPosition(this.heading);
		pos_top += pos.top;
		pos_left += pos.left;
	}
	if(this.box_position == 0) { //north side
		pos_top -= this.box.offsetHeight;
	}
	else if(this.box_position == 1) { //north east side
		pos_top -= this.box.offsetHeight;
		pos_left += this.heading.offsetWidth;
	}
	else if(this.box_position == 2) { //east side
		pos_left += this.heading.offsetWidth;
	}
	else if(this.box_position == 3) { //south east side
		pos_top += this.heading.offsetHeight;
		pos_left += this.heading.offsetWidth;
	}
	else if(this.box_position == 4) { //south side
		pos_top += this.heading.offsetHeight;
	}
	else if(this.box_position == 5) { //south west side
		pos_top += this.heading.offsetHeight;
		pos_left -= this.box.offsetWidth;
	}
	else if(this.box_position == 6) { //west side
		pos_left -= this.box.offsetWidth;
	}
	else if(this.box_position == 7) { //north west side
		pos_top -= this.box.offsetHeight;
		pos_left -= this.box.offsetWidth;
	}
	else if(this.box_position == 8) { //Relative to the document
		//nothing to do :D
	}
	else if(this.box_position == 9) { //Relative to the viewport
		pos = jpxLib.getScrollPosition();
		pos_top += pos.top;
		pos_left += pos.left;
	}
	else {
		alert('Invalid box-position set.');
	}
	return {left: pos_left, top: pos_top};
}

/**
 * A few functions which make dropdown combinations usable
 * This is only for boxes which don't belong to a collection.
 */
jpxDropDown.collection = new Array();

jpxDropDown.add = function(item) {
	jpxDropDown.collection.push(item);
}

jpxDropDown.closeAll = function() {
	for(var i = 0; i < jpxDropDown.collection.length; i++) {
		if(jpxDropDown.collection[i].toggle_open == false) {
			jpxDropDown.collection[i].close();
		}
	}
}

jpxDropDown.getItem = function(in_name) {
	for(var i = 0; i < jpxDropDown.collection.length; i++) {
		if(jpxDropDown.collection[i].name == in_name) {
			return jpxDropDown.collection[i];
		}
	}
	return false;
}

/**
 * A class to make collections of DropDown's
 */
function JPXDDCollection(in_name) {
	this.collection = new Array();
	this.name = in_name;
}

JPXDDCollection.prototype.add = function(item) {
	this.collection.push(item);
}

JPXDDCollection.prototype.openAll = function() {
	for(var i = 0; i < this.collection.length; i++) {
		this.collection[i].open();
	}
}

JPXDDCollection.prototype.closeAll = function(forced) {
	for(var i = 0; i < this.collection.length; i++) {
		if(this.collection[i].toggle_open == false || forced == true) {
			this.collection[i].close();
		}
	}
}

JPXDDCollection.prototype.getItem = function(in_name) {
	for(var i = 0; i < this.collection.length; i++) {
		if(this.collection[i].name == in_name) {
			return this.collection[i];
		}
	}
	return false;
}