/*
	SimpleTest XUL Interface
	Author: Maxim "Maxx" Poltarak <http://maxx.e-taller.net/>
	WWW: http://dev.e-taller.net/simpletestxul/

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
var RCounter;

//*****************************************************************************
function mainOnLoad() {
	RCounter	= new ResultCounter();

	document.title = document.getElementById("mainWindow").getAttribute("title");

	var opt;
	if(!(opt = document.getElementById("optDetailP")).selectedItem) opt.selectedIndex = 0;
	if(!(opt = document.getElementById("optDetailF")).selectedItem) opt.selectedIndex = 3;

	projectsRefreshCommand();
}

//*****************************************************************************
function projectsRefreshCommand()
{
	setStatus(getString("status.projects.loading"));
	document.getElementById("projectsButtonRefresh").setAttribute("disabled", true);

	// create connection
	var conn = new XHttpConnection();
	conn.url = getString("conf.data.projects") 
		+ "&token="+parseInt(Math.random() * 1000000)
	;
	conn.async = true;

	var handler = new Object();
	handler.onError = function(connection)
	{
		alert(connection.httpError.description);
		setStatus(getString("status.projects.failed"));
		document.getElementById("projectsButtonRefresh").setAttribute("disabled", false);
	}
	handler.onLoad = function(dom) {
		setStatus(getString("status.projects.processing"));
		processProjectsData(dom);
		setStatus();
		document.getElementById("projectsButtonRefresh").setAttribute("disabled", false);
	}
	conn.setAsyncHandler(handler);
	conn.execute();
}

//*****************************************************************************
function processProjectsData(dom)
{
	var list = document.getElementById("prjItems");
	var prjCurrent = list.parentNode.selectedIndex;

	// clear Projects list...
	while(list.hasChildNodes()) list.removeChild(list.lastChild);

	// build Projects list
	var projects = dom.getElementsByTagName("project");

	if(0 == projects.length) {
		document.getElementById("listFilesButtonRefresh").setAttribute("disabled", true);
		return;
	}

	for(var i=0; i < projects.length; i++)
	{
		var project = projects.item(i);

		var item = document.createElement("menuitem");
		item.setAttribute("label", project.getAttribute("title"));
		list.appendChild(item);
	}

	document.getElementById("prjBox").setAttribute("style", projects.length > 1 ? "" : "display:none");

	if(-1 == prjCurrent) list.parentNode.selectedIndex = 0;
	else if(prjCurrent < projects.length) list.parentNode.selectedIndex = prjCurrent;

	filesRefreshCommand();
}

//*****************************************************************************
function filesRefreshCommand()
{
	setStatus(getString("status.files.loading"));
	document.getElementById("listFilesButtonRefresh").setAttribute("disabled", true);

	// create connection
	var conn = new XHttpConnection();
	conn.url = getString("conf.data.files") 
		+ "&project="+document.getElementById("prjList").selectedIndex
		+ "&token="+parseInt(Math.random() * 1000000);
	conn.async = true;

	var handler = new Object();
	handler.onError = function(connection)
	{
		alert(connection.httpError.description);
		setStatus(getString("status.files.failed"));
		document.getElementById("listFilesButtonRefresh").setAttribute("disabled", false);
	}
	handler.onLoad = function(dom) {
		setStatus(getString("status.files.processing"));
		processFilesData(dom);
		setStatus();
		document.getElementById("listFilesButtonRefresh").setAttribute("disabled", false);
	}
	conn.setAsyncHandler(handler);
	conn.execute();
}

//*****************************************************************************
function processFilesData(dom)
{
	var list = document.getElementById("listFiles");

	// clear Files list...
	while(list.lastChild.nodeName != "listhead") list.removeChild(list.lastChild);

	// build Files list
	var files = dom.getElementsByTagName("file");
	for(var i=0; i < files.length; i++)
	{
		var file = files.item(i);

		var item = document.createElement("listitem");
		item.setAttribute("allowevents", true);
		item.appendChild(document.createElement("checkbox"));
		item.lastChild.setAttribute("value",	1);
		item.lastChild.setAttribute("hash",		file.getAttribute("hash"));
		item.lastChild.setAttribute("label",	file.getAttribute("name"));

		list.appendChild(item);
	}

}

//*****************************************************************************
function runTestsCommand() 
{
	setWaitMode(true);

	RCounter.clear();

	// clear Results tree
	var children = document.getElementById("treeResults");
	while(children.hasChildNodes()) children.removeChild(children.lastChild);

	// clear status toolbar
	var stLabel = document.getElementById("statusLabel");
	while(stLabel.nextSibling) stLabel.parentNode.removeChild(stLabel.nextSibling);

	// create Test queue
	if(!this.testQueue) this.testQueue = new Array();
	while(this.testQueue.length) this.testQueue.pop();

	// fill Test queue
	var list = document.getElementById("listFiles").getElementsByTagName("checkbox");
	for(var i=0; i < list.length; i++) 
	{
		if("true" != list[i].getAttribute("checked")) continue;

		var item = new Object();
		item.file = list[i].getAttribute("label");
		item.hash = list[i].getAttribute("hash");

		testQueue.push(item);
	}

	// run tests
	runNextTest();
}

//*****************************************************************************
function runNextTest() 
{
	if(!this.testQueue || !this.testQueue.length) 
	{
		// reset toolbar info labels
		var tbar = document.getElementById("infoToolbar");
		tbar.appendChild(document.createElement("toolbarseparator"));
		for(var i in RCounter)
		{
			if("number" != typeof(RCounter[i])) continue;
			if("pass" != i && "fail" != i && 0 == RCounter[i]) continue;
    
			tbar.appendChild(document.createElement("label"));
			tbar.lastChild.setAttribute("id", i+"Info");
			tbar.lastChild.setAttribute("value", getString("options.detail."+i.toLowerCase())+" : "+RCounter[i]);
			tbar.appendChild(document.createElement("toolbarseparator"));
		}

		setWaitMode(false);
		setStatus();
		return;
	}

	setStatus(getString("status.tests.loading"));

	var testItem = this.testQueue.shift();

	var conn = new XHttpConnection();
	conn.url = getString("conf.data.tests") 
		+ "&project="+document.getElementById("prjList").selectedIndex
		+ "&file="+escape(testItem.file)
		+ "&hash="+testItem.hash
		+ "&token="+parseInt(Math.random() * 1000000)
	;
	conn.async = true;
	var handler = new Object();
	handler.onError = function(connection) {
		alert(connection.httpError.description);
		setStatus(getString("status.tests.failed"));
		setWaitMode(false);
	};
	handler.onLoad = function(dom) {
		setStatus(getString("status.tests.processing"));
		processResultsData(dom);
		runNextTest();
	};
	conn.setAsyncHandler(handler);
	conn.execute();
}

//*****************************************************************************
function processResultsData(dom)
{
	// build Results tree
	var from = dom.getElementsByTagName("group")[1];
	var tree = document.getElementById("treeResults");
	buildResultsTree(from, tree);
}

//*****************************************************************************
function buildResultsTree(from, to)
{
	if(!from.hasChildNodes()) return;

	var i=0;
	for(var fromNode=from.childNodes[i]; i < from.childNodes.length; fromNode = from.childNodes[++i])
	{
		if(1 != fromNode.nodeType) continue;

		switch(fromNode.nodeName)
		{
			case "name" :
				var item = to.appendChild(document.createElement("treeitem"));
					item.setAttribute("container", true);

				var row = item.appendChild(document.createElement("treerow"));
					row.setAttribute("properties", fromNode.parentNode.nodeName);
					row.setAttribute("class", fromNode.parentNode.nodeName);

					row.appendChild(document.createElement("treecell"));
						row.lastChild.setAttribute("label", fromNode.textContent);
						row.lastChild.setAttribute("properties", fromNode.parentNode.nodeName);

				to = item.appendChild(document.createElement("treechildren"));

				break;

			case "pass" :
			case "fail" :
//			case "exception" :
//			case "message" :
//			case "formatted" :
//			case "signal" :
				var row = to.appendChild(document.createElement("treeitem")).appendChild(document.createElement("treerow"));
					row.setAttribute("properties", fromNode.nodeName);
	
				row.appendChild(document.createElement("treecell"));
					row.lastChild.setAttribute("properties", fromNode.nodeName);
					row.lastChild.setAttribute("label", fromNode.textContent);
				row.appendChild(document.createElement("treecell"));
					row.lastChild.setAttribute("properties", [fromNode.nodeName, "result"].join(' '));
					row.lastChild.setAttribute("label", getString("options.detail."+fromNode.nodeName.toLowerCase()));

				RCounter.increment(fromNode.nodeName);

				// process parent nodes
				if("fail" == fromNode.nodeName || "pass" == fromNode.nodeName)
				{
					for(n=row; "tree" != n.nodeName; n=n.parentNode)
					{
						if("treeitem" != n.nodeName || "true" != n.getAttribute("container")) continue;

						var cellNum = n.firstChild.childNodes.length;
						var cell;

						if(1 == cellNum) cell = n.firstChild.appendChild(document.createElement("treecell"));
						else if("pass" != fromNode.nodeName) cell = n.firstChild.lastChild;
						else break;

						if(cell.getAttribute("label") == getString("options.detail."+fromNode.nodeName.toLowerCase())) break;

						cell.setAttribute("label", getString("options.detail."+fromNode.nodeName.toLowerCase()));
						cell.setAttribute("properties", fromNode.nodeName);

						// ::TODO:: Too much DOM here. Some performance optimization is needed.
						var optLetter = ("pass" == fromNode.nodeName) ? "P" : "F";
						var optDetail = parseInt(document.getElementById("optDetail"+optLetter).selectedItem.getAttribute("value"));
						var optNode = parseInt(document.getElementById("optDetail"+optLetter+n.firstChild.getAttribute("class")).getAttribute("value"));
						if(optDetail > optNode) n.setAttribute("open", true);

					}
				}

				break;
		}

		if(fromNode.hasChildNodes()) buildResultsTree(fromNode, to);
	}
}

//*****************************************************************************
function ResultCounter()
{
	this.pass = 0;
	this.fail = 0;
	this.exception = 0;
	this.message = 0;
	this.formatted = 0;
	this.signal = 0;
	this.increment = function(what)
	{
		this[what] += 1;
	}
	this.clear = function()
	{
		this.pass = this.fail = this.exception
			= this.message = this.formatted = this.signal
			= 0;
	}
}

//*****************************************************************************
function setWaitMode(mode)
{
	document.getElementById("btnRun").disabled = mode;
}

//*****************************************************************************
function setStatus(mesg)
{
	if(!this.statusLabel) this.statusLabel = document.getElementById("statusLabel");
	this.statusLabel.setAttribute("value", mesg ? mesg : getString("status.default"));
}

//*****************************************************************************
function filesMarkAllCommand(mode)
{
	var list = document.getElementById("listFiles").getElementsByTagName("checkbox");
	for(var i=0; i < list.length; i++)
	{
		var item = list.item(i);
		item.setAttribute("checked", undefined === mode
			? ("true" == item.getAttribute("checked") ? false : true)
			: mode
		);
	}
}

//*****************************************************************************
function getString(id)
{
	if(!this.stringCache) this.stringCache = new Object();

	if(!this.stringCache[id])
	{
//		if(!document.getElementById(id)) alert(id);
		this.stringCache[id] = document.getElementById(id).getAttribute("label");
	}

	return this.stringCache[id];
}

//*****************************************************************************
function XHttpConnection(){
	 this.url = "";
	 this.method = "get";
	 this.async = false;
	 this.postData = null;
	 this.asyncHandler = null;

     this.httpError = new Object();
	 this.resetError = function () {
		 this.httpError.code = 0;
		 this.httpError.description = "";
	 };
	 this.setAsyncHandler = function (asyncHandler) {
		 this.asyncHandler = asyncHandler;
	 }

	 this.execute = function () {
		this.resetError();
		if(!this.asyncHandler && this.async) {
			this.httpError.code = 1;
			this.httpError.description = "Asynchronous Handler Required";
			return null;
		}
		if(this.async && (!this.asyncHandler.onError || !this.asyncHandler.onLoad)) {
			this.httpError.code = 2;
			this.httpError.description = "Invalid Asynchronous Handler";
			return null;
		}
		var dom = null;
		try{
			var mainRequest = new XMLHttpRequest();
			mainRequest.open(this.method, this.url, this.async);
			mainRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
			if(this.async) {
				var thiz = this;
				mainRequest.onerror = function(){
					thiz.httpError.code = 3;
					thiz.httpError.description = getString("error.http.badresponse") + mainRequest.statusText;
					thiz.asyncHandler.onError(thiz);
				};
				mainRequest.onload = function(){
					var xmlDoc = mainRequest.responseXML;
					if(xmlDoc) {
						var response = xmlDoc.getElementsByTagName("response")[0];
						if(response) {
							if (response.getAttribute("status") == "OK") {
								dom = response;
								thiz.asyncHandler.onLoad(dom);
							} else {
								var des = "";
								try{
									des = response.getElementsByTagName("errorDescription")[0].childNodes[0].nodeValue;
								}catch(e){}
								thiz.httpError.code = 4;
								thiz.httpError.description = getString("error.http.error") + "\n" + des;
								thiz.asyncHandler.onError(thiz);
							}
						} else {
							thiz.httpError.code = 7;
							thiz.httpError.description = getString("error.http.badresponse") + "\n" + mainRequest.responseText;
							thiz.asyncHandler.onError(thiz);
						}
					} else {
						thiz.httpError.code = 6;
						thiz.httpError.description = getString("error.http.badresponse") + mainRequest.statusText + "\n\n" + mainRequest.responseText;
						thiz.asyncHandler.onError(thiz);
					}
				};
				mainRequest.send(this.postData);
			} else {
				mainRequest.send(this.postData);
				if(mainRequest.readyState == 4) { //4 = load complete
					var xmlDoc = mainRequest.responseXML;
					var response = xmlDoc.getElementsByTagName("response")[0];
					if (response.getAttribute("status") == "OK") {
						dom = response;
					}
				}
			}
		}catch(e){
			this.httpError.code = 5;
			this.httpError.description = getString("error.http.unknown") + e;
			if(this.async) this.asyncHandler.onError(this);
		}finally{}
		if(!this.async) return dom;
	 };
 }
