if (!__CATDATA_JS__)
{
	alert ("catdata.js isn't loaded.  Expect trouble.");
}

function cmp (opa, opb)
{
	if (typeof (opa) != typeof (opb))
	{
		throw "Type mismatch: Both operands sent to cmp must be of the same type.";
	}
	
	if (typeof (opa) == "number")
	{
		// Numeric comparrison
		return (opa-opb);
	}
	else if (typeof (opa) == "string")
	{
		if (opa.toLowerCase () < opb.toLowerCase ())
		{
			return -1;
		}
		else if (opa.toLowerCase () > opb.toLowerCase ())
		{
			return 1;
		}
		else
		{
			return 0;
		}
	}
	
	return 0;
};

function objectCount (obj)
{
	var count = 0;
	
	var x = 0;
	
	for (x in obj)
	{
		count += 1;
	}
	
	return count;
}

function CategoryContainer ()
{
	var one = null;
	this.rows = new Array ();
	this.catData = new Object ();
	this.table = null;
	this.nowShowingId = 0;
	this.toplevel = new Array ();
	this.currentRow = -1;
	this.currentCol = -1;
	this.crumbs = new Object ();
	this.crumbs.handle = null;
	this.message = new Object ();

	for (one in Categories)
	{
		this.toplevel[this.toplevel.length] = Categories[one];
		MakeCatsFlat (this, Categories[one]);
	}

	return this;
};

/*
	This should be called from inside the calling page with the following code:
	catContainer.init (
		{
			placeholder : "PLACEHOLDER_DIV_ID",
			cols : 3,
			type : 'W',
			please_wait : true,
			width : "100%",
			cat_id : 0,
			select_callback : function_name,
			varname : "catContainer"
		});
 */
CategoryContainer.prototype.init = function (args)
{
	this.placeName = args.placeholder;
	this.placeHandle = document.getElementById (this.placeName);
	if (!this.placeHandle)
	{
		throw "Unable to obtain handle: " + placeName;
	}
	this.colLimit = args.cols;
	this.showType = args.type;
	this.pleaseWait = args.please_wait;
	this.tableWidth = args.width || "100%";
	this.nowShowingId = args.cat_id || this.nowShowingId;
	this.selectCallback = args.select_callback || false;
	this.varname = args.varname || "catContainer";

	if (!this.catData[this.nowShowingId])
	{
		this.nowShowingId = 0;
	}

	// Show the widget
	this.Show ();

	return this;
};

CategoryContainer.prototype.DisplayMessage = function (msg)
{
	try
	{
		if (!this.message.handle)
		{
			this.message.handle = document.createElement ("span");
			this.message.handle.className = "_jscatMessage";
			this.message.handle.setAttribute ("id", "__ZSCategoryMessage");
			this.placeHandle.appendChild (this.message.handle);
			this.message.handle.innerHTML = msg;
		}
		else
		{
			this.HideMessage ();
			this.message.handle.innerHTML = msg;
			this.message.handle.style.display = "";
		}
	}
	catch (err)
	{
		throw "CategoryContainer.DisplayMessage(): " + err;
	}
	
	return;
};

CategoryContainer.prototype.HideMessage = function ()
{
	if (this.message.handle && this.message.handle.style.display == "")
	{
		this.message.handle.style.display = "none";
	}
	
	return;
};

CategoryContainer.prototype.DropBreadcrumbs = function ()
{
	var crumb = null;
	
	try
	{
		if (!this.crumbs.handle)
		{
			this.crumbs.handle = document.createElement ("span");
			this.crumbs.handle.setAttribute ("id", "__ZSCategoryBreadcrumbs");
			this.crumbs.list = new Array ();

			if (this.placeHandle.firstChild)
			{
				this.placeHandle.insertBefore (this.crumbs.handle, this.placeHandle.firstChild);
			}
			else
			{
				this.placeHandle.appendChild (this.crumbs.handle);
			}
			
			this.AddCrumb (this.nowShowingId, null);
		}
		else if (this.crumbs.handle.style.display == "")
		{
			this.SweepBreadcrumbs ();
			this.crumbs.handle.style.display = "";
			this.AddCrumb (this.nowShowingId, null);
		}
	}
	catch (err)
	{
		throw "CategoryContainer.DropBreadcrumbs(): " + err;
	}
	
	return;
};

