var currentPicker;
var currentPopup;

/**
 * DoPicker function checks whether or not the Picker object is instantiated and does so if it isn't
 *
 * If a popupLocation is given it also pops up the picker popup
 */
function doPicker(pickerClass, buttonObject, minAmount, maxAmount, base, inputName, popupLocation, popWidth, popHeight, allowManualOrdering, isDialog, dialogOptions)
{
	if (!buttonObject.Picker) {
		new pickerClass(buttonObject, minAmount, maxAmount, base, inputName, allowManualOrdering, isDialog);
	}

	/**
	 * This variable can be used to initiate the Picker object, but prevent the popup/dialog to open.
	 * It allows the developer to call the doPicker() function of a button, without triggering a popup/dialog.
	 * Initial support for this was needed by mod_products_pod (to set the default document of a DocumentPicker through javascript).
	 */
	if (Picker.disableOpener) {
		return true;
	}

	if (popupLocation && currentPicker && currentPicker != buttonObject.Picker && currentPopup && currentPopup.close) {
		currentPopup.close();
	}

	if (popupLocation) {
		currentPicker = buttonObject.Picker;

		if (!currentPopup || currentPopup.closed) {

			var count = currentPicker.countItems();
			var testFields	= currentPicker.getElementsByName(currentPicker.inputName, currentPicker.list);

			// Add currently selected item
			if (maxAmount == 1 && count == 1) {
				var valueField = $(testFields[0]);
				if (valueField.hasClassName('value-by-hash')) {
					var selectedId = '?selected=h.' + escape(valueField.className.replace(/^.*valuehash-(\S+).*$/, '$1'));
				} else {
					var selectedId	= '?selected=' + escape(testFields[0].value);
				}
			} else {
				var selectedId	= '';
			}

			if (isDialog) {
				popupLocation += '/1';
				currentPopup = PbLib.createDialog(popupLocation + selectedId, popWidth, popHeight, Object.extend({
						enableMaximize: false,
						enableResize: false,
						enableScrollBars: true}, dialogOptions));
				return;
			} else {
				currentPopup = PbLib.createPopup(popupLocation + selectedId, popWidth, popHeight, null, 2, true);
			}
		}

		currentPopup.focus();
	}
}

/**
 * Recusively searches the elements parents for the picker list and returns the element preceeding it (the button)
 */
function findPickerButton(elem)
{
	while (elem.tagName.toLowerCase() != 'ul' || !elem.className.match(/picker/i)) {
		if ( !(elem = elem.parentNode) ) {
			return false;
		} else if (!elem.tagName) {
			return false;
		}
	}

	return elem.previousSibling;
}

/**
 * The Picker class returning a picker object that adds items to the list
 */
function Picker(parentObject, minAmount, maxAmount, base, inputName, allowManualOrdering, isDialog)
{
	parentObject.Picker = this;

	this.parent		= $(parentObject);
	this.minAmount	= minAmount;
	this.maxAmount	= maxAmount;
	this.base		= base;
	this.inputName	= inputName;
	this.content	= new Array();
	this.allowManualOrdering = allowManualOrdering;
	this.isDialog	= !!(isDialog);

	var self = this;
}
/**
 * Wrappers for document.createElement and document.createTextNode, easy to change if we're in a different situation some day (like opener.document....)
 */
Picker.prototype.createElement = function (string)
{
	return document.createElement(string);
}

Picker.prototype.createTextNode = function (string)
{
	return document.createTextNode(string);
}

/**
 * The addItem function, by default this adds a row with an itemDescription and a hidden formfield containing the item's ID
 */
Picker.prototype.addItem = function(properties)
{
	var self = this;

	if ( !(self.setList(properties[0])) ) {
		self.removeRow(document.getElementById('picker_item_' + properties[0]), true);
		self.removeItem(properties[0]);
		return false;
	}

	var img, input, row;

	// Create the list row
	row = self.createElement('li');
	row.id = 'picker_item_' + properties[0];

		// Create cell with remove button and hidden input
		input 		= self.createElement('input');
		input.type	= 'hidden';
		input.name	= self.inputName;
		input.value	= properties[0];

		if (self.minAmount != 1 || self.maxAmount != 1) {
			img					= self.createElement('img');
			img.src				= PbLib.getNewURI('files/mod_picker/icons/unpick16.png');
			img.className		= 'icon';
			img.alt				= '';
			img.style.cursor	= 'pointer';
			if (img.style.cursor != 'pointer') {
				img.style.cursor = 'hand';
			}
			Event.observe(img, 'click', function(e){
					self.removeRow(e);
					self.removeItem(properties[0]);
				});
			row.appendChild(img);
			row.appendChild(input);
		}

		// Add picker specific cells
		self.addCells(row, properties);

		if (self.minAmount == 1 && self.maxAmount == 1) {
			row.firstChild.appendChild(input);
		}

	self.list.appendChild(row);

	// update up/down button visibility
	self.setActionButtonVisibility(self.list);

	// deactive the row in the itemlist
	if (currentPopup && !currentPopup.closed) {
		var element;
		if (self.isDialog) {
			element = currentPopup.contentWindow.document.getElementById('itemlist_item_' + properties[0]);
		} else {
			element = currentPopup.document.getElementById('itemlist_item_' + properties[0]);
		}
		if (element) {
			element.className += ' selected';
		}
	}

	self.parent.fire(':changefunction');

	if (self.isDialog && !Object.isUndefined(currentPopup)) {
		Event.observe(currentPopup, 'dialog:close', function() { self.parent.fire(':autosubmitfunction'); });
	} else if (!Object.isUndefined(currentPopup)) {
		Event.observe(currentPopup, 'beforeunload', function() { self.parent.fire(':autosubmitfunction'); });
	}

	self.setButton();
	return true;
}

