#!/usr/pkg/bin/perl
#
# Authen::PluggableCaptcha::Challenge::DoMath
# Authen::PluggableCaptcha 
#
######################################################

use strict;

package Authen::PluggableCaptcha::Challenge::DoMath;

use vars qw(@ISA $VERSION);
$VERSION= '0.01';

use Authen::PluggableCaptcha::Challenge ();
our @ISA= qw( Authen::PluggableCaptcha::Challenge );

######################################################

use Digest::MD5 qw(md5_hex);
use Number::Spell;

######################################################

=pod

This is a type string captcha.

You have to type a string.  


Number::Spell
	Perl extension for spelling out numbers
	http://search.cpan.org/~lhoward/Number-Spell-0.04/Spell.pm

Lingua::EN::Numericalize
	Replaces English descriptions of numbers with numerals
	http://search.cpan.org/~ecalder/Lingua-EN-Numericalize-1.52/Numericalize.pm

Lingua::EN::WordsToNumbers
	convert numbers written in English to actual numbers
	http://search.cpan.org/~joey/Lingua-EN-Words2Nums-0.14/Words2Nums.pm	
	http://search.cpan.org/~emartin/Lingua-EN-WordsToNumbers-0.11/lib/Lingua/EN/WordsToNumbers.pm
	


=cut

##########################

our ( @_letters , @_digits , %_letters2digits , %_digits2letters );

BEGIN {

	# we need a mapping of letters to digits
	# it's done in a BEGIN block to only run 1x in a persistent environment
	@_letters= qw| a b c d e f g h i j k l m n o p q r s t u v w x y z |;
	@_digits= qw| 0 1 2 3 4 5 6 7 8 9 |;

	my 	$i;

	$i= 0;
	foreach my $char ( @_letters ) {
		$_letters2digits{ $char }= $_digits[ $i ];
		$i++;
	}
	$i= 0;
	foreach my $char ( @_digits ) {
		$_digits2letters{ $char }= $_letters[ $i ];
		$i++;
	}
	$i= undef;
}

##########################

sub new {
	my  ( $proto , %kw_args )= @_;
	my  $class= ref($proto) || $proto;
	my  $self= bless ( {} , $class );

		die "must supply 'keymanager_instance'" unless $kw_args{'keymanager_instance'};

		$self->_keymanager( $kw_args{'keymanager_instance'} );
		$self->_instructions("Please solve this math problem");

		$self->{'_internal_setup'}= {
			'response_type'=> {},
		};		

	# to make a math problem, we'll first make a hash off the publickey and site secret.
		my 	$working= md5_hex( 
				sprintf(
					"%s|%s" , 
						$self->keymanager->site_secret,
						$self->keymanager->publickey,
				)
			);

	# then we the hash into letters and numbers
		my 	( @letters , @digits );
		my 	@tmp= split // , $working;

		# if the last char of the md5 is a letter, we'll require a text (non numberc) response
		if ( $tmp[ -1 ] =~ /[a-zA-Z]/ ) {
			$self->{'_internal_setup'}{'response_type'}{'text'}= 1;
		}
		else {
			$self->{'_internal_setup'}{'response_type'}{'numeric'}= 1;
		}

		foreach my $char ( @tmp ) {
			if ( $char =~ /[a-zA-Z]/ ) {
				push @letters, $char;
			}
			elsif ( $char =~ /\d/ ) {
				push @digits, $char;
			}
		}
		
		# we want these to both be even:
		if ( $#letters < $#digits ) {
			my 	$i=0;
			while ( $#letters < $#digits ) {
				push @letters, $_digits2letters{ $digits[$i] };
				$i++;
			}
		}
		if ( $#digits < $#letters ) {
			my 	$i=0;
			while ( $#digits < $#letters ) {
				push @digits, $_letters2digits{ $letters[$i] };
				$i++;
			}
		}

		my 	( $int_1 , $int_2 )= ( $digits[0] , $digits[1] );
		my 	$operator= ( $digits[3] > 4 ) ? 'plus' : 'times' ;
		my 	$solution;
		if ( $operator eq 'plus' ) {
			$solution= $int_1 + $int_2 ;
		}
		elsif ( $operator eq 'times' ) {
			$solution= $int_1 * $int_2 ;
		}
		
		$self->_user_prompt( 
			sprintf( 
				'What is %s %s %s ? ' , 
					spell_number($int_1) , 
					$operator , 
					spell_number($int_2) 
			) 
		);

		if ( $self->{'_internal_setup'}{'response_type'}{'text'} ) {
		
			$self->_user_prompt( $self->user_prompt . '(in English as alphabetical characters)' );
			$self->_correct_response( spell_number($solution) );
		}
		else {
			$self->_user_prompt( $self->user_prompt . '(in digits)' );
			$self->_correct_response( $solution );
		}

	return $self;
}

sub validate {
	my 	( $self , %kw_args )= @_;
	
	if ( !defined $kw_args{'user_response'} ) {
		die "validate must be called with a 'user_response' argument";
	}
	if ( lc($kw_args{'user_response'}) eq lc($self->correct_response) ) {
		return 1;		
	}
	return 0;
}







###
1;