/** @file nri_ureg.js
  * @brief Controller for NRi User Registration module
  * @author "Stephen P. Paschall" <spaschall@news-record.com>
  * @created 7-October-2008
*/

if (typeof(nri) == "undefined")
{
	nri = {};
}

// constructor
nri.ureg = function()
{
	// map for help dialogs
	this.help = new Object();
}

nri.ureg.NAME_MINLENGTH = 4;
nri.ureg.NAME_MAXLENGTH = 60;
nri.ureg.USEREXISTS_REGEX = /sys|admin|manag|master|account|service|help|support/i;
nri.ureg.EMAIL_REGEX = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/i;
nri.ureg.NAME_REGEX = /[^A-Z0-9_\-@\. ]/i;
nri.ureg.CACHETTL = 1000 * 30;
nri.ureg.POLLFREQ = 1000 * 45; // this can be overridden by the authentication response object from the server! (see nri.ureg._check_auth())
nri.ureg.POLLRETRY = 1000 * 30; // if auth status check failed, how long before we automatically retry?

nri.ureg.call_form_https = function( /*[e,]url*/ )
{
	var e = void(0);
	var url = false;
	var tobj = nri.ureg.get();
	
	if (arguments.length > 1) // if this was triggered by an event, save the Event object so we can pass it along
	{
		e = arguments[0];
		url = arguments[1];
	}
	else
	{
		url = arguments[0];
	}
	
	if ( nri.ureg.is_authenticated() )
	{
		tobj.set_content("<p>You're already signed in.</p>");
		tobj.ready();
		return false;
	}
	
	tobj.wait(e);

	tobj.set_content('','https://' + window.document.location.hostname + url);
	
	return true;	
}

nri.ureg.login = function()
{
	var e = void(0);
	
	if (arguments.length && typeof(arguments[0])=="object")
	{
		e = arguments[0];
	}
	
	
	var tobj = nri.ureg.get();
	tobj.set_content("<p>Checking status</p>");
	tobj.wait(e);
	tobj.show(e);
	
	nri.ureg._check_auth( false );
	
	if (nri.ureg.is_authenticated())
	{
		tobj.set_content("<p>You're already authenticated; please wait.</p>");
		tobj.ready();
		tobj.hide();
		return true;
	}
	else
	{
		return nri.ureg.call_form_https(e,'/nri/ureg/login');
	}
}

nri.ureg.register = function()
{
	var e = void(0);
	
	if (arguments.length && typeof(arguments[0])=="object")
	{
		e = arguments[0];
	}

	var tobj = nri.ureg.get();
	tobj.set_content("<p>Checking status</p>");
	tobj.wait(e);
	tobj.show(e);
	
	nri.ureg._check_auth( false );
	
	if (nri.ureg.is_authenticated())
	{
		tobj.set_content("<p>You're already authenticated; please wait.</p>");
		tobj.ready();
		tobj.hide();
		return true;
	}
	else
	{
		return nri.ureg.call_form_https(e,'/nri/ureg/register');
	}	
}

nri.ureg.logout = function()
{
	var e = void(0);
	var tobj = nri.ureg.get();
	
	if (arguments.length && (typeof(arguments[0]) == "object") ) // if this was triggered by an event, save the Event object so we can pass it along
	{
		e = arguments[0];
	}
	
	var efxn = function(x,er,ex)
	{
		nri.ureg.error("Unable to verify logout: "+(er?er:'')+" : "+(ex?ex:''));
	}

	var sfxn = function(data,stat)
	{
		var tobj = nri.ureg.get();
		
		tobj.touch();
		tobj.authenticated = data.authenticated?true:false;
		tobj.authdata = data;
			
		tobj.set_content( data.response );
		tobj.ready();
		$("*").trigger("nri_ureg_logout");
		tobj.hide();
	}
	
	tobj.wait(e);
	
	$.ajax({
		url:"/nri/ureg/logout/json",
		cache: false,
		global: false,
		dataType:"jsonp",
		jsonp:"callback",
		error: efxn,
		success: sfxn,
		type:"GET"
	});
	
}

