/**
 * Class: cpscaptcha
 *		Insert captcha popup before form submission
 *
 * Usage:
 *		Include cpscaptcha.css and cpscaptcha.js in this order
 *		Add the class formSubmit to the form submit element
 *
 * Example:
 *		Instantiate an object of the cpscaptcha class on domready:
 *		window.addEvent( 'domready', function() {
 *			new captcha( 'form_id', 'form_action' );
 *		});
 *
 *		Insert on the file that handle form submission:
 *		if( isset( $_POST['captcha_code'] ) ) {
 *			require_once( '_tools/cpscaptcha/securimage/securimage.php' );
 *			if( !$securimage->check( $_POST['captcha_code'] ) ) {
 *				// incorrect code
 *			} else {
 *				// correct code
 *			}
 *		}
 *
 * @name cpscaptcha.js
 * @version 1.0.2
 * @date 09-03-2011
 * @author Cápsula - Soluções Multimédia
 * @copyright 2011 Cápsula
*/
var cpscaptcha = new Class({
	Implements: [Options, Events],

	options: {
		path: '/_tools/cpscaptcha/',
		submitByAjax: false,
		submitByAjaxPath: '',
		submitElement: false,
		duration: 300,
		offsetX: 0,
		offsetY: 5,
		width: 255,
		height: 109,
		coordinates: false,
		bgClass: '',
		alerts: {
			confirmCode: 'confirme o código',
			newImage: 'nova imagem',
			send: 'enviar',
			confirmationError: 'código incorrecto!'
		},
		// function to fire before the ajax request starts
		onValidateRequest: $empty,
		// function to fire when the ajax request succeeds
		onValidateSuccess: $empty,
		// function to fire when the ajax request fails
		onValidateFailure: $empty
	},

	/**
	 * Class initialization
	 *
	 * @constructor
	 * @param string formId
	 * @param string action
	 * @param object options
	 */
	initialize: function( formid, action, options ) {
		if( !$( formid ) ) {
			alert( 'Form not found' );
			return false;
		}
		if( $( formid + '_cpscaptcha' ) ) return false;
		this.setOptions( options );

		// internalization
		if( typeof( cpscaptchaLanguage ) != 'undefined' ) {
			this.options.alerts = $merge( this.options.alerts, cpscaptchaLanguage );
		}

		this.form = $( formid );
		if( typeof( action ) != 'undefined' ) this.form.action = action;
		this.options.submitElement = $$( '#' + this.form.get( 'id' ) + ' .formSubmit' )[0];
		this.showOverlay();
		this.calcCoordinates();
		this.showCaptcha();
		this.createEvents();

		// cancel form submission
		return false;
	},

	/**
	 * Create overlay's element
	 */
	showOverlay: function() {
		new Element( 'div', {
			'class': 'cpsCaptchaOverlay',
			'id': this.form.get( 'id' )+'_overlay',
			events: {
				'click': function() {
					this.removeOverlay();
					this.removeCaptcha();
				}.bind( this )
			}
		}).inject( document.body );
	},

	/**
	 * Calculate coordinates for displaying captcha
	 */
	calcCoordinates: function() {
		// obtain top and left coordinates
		var coordsBody = $( document.body ).getCoordinates();
		var coordsSubmit = this.options.submitElement.getCoordinates( document.body );

		if( coordsSubmit.top >= this.options.height + this.options.offsetY ) { // bottom
			this.options.bgClass += 'b';
			var top = coordsSubmit.top - this.options.height - this.options.offsetY;
		} else { // top
			this.options.bgClass += 't';
			var top = coordsSubmit.bottom + this.options.offsetY;
		}
		if( coordsBody.right - coordsSubmit.left >= this.options.width + this.options.offsetX ) { // left
			this.options.bgClass += 'l';
			var left = coordsSubmit.left + this.options.offsetX;
		} else { // right
			this.options.bgClass += 'r';
			var left = coordsSubmit.right - this.options.width - this.options.offsetX;
		}

		this.options.coordinates = {
			'left': left,
			'top': top
		};
	},

	/**
	 * Create captcha's element
	 */
	showCaptcha: function() {
		var wrapper = new Element( 'div', {
			'class': 'cpsCaptcha ' + this.options.bgClass,
			'id': this.form.get( 'id' )+'_cpscaptcha',
			'styles': this.options.coordinates
		});

		var div = new Element( 'div' ).inject( wrapper );

		new Element( 'img', {
			'alt': 'captcha image',
			'class': 'captchaimage',
			'src': this.options.path+'securimage/securimage_show.php?' + Math.random()
		}).inject( div );

		var span = new Element( 'span' ).inject( div );

		new Element( 'label', {
			'for': this.form.get( 'id' )+'_code',
			'html': this.options.alerts.confirmCode
		}).inject( span );

		new Element( 'input', {
			'class': 'default',
			'id': this.form.get( 'id' )+'_code',
			'name': 'captcha_code',
			'maxlength': '4',
			'type': 'text'
		}).inject( span );

		new Element( 'a', {
			'class': 'refresh',
			'href': '#',
			'html': this.options.alerts.newImage,
			'id': this.form.get( 'id' )+'_refresh',
			'title': this.options.alerts.newImage
		}).inject( span );

		new Element( 'a', {
			'class': 'submit',
			'href': '#',
			'html': this.options.alerts.send,
			'id': this.form.get( 'id' )+'_send',
			'title': this.options.alerts.send
		}).inject( span );

		var span = new Element( 'span', {
			'class': 'pointer'
		}).inject( div );

		wrapper.inject( document.body );
	},

	/**
	 * Create captcha's events
	 */
	createEvents: function() {
		// label events
		$$( '#' + this.form.get( 'id' ) + '_cpscaptcha label' )[0].addEvent( 'click', function() {
			this.addClass( 'hide' );
			this.getNext( 'input' ).focus();
		});
		// input events
		$$( '#' + this.form.get( 'id' ) + '_cpscaptcha input' )[0].addEvent( 'blur', function() {
			if( this.get( 'value' ).length == 0 ) {
				this.getPrevious( 'label' ).removeClass( 'hide' );
				this.blur();
			}
		});
		$$( '#' + this.form.get( 'id' ) + '_cpscaptcha input' )[0].addEvent( 'keydown', function( e ) {
			if( e.key == 'enter' ) {
				this.fireEvent( 'blur' );
				$( this.form.get( 'id' ) + '_send' ).fireEvent( 'click' );
			}
		}.bindWithEvent( this ) );
		// refresh events
		$( this.form.get( 'id' ) + '_refresh' ).addEvent( 'click', function( e ) {
			new Event( e ).stop();
			this.refreshImage();
		}.bindWithEvent( this ) );
		// send events
		$( this.form.get( 'id' ) + '_send' ).addEvent( 'click', function( e ) {
			if( $( this.form.get( 'id' ) + '_code' ).value.length != 4 ) {
				$$( '#' + this.form.get( 'id' ) + '_cpscaptcha label' )[0].addClass( 'error' );
			} else {
				var value = $$( '#' + this.form.get( 'id' ) + '_cpscaptcha input' )[0].get( 'value' );
				var list = $$( '#' + this.form.get( 'id' ) + ' .captcha_code' );
				if( list.length > 0 ) list[0].set( 'value', value );
				else {
					new Element( 'input', {
						'class': 'captcha_code',
						'name': 'captcha_code',
						'value': value,
						'type': 'hidden'
					}).inject( $( this.form.get( 'id' ) ), 'bottom' );
				}
				if( this.options.submitByAjax ) this.submitByAjax();
				else $( this.form.get( 'id' ) ).submit();
			}
			return false;
		}.bindWithEvent( this ) );
	},

	/**
	 * Refresh captcha image
	 */
	refreshImage: function() {
		$$( '#' + this.form.get( 'id' ) + '_cpscaptcha .captchaimage' )[0].set(
			'src',
			this.options.path + 'securimage/securimage_show.php?' + Math.random()
		);
	},

	/**
	 * Validate captcha code by ajax
	 */
	submitByAjax: function() {
		new Request.JSON({
			url: this.options.submitByAjaxPath,
			method: 'post',
			onRequest: function() {
				this.fireEvent( 'validateRequest' );
			},
			onSuccess: function( json ) {
				if( !json ) {
					var wrapper = $( this.form.get( 'id' ) + '_cpscaptcha' );
					wrapper.getElement( 'input' ).set( 'value', '' );
					wrapper.getElement( 'input' ).fireEvent( 'blur' );
					wrapper.getElement( 'label' ).addClass( 'error' );
					wrapper.getElement( 'label' ).set( 'html', this.options.alerts.confirmationError );
					this.refreshImage();
					this.fireEvent( 'validateFailure' );
				} else {
					this.removeOverlay();
					this.removeCaptcha();
					this.fireEvent( 'validateSuccess' );
				}
			}.bind( this )
		}).send( $( this.form.get( 'id' ) ).toQueryString() );
	},

	/**
	 * Dispose overlay's element
	 */
	removeOverlay: function() {
		$( this.form.get( 'id' )+'_overlay' ).dispose();
	},

	/**
	 * Dispose captcha's element
	 */
	removeCaptcha: function() {
		$( this.form.get( 'id' ) + '_cpscaptcha' ).dispose();
	}
});

