// ------------------------------------------------------
// CLASS: ItemList 
//
// Implements a list of items, where each item is contained in a div.
// Currently the only operation that is supported is selecting
// an item, which changes its class. Other conceivable
// operations: add, remove, alphabetize...
// ------------------------------------------------------

function ItemList(itemPrefix, strColor, strSelectedColor, strOverColor, strClickHandler) {
   	if (arguments.length > 0) {
		this.init(itemPrefix, strColor, strSelectedColor, strOverColor, strClickHandler);
	}
	
}

ItemList.prototype.init = function(itemPrefix, strColor, strSelectedColor, strOverColor, strClickHandler) {
	this.intCount = 0;
	this.strItemPrefix = itemPrefix;
	this.strColor = strColor;
	this.strSelectedColor = strSelectedColor;
	this.intCurrentSelectedIndex = -1;
	this.objCurrentSelectedItem = null;
	this.strClickHandler = strClickHandler;
	this.strOverColor = strOverColor;
	this.strJustMoved = "";
	this.arrItems = new Array();
	
	//this maps item IDs to their indexes
	//for fast access
	this.hshItemsByID = new Array();
}

//register an item on the page with this list. 
//the user is responsible for not using an index
//that already exists
ItemList.prototype.registerItem = function(intIndex, strUniqueID) {
	if (this.arrItems[intIndex] == null) {
		var strID = this.strItemPrefix 	+ intIndex + "-" + strUniqueID;
		this.arrItems[intIndex] = strID;
		this.hshItemsByID[strID] = intIndex;
		++this.intCount;
	}
}	

ItemList.prototype.getUniqueID = function(strID) {
	var arrElements = strID.split('-');
	return arrElements[1];
}

//set up the object for display
//this must be called in the page's onload method
ItemList.prototype.initDisplay = function() {
	for (var i = 0; i < this.arrItems.length; ++i) {
		//get an object reference
		var objRef = objDOM.getLayerReference(this.arrItems[i]);
		this.initItemForDisplay(objRef);		
	}
	
	//get a refeference to this list's container
	this.objListContainer = objDOM.getLayerReference(this.strItemPrefix + "List"); 
	
	//and a reference to this list's table body
	this.objTableBody = objDOM.getLayerReference(this.strItemPrefix + "TableBody");
}

ItemList.prototype.initItemForDisplay = function(objItem) {
	//give the object a pointer back to this itemlist
	objItem.objParentList = this;

	//assign the click handler
	this.attachEvents(objItem);
	
	//set the default class
	//objItem.className = this.strClassName;
}

ItemList.prototype.attachEvents = function(objItem) {
	objItem.onclick = function() {
		this.style.backgroundColor = this.objParentList.strSelectedColor;
		this.objParentList.selectItem(this);
	}
	objItem.onmouseover = function() {
		if (this.objParentList.objCurrentSelectedItem != this) {
			this.style.backgroundColor = this.objParentList.strOverColor;
			//this.className = this.objParentList.strOverClassName;
		}
	}
	objItem.onmouseout = function() {
		if (this.objParentList.objCurrentSelectedItem != this) {
			this.style.backgroundColor = this.objParentList.strColor;
			//this.className = this.objParentList.strClassName;
		}
	}
}

ItemList.prototype.addItem = function(objItem) {
	
	this.strJustMoved = objItem.id;
	
	//initialize this object for display
	this.initItemForDisplay(objItem);

	//increment our count
	++this.intCount;

	//add the element to the end of the array
	var intIndex = this.arrItems.length;
	this.arrItems[intIndex] = objItem.id;
	this.hshItemsByID[objItem.id] = intIndex;

	//attach the item to this list's container
	//this.objListContainer.appendChild(objItem);	
	this.objTableBody.appendChild(objItem);
	
	//alert("adding " + objItem.innerHTML);
}