nri.ureg.userexists = function(e)
{
	var fld = e.target;
	var fldname = $(fld).attr('name');
	var val = fld.value;
	
	$(fld).removeClass("throbbing");
	
	if (! fldname.match(/name|mail/))
	{
		nri.ureg.field_warn_clear(fld);
		return false;
	}
	
	if (fldname == 'mail' && (! nri.ureg.validate_email(val)))
	{
		nri.ureg.field_warn_clear(fld);
		return false;
	}
	
	switch (e.keyCode) {
	    case 16: // shift
	    case 17: // ctrl
	    case 18: // alt
	    case 20: // caps lock
	    case 33: // page up
	    case 34: // page down
	    case 35: // end
	    case 36: // home
	    case 37: // left arrow
	    case 38: // up arrow
	    case 39: // right arrow
	    case 40: // down arrow
	      return true;
	  }
	
	if (typeof(nri.ureg.userexists_cache[fldname]) == "undefined")
	{
		nri.ureg.userexists_cache[fldname] = {};
	}
	
	if (! fld.value.length)
	{
		nri.ureg.field_warn_clear(fld);
	}
	if (fldname == "name" && val.match(nri.ureg.USEREXISTS_REGEX))
	{
		nri.ureg.userexists_warn(fld);
	}		
	else if (typeof(nri.ureg.userexists_cache[fldname][val]) != "undefined")
	{
		if (nri.ureg.userexists_cache[fldname][val])
		{
			nri.ureg.userexists_warn(fld);
		}
		else
		{
			nri.ureg.field_warn_clear(fld);
			
			if (fldname == 'name' && (nri.ureg.validate_email(val)))
			{
				nri.ureg.field_warn(fld,'For your privacy and security, using your email address as your username is *strongly* discouraged.  You may use your email address to sign in regardless.');
			}
		}
	}
	else
	{
		
		if (nri.ureg.userexists_timer)
		{
			clearTimeout(nri.ureg.userexists_timer);
			nri.ureg.userexists_timer = false;
			$(fld).removeClass("throbbing");
		}
		
		nri.ureg.userexists_timer = setTimeout( function(){
	
			if (fldname == 'name')
			{
				var terrs = nri.ureg.validate_name(val);
				var msg = "";
				
				if (terrs)
				{
					if (fldname == 'name' && (nri.ureg.validate_email(val)))
					{
						terrs[terrs.length] = 'For your privacy and security, using your email address as your username is *strongly* discouraged. You may use your email address to sign in regardless.';
					}
					
					var msg = "<ul>";
					
					for (var i = 0; i < terrs.length; i++)
					{
						msg += "<li>"+terrs[i]+"</li>";
					}
					
					msg += "</ul>";
					
					nri.ureg.userexists_warn(fld,msg);
					return false;
				}
			}
			
			$.ajax({
				url:'http://'+window.location.hostname+'/nri/ureg/userexists/'+fldname, // ensure http
				data:{
					nri_ureg_acval:val
				},
				dataType:'jsonp',
				jsonp:'callback',
				error:function(){nri.ureg.field_warn_clear(fld,"There was a communications error with the server.");},
				success:function(data,stat)
				{
					if (typeof(data.type) == "undefined" || (!data.type.length)) return;
					var fld = $("input[@name="+data.type+"]").removeClass("throbbing")[0];
					
					if (data.exists)
					{
						nri.ureg.userexists_cache[data.type][data.value] = true;
			
						if (fld.value == data.value)
						{
							nri.ureg.userexists_warn(fld);
						}
					}
					else
					{					
						nri.ureg.userexists_cache[data.type][data.value] = false;
						if (fld.value == data.value)
						{
							nri.ureg.field_warn_clear(fld);
							
							if (data.type == 'name' && (nri.ureg.validate_email(data.value)))
							{
								nri.ureg.field_warn(fld,'For your privacy and security, using your email address as your username is *strongly* discouraged. You may use your email address to sign in regardless.');
							}
						}
					}
				},
				type:'GET',
				timeout:2000
			});
			$(fld).addClass("throbbing");
		},200);
	}
}

