// Very basic but fast W3C / IE event handler stuff
// - no memory leaks fix
// - no fix to get 'this' working for IE


// Quick and Dirty !
// 2011 04 09 Frank Kooiman
// This event handling mechanism assumes :
// 1. class instance name in javascript should be the same as the class instance id because we are using eval() to contruct a call to the correct class method
// 2. class instance should be a global variable
// 3. eventDispatch calls : if (classInstance.handler) { classInstance.handler('handler',event); }
// 4. mind spelling and lower- uppercase !
// 5. typical application : 
//
// function eventDispatch(self,event,'onClick') { 
//		if (submitButton.onClick) { submitButton.onClick(self,event); } 				N.B. the 'onClick' part is a variable and passed to eval() !
// }
//	HTML part:
//	htmlContent += '<input 	type="button" 	
//							id="submitButton"
//							onclick=	"eventDispatch(this,event,\'onClick\')" 		N.B. you will need espaced quotes:  \'onClick\' for working in a string !
//							onmouseover="eventDispatch(this,event,\'onMouseOver\')" 
//							onmouseout=	"eventDispatch(this,event,\'onMouseOut\')" 
//						   value="click here">'
//


function toNextTabStop(field)
{
	for (i = 0; i < field.form.elements.length; i++)
	if (field.form.elements[i].tabIndex == field.tabIndex+1) {
		try {
		if (field.form.elements[i].focus) field.form.elements[i].focus();
		/*
		if (field.form.elements[i].type == "text")
			field.form.elements[i].select();
		*/	
		}

		catch (e) {}
		return;
	}
	
}

function onQueryDone(queryResult,field) {

	var jsonQueryResult = JSON.stringify(queryResult);
	console.log('onQueryDone: ' + jsonQueryResult);
	// alert('onQueryDone:' + jsonQueryResult);
	// if (queryResult.success) toNextTabStop(field);

}



function eventDispatchDatabase(self,event,handler,tableName,fieldName,keyField)
{
	var selfid = self.id;

	// Which key has been pressed :
	var eventKeyCode;
	if (event.keyCode) eventKeyCode = event.keyCode;
	else if (event.which) eventKeyCode = event.which;
	var eventKeyChar = String.fromCharCode(eventKeyCode);
	
	// Key ENTER causes data to be stored in database
	// 
	
	console.log('eventDispatchDatabase(' + handler + "," + eventKeyCode + ')');
	if ((handler=='onkeyup') && (eventKeyCode==13)) {
		
	}
	
	if ((handler=='onblur') || (eventKeyCode==13)) {
		var field = document.getElementById(selfid);  
		var id = document.getElementById(keyField); 
		var query = '';			
		if (id && field ) {
			query = 'UPDATE ' + tableName + ' SET ' + fieldName  + '=\'' + field.value + '\' WHERE ID=' + id.value;
			var database = new spcDatabase();
			database.fetchQuery(query,function (queryResult) {onQueryDone(queryResult,field);} );
			//alert('query: ' + query);	
		}
	}
	
	if (handler=='onchange') {
	
		var field = document.getElementById(self.id);  
		var id = document.getElementById(keyField); 
		var query = '';	
		var x = field.selectedIndex;
		if (x) {
			query = 'UPDATE ' + tableName + ' SET ' + fieldName  + '=\'' + field.options[x].value + '\' WHERE ID=' + id.value;
			var database = new spcDatabase();
			database.fetchQuery(query,function (queryResult) {onQueryDone(queryResult,field);} );
			//alert('query: ' + query);
		}
	}
}

var dispatchRecursion = 0;

