// atHomeAllocation.js
// (c) Tom Humphrey 2006
// allocate and release sheets

// version 0.01j

/*extern  userUpdateHandle*/

var standardBrowser= (navigator.appName!='Microsoft Internet Explorer');
var IEversion;

if (!standardBrowser) {
	IEversion = navigator.appVersion;
	IEversion = parseInt(IEversion.substr(IEversion.indexOf("MSIE")+4),10);
}
else {
	IEversion=0;
}

var globalUpdateCount=0;

var globalEventStack=[];
var globalEventMethodName=[];
var globalEventTarget=[];
var globalEventCapturing=[];
var globalEventType=[];
var globalBlockSave;

var globalVersion='001h';

var globalModifiedSinceLastBackup=false;

var onlineUsers=null;
var allocation=null;
var sheetList=null;

//var scriptUrl='http://herbariaunited.org/';

/*
try
{
	var tr=document.createElement("TR");
	tr.focus=false;
	tr=null;
}
catch (err)
{
	window.location.href=scriptUrl+"content/incompat/";
}
*/

// ignore all ctrl+key combinations except ctrl+V and ctrl+X
if (standardBrowser)
{
	var valid_key=function(event) {
		//alert ('keycode='+event.which);

		return (event.keyCode >= 46 || event.keyCode==32 || event.keyCode==8 || event.keyCode==0) && !(event.ctrlKey && !(event.keyCode==86 || event.keyCode==88));
		// see http://www.js-examples.com/page/tutorials__key_codes.html
	};
}
else
{
	var valid_key=function(event) {
		return (event.keyCode >= 46 || event.keyCode==32 || event.keyCode==8) && !(event.ctrlKey && !(event.keyCode==86 || event.keyCode==88));
		//event.returnValue = ((event.keyCode <=58) || (event.keyCode == 191)) && (event.keyCode !=32);
	};
}

function showForm(url) {
	// open edit window
	var slow=document.getElementById('slow');
	slow=(slow && slow.checked);
	var formWindow=window.open(url+(slow?'&slow=1':'')+phpSession,'atHomeForm','width=900,status=no,resizable=yes,scrollbars=yes');
	formWindow.focus();
	return false;
}

function OnlineUsers()
{
	this.XMLrequest=null;
	this.userList=document.getElementById('userlist');
	this.usersOnline=document.getElementById('useronlineblock');
	
	this.usersOnline.style.display="none"; // hide until updated
	
	this.requestUpdate();
}

OnlineUsers.prototype.destroy = function () {
	//alert('destroying user list');
	
	if (userUpdateHandle) {
		window.clearInterval(userUpdateHandle);
		userUpdateHandle=null;
	}
	
	this.XMLrequest=null;
	this.clearUserList();
	this.userList=null;
	this.usersOnline=null;
};

OnlineUsers.prototype.requestUpdate = function () {
	// send request to release current specimens and refresh window
	// only do this for the first 40 (4*10) minutes
	
	//globalUpdateCount=0;
	
	this.clearUserList();
	if (globalUpdateCount++ < 10) {
		this.XMLrequest=agnosticXMLHttpRequest(); // create the request object
		xmlRequest(this.XMLrequest,scriptUrl+"XMLOnlineUsers.php?seed="+(Math.random()),associateObjectWithXMLRequest(this, "XMLhandler", ''));
	}
	else {
		this.usersOnline.style.display="none";
		if (userUpdateHandle) {
			window.clearInterval(userUpdateHandle);
			userUpdateHandle=null;
		}
	}
};

OnlineUsers.prototype.XMLhandler = function () {
	// refresh window
	
	if (this.XMLrequest && this.XMLrequest.readyState == 4 && this.XMLrequest.status == 200)
	{
		var response  = this.XMLrequest.responseXML.documentElement;

		var users = response.getElementsByTagName('user');
		
		if (users.length)
		{
			this.usersOnline.style.display="block";
			
			var l=users.length;

			for (var i=0; i<l;i++) {	
				if (users[i].firstChild && this.userList) {
					var li=document.createElement("li");
					li.id=uniqueId('onlineuser');
					li.appendChild(document.createTextNode(users[i].firstChild.data));
					this.userList.appendChild(li);
				}
			}
		}
		else {this.usersOnline.style.display="none";}
    }
};