nri.ureg.userexists_warn = function(fld)
{
	var msg = "In use or unavailable.";
	
	if (arguments.length > 1)
	{
		msg = arguments[1];
	}

	nri.ureg.field_warn(fld,msg);
}


nri.ureg.validate_name = function( name )
{
	var terrs = new Array();
	
	if (!name.length) terrs[terrs.length] = 'You must enter a username.';
	if (name.substr(0,1) == ' ') terrs[terrs.length] = 'The username cannot begin with a space.';
	if (name.substr(name.length-1) == ' ') terrs[terrs.length] = 'The username cannot end with a space.';
	if (name.indexOf('  ') != -1) terrs[terrs.length] = 'The username cannot contain multiple spaces in a row.';
	if (name.length < nri.ureg.NAME_MINLENGTH || name.length > nri.ureg.NAME_MAXLENGTH) terrs[terrs.length] = 'The username must be between '+nri.ureg.NAME_MINLENGTH+' and '+nri.ureg.NAME_MAXLENGTH+' characters in length.';
	
	if (name.match(nri.ureg.NAME_REGEX))
	{
		terrs[terrs.length]= 'The username may only contain the letters A-Z, numbers, dashes, underscores, periods, and the space character.';
	}
	
	return terrs.length?terrs:false;	
}

nri.ureg.validate_email = function( email )
{
	return email.match( nri.ureg.EMAIL_REGEX );
}

nri.ureg.userexists_cache = {};
nri.ureg.userexists_timer = false;

nri.ureg.prototype.set_content = function( content/*[,iframe_src]*/ )
{
	if (! this.modal ) nri.ureg._modal_init();
	
	if (arguments.length > 1)
	{
		this.modal.empty();
		this.modal.addClass('nri_ureg_wIframe');
		this.modal.append('<iframe id="nri_ureg_modal_iframe" name="nri_ureg_modal_iframe" src="'+arguments[1]+'" frameborder="0" marginwidth="0" marginheight="0" scrolling="auto" width="100%" height="100%" allowtransparency="true" style="visibility:hidden;"><p><strong>This interface requires frame support.</strong> Your browser does not appear to support frames, or frame support is disabled in its configuration. Please visit <a href="/user/login">our user sign-in page</a> to sign in instead.</p></iframe>');
		this.modal.append(content);
		
		this.wait();
		
		this.modal.iframe = this.modal.find("iframe");
		
		var ifr = this.modal.iframe.get(0);
		try
		{
			this.modal.iframe.load(
				function()
				{
					var tobj = nri.ureg.get();
					tobj.ready();
				}
			);
			
			var win = typeof(ifr.contentWindow)!="undefined"?ifr.contentWindow:ifr;
			
			// bind event handlers to common controls
			$(win).load(
				function(e)
				{	
					try
					{		
					var win = e.target;
					var doc = $(typeof(win.document)!="undefined"?win.document:win.contentDocument);			
					$(doc).find("a[@href*=/user/login]").click(function(){nri.ureg.login();return false;});
					$(doc).find("a[@href*=/user/register]").click(function(){nri.ureg.register();return false;});
					$(doc).find("a[@href*=/openid/authenticate]").click(function(){nri.ureg.openid();return false;});
					}
					catch(e)
					{
						void(0);
					}
				}
			);
		}
		catch(e)
		{
			this.ready();
		}
		
		try
		{
			this.modal.iframe.unload(
				function()
				{
					var tobj = nri.ureg.get();
					tobj.wait();
				}
			);
		}
		catch(e)
		{
			void(0);
		}

	}
	else
	{
		this.modal.removeClass('nri_ureg_wIframe');
		this.modal.iframe = false;
		this.modal.html('<div id="nri_ureg_content">'+content+'</div>');
	}
	
	this.modal.append(nri.ureg.window_ctrls);
		
	// bind event handlers to common controls
	this.modal.find("a[@href*=/user/login]").click(function(){nri.ureg.login();return false;});
	this.modal.find("a[@href*=/user/register]").click(function(){nri.ureg.register();return false;});
	this.modal.find("a[@href*=/openid/authenticate]").click(function(){nri.ureg.openid();return false;});
	
	// if the user changes a form element, disable the "click on overlay to close" handler
	this.modal.find("input").change( function()
		{
			var tobj = nri.ureg.get();
			tobj.overlay.unbind("click");			
		}
	);
	
	if (this.modal.is(":visible"))
	{
		this.position();
	}
}