CategoryContainer.prototype.SweepBreadcrumbs = function ()
{
	try
	{
		while (this.crumbs.handle.firstChild)
		{
			this.crumbs.handle.removeChild (this.crumbs.handle.firstChild);
		}
		this.crumbs.handle.display = "none";
	}
	catch (err)
	{
		throw "CategoryContainer.SweepBreadcrumbs(): " + err;
	}
	
	return;
};

CategoryContainer.prototype.AddCrumb = function (id, node)
{
	var a = null;
	var raquo = document.createTextNode (" \xBB ");
	
	try
	{
		if (this.nowShowingId == 0)
		{
			return;
		}
		else if (this.catData[id])
		{
			if (id == this.nowShowingId)
			{
				a = document.createElement ("span");
			}
			else
			{
				a = document.createElement ("a");
				a.setAttribute ("href", "javascript:"+this.varname+".SelectCategory('"+this.catData[id].id+"')");
			}
			a.appendChild (document.createTextNode (this.catData[id].name));
		}
		else if (id == 0)
		{
			a = document.createElement ("a");
			a.setAttribute ("href", "javascript:"+this.varname+".SelectCategory('0')");
			a.appendChild (document.createTextNode ("Start"));
		}
		else
		{
			a = document.createElement ("a");
			a.setAttribute ("href", "javascript:"+this.varname+".SelectCategory('0')");
			a.appendChild (document.createTextNode ("Start"));
		}
		
		if (node == null)
		{
			this.crumbs.handle.appendChild (a);
			if (id == this.nowShowingId)
			{
				this.crumbs.handle.appendChild (document.createElement ("br"));
			}
		}
		else
		{
			this.crumbs.handle.insertBefore (raquo, this.crumbs.handle.firstChild);
			this.crumbs.handle.insertBefore (a, this.crumbs.handle.firstChild);
			if (id == this.nowShowingId)
			{
				this.crumbs.handle.appendChild (document.createElement ("br"));
			}
		}
		
		if (id != 0 && this.catData[id])
		{
			this.AddCrumb (this.catData[id].parent, this.crumbs.handle.firstChild);
		}
	}
	catch (err)
	{
		throw "CategoryContainer.AddCrumb(): " + err;
	}
	
	return;
};

CategoryContainer.prototype.CreateTable = function ()
{
	var tbl = null;
	
	try
	{
		if (!this.placeHandle)
		{
			throw "CODE ERROR: No place-holder handle available for CategoryContainer.CreateTable().";
		}

		if (this.table == null)
		{
			// Create a new table because none exists.
			tbl = document.createElement ("table");
			tbl.setAttribute ("id", "__ZS_CategoryContainer");
			tbl.setAttribute ("border", "0");
			tbl.setAttribute ("width", this.tableWidth);
			tbl.setAttribute ("cellpadding", "0");
			tbl.setAttribute ("cellspacing", "2");
			tbl.className = "_jscatTable";
			this.table = document.createElement ("tbody");
			this.table.className = "_jscatTBody";
			tbl.appendChild (this.table);
			this.placeHandle.appendChild (tbl);
		}
		else
		{
			// If the table isn't cleared out, let's make it that way
			if (this.table.style.display == "")
			{
				this.Clear ();
			}
			
			// Display the table
			this.table.style.display = "";
		}
	}
	catch (err)
	{
		throw "CategoryContainer.CreateTable(): " + err;
	}
	
	return;
};