function eventDispatch(self,event,handler,tableName,fieldName,keyField) 											   
{
	if (!event) { var event = window.event; } 		// http://www.quirksmode.org/js/introevents.html
	if (!self) return;
	//alert("Called eventDispatch("+self.id+"," + handler +")");
	
	dispatchRecursion++;
	
	if (console) console.log("Called eventDispatch("+self.id+"," + handler +") # " + dispatchRecursion);
	
	if (dispatchRecursion > 2) {
		dispatchRecursion-=2;
		return;
	}
	
	var selfid = self.id;

	//if (console) console.log("Called eventDispatch("+selfid+", "+event.type+", "+handler+")"); 
	
	//try {

		// Type of the event: 			event.type
		var eventType = event.type;
		
		// The target of the event :	
		var eventTarget;
		if (event.target) eventTarget = event.target;
		else if (event.srcElement) eventTarget = event.srcElement;
		
		if(eventTarget) {
			if (eventTarget.nodeType)
				if (eventTarget.nodeType == 3) // defeat Safari bug
					eventTarget = eventTarget.parentNode;
		}	
		
		// Which key has been pressed :
		var eventKeyCode;
		if (event.keyCode) eventKeyCode = event.keyCode;
		else if (event.which) eventKeyCode = event.which;
		var eventKeyChar = String.fromCharCode(eventKeyCode);
		
		// Which mouse key has been pressed : we scip this because of incompatibility
		
		console.log('Keycode: ' + eventKeyCode);

		// Mutations on database
		if (tableName && fieldName && keyField) {
		
			eventDispatchDatabase(self,event,handler,tableName,fieldName,keyField);
			
		}
		else if (((eventKeyCode==13) || (eventKeyCode==7)) && (handler=='onkeyup')) {
		
			// ENTER means store and go to next line
			toNextTabStop(self);
			
		}

		// Mouse cursor location :
		
		var posx = 0;
		var posy = 0;
		//if (!event) var event = window.event;
		if (event.pageX || event.pageY) 	{
			posx = event.pageX;
			posy = event.pageY;
		}
		else if (event.clientX || event.clientY) 	{
			posx = event.clientX + document.body.scrollLeft
				+ document.documentElement.scrollLeft;
			posy = event.clientY + document.body.scrollTop
				+ document.documentElement.scrollTop;
		}
		// posx and posy contain the mouse position relative to the document
	
	//}
	//catch (e) 
	//{
	//	console.log('Exception caught: eventDispatch()');
	//}

	/*
	So if you want to know where the mouse comes from in case of mouseover, do:

		function doSomething(e) {
			if (!e) var e = window.event;
			var relTarg = e.relatedTarget || e.fromElement;
		}

		If you want to know where the mouse goes to in case of mouseout, do:

		function doSomething(e) {
			if (!e) var e = window.event;
			var relTarg = e.relatedTarget || e.toElement;
		}
	*/
	
	//if (console) console.log("Called eventDispatch() eventTarget: "+eventTarget.id+" keycode: " + eventKeyCode + ' X: ' + posx + ' Y: ' + posy);
	
	// submitButton.onClick
	var classMethod;
	var objectId;
	classMethod = selfid + '.' + handler;
	objectId = selfid;

	var obj = document.getElementById(objectId);
	
	if (obj) {
	
		if (console) console.log("Called eventDispatch() classMethod: "+classMethod);
		
		// submitButton.onClick('onClick',event)
		var classMethodInvocation = classMethod + '(\'' + selfid + '\', event)';
		
		// if (submitButton.onClick) { submitButton.onClick(self,event); }
		var command = 'if (' + selfid + ') {';
		command += 'if (' + classMethod + ') ';
		command += '{ ' + classMethodInvocation + '; }}';
		
		//console.log('command: ' + command);
		
		try {
			// methodToCall = eval(classMethod);
			eval(command);
			//alert('eventDispatch(): \r\n' + command );
		}
		catch (e) {
			if (console) console.log("failed eventDispatch(): "+classMethodInvocation);
		}
	
	}
	else
	{
		if (console) console.log("Called eventDispatch(), unknown: "+classMethod);
	}
	
	if (console) console.log("Done eventDispatch() # " + dispatchRecursion);
	dispatchRecursion--;
	
}