OnlineUsers.prototype.clearUserList = function () {
	var users=this.userList.getElementsByTagName('li');
	this.userList.style.display='block'; // not sure if this help clean delete (IE bug)
	//alert('clearing user list');
	if (users.length)
	{
		var l=users.length;
		
		for (var i=l-1; i>=0;i--) {
			users[i].id=null;
			if (this.userList) {this.userList.removeChild(users[i]);}
		}
	}
};

function SpecimenAllocation()
{
	this.XMLrequest=null;
	this.allocationList=document.getElementById('allocationlist');
	this.allocationBlock=document.getElementById('allocationblock');
	this.allocateMessage=document.getElementById('allocationmessage');
	this.totalList=document.getElementById('sheetlist');
}

SpecimenAllocation.prototype.destroy = function () {
	this.XMLrequest=null;
	this.allocationList=null;
	this.allocationBlock=null;
	this.allocateMessage=null;
	this.totalList=null;
};

SpecimenAllocation.prototype.release = function () {
	// send request to release current specimens and refresh window
	
	var url=scriptUrl+"XMLAllocatedSpecimens.php?release=true&seed="+(Math.random());
		
	this.XMLrequest=agnosticXMLHttpRequest(); // create the request object
	xmlRequest(this.XMLrequest,url,associateObjectWithXMLRequest(this, "XMLhandler", null));
	
	return false; // stop default action if called as an onclick handler
};

SpecimenAllocation.prototype.setSheetList = function () {
	// get list
	var url=scriptUrl+"XMLAllocatedSpecimens.php?seed="+(Math.random());
	
	this.XMLrequest=agnosticXMLHttpRequest(); // create the request object
	xmlRequest(this.XMLrequest,url,associateObjectWithXMLRequest(this, "XMLhandler", null));
};

SpecimenAllocation.prototype.setSheetListSynchronous = function () {
	// get list
	var url=scriptUrl+"XMLAllocatedSpecimens.php?seed="+(Math.random());
	
	this.XMLrequest=agnosticXMLHttpRequest(); // create the request object
	synchronousXMLRequest(this.XMLrequest,url,associateObjectWithXMLRequest(this, "XMLhandler", null));
};

/*
<response uid="n">
	<sheet id="n" p="n" review="null|peer|expert" documented="1|0" invalid="1|0">
		<taxon id="">taxon name</taxon>
	</sheet>
</response>
*/

SpecimenAllocation.prototype.XMLhandler = function () {
	// refresh window
	
	//&& this.XMLrequest.status == 200
	if (this.XMLrequest && this.XMLrequest.readyState == 4)
	{	
		var response  = this.XMLrequest.responseXML.documentElement;

		// taxon name
		var sheets = response.getElementsByTagName('sheet');
		
		this.clearSheetList();
		
		if (sheets.length >0)
		{
			this.allocationBlock.style.display="block";
			if (this.totalList) {this.totalList.style.display="none";}
			this.allocateMessage.style.display="none";
			
			var l=sheets.length;

			for (var i=0; i<l;i++)
			{	
				var taxon=sheets[i].getElementsByTagName('taxon');
			
				if (taxon[0].firstChild && taxon[0].firstChild.data) {
					var labelText=taxon[0].firstChild.data;
				} else {
					var labelText='unnamed sheet';
				}
				
				var li=document.createElement("li");
				var img=document.createElement("img");
				img.src='http://'+sheets[i].getAttribute('thumb');
				img.width=sheets[i].getAttribute('thumbw');
				img.height=sheets[i].getAttribute('thumbh');
				li.appendChild(img);
				li.appendChild(document.createTextNode(labelText));
				this.allocationList.appendChild(li);
			}
		}
		else
		{
			this.allocationBlock.style.display="none";
			if (this.totalList) this.totalList.style.display="block";
			this.allocateMessage.style.display="block";
		}
		
		var totalSpecimens=response.getElementsByTagName('total');
		
		if (totalSpecimens.length >0) {
			var totalElement=document.getElementById('specimencount');
			if (totalElement) {
				totalElement.firstChild.data=totalSpecimens[0].firstChild.data;
				//alert('t='+totalSpecimens[0].firstChild.data);
			}
		}
    }
};

