/*	Recaptcha Javascript Library

	Requires: JQuery

	Ensure that any form onsubmit function returns true to proceed with form submission, or false to cancel.
	The function will get executed after the captcha validation.
	
	configure window.CAPTCHA.targetDiv and any other desired parameters.
	add onsubmit="return window.CAPTCHA.validate(this, validationFunction);" to form.
	
	
*/

// JSLint Global Var Declarations
/*global $ alert, document, escape, setTimeout, window */

window.CAPTCHA = {
	// Make it a singleton. Only one CAPTCHA object is available per window.
	targetDiv: "", // DIV id where Recaptcha will display
		
	verificationUrl: "/secure/securjson.php",

	captchaUrl: "/secure/securimage_show.php",
	
	audioUrl: "/secure/securimage_play.php",
	
	refreshImg: "/secure/images/refresh.gif",
	
	audioImg: "/secure/images/audio_icon.gif",
		
	templateProperties: {
		'CAPTCHA_CONTAINER': {style: {width: '200px', marginLeft: 'auto', marginRight: 'auto', position: 'relative'}},
		'CAPTCHA_IMAGE_CONTAINER': {style: {width: '175px', 'float': 'left'}},
		'CAPTCHA_IMAGE': {alt: "Security Image", title: "Security Image"},
		'CAPTCHA_RELOAD_CONTAINER': {style: {'float': 'left', position: 'relative', left: '176px', top: '-45px', clear: 'right'}},
		'CAPTCHA_RELOAD_LINK': {},
		'CAPTCHA_RELOAD_IMAGE': {style: {border: "1px solid #cccccc", position: 'absolute'}, alt:"Click to reload security image", title: "Click to reload security image"},
		'CAPTCHA_AUDIO_CONTAINER': {style: {'float': 'left', position: 'relative', left: '176px', top: '-22px', clear: 'right'}},
		'CAPTCHA_AUDIO_LINK': {},
		'CAPTCHA_AUDIO_IMAGE': {style: {border: "1px solid #cccccc", position: 'absolute'}, alt: "Click to hear the security code.", title: "Click to hear the security code." },
		'CAPTCHA_STATUS_CONTAINER': {style: {'float': 'left', clear: 'both'}},
		'CAPTCHA_STATUS': {style: {'margin': '3px'}},
		'CAPTCHA_CODE_CONTAINER': {style: {'float': 'left', 'marginTop': '5px'}},
		'CAPTCHA_CODE_LABEL': {innerHTML: "Security Code: "},
		'CAPTCHA_CODE': {style: {'width': '90px'}, title: "Enter security code"}	
		},
		
	// set allowed properties in templateProperties
	allowedProperties: {style: "", alt: "", title: "", href: "", src: "", onmouseover: "", onmouseout: "", onmousedown: "", onmouseup:"", name: "",  onchange: "", target: "", onkeydown: "", onkeyup: "", onkeypress: "", onload: "", onblur: "", onfocus: "", onclick: "", ondblclick: "", maxlength: "", innerHTML: "", className: "", disabled: "", autocomplete: "", checked: ""},
	

	template: "<div id=\"CAPTCHA_CONTAINER\"><div id=\"CAPTCHA_IMAGE_CONTAINER\"><img id=\"CAPTCHA_IMAGE\" src=\"[:captchaUrl:]\" /></div><div id=\"CAPTCHA_RELOAD_CONTAINER\"><a href=\"#\" onclick=\"window.CAPTCHA.reload(); return false\" id=\"CAPTCHA_RELOAD_LINK\"><img src=\"[:refreshImg:]\" id=\"CAPTCHA_RELOAD_IMAGE\"></a></div><div id=\"CAPTCHA_AUDIO_CONTAINER\" ><a href=\"[:audioUrl:]\" target='_blank' id=\"CAPTCHA_AUDIO_LINK\"><img src=\"[:audioImg:]\" id=\"CAPTCHA_AUDIO_IMAGE\"></a></div><div id=\"CAPTCHA_STATUS_CONTAINER\"><span id=\"CAPTCHA_STATUS\"></span></div><div id=\"CAPTCHA_CODE_CONTAINER\"><label for=\"CAPTCHA_CODE\" id=\"CAPTCHA_CODE_LABEL\"></label><input type=\"text\" name=\"captcha_code\" id=\"CAPTCHA_CODE\" /></div></div>",
	
	templateVars: ['verificationUrl', 'captchaUrl', 'audioUrl', 'refreshImg', 'audioImg', 'noscriptWarning'], // variable substitution allowed in template
	
	formObj: "", // reference to form object
	
	formAction: "", // action of form. Recaptcha will remove existing action to prevent bypassing captcha. This action value will be inserted upon successful challenge response.
		
	statusDiv: "CAPTCHA_STATUS", //  status div ID from template
	
	timeOut: 5, // Number of seconds to wait between, Recaptcha.ajaxverify(callbackFunction) and response in validateResponse(); If timeOut seconds pass, then trigger recaptcha-not-reachable error.
	
	timerObj: {},
	
	statusCodes: {
		// define error codes and descriptions
		'pending': "Verifying security code.",
		
		'unknown': "Unknown error.",
				
		'pass': "Success.",
		
		'fail': "Failed.",
		
		'error': "System error:",
		
		'timedout': "Server timed out.",

		'nocode': "Please enter the security code."
	
	},
	
	showAlerts: true, // if true, failure status messages will also be popped to the user in an alert. Exception is the pending and pass statuses.
	
	validate: function(formObj, formValidation){
	
		//formObj = document.getElementById(window.CAPTCHA.formId);
		window.CAPTCHA.formObj = formObj;
		if (formObj === undefined) { 
			alert("CAPTCHA Error: Invalid form object. Verfiy onsubmit is in following format:\n\n onsubmit=\"return window.CAPTCHA.validate(this [,optional-validation-function]);\"");
			return false; 
		}
		
		// remove form action to prevent captcha bypass
		if (formObj.action !== "")
		{
			window.CAPTCHA.formAction = formObj.action;
			formObj.action = "";
		}
		
		// store reference to callback function
		if (typeof formValidation == 'function')
		{
			// continue if formValidation function returns true
			if (!formValidation())
			{
				return false;
			}			
		}		
	
		
		window.CAPTCHA.displayStatus({status: 'pending'});
		var codeInpObj = document.getElementById('CAPTCHA_CODE');
		if (codeInpObj.value.length === 0)
		{
			window.CAPTCHA.displayStatus({status: 'nocode'});			
			return false;
		}
		
		// turn on timeOut timer.
		window.CAPTCHA.timerObj = setTimeout(window.CAPTCHA.displayStatus, window.CAPTCHA.timeOut * 1000, {status: 'timedout'});
		//~ var capcode = ;
		var url = window.CAPTCHA.verificationUrl + "?code=" + escape(codeInpObj.value) + "&callback=?";
		$.getJSON(url, window.CAPTCHA.verifyResponse);
		
		return false; // return false to prevent form submission;			
	},
	
	
	verifyResponse: function (data, textStatus){
	// checks response of captcha validation
	
		window.clearTimeout(window.CAPTCHA.timerObj);
		if (data.result == "pass")
		{
			window.CAPTCHA.displayStatus({status: 'pass'});
			window.CAPTCHA.formObj.action = window.CAPTCHA.formAction; // reassign form action			
			window.CAPTCHA.formObj.submit();
		}
		else if (data.result == "fail")
		{
			
			window.CAPTCHA.reload({clearstatus: false});
			window.CAPTCHA.displayStatus({status: 'fail'});
			return false;
		}
		else if (data.result == "error")
		{			
			window.CAPTCHA.reload({clearstatus: false});
			window.CAPTCHA.displayStatus({status: 'error', message: data.message});
			return false;
		}
		
		return true;
	},
	
		
	displayStatus: function(param){
		// presents status message to targetDiv.
		var message;
		var alertOk = false;
		
		if (typeof(param) == 'object')
		{
			if (param.status) {				
				message = window.CAPTCHA.statusCodes[param.status];				
				if (param.message)
				{
					message += " " + param.message;
				}
				if ((param.status != "pending") && (param.status != "pass"))
				{
					alertOk = true; // ok to allow alerts for status messages except for pending
				}
			}
			else if (param.message) {
				message = param.message;
			}
		}
		else if (typeof(param) == 'string')
		{
			message = param;
		}
			
		document.getElementById(window.CAPTCHA.statusDiv).innerHTML = message;
		
		if ((window.CAPTCHA.showAlerts) && (alertOk)) { 
			alert(message); 
		}
		return true;
	},

	
	createCaptcha: function()
	{
		var targetDivObj;
		
		// creates captcha image 
		if ((window.CAPTCHA.targetDiv === undefined) || (window.CAPTCHA.targetDiv.length === 0))
		{
			alert("CAPTCHA Configuration Error: No target DIV id specified.");
			return false;
		}		
		targetDivObj = document.getElementById(window.CAPTCHA.targetDiv);
		if (targetDivObj === undefined)
		{
			alert("CAPTCHA Configuration Error: No target DIV with id '" + window.CAPTCHA.targetDiv + "' found in document.");
			return false;
		}
		$(targetDivObj).hide();
		// perform variable substitution on template
		for (var i = 0; i < window.CAPTCHA.templateVars.length; i++)
		{
			// perform regex variable replacement on template 
			var chkVarRe = new RegExp("\\[:" + window.CAPTCHA.templateVars[i] + ":\\]", "i");
			if (chkVarRe.test(window.CAPTCHA.template))
			{
				window.CAPTCHA.template = window.CAPTCHA.template.replace(chkVarRe, window.CAPTCHA[window.CAPTCHA.templateVars[i]]);
			}
		}
			
		targetDivObj.innerHTML = window.CAPTCHA.template;
		
		// apply properties and styles
		for (var p in window.CAPTCHA.templateProperties)
		{
			if (/^CAPTCHA_/.test(p))
			{
				var thisObj = document.getElementById(p);
				//~ if (typeof thisObj == "object")
				if (thisObj)
				{
					for (var a in window.CAPTCHA.templateProperties[p])
					{
						if (window.CAPTCHA.allowedProperties[a] !== undefined)
						{
							if (typeof window.CAPTCHA.templateProperties[p][a] == "object")
							{
								for (var s in window.CAPTCHA.templateProperties[p][a])
								{
									if (typeof s == 'string')
									{
										thisObj[a][s] = window.CAPTCHA.templateProperties[p][a][s];
									}
								}
							}
							else
							{
								thisObj[a] = window.CAPTCHA.templateProperties[p][a];
							}
						}
					}
				}
			}
		}
		
		$(targetDivObj).show();
		
		return true;

	},
	
	reload: function (input) {
		var parameters = {};
		parameters.clearstatus = true;
		
		if ((input) && (typeof(input) == 'object'))
		{
			for (var i in input)
			{
				if (parameters[i])
				{
					parameters[i] = input[i];
				}
			}
		}
		
		document.getElementById('CAPTCHA_IMAGE').src = window.CAPTCHA.captchaUrl + '?' + Math.random();
		document.getElementById('CAPTCHA_CODE').value = "";
		document.getElementById('CAPTCHA_CODE').focus();
		if (parameters.clearstatus === true)
		{		
			window.CAPTCHA.displayStatus("");
		}
		return true;
	},
	
	autoLoad: function()
	{
		// set attachForm to be called after window contents load.
		if (typeof window.onload == 'function')
		{
			var prevOnload = window.onload;
			window.onload = function(){ window.CAPTCHA.createCaptcha(); prevOnload();};
		}
		else
		{
			window.onload = window.CAPTCHA.createCaptcha;
		}
		return true;
	}

};

window.CAPTCHA.autoLoad();