/*
function addEventSimple(obj,evt,fn) {
	if (obj.addEventListener)
		obj.addEventListener(evt,fn,false);
	else if (obj.attachEvent)
		obj.attachEvent('on'+evt,fn);
}

function removeEventSimple(obj,evt,fn) {
	if (obj.removeEventListener)
		obj.removeEventListener(evt,fn,false);
	else if (obj.detachEvent)
		obj.detachEvent('on'+evt,fn);
}
*/

function addEvent(element, type, handler)
{
	if (element.addEventListener)
		element.addEventListener(type, handler, false);
	else {
		//if (!element.attachEvent('on'+type, handler)) alert('fail');
		if (element.attachEvent) {
			element.attachEvent('on'+type, handler)
		}
		else {
			alert('addEvent() fail');
		}
	}
}
function removeEvent(element, type, handler)
{
	if (element.removeEventListener)
		element.removeEventListener(type, handler, false);
	else
		element.detachEvent('on'+type, handler);
}



// Firefox, Safari support pageX
// IE only has clientX

/*
- In Safari clientX/Y just gives back pageX/Y (so it gives the absolute pos on the page
  instead of relative to the windowcorner).
  So whe'll have to subtract the scrollLeft ourselves to also be compatible with Safari.

- We can't use offsetX because we didn't register onmousemove
  on the same object as we want the position from.

- Firefox doesn't support offsetX !!
*/
function getMouseX(e)
{
	return (e.pageX)?e.pageX:e.clientX + document.body.scrollLeft - (document.documentElement.clientLeft || 0);
}
function getMouseY(e) {
	return (e.pageY)?e.pageY:e.clientY + document.body.scrollTop - (document.documentElement.clientTop || 0);
}

// fixme
getPointerX = getMouseX; // for slider
getPointerY = getMouseY; // for slider


function stopPropagation(event)
{
	if (event.stopPropagation)
		event.stopPropagation();
	else
		event.cancelBubble = true; // IE

	// event.preventDefault();
	event.returnValue = false; // Also prevent selection of tekst/elements when dragging something in IE8
}


// Used in questionair.js
// http://www.openjs.com/articles/prevent_default_action/
function stopEvent(e) {
	if(!e)
		var e = window.event;
	
	//e.cancelBubble is supported by IE - this will kill the bubbling process.
	e.cancelBubble = true;
	e.returnValue = false;

	//e.stopPropagation works only in Firefox.
	if (e.stopPropagation)
	{
		e.stopPropagation();
		e.preventDefault();
	}
	return false;
}


// Prevent event from bubbling up
function toddDontPropagateEvent(theEvent)
{
  if(theEvent.stopPropagation)
  {
    if (theEvent.cancelable)
      theEvent.preventDefault();
    theEvent.stopPropagation();
  }
  else
  {
    theEvent.returnValue = false;
    theEvent.cancelBubble = true;
    if(theEvent.keyCode)
      theEvent.keyCode = 0;
  }
  return false;
}




function preventSelection(elem)
{

alert("OBSOLETE?");
return;

	//elem.setAttribute('unselectable', 'true'); // IE only

	// IE
	elem.onselectstart = function (e)
	{
		if (!e) e = window.event;
		
		var targ = e.target ? e.target : e.srcElement;		// IE uses srcElement instead

		var tname = targ.tagName;
		tname = toLowerCase(tname);

		if (targ.tagName != 'input' && targ.tagName != 'textarea')
			return false;
	}

//  elem.onmousedown = function (e) {
//		var targ = e.target ? e.target : e.srcElement;		// IE uses srcElement instead
//		alert(targ);
//		return false;
//	}

}

var gprevtarget=null;

function makeElementPassEvents(elem)
{
	elem.onclick     = passEvents;
	elem.onmousemove = passEvents;
	elem.onmousedown = passEvents;
	elem.onmouseup   = passEvents;
	elem.ondrag      = passEvents;
	elem.ondragstart = passEvents;
	elem.ondragend   = passEvents;
}