/**
 * Deselects the row in the itemlist of the popup window.
 */
Picker.prototype.removeItem = function(itemId)
{
	var self = this;
	if (currentPopup && !currentPopup.closed) {
		var element;
		if (self.isDialog) {
			element = currentPopup.contentWindow.document.getElementById('itemlist_item_' + itemId);
			Event.observe(currentPopup.contentWindow, 'beforeunload', function() { self.parent.fire(':autosubmitfunction'); });
		} else {
			element = currentPopup.document.getElementById('itemlist_item_' + itemId);
			Event.observe(currentPopup, 'beforeunload', function() { self.parent.fire(':autosubmitfunction'); });
		}
		if (element) {
			element.className =	element.className.replace(/(^|\s)selected(\s|$)/, '');
		}
		self.parent.fire(':changefunction');
	} else {
		self.parent.fire(':changefunction');
		self.parent.fire(':autosubmitfunction');
	}
}

Picker.prototype.addParserChildren = function(newParent, object)
{
	var obj;
	var self = this;

	for (var i = 0; i < object.childNodes.length; i++) {
		if (Object.isUndefined(object.childNodes[i].tagName)) {
			// String
			newParent.appendChild(object.childNodes[i]);
		} else {
			obj = document.createElement(object.childNodes[i].tagName);
			for (var j = 0; j < object.childNodes[i].attributes.length; j++) {
				obj.setAttribute(object.childNodes[i].attributes[j].name, object.childNodes[i].attributes[j].value);
			}
			self.addParserChildren(obj, object.childNodes[i]);
			newParent.appendChild(obj);
		}
	}
}

/**
 * The addCells function, by default this adds a cell with an itemDescription
 * This function can be overwritten by childclasses
 */
Picker.prototype.addCells = function (row, properties)
{
	var span, text;
	var self = this;

	// add up and down cells
		if (self.allowManualOrdering) {

			var actions = ['up', 'down'];

			for (var i = 0; i < actions.length; i++) {

				var action = actions[i];

				img					= self.createElement('img');
				img.src				= self.base + (self.base.substr(self.base.length - 1, 1) == '/' ? '' : '/') +
					'ui/uibase/icons/16/arrow_' + action + '_blue.png';
				img.className		= 'icon';
				Event.observe(img, 'click', action == 'up' ?
						function(e) { self.moveRow(row, 'up'); } :
						function(e) { self.moveRow(row, 'down'); });
				span = self.createElement('span');
				span.className = action;
				span.style.cursor = 'pointer';
				span.appendChild(img);
				row.appendChild(span);
			}
		}

	// Create cell with hidden input and description
		span = self.createElement('span');
			if (properties[1].match(/<[^\s<>][^<>]*>/)) {
				// Html in string
				if (!Object.isUndefined(DOMParser)) {
					var parser = new DOMParser();
					var doc = parser.parseFromString('<div>' + properties[1] + '</div>', "text/xml");

					self.addParserChildren(span, doc.documentElement);
				} else {
					span.innerHTML = properties[1];
				}
			} else {
				text = self.createTextNode(properties[1]);
				span.appendChild(text);
			}
		row.appendChild(span);
}

/**
 * If config option 'allowManualOrdering' is turned on, this function moves a row (a picked item)
 * one postion up or down
 *
 * @param row The DOM element.
 * @param action string Either 'up' or 'down'
 */
Picker.prototype.moveRow = function(row, action)
{
	if (action == 'up') {
		row.parentNode.insertBefore(row, row.previousSibling);
	} else {
		var target = (!row.nextSibling) ? row.previousSibling : row.nextSibling.nextSibling;
		row.parentNode.insertBefore(row, target);
	}

	this.setActionButtonVisibility(row.parentNode.parentNode);
}