CategoryContainer.prototype.AddRow = function ()
{
	var row = null;
	
	try
	{
		// Make sure that we have a table to work with
		if (this.table == null)
		{
			this.CreateTable ();
		}
		
		if ((this.currentRow + 1) >= this.rows.length)
		{
			// We need to create a new row.
			row = document.createElement ("tr");
			row.className = "_jscatRow";
			this.table.appendChild (row);
			this.currentRow = this.rows.length;
			this.rows[this.currentRow] = new Object ();
			this.rows[this.currentRow].handle = row;
			this.rows[this.currentRow].cols = new Array ();
		}
		else
		{
			// We already have an existing row here.
			this.currentRow += 1;
			// Unhide the row for display.
			this.rows[this.currentRow].handle.style.display = "";
		}
	}
	catch (err)
	{
		throw "CategoryContainer.AddRow(): " + err;
	}
	
	return;
}

CategoryContainer.prototype.AddCell = function ()
{
	var cell = null;
	
	try
	{
		// Make sure that we have a row to work with.
		if (this.currentRow < 0 || !this.rows[this.currentRow])
		{
			this.AddRow ();
		}
		
		// Make sure we still have room in this row
		if ((this.currentCol + 1) >= this.colLimit)
		{
			// Add a new row to make room for this cell
			this.AddRow ();
			this.currentCol = -1;
		}
		
		if (!this.rows[this.currentRow].cols[this.currentCol+1])
		{
			// Create the cell node
			cell = document.createElement ("td");
			cell.setAttribute ("align", "left");
			cell.setAttribute ("valign", "top");
			cell.setAttribute ("width", (100/this.colLimit) + "%");
			cell.className = "_jscatCell";
			
			// Get the new column index
			this.currentCol = this.rows[this.currentRow].cols.length;
			
			// Add the new cell to the row
			this.rows[this.currentRow].handle.appendChild (cell);
			this.rows[this.currentRow].cols[this.currentCol] = new Object ();
			this.rows[this.currentRow].cols[this.currentCol].handle = cell;
		}
		else
		{
			this.currentCol += 1;
			this.rows[this.currentRow].cols[this.currentCol].handle.style.display = "";
		}
	}
	catch (err)
	{
		throw "CategoryContainer.AddCell(): " + err;
	}
}

CategoryContainer.prototype.AddCategory = function (obj)
{
	try
	{
		this.AddCell ();
		this.rows[this.currentRow].cols[this.currentCol].handle.appendChild (obj.handle);
		//this.rows[this.currentRow].cols[this.currentCol].handle.appendChild (document.createTextNode (this.currentRow + "x" + this.currentCol));
		this.rows[this.currentRow].cols[this.currentCol].category = obj;
	}
	catch (err)
	{
		throw "CategoryContainer.AddCategory(): " + err;
	}
	
	return;
}

CategoryContainer.prototype.Show = function ()
{
	var elm = null;
	var parentId = this.nowShowingId;
	var list = null;
	var x = 0;
	var len = 0;
	var colnum = 0;
	var currow = null;
	var cell = null;
	var cat = null;
	var nameList = new Array ();
	var one = null;
	
	this.currentRow = -1;
	this.currentCol = -1;

	try
	{
		// If the ID doesn't exist, default to zero.
		if (!this.catData[this.nowShowingId])
		{
			this.nowShowingId = 0;
		}

		// If we're drilled down as far as we can go, then show selected without
		// executing the callback
		if (this.catData[parentId] && objectCount(this.catData[parentId].children) == 0)
		{
			this.ShowSelected ();
			return;
		}
		
		// Clean up previous displays and create the table if it doesn't exist.
		this.Clear ();
		this.CreateTable ();
		
		// Show breadcrumbs
		this.DropBreadcrumbs ();
		
		// Loop through all necessary nodes
		if (parentId == 0)
		{
			list = this.toplevel;
		}
		else
		{
			if (this.catData[parentId])
			{
				list = this.catData[parentId].children;
			}
			else
			{
				list = new Array ();
			}
		}

		if (!list || list.length == 0)
		{
			throw "No Data.";
		}
		for (x in list)
		{
			nameList[nameList.length] = list[x];
		}
		nameList.sort (
			function (opa, opb) {
				if (typeof(opa.name) != "string")
				{
					return 1;
				}
				else if (typeof(opb.name) != "string")
				{
					return -1;
				}
				return (cmp (opa.name, opb.name))
			});
		for (x = 0, len = nameList.length; x < len; x++)
		{
			one = nameList[x];
			// Create a new Category
			if (one.type == this.showType && one.displayed)
			{
				this.AddCategory (new Category (one.id, one.name, this.varname));
			}
		}
	}
	catch (err)
	{
		throw "CategoryContainer.Show(): " + err;
	}
	
	return true;
}