nri.ureg.error = function( msg )
{
	var tobj = nri.ureg.get();
	
	tobj.modal.append("<div id=\"nri_ureg_error\"><p>"+msg+"</p><a class=\"nri_ureg_ctrl_ok\" href=\"javascript:void(0);\" onclick=\"$(this).parent().remove();return false;\">close</a></div>");
}

nri.ureg.field_warn = function(fld)
{
	var msg = "Invalid value";
	
	if (arguments.length > 1)
	{
		msg = arguments[1];
	}
	
	nri.ureg.field_warn_clear(fld);
	$(fld).after("<div id=\"nri_ureg_warning-"+fld.id+"\" class=\"warning\">"+msg+"</div>");
}

nri.ureg.field_warn_clear = function(fld)
{
	$("#nri_ureg_warning-"+fld.id).remove();
}

nri.ureg.is_authenticated = function()
{
	var tobj = nri.ureg.get();
	
	var now = new Date();
	
	if (tobj.timestamp < (now.getTime() - nri.ureg.CACHETTL))
	{
		if (tobj.modal && tobj.modal.is(":visible"))
		{
			tobj.wait();
		}
		
		nri.ureg._check_auth( false );
	}
	
	tobj.ready();
		
	return tobj.authenticated;
}

/** Poll server for authentication status.
  *  @param bool async
  *  	Should check occur in the background (asynchronously) or foreground (synchronously)?
  *		If another routine is depending on a trustworthy result, go synchronous.
*/	
nri.ureg._check_auth = function( /* [async=TRUE] */ )
{
	var async = true;
	
	if (nri.ureg.checkauth_to) clearTimeout(nri.ureg.checkauth_to);
	
	if (arguments.length)
	{
		async = arguments[0];
	}
	
	var efxn = function(x,er,ex)
	{
		// if auth check failed, retry in nri.ureg.POLLRETRY ms
		clearTimeout(nri.ureg.checkauth_to);		
		nri.ureg.checkauth_to = setTimeout(nri.ureg._check_auth,nri.ureg.POLLRETRY);
	}
	
	var sfxn = function(data,stat)
	{
		var tobj = nri.ureg.get();
		
		if (data.authenticated && (! tobj.authenticated))
		{
			tobj.authenticated = true;
			tobj.authdata = data;
			
			if (tobj.timestamp) // if login state has changed since last check, fire appropriate events
			{				
				tobj.touch();
				$("*").trigger("nri_ureg_login");
			}
			
			tobj.touch();
		}
		else if (tobj.authenticated && (! data.authenticated))
		{
			tobj.touch();
			tobj.authenticated = false;
			tobj.authdata = false;
			$("*").trigger("nri_ureg_logout");
		}
		else
		{
			tobj.touch();
		}
		
		if (typeof(data.pollfreq) != "undefined")
		{
			nri.ureg.POLLFREQ = data.pollfreq;
		}
		
		$("*").trigger("nri_ureg_authchecked");
	}
	
	$.ajax({
		url:'/nri/ureg/authcheck',
		async:async,
		cache:false,
		dataType:'jsonp',
		jsonp:'callback',
		timeout:15000,
		error:efxn,
		success:sfxn
	});
	
	//nri.ureg.checkauth_to = setTimeout(nri.ureg._check_auth,nri.ureg.POLLFREQ);
}