SpecimenAllocation.prototype.clearSheetList = function () {
	var sheets=this.allocationList.getElementsByTagName('li');
	
	if (sheets.length)
	{
		var l=sheets.length;
		
		for (var i=l-1; i>=0;i--)
		{
			this.allocationList.removeChild(sheets[i]);
		}
	}
};

/*
function SpecimenTotalList()
{
	this.XMLrequest=null;
	this.sheetsTable=document.getElementById('sheetstable');
}

SpecimenTotalList.prototype.clear = function () {
	this.sheetsTable.deleteTFoot();
	
	var rows=this.sheetsTable.rows.length;
	
	if (rows >1) {
		// more than just the header
		for (var row=rows-1; row>1; row--) {
			this.sheetsTable.rows[row].cells[0].firstChild.onclick=null;
			this.sheetsTable.rows[row].cells[0].removeChild(this.sheetsTable.rows[row].cells[0].firstChild);
			this.sheetsTable.deleteRow(row);
		}
	}
	
	if (this.sheetsTable.tBodies.length) {
		this.sheetsTable.removeChild(this.sheetsTable.tBodies[0]);
	}
};

SpecimenTotalList.prototype.destroy = function () {
	
	this.clear();
	this.XMLrequest=null;
	this.sheetsTable=null;
};

SpecimenTotalList.prototype.setSheetList = function () {
	// get list
	
	var url=scriptUrl+"XMLTotalList.php?seed="+(Math.random());
	
	this.XMLrequest=agnosticXMLHttpRequest(); // create the request object
	xmlRequest(this.XMLrequest,url,associateObjectWithXMLRequest(this, "XMLhandler", null));
};
*/ 

/*
<response>
	<proj id="n" title="">name</proj> ...
	<inst id="n" title="">name</inst> ...
	<g c="n" a="n" t="n">name
		<t id="n" c="n" a="n" t="n">taxon name<proj id=""/><inst id=""/></t>
	</g>
	<complete t="n" />
	<total c="n" a="n" t="n" />
</response>
*/