CategoryContainer.prototype.Clear = function ()
{
	var x = 0;
	var y = 0;
	var len = 0;
	var len2 = 0;
	
	try
	{
		if (!this.table)
		{
			return;
		}
		
		// Loop through rows
		for (y = 0, len = this.rows.length; y < len; y++)
		{
			// Loop through columns
			for (x = 0, len2 = this.rows[y].cols.length; x < len2; x++)
			{
				// Remove all children nodes
				while (this.rows[y].cols[x].handle.firstChild)
				{
					this.rows[y].cols[x].handle.removeChild (this.rows[y].cols[x].handle.firstChild);
				}
				// Hide the cell element for future use
				this.rows[y].cols[x].handle.style.display = "none";
				this.rows[y].cols[x].category = null;
			}
			// Hide the row element for future use
			this.rows[y].handle.style.display = "none";
		}
		// Hide the table element for future use
		this.table.style.display = "none";
		
		// Reset the current coords values
		this.currentRow = -1;
		this.currentCol = -1;
		
		this.SweepBreadcrumbs ();
		this.HideMessage ();
	}
	catch (err)
	{
		throw "CategoryContainer.Clear(): " + err;
	}
	
	return;
};

CategoryContainer.prototype.ShowSelected = function (execute)
{
	var msg = "";
	
	try
	{
		this.Clear ();
		this.DropBreadcrumbs ();
		msg = '<hr/>Your current category is:<br/><span style="font-weight:bold;color:#CC0000;">' +
			this.catData[this.nowShowingId].name + '</span>';
		if (this.pleaseWait)
		{
			msg += "<br/><br/>Please wait...";
		}
		else
		{
			msg += '<br/><br/>To change your category, please click "Start".';
		}
		this.DisplayMessage (msg);

		// Call our callback
		if (this.selectCallback && execute)
		{
			this.selectCallback (this.nowShowingId);
		}
	}
	catch (err)
	{
		throw "CategoryContainer.ShowSelected(): " + err;
	}
	
	return;
};

CategoryContainer.prototype.SelectCategory = function (id)
{
	try
	{
		this.nowShowingId = id;
		if (this.catData[id] && objectCount (this.catData[id].children) == 0)
		{
			this.ShowSelected (true);
		}
		else
		{
			this.Show ();
		}
	}
	catch (err)
	{
		alert ("SelectCategory: " + err);
	}
	
	return;
};

function Category (id, name, varname)
{
	this.catId = id;
	this.catName = name;
	
	this.handle = document.createElement ("a");
	this.handle.setAttribute ("href", "javascript:"+varname+".SelectCategory('"+id+"')");
	this.handle.className = "_jscatCategory";
	this.textHandle = document.createTextNode (this.catName);
	this.handle.appendChild (this.textHandle);
	
	return this;
};

function MakeCatsFlat (container, cat)
{
	var x = 0;
	var len = 0;
	
	
	container.catData[cat.id] = cat;
	
	for (x in cat.children)
	{
		MakeCatsFlat (container, cat.children[x]);
	}
	
	return;
};

// Cat container
var catContainer = new CategoryContainer ();

var __headAry = document.getElementsByTagName ("head");
var __cssTag = document.createElement ("link");

function doOnload ()
{
	__cssTag.setAttribute ("rel", "stylesheet");
	__cssTag.setAttribute ("type", "text/css");
	__cssTag.setAttribute ("href", "/lib/suffixapp/jscat/jscat.css");
	__headAry[0].appendChild (__cssTag);

	return true;
}

if (window.addEventListener)
{
	window.addEventListener("load",doOnload,false);
}
else if (window.attachEvent)
{
	window.attachEvent("onload",doOnload);
}