// fetch singleton
nri.ureg.get = function()
{
	if (typeof(nri.ureg.singleton) == "object")
	{
		return nri.ureg.singleton;
	}
	
	var tobj = new nri.ureg();
	nri.ureg.singleton = tobj;
	
	$(window).load( nri.ureg._modal_init );
	
	// on login, logout, and window focus, check authentication status and replace
	// template placeholders / hide blocks as necessary
	$("body").bind("nri_ureg_login",nri.ureg.repl_tpl_vars);
	$("body").bind("nri_ureg_logout",nri.ureg.repl_tpl_vars);
	
	// poll the server every POLLFREQ ms to see if authentication status has changed
	//nri.ureg.checkauth_to = setTimeout(nri.ureg._check_auth,nri.ureg.POLLFREQ);

	return nri.ureg.singleton;
}

// init modal dialog elements
nri.ureg._modal_init = function()
{
	var tobj = nri.ureg.get();
	
	if (! tobj.modal )
	{
		$("body").append('<div id="nri_ureg_overlay"></div>');
		$("body").append('<div id="nri_ureg_modal"></div>');
		$("body").append('<div id="nri_ureg_help"></div>');
		
		tobj.modal = $("#nri_ureg_modal");
		tobj.overlay = $("#nri_ureg_overlay");
		tobj.help.modal = $("#nri_ureg_help");
		
		tobj.modal.hide();
		tobj.overlay.hide();
		tobj.help.modal.hide();
		
		tobj.set_content("");
	}
}

nri.ureg.prototype.touch = function()
{
	var now = new Date();
	this.timestamp = now.getTime();
}

nri.ureg.prototype.wait = function()
{
	if (this.modal) // do only if dialog initialized
	{
		nri.ureg._modal_init();
	
		// @todo Handle "waiting for data" gracefully
		if (! this.modal.find("#nri_ureg_wait").length)
		{
			this.modal.append("<div id=\"nri_ureg_wait\"><span class=\"label\">Please wait...</span></div>");
		}
		if(this.modal.iframe) this.modal.iframe.css('visibility','hidden');
		this.show(arguments.length?arguments[0]:void(0));
	}
	
	return true;
}

nri.ureg.prototype.ready = function()
{
	if (this.modal) // do only if dialog initialized
	{
		// @todo Handle "wait complete" gracefully
		this.modal.find("#nri_ureg_wait").remove();
		if(this.modal.iframe) this.modal.iframe.css('visibility','visible');
	
		//this.show(arguments.length?arguments[0]:void(0));
	}
	
	return true; 
}

nri.ureg.prototype.show = function()
{
	if (! this.modal ) nri.ureg._modal_init();
	
	this.overlay.height( $("body").height() );
	this.overlay.width( $("body").width() );
	this.overlay.fadeIn('fast');
	this.modal.fadeIn('fast');
	
	this.overlay.bind("click",{callback:'hide'},nri.ureg.callback);
	
	if (arguments.length && typeof(arguments[0])=="object") //assume arg[0] is Event object
	{
		var e = arguments[0];
		var anchor = 'tl';
		
		if (typeof(e.data)!="undefined" && typeof(e.data.anchor)!="undefined")
		{
			anchor = e.data.anchor;
		}
		
		this.position(e.target,anchor);
	}
	else
	{
		this.position();
	}
	
	return true;
}

nri.ureg.prototype.hide = function()
{
	if (! this.modal ) nri.ureg._modal_init();
	
	// zero out the content of the dialog for security
	this.modal.fadeOut('normal',function(){var tobj=nri.ureg.get();tobj.set_content("");});
	this.overlay.fadeOut('slow');
	this.overlay.unbind("click");
	
	// force an authentication check
	nri.ureg._check_auth();
	return true;
}