/*
SpecimenTotalList.prototype.XMLhandler = function () {
	var i,l,tr,td,sp,spCount,proj,inst,projCount,instCount,abbr,id,a,key;
	
	if (this.XMLrequest.readyState == 4 && this.XMLrequest.status == 200)
	{
		
		//alert('got here (XML handler)');
		this.clear();
		
		var response  = this.XMLrequest.responseXML.documentElement;

		key=response.getAttribute('key');

		// set list of projects and institutions
		var projects=[];
		var institutions=[];
		
		proj=response.getElementsByTagName('projdef');
		l=proj.length;
		
		if (l>0){
			for (i=0; i<l;i++) {
				projects[proj[i].getAttribute('id')]=[];
				projects[proj[i].getAttribute('id')].name=proj[i].firstChild.data;
				projects[proj[i].getAttribute('id')].title=proj[i].getAttribute('title');
			}
		}
		
		inst=response.getElementsByTagName('instdef');
		l=inst.length;
		if (l) {
			for (i=0; i<l;i++) {
				institutions[inst[i].getAttribute('id')]=[];
				institutions[inst[i].getAttribute('id')].name=inst[i].firstChild.data;
				institutions[inst[i].getAttribute('id')].title=inst[i].getAttribute('title');
			}
		}
		
		var genii = response.getElementsByTagName('g');
		var tbody=document.createElement('tbody');
		this.sheetsTable.appendChild(tbody);
		
		var row=1; // header row is first row
		var genus=0;
		
		if (genii.length) {
			l=genii.length;

			for (i=0; i<l;i++)
			{	
				tr=document.createElement('tr');
				tr.className=((genus++%2)?'light':'dark');
				
				sp=genii[i].getElementsByTagName('t');
				spCount=sp.length;
				
				//a=document.createElement('a');
				//a.appendChild(document.createTextNode(genii[i].firstChild.data+" ("+spCount+" sp)"));
				
				//tr.insertCell(0).appendChild(a);
				
				td=document.createElement('td');
				tr.appendChild(td).appendChild(document.createTextNode(genii[i].firstChild.data+" ("+spCount+" sp)"));
				td.setAttribute('onclick','r('+(row+1)+','+(row+spCount)+')');
				
				//tr.insertCell(1).appendChild(document.createTextNode(genii[i].getAttribute('c')+' / '+genii[i].getAttribute('a')+' / '+genii[i].getAttribute('t')));
				td=tr.appendChild(document.createElement('td'));
				td.appendChild(document.createTextNode(genii[i].getAttribute('c')+' / '+genii[i].getAttribute('a')+' / '+genii[i].getAttribute('t')));
				td.colSpan=3;
				tbody.appendChild(tr);
				
				row++;
				
				for (s=0; s<spCount; s++) {
					tr=document.createElement('tr');
					
					tr.className=((row++%2)?'glight':'gdark');
					tr.style.display="none";
					
					a=document.createElement('a');
					a.appendChild(document.createTextNode(sp[s].firstChild.data));
					
					
					//tr.insertCell(0).appendChild(a);
					td=tr.appendChild(document.createElement('td'));
					td.appendChild(a);
					
					a.setAttribute('onclick',"showForm('/atHomeForm/?allocate="+sp[s].getAttribute('id')+"&ref=main&key="+key+"')");
					td.style.paddingLeft="1em";
					
					//tr.insertCell(1).appendChild(document.createTextNode(sp[s].getAttribute('c')+'/'+sp[s].getAttribute('a')+'/'+sp[s].getAttribute('t')));
					tr.appendChild(document.createElement('td')).appendChild(document.createTextNode(sp[s].getAttribute('c')+'/'+sp[s].getAttribute('a')+'/'+sp[s].getAttribute('t')));
					
					inst=sp[s].getElementsByTagName('inst');
					instCount=inst.length;
					if (instCount) {
						td=tr.appendChild(document.createElement('td'));
						
						for (h=0;h<instCount;h++) {
							id=inst[h].getAttribute('id');
							if (institutions[id]) {
								abbr=document.createElement('abbr');
								abbr.appendChild(document.createTextNode(institutions[id].name));
								abbr.title=institutions[id].title;
								td.appendChild(abbr);
								
								if (h <instCount-1) {
									td.appendChild(document.createTextNode(' '));
								}
							}
						}
					} else {
						tr.appendChild(document.createElement('td'));
					}
					
					proj=sp[s].getElementsByTagName('proj');
					projCount=proj.length;
					if (projCount) {
						td=tr.appendChild(document.createElement('td'));
						
						for (h=0;h<projCount;h++) {
							id=proj[h].getAttribute('id');
							if (projects[id]) {
								abbr=document.createElement('abbr');
								abbr.appendChild(document.createTextNode(projects[id].name));
								abbr.title=projects[id].title;
								td.appendChild(abbr);
								
								if (h <projCount-1) {
									td.appendChild(document.createTextNode(' '));
								}
							}
						}
					} else {
						tr.appendChild(document.createElement('td'));
					}
					
					tbody.appendChild(tr);
				}
			}
			
			this.sheetsTable.appendChild(tbody);
			
			
		}
		else
		{
			
		}
    }
};
*/

function windowBeforeUnloadHandler()
{
	window.onbeforeunload=null;
	
	if (!standardBrowser) {
		var rows=document.getElementsByTagName('tr');
	
		for (var l=rows.length-1;l>=0;l--) {
			rows[l].style.display="block";
		}
	}
	//return 'am here';
}

/*
function onLoadHandler()
{
	sheetList.setSheetList();
}
*/

function windowUnloadHandler()
{
	window.onunload=null;
	window.onbeforeunload=null;
	
	if (onlineUsers) {
		onlineUsers.destroy();
		onlineUsers=null;
	}
	
	if (allocation) {
		allocation.destroy();
		allocation=null;
	}
	
	//if (sheetList) {
	//	sheetList.destroy();
	//	sheetList=null;
	//}
	
	var links=document.getElementsByTagName('a');

	for (var l=links.length-1;l>=0;l--) {
		links[l].onclick=null;
	}
	links=null;
	
	/*var rows=document.getElementsByTagName('tr');
	for (var l=rows.length-1;l>=0;l--) {
		rows[l].parentNode.removeChild(rows[l]);
	}*/
}