ItemList.prototype.selectItem = function(objSelectedItem) {

	if (objSelectedItem != null && this.strJustMoved != objSelectedItem.id) {

		//get the index for this item
		var index = -1;
		if (this.hshItemsByID[objSelectedItem.id] != null) {
			index = this.hshItemsByID[objSelectedItem.id];
		}
		/**
		for (var i = 0; i < this.arrItems.length; ++i) {
			if (objSelectedItem.id == this.arrItems[i]) {
				index = i;
				break;
			}
		}
		**/	
	
		//don't continue if this item wasn't in the list
		if (index != -1) {
		
			var blnContinue = true
	
			//call the global click handler
			if (this.strClickHandler != "" && this.strClickHandler != null) {
				//build the click event data structure
				var objClickEvent = new ClickEvent();
				objClickEvent.strListID = objSelectedItem.id;
				var arrTokens = objSelectedItem.id.split("-");
				objClickEvent.strUniqueID = arrTokens[1];			
				
				//call the function
				blnContinue = eval(this.strClickHandler + "(objClickEvent)");
			}
			
			//if we called the click handler and it returned true
			if (blnContinue) {
	
				//set the new item to selected
				if (this.objCurrentSelectedItem != null) {
					this.objCurrentSelectedItem.style.backgroundColor = this.strColor;
				}
				//objSelectedItem.className = this.strSelectedClassName;
				this.objCurrentSelectedItem = objSelectedItem;
			
				//set the index for this item 		
				this.intCurrentSelectedIndex = index;
			
			}
		
		}
	
	}

	if (objSelectedItem != null && this.strJustMoved == objSelectedItem.id) {
		this.strJustMoved = "";
	}
	
}

ItemList.prototype.removeSelected = function() {
	var strItemID = this.arrItems[this.intCurrentSelectedIndex];
	this.remove(strItemID);
}

ItemList.prototype.removeAll = function() {
	if (this.arrItems.length > 0) {
		var lstIDs = this.arrItems.join(",");
		var arrIDs = lstIDs.split(",");
		for (var i = 0; i < arrIDs.length; ++i) {
			this.remove(arrIDs[i]);
		}
		this.hshItemsByID = new Array();
		this.arrItems = new Array();
	}
}

ItemList.prototype.remove = function(strItemID) {

	--this.intCount;
	var objItem = objDOM.getLayerReference(strItemID);
	
	if ( !objItem ) return false;
	
	this.objTableBody.removeChild(objItem);

	//remove the item from our internal arrays
	
	//first find the index of the removed element
	//and set it to NULL
	var index = 0;
	var validIndex = -1;
	if (this.hshItemsByID[strItemID] != null) {
		index = this.hshItemsByID[strItemID];
	}
	/**
	for (var i = 0; i < this.arrItems.length; ++i) {
		if (this.arrItems[i] == strItemID) {
			this.arrItems[i] = null;
			index = i;
		}
	}
	**/
	
	//now copy the remaining elements into a new array
	var arrItemsNew = new Array();
	var hshItemsNew = new Array();
	var newIndex = 0;
	for (var i = 0; i < this.arrItems.length; ++i) {
		if (this.arrItems[i] != null) {
			arrItemsNew[newIndex] = this.arrItems[i];
			hshItemsNew[this.arrItems[i]] = newIndex;
			++newIndex;
		}	
	}
	
	this.arrItems = arrItemsNew;
	this.hshItemsByID = hshItemsNew;

	if (index == this.intCurrentSelectedIndex) {
	
		//get the next valid index
		for (var i = index + 1; i < this.arrItems.length; ++i) {
			if (this.arrItems[i] != null) {
				validIndex = i;
				break;
			}
		}

		//we didn't find an index after this one, so find one before
		if (validIndex == -1) {
			for (var i = index - 1; i >= 0; --i) {
				if (this.arrItems[i] != null) {
					validIndex = i;
					break;
				}
			}
		}

		if (validIndex != -1) {
			//this.selectItem(objDOM.getLayerReference(this.arrItems[validIndex]), validIndex);
		}
	}
}