function makeElementPassEventsTo(elem, passto)
{
	elem.onclick     = function(evt) { passEvents(evt, passto) };
	elem.onmousemove = function(evt) { passEvents(evt, passto) };
	elem.onmousedown = function(evt) { passEvents(evt, passto) };
	elem.onmouseup   = function(evt) { passEvents(evt, passto) };
	elem.ondrag      = function(evt) { passEvents(evt, passto) };
	elem.ondragstart = function(evt) { passEvents(evt, passto) };
	elem.ondragend   = function(evt) { passEvents(evt, passto) };
}


/*
passEvents by Spellcoder (Mark de Jong)

Works in IE8, Opera 10.53, Safari 5
(lower versions untested)

Works partly in Firefox 3+ ? (problems with imagemaps?)
*/
function passEvents(e, passto)
{		
	if (!e)
		e = window.event;

	if (!(document.elementFromPoint || passto))
		return;
	
	var eTarget = e.target ? e.target : e.srcElement; // IE uses srcElement instead

	var scrolltop = document.body.scrollTop;
	var scrollleft = document.body.scrollLeft;	
	var docx = e.clientX+scrollleft;
	var docy = e.clientY+scrolltop;
/*
	if (passto)
	{
	console.log('passing event');
	console.log(passto);

		var eTarget = passto;
		eTarget.style.visibility = 'hidden';
		var eBehind = document.elementFromPoint(docx, docy);
		eTarget.style.visibility = 'visible';

	}
	else
	{
*/
		eTarget.style.visibility = 'hidden';
		var eBehind = document.elementFromPoint(docx, docy);
		eTarget.style.visibility = 'visible';
//		}

	var tagname = eTarget.tagName;

	// small hack for imagemaps (for Google Maps) and Firefox.
	// Firefox uses the map as event area instead of the image?
	// luckely GMaps also uses the name as id for the map.
	// (we need to check for existance of function hasAttribute for IE (does it fire on textnodes?)
	if (!eBehind) return;
	if (eBehind.hasAttribute && eBehind.hasAttribute('usemap'))
	{
		var mapname = eBehind.getAttribute('usemap');
		mapname = mapname.substr(1,mapname.length-1);
		var mapelem = document.getElementById(mapname);

		//console.log("map "+mapname);
		//console.log(mapelem);
		
		eBehind = mapelem.firstChild;
	}
	

	if (gprevtarget && gprevtarget != eBehind)
//		if (gprevtarget && !gprevtarget.isSameNode(eBehind))
	{
		if (useragent.isIE)
		{
			eBehind.fireEvent('onmouseover');

			// previous target might not exist in the DOM anymore
			try { gprevtarget.fireEvent('onmouseout'); }
			catch(err) { }
		}
		else
		{
			//console.log('Mouseover on '); console.log(eBehind);
			//console.log('Mouseout on '); console.log(gprevtarget);

			// ''For the mouseover event and the non-standard dragenter event this property indicates the EventTarget  which the pointing device exited''
			var evt = document.createEvent("MouseEvents");
			evt.initMouseEvent(/*type*/     'mouseover'
							,/*canBubble*/  true
							,/*cancelable*/ true
							,/*view*/       e.view
							,/*detail*/     e.detail
							,/*screenX*/    e.screenX
							,/*screenY*/    e.screenY
							,/*clientX*/    e.clientX
							,/*clientY*/    e.clientY
							,/*ctrlKey*/    false
							,/*altKey*/     false
							,/*shiftKey*/   false
							,/*metaKey*/    false
							,/*button*/     e.button
							,/*relatedTarget*/ gprevtarget);
			eBehind.dispatchEvent(evt);	// W3C

			// ''For the mouseout event and the non-standard dragexit event this property indicates the EventTarget  which the pointing device entered.''
			var evt = document.createEvent("MouseEvents");
			evt.initMouseEvent(/*type*/'mouseout'
							,/*canBubble*/ true
							,/*cancelable*/ true
							,/*view*/ e.view
							,/*detail*/ e.detail
							,/*screenX*/e.screenX
							,/*screenY*/e.screenY
							,/*clientX*/e.clientX
							,/*clientY*/e.clientY
							,/*ctrlKey*/false
							,/*altKey*/false
							,/*shiftKey*/ false
							,/*metaKey*/ false
							,/*button*/ e.button
							,/*relatedTarget*/ eBehind);
			gprevtarget.dispatchEvent(evt);	// W3C
		}
	}
	gprevtarget = eBehind;

	
	if (useragent.isIE)
	{
		eBehind.fireEvent('on'+e.type);
	}
	else
	{
		//console.log('Firing on'+e.type+' on element: ');
		//console.log(eBehind);
					
		var evt = document.createEvent("MouseEvents");
		evt.initMouseEvent(/*type*/e.type
						,/*canBubble*/ e.bubbles
						,/*cancelable*/ e.cancelable
						,/*view*/ e.view
						,/*detail*/ e.detail
						,/*screenX*/e.screenX
						,/*screenY*/e.screenY
						,/*clientX*/e.clientX
						,/*clientY*/e.clientY
						,/*ctrlKey*/false
						,/*altKey*/false
						,/*shiftKey*/ false
						,/*metaKey*/ false
						,/*button*/ e.button
						,/*relatedTarget*/ null // for mouseout and dragexit
						); //e.relatedTarget;

		// properties we cannot emulate are isTrusted, timestamp, layerX and layerY
		/*
		console.group();
		console.log(e);
		console.log(evt);
		console.groupEnd();
		*/
		var canceled = !eBehind.dispatchEvent(evt);	// W3C
		/*
		if(canceled) {
			console.warn("Event was cancelled");
			// A handler called preventDefault
		} else {
			// None of the handlers called preventDefault
		}
		*/
	}
		
	
	stopPropagation(e);

	// prevent the browser trying to cause a drag on the images
	// which will stall other mouseovers which we need to send
	if (useragent.isIE)
		return true;
	else
		e.preventDefault();
}