// @todo IE7: Positioning not working properly
nri.ureg.prototype.position = function( /* [target[, anchor]] */ )
{
	var target = false;
	var anchor = false;
	
	if (! this.modal ) nri.ureg._modal_init();
	
	if ( arguments.length && (typeof(arguments[0]) == "object") )
	{
		// is argument[0] a DOM element? or an Event object?
		target = (typeof(arguments[0].target)=="object") ? arguments[0].target : arguments[0];
		anchor = (arguments.length>1)?arguments[1]:'tl';
		
		this.anchor = {target:target,point:anchor};
	}
	else if (this.anchor)
	{
		target = this.anchor.target;
		anchor = this.anchor.point;
	}
	
	var mwid = this.modal.get(0).offsetWidth;
	var mhi = this.modal.get(0).offsetHeight + 50;
	var scrwid = window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth;
	var scrhi = window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight;
	var oscrx = window.scrollX||document.documentElement.scrollLeft||document.body.scrollLeft;
	var oscry = window.scrollY||document.documentElement.scrollTop||document.body.scrollTop;
	var scrx = oscrx;
	var scry = oscry;
	var currpos = this.modal.offset();
	
	//alert(this.modal.attr('id')+" "+mwid+" "+mhi+" "+target.tagName);
	
	var t = currpos.top;
	var l = currpos.left;
	
	if (target)
	{
		var offset = $(target).offset();
		var twid = target.offsetWidth;
		var thi = target.offsetHeight;
		
		//alert(twid + " " + thi + " " + mwid + " " + mhi + " " + scrwid + " " + scrhi + " " +scrx+ " " + scry);
		
		/**
		 * @todo Calculate new top and left position according to 'anchor' point
		 */
		 
		// default top left
		l = offset.left;
		t = offset.top;
		
		if ( anchor.indexOf('r') > -1 )
		{
			l = offset.left - mwid + twid;
		}
		
		if ( anchor.indexOf('b') > -1 )
		{
			t = offset.top + thi;
		}
		
		// position ureg window appropriately relative to caller
		this.modal.css({left:l+"px",top:t+"px"});
	}
	
	// resize iframe to accomodate document
	/*try
	{
		var ifr = this.modal.iframe.get(0);
		var doc = typeof(ifr.contentDocument)!="undefined"?ifr.contentDocument:ifr.contentWindow.document;
		var dw = doc.width;
		var dh = doc.height;
		
		if ( dw && dh && (this.modal.iframe.width() != dw || this.modal.iframe.height() != dh))
		{
			var oncmpl = function(){var tobj = nri.ureg.get(); tobj.position();}
			this.modal.iframe.animate({width:dw+"px",height:dh+"px"},{easing:'linear',duration:'fast',complete:oncmpl});
			return void(0);
		}
	}
	catch(e)
	{
		void(0);
	}*/
		
	// attempt to adjust scroll to accomodate module
	if ( (t + mhi) > (scry + scrhi) )
	{
		scry = scry + t + mhi - scry - scrhi;
	}
	if ( t < scry )
	{
		scry = t;
	} 
	if ( (l + mwid) > (scrx + scrwid) )
	{
		scrx = scrx + l + mwid - scrx - scrwid;
	}
	if ( l < scrx )
	{
		scrx = l;
	}
	
	
	$(window).trigger("nri_ureg_position");
	$("*").trigger("nri_ureg_position");
	
	nri.ureg.scroll_to(oscrx,oscry,scrx,scry,20,5);
}