if (standardBrowser)
{
	registerEventHandler = function(target,eventName,obj,methodName,param,capturing)
	{
		var stackElement=globalEventStack.length;
		target.addEventListener(eventName,globalEventStack[stackElement]=stdAssociateObjWithEvent(target,obj, methodName,param),capturing===true);
		
		globalEventTarget[stackElement]=target;
		globalEventMethodName[stackElement]=methodName;
		globalEventType[stackElement]=eventName;
		globalEventCapturing[stackElement]=(capturing===true);
		return stackElement; // ref to attached function, which is returned (in case needed for removal later)
	};
	
	function stdAssociateObjWithEvent(target,obj, methodName,param){
	   return (function(e){
	       return obj[methodName](e, target, param);
	   });
	}
}
else 
{
	registerEventHandler = function(target,eventName,obj,methodName,param)
	{
		var stackElement=globalEventStack.length;
		target.attachEvent('on'+eventName,globalEventStack[stackElement]=IEAssociateObjWithEvent(obj, methodName,param));
		
		globalEventTarget[stackElement]=target;
		globalEventMethodName[stackElement]=methodName;
		globalEventType[stackElement]=eventName;
		return stackElement; // ref to attached function, which is returned (in case needed for removal later)
	};
	
	function IEAssociateObjWithEvent(obj, methodName,param){
		return (function(){
			return obj[methodName](window.event, this.event.srcElement, param);
		});
	}
}

if (document.removeEventListener) { // DOM event model
	var removeEventHandler = function(handler) {
		
		if (globalEventStack[handler]) globalEventTarget[handler].removeEventListener(globalEventType[handler],globalEventStack[handler], globalEventCapturing[handler]);
		else alert('remove failure');
		delete globalEventStack[handler];
		delete globalEventMethodName[handler];
		delete globalEventType[handler];
		delete globalEventTarget[handler];
		delete globalEventCapturing[handler];
	};
}
else
{
	var removeEventHandler = function(handler) {

		if (globalEventStack[handler]) globalEventTarget[handler].detachEvent("on"+globalEventType[handler],globalEventStack[handler]);
		else alert('remove failure');
		delete globalEventStack[handler];
		delete globalEventMethodName[handler];
		delete globalEventTarget[handler];
		delete globalEventType[handler];
	};
}

// from http://jibbering.com/faq/faq_notes/closures.html
function associateObjWithEvent(obj, methodName,param){
    /* The returned inner function is intended to act as an event
       handler for a DOM element:-
    */
    return (function(e){
        /* The event object that will have been parsed as the - e -
           parameter on DOM standard browsers is normalised to the IE
           event object if it has not been passed as an argument to the
           event handling inner function:-
        */
        e = e||window.event;
        /* The event handler calls a method of the object - obj - with
           the name held in the string - methodName - passing the now
           normalised event object and a reference to the element to
           which the event handler has been assigned using the - this -
           (which works because the inner function is executed as a
           method of that element because it has been assigned as an
           event handler):-
        */
        return obj[methodName](e, this, param);
    });
}

function associateObjectWithXMLRequest(obj, methodName, param) {
	// returns an XML http request object
	
	return (function(){
		return obj[methodName](param);
	});
}

if (window.XMLHttpRequest) {
	var agnosticXMLHttpRequest = function () {	
		return new XMLHttpRequest();
	};
}
else {
	var agnosticXMLHttpRequest = function () {
		return new ActiveXObject("Microsoft.XMLHTTP");
	};
}

function xmlRequest(req,url,handler)
{
	req.onreadystatechange = handler;
	req.open("GET", url, true);
	req.send(null); 
}

function XMLSave(req,url,handler,data)
{
	req.onreadystatechange = handler;
	req.open("POST", url, true);
	req.send(data);
}

function synchronousXMLRequest(req,url,handler)
{
	req.open("GET", url, false);
	req.send(null);
	handler();
}
	
function loadXMLDoc(url,handler)
{
	var req;
	
	// branch for native XMLHttpRequest object
    if (window.XMLHttpRequest)
    {
		req = new XMLHttpRequest();
		req.onreadystatechange = handler;
		req.open("GET", url, true);
		req.send(null);
    // branch for IE/Windows ActiveX version
    }
	else if (window.ActiveXObject)
    {
		req = new ActiveXObject("Microsoft.XMLHTTP");
		req.onreadystatechange = handler;
		req.open("GET", url, true);
		req.send();
	}

	return req;
}

function init_allocation() {
	allocation=new SpecimenAllocation();
	allocation.setSheetList();
	
	//sheetList=new SpecimenTotalList();
	//sheetList.setSheetList();
}

uniqueId.counter=0;
function uniqueId(prefix) {
	return prefix+(uniqueId.counter++);
}