/* todd's mouse move handler

   We take care of (de-)registering the events on all iframes. The user should call
   toddSetupMouseMoveHandler in his mousedown handler, and pass a 'mousemove' function,
   a 'mouseup' function and an opaque pointer. The opaque pointer is passed as the first
   parameter to the mousemove and mouseup function. Additionally, the mousemove function
   will receive the last 'x' and 'y' coordinates.

   When a dragaction is active global toddMMH contains info on the dragaction,
   when there's no active dragaction toddMMH will be null */

var toddMMH=null;
function toddMMH_MouseDummy(e) //eat new down events caught while handling the first move to prevent odd drag behaviours
{
  if(!toddMMH) return true; //no drag action active to handle at the moment?
  if(!e) e=this.parentWindow ? this.parentWindow.event : window.event;
  toddDontPropagateEvent(e);
  return false;
}

function toddMMH_MouseMove(e)
{
  if(!toddMMH)
	return true;

  if(!e)
	e=this.parentWindow ? this.parentWindow.event : window.event;

//  if (toddMouseOverCanSeeButtonDown && toddGetMouseButton(e)!=0)
//    return toddMMH_MouseUp(e);

  toddMMH.x = getMouseX(e); //ADDME: Merge getmousex/y into this function ?
  toddMMH.y = getMouseY(e);
  toddMMH.lastthis = this;

  if(!toddMMH.didtimer)
  {
    window.setTimeout(toddMMH_MouseMoveFinalize,1);
    toddMMH.didtimer=true;
  }
  
  return false; // prevent selection of elements under mouse in IE
}
function toddMMH_BoundsCheck() //Keep inside bounds
{
return;


  if(toddMMH.x<0)
    toddMMH.x = 0;
  else if(toddMMH.viewport && toddMMH.x >= toddMMH.viewport.width)
    toddMMH.x = toddMMH.viewport.width - 1;

  if(toddMMH.y<0)
    toddMMH.y = 0;
  else if(toddMMH.viewport && toddMMH.y >= toddMMH.viewport.height)
    toddMMH.y = toddMMH.viewport.height - 1;
}
function toddMMH_MouseMoveFinalize()
{
  if(!toddMMH) return true; //no drag action active to handle at the moment?

  toddMMH_BoundsCheck();
  toddMMH.didtimer=false;
  toddMMH.onmove(toddMMH.opaque, toddMMH.x, toddMMH.y);
}
function toddMMH_MouseUp(e)
{
  if(!toddMMH) return true; //no drag action active to handle at the moment?
  if(!e) e=this.parentWindow ? this.parentWindow.event : window.event;
  if (e)
  {
    toddMMH.x = getMouseX(e); //ADDME: Merge getmousex/y into this function ?
    toddMMH.y = getMouseY(e);
  }
  toddMMH_BoundsCheck();
/*
  // clean up iframe overlappers
  for (var i=0;i<toddMMH.iframes.length;++i)
    toddMMH.iframes[i].overlapper.parentNode.removeChild(toddMMH.iframes[i].overlapper);
*/
  toddMMH.onup(toddMMH.opaque, toddMMH.x, toddMMH.y);
  toddMMH=null;
  return false;
}