//move the given item out of this list and into the new list
ItemList.prototype.moveToList = function(strItemID, objNewList) {

	var objItem = objDOM.getLayerReference(strItemID);
	
	//get the unique id for this item. this id needs to persist
	//across the move
	//the div IDs is of the form: [strItemPrefix][index]-[unique id]
	//e.g., main1-123
	//where:
	// main is the list name
	// 1 is the list index
	// and 123 is the unique id
	var arrElements = strItemID.split('-');
	var strUniqueID = arrElements[1];

	//create a copy of this item
	var objNewItem = document.createElement("tr");
	
	
	//hacktacular -- safari 1.0 doesn't support the cells object
	//so we use the children object instead	
	var objCells = null
	if (objItem.cells.length == 0) {
		if (objItem.children != null) {
			objCells = objItem.children;
		}
	} else {
		objCells = objItem.cells;
	}
	
	//loop through each cell in this row
	//and append it to our new row
	//the act of appending removes the cell from the old row
	while (objCells.length > 0) {
		objNewItem.appendChild(objCells[0]);
	}

	//give it a new ID
	var strNewID = objNewList.strItemPrefix + objNewList.arrItems.length + "-" + strUniqueID;
	objNewItem.id = strNewID;

	//remove the item from this list
	this.remove(strItemID);
	
	//now add it to the new list
	objNewList.addItem(objNewItem);

	//select this new item
	objNewList.selectItem(objNewItem);

}

ItemList.prototype.size = function() {
	return this.intCount;
}

ItemList.prototype.selectFirst = function() {
	var objFirst = objDOM.getLayerReference(this.arrItems[0]);
	if (objFirst != null) {
		this.selectItem(objFirst);
	}
}

ItemList.prototype.moveItem = function(intDirection) {
	var blnMove = true;
	var objListContainer = this.objTableBody;
	
	if ((this.intCurrentSelectedIndex > 0 || intDirection == 1)
		&& (this.intCurrentSelectedIndex < this.intCount || intDirection == -1)) {
		
		for (var i = 0; i < objListContainer.childNodes.length; ++i) {
			if (objListContainer.childNodes[i].id == null) {
	//			alert('removing ' + objListContainer.childNodes[i].id);
				objListContainer.removeChild(objListContainer.childNodes[i]);
			}
		}
		/**
		if (intDirection == -1) {
			blnMove = (this.intCurrentSelectedIndex > 0);
		} else {
			blnMove = (this.intCurrentSelectedIndex < this.arrItems.length - 1);
		}
		**/
		if ((objListContainer.firstChild == this.objCurrentSelectedItem && intDirection == -1) || (objListContainer.lastChild == this.objCurrentSelectedItem && intDirection == 1)) {
			blnMove = false;
		}
		
		if (blnMove) {
			var objItemToDisplace;
			if (intDirection == 1) {
				objItemToDisplace = this.objCurrentSelectedItem.nextSibling;	
			} else {
				objItemToDisplace = this.objCurrentSelectedItem.previousSibling;	
			}
			
			objListContainer.removeChild(this.objCurrentSelectedItem);
			
			if (intDirection == 1) {
				//alert('moving ' + this.objCurrentSelectedItem.id + ' after ' + objItemToDisplace.id);
				objListContainer.insertBefore(this.objCurrentSelectedItem, objItemToDisplace.nextSibling);
			} else {
				//alert('moving ' + this.objCurrentSelectedItem.id + ' before ' + objItemToDisplace.id);
				objListContainer.insertBefore(this.objCurrentSelectedItem, objItemToDisplace);
			}
			
			//swap the elements in our internal array
			var intOldIndex = this.intCurrentSelectedIndex;
			var intNewIndex = this.intCurrentSelectedIndex + intDirection;
			var objDisplacedValue = this.arrItems[intNewIndex];
			var objValue = this.arrItems[intOldIndex];
			this.arrItems[intNewIndex] = objValue;
			this.arrItems[intOldIndex] = objDisplacedValue;
			this.hshItemsByID[objValue] = intNewIndex;
			this.hshItemsByID[objDisplacedValue] = intOldIndex;
			this.intCurrentSelectedIndex = intNewIndex;			
			
		}
	}
	
}