Picker.prototype.setActionButtonVisibility = function(list)
{
	var rows = list.getElementsByTagName('li');
	for (var i = 0; i < rows.length; i++) {
		var spans = rows[i].getElementsByTagName('span');
		for (var j = 0; j < spans.length; j++) {
			var isButton = !Object.isUndefined(spans[j].className) && (spans[j].className == 'down' || spans[j].className == 'up');
			if (isButton && rows.length > 1) {
				var visibility = '';
				if (spans[j].className == 'up' && i == 0) {
					visibility = 'hidden';
				} else if (spans[j].className == 'down' && (i + 1 == rows.length)) {
					visibility = 'hidden';
				}
				spans[j].style.visibility = visibility;
				spans[j].style.position = 'relative';
			} else if (isButton && rows.length == 1) {
				spans[j].style.visibility = 'hidden';
				spans[j].style.position = 'absolute';
			}
		}
	}
}

/**
 * Recursively searches for a parent of the type 'li' and removes that element from the dom
 */
Picker.prototype.removeRow = function(event, internal)
{
	var self = this;
	if (internal) {
		var row = event;
	} else {
		self.setList();
		var row = document.all ? event.srcElement : event.target;
	}

	while (row.tagName.toLowerCase() != 'li') {
		if ( !(row = row.parentNode) ) {
			return false;
		}
	}

	if (row.parentNode == null) {
		self.list = false;
	} else {

		row.parentNode.removeChild(row);
		self.setActionButtonVisibility(self.list);
	}

	self.setButton();

	if (self.countItems() == 0 && self.list) {
		self.list.parentNode.removeChild(self.list);
		self.setActionButtonVisibility(self.list);
		self.list = false;
	}
	return true;
}

/**
 * Sets the button to disabled or enabled according to the min- and maxAmount
 */
Picker.prototype.setButton = function()
{
	var self = this;
	var amount = self.countItems();
	if (currentPopup && currentPopup.closed == false && self.maxAmount >= 1 && amount >= self.maxAmount) {
		if (self.isDialog) {
			PbLib.destroyDialog();
		} else {
			currentPopup.close();
		}
	}
	if (self.maxAmount > 1 && amount >= self.maxAmount) {
		self.parent.disabled = true;
	} else {
		self.parent.disabled = false;
	}
}

Picker.prototype.countItems = function()
{
	var self = this;

	self.setList('check');
	if (!self.list) {
		return 0;
	}

	return self.getElementsByName(self.inputName, self.list).length;
}

/**
 * Sets the variable self.list to the correct picker list domobject
 */
Picker.prototype.setList = function(itemId)
{
	var self = this;
	if (self.parent.nextSibling) {
		self.list = self.parent.nextSibling;
		if (self.list.tagName.toLowerCase() != 'ul' || !self.list.className.match(/picker/i)) {
			self.list = null;
		}
	}

	if (!self.list) {
		self.list = self.createElement('ul');
		self.list.className = 'picker';

		if (self.maxAmount > 1) {
			self.list.className += ' list';
		}

		if (self.maxAmount != 1) {
			self.list.style.clear = 'both';
			self.list.className += ' list';
		}

		if (self.parent.nextSibling) {
			self.parent.parentNode.insertBefore(self.list, self.parent.nextSibling);
		} else {
			self.parent.parentNode.appendChild(self.list);
		}
	}

	if (itemId == 'check') {
		return true;
	}

	var testFields	= self.getElementsByName(self.inputName, self.list);
	var amount = testFields.length;
	if (self.maxAmount <= 1 || amount < self.maxAmount) {
		for (var i = 0; i < amount; i++) {
			if (i == 0 && self.maxAmount == 1 && amount == 1) {
				self.removeRow(testFields[i], true);
				return self.setList(itemId);
			} else if (testFields[i].value == itemId) {
				return false;
			}
		}
	} else {
		return false;
	}

	return true;
}

/**
 * Gets all elements with a given name from a given object (since getElementsByName in IE doesn't return any dynamically created elements :|
 */
Picker.prototype.getElementsByName = function (matchName, parent)
{
	var self = this;
	var elms = new Array();
	var i, children;

	if (!!Object.isUndefined(parent) || !parent || !!Object.isUndefined(parent.childNodes)) {
		return false;
	}

	if (children = parent.childNodes) {
		for (i = 0; i < children.length; i++) {
			if (children[i] && children[i].name && children[i].name == matchName) {
				elms[elms.length] = children[i];
			}
			elms = elms.concat(self.getElementsByName(matchName, children[i]));
		}
	}

	return elms;
}