function toddSetupMouseMoveOnDoc(doc)
{
  try
  {
    // we only add these once, and then ignore them. repeated adding/moving slows down the use of the global handler
    if(doc.toddMouseMoveHandlerConfigured)
      return;

    if(doc.addEventListener)
    {
      doc.addEventListener("mousemove", toddMMH_MouseMove,  false);
      doc.addEventListener("mouseup",   toddMMH_MouseUp,    false);
      doc.addEventListener("mousedown", toddMMH_MouseDummy, false);
      doc.addEventListener("mouseover", toddMMH_MouseDummy, false);
      doc.addEventListener("mouseout",  toddMMH_MouseDummy, false);
    }
    else if(doc.attachEvent)
    {
      doc.attachEvent('onmousemove', toddMMH_MouseMove);
      doc.attachEvent('onmouseup',   toddMMH_MouseUp);
      doc.attachEvent('onmousedown', toddMMH_MouseDummy);
      doc.attachEvent('onmouseover', toddMMH_MouseDummy);
      doc.attachEvent('onmouseout',  toddMMH_MouseDummy);
    }
    doc.toddMouseMoveHandlerConfigured=true;
  }
  catch(e) //iframes with an external src..
  {
    return;
  }
}

function toddSetupMouseMoveHandler(opaque, onmove, onup)
{
  if(toddMMH)
    toddMMH_MouseUp();

  toddMMH = { onmove: onmove
            , onup: onup
            , opaque: opaque
          //, iframes: new Array()
		    , startx: 0 // TODO
			, starty: 0 // TODO
            , x: 0
            , y: 0
          //, viewport: toddCurrentViewPort
            , max_y: 0
            , lastthis: null
            , didtimer: false
            };

  toddSetupMouseMoveOnDoc(document);
/*
  var iframes = document.getElementsByTagName('iframe');
  for(var i=0;i<iframes.length;++i)
  {
    var overlapper = toddCreateElement('div');
    overlapper.className = 'toddModalityLayer';
//    overlapper.style.top = toddGetObjectPosY(iframes[i]) + 'px';
//    overlapper.style.left = toddGetObjectPosX(iframes[i]) + 'px';
    overlapper.style.width = iframes[i].clientWidth + 'px';
    overlapper.style.height = iframes[i].clientHeight + 'px';
    overlapper.style.zIndex = 999999;

    // Fix for IE, which somehow seems to add baseline pixels
    // as soon as we insert our overlapper before the iframe into the <td>
//    iframes[i].parentNode.style.fontSize = '0px';
    iframes[i].parentNode.insertBefore(overlapper, iframes[i]);

    toddMMH.iframes.push ( { el: iframes[i], overlapper: overlapper } );
    //toddSetupMouseMoveOnDoc(doc);
  }
*/
}