nri.ureg.scroll_to = function(fromX,fromY,toX,toY,increment,delay)
{

	// @todo Add easing
	var dirx = (fromX<toX)?1:-1, diry = (fromY<toY)?1:-1;
	
	if ( Math.abs(fromX-toX) > increment)
	{
		fromX += increment * dirx;
	}
	else
	{
		fromX = toX;		
	}
	
	if (Math.abs(fromY-toY) > increment)
	{
		fromY += increment * diry;
	}
	else
	{
		fromY = toY;
	}
	
	window.scroll(fromX,fromY);
	
	if (fromX != toX || fromY != toY)
	{
		var to = setTimeout("nri.ureg.scroll_to("+fromX+","+fromY+","+toX+","+toY+","+increment+","+delay+")",delay);
		$(window).bind("mousedown",{timeout:to},
			function(e){
				clearTimeout(e.data.timeout);
			}
		).bind("keydown",{timeout:to},
			function(e){
				clearTimeout(e.data.timeout);
			}
		).bind("nri_ureg_position",{timeout:to},
			function(e){
				clearTimeout(e.data.timeout);
			}
		);
		
	}
}

// replace template variable placeholders and show/hide anonymous/authenitcated content
// blocks according to authentication status
nri.ureg.repl_tpl_vars = function()
{
	nri.ureg.is_authenticated(); // update authentication status
	var tobj = nri.ureg.get();
	var uid = 0; var user = '';	var email = '';
	
	if ( tobj.authdata && (typeof(tobj.authdata.uid) != "undefined"))
	{
		uid = tobj.authdata.uid;
		user = tobj.authdata.name;
		email = tobj.authdata.email;
	}
	
	var editlink = "/user/" + uid + "/edit"; var logout = "/logout";
	
	$(".nriuregTpl_val_name").text(user);
	$(".nriuregTpl_val_email").text(email);
	$(".nriuregTpl_val_uid").text(uid);
	$(".nriuregTpl_lnk_edit").attr("href",editlink);
	$(".nriuregTpl_lnk_logout").attr("href",logout);
	
	if ( tobj.authenticated )
	{
		$(".nriuregTpl_anonymous").hide();
		$(".nriuregTpl_authenticated").show();
	}
	else
	{
		$(".nriuregTpl_authenticated").hide();
		$(".nriuregTpl_anonymous").show();
	}
}

nri.ureg.callback = function(e)
{
	var opts = e.data;
	var tobj = nri.ureg.get();
	
	// if callback is a function reference, call it directly
	if ( $.isFunction( opts.callback ) )
	{
		opts.callback(e);
	}
	else // otherwise, assume it's a method of our singleton
	{
		tobj[opts.callback](e);
	}
	
	// don't follow the link!
	return false;
}

nri.ureg.ctrl_close = "<a href=\"javascript:void(0);\" onclick=\"nri.ureg.singleton.hide();\" class=\"nri_ureg_ctrl_close\">close</a>";
nri.ureg.ctrl_cancel = "<a href=\"javascript:void(0);\" onclick=\"nri.ureg.singleton.hide();\" class=\"nri_ureg_ctrl_cancel\">cancel</a>";

nri.ureg.window_ctrls = '<div id="nri_ureg_winctrls">'+nri.ureg.ctrl_close+'</div>';

nri.ureg.bind_ctrls = function( selector, anchor )
{
	$(selector).attr('href','javascript:void(0)').bind(
		"click",
		{
			callback:nri.ureg.login,
			anchor:anchor
		},
		nri.ureg.callback
	);
}

/**
 * privates
 */
nri.ureg.prototype.modal = false;
nri.ureg.prototype.overlay = false;
nri.ureg.prototype.login_form = false;
nri.ureg.prototype.reg_form = false;
nri.ureg.prototype.error = false;
nri.ureg.prototype.help = false;
nri.ureg.prototype.authenticated = false;
nri.ureg.prototype.authdata = false;
nri.ureg.prototype.timestamp = false;
nri.ureg.prototype.authenticating = false;
nri.ureg.prototype.anchor = false;

/**
 * statics
 */
nri.ureg.singleton = false;
nri.ureg.checkauth_to = false;