#!/usr/bin/perl

# concordance.cgi - Web-based concordance using Lingua::Concordance

# Eric Lease Morgan <eric_morgan@infomotions.com>
# June 10, 2009 - first investigations
# June 12, 2009 - tweaked subform ("Thanks Rob!"); tweaked display


# define; change this to point to your own text
use constant EMERSON     => '../corpus/emerson-representative-755.txt';
use constant MACHIAVELLI => '../corpus/machiavelli-prince-680.txt';

# require
use CGI;
use CGI::Carp qw( fatalsToBrowser );
use Lingua::Concordance;
use strict;

# initalize
my $cgi   = CGI->new;
my $query = $cgi->param( 'query' );
my $work  = $cgi->param( 'work' );

# denote the work to evaluate
my $file = '';
if ( $work eq 'prince' ) { $file = MACHIAVELLI }
elsif ( $work eq 'representative' ) { $file = EMERSON }

# display home page
if ( ! $query ) {

	# display the home page and quit
	my $html = &template;
	$html =~ s/##QUERY##//;
	$html =~ s/##LINES##//;
	$html =~ s/##SUBFORM##//;
	&gracefulExit ( $html );

}

# search and display
else {

	# set up
	my $concordance = Lingua::Concordance->new;
	$concordance->text( &slurp( $file ));
	$concordance->query( $query );
	
	# configure radius
	my $radius = $cgi->param( 'radius' ) ? $cgi->param( 'radius' ) : $concordance->radius;
	$concordance->radius( $radius );
	
	# configure sort
	my $sort = $cgi->param( 'sort' ) ? $cgi->param( 'sort' ) : $concordance->radius;
	$concordance->sort( $sort );
	
	# do the work
	my $lines = '';
	my $index = 0;
	foreach my $line ( $concordance->lines ) {
	
		# build padding
		$index++;
		my $spaces = '';
		if ( length( $index ) == 1 ) { $spaces = '   ' }
		if ( length( $index ) == 2 ) { $spaces = '  ' }
		if ( length( $index ) == 3 ) { $spaces = ' ' }
		
		# format line
		$lines .= "$index.$spaces$line" . $cgi->br;
	
	}
	
	# format results, some more
	my $pattern = '\w+' . $query . '\w+|' . $query . '\w+|' . $query . '|\w+' . $query ;
	$lines =~ s|($pattern)|<b style='color:red'>$1</b>|gi;
	$lines = $cgi->pre({ style => 'text-align: center' }, $lines );
	
	# display
	my $html = &template;
	$html =~ s/##QUERY##/$query/ge;
	$html =~ s/##SUBFORM##/&subform ($concordance->radius( $radius ), $concordance->sort( $sort ))/e;
	$html =~ s/##LINES##/$lines/e;
	$html =~ s/##WORK##/$work/ge;
	&gracefulExit ( $html );

}

# done
exit;


# open a file named by the input and return its contents
sub slurp {

	my $f = shift;
	open ( F, $f ) or die "Can't open $f: $!\n";
	my $r = do { local $/; <F> };
	close F;
	return $r;

}


# send a header; send the html
sub gracefulExit {

	print $cgi->header();
	print shift;

}


# return basic layout of page; note tokens (QUERY, SUBFORM, CONTENT, and LINES)
sub template {

	my $script = $cgi->url;
	
	return <<EOT;
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Concordance</title></head>
<body style='margin: 5%; text-align: center'>
<h1>Concordance</h1>
<p style='color: silver; font-size: large'>Enter a word, phrase, or regular expression to see how it is used in the text or search for "<a href="http://dh.crc.nd.edu/sandbox/thatcamp-2015/bin/concordance.cgi?work=##WORK##&amp;query=%5Cb(angel%7Canimal%7Caristocracy%7Cart%7Castronomy%7Cbeauty%7Cbeing%7Ccause%7Cchance%7Cchange%7Ccitizen%7Cconstitution%7Ccontingency%7Cconvention%7Ccosmology%7Ccourage%7Ccustom%7Cdeath%7Cdefinition%7Cdemocracy%7Cdesire%7Cdespotism%7Cdialectic%7Cduty%7Ceducation%7Celement%7Cemotion%7Cequality%7Ceternity%7Cevil%7Cevolution%7Cexperience%7Cfamily%7Cfate%7Cform%7Cgod%7Cgood%7Cgovernment%7Chabit%7Chappiness%7Chistory%7Chonor%7Chypothesis%7Cidea%7Cimagination%7Cimmortality%7Cinduction%7Cinfinity%7Cjudgment%7Cjustice%7Cknowledge%7Clabor%7Clanguage%7Claw%7Cliberty%7Clife%7Clogic%7Clove%7Cman%7Cmany%7Cmathematics%7Cmatter%7Cmechanics%7Cmedicine%7Cmemory%7Cmetaphysics%7Cmind%7Cmonarchy%7Cnature%7Cnecessity%7Coligarchy%7Cone%7Copinion%7Copposition%7Cother%7Cpain%7Cparticular%7Cpeace%7Cphilosophy%7Cphysics%7Cpleasure%7Cpoetry%7Cprinciple%7Cprogress%7Cprophecy%7Cprudence%7Cpunishment%7Cquality%7Cquantity%7Creasoning%7Crelation%7Creligion%7Crevolution%7Crhetoric%7Csame%7Cscience%7Csense%7Csign%7Csin%7Cslavery%7Csoul%7Cspace%7Cstate%7Csymbol%7Ctemperance%7Ctheology%7Ctime%7Ctruth%7Ctyranny%7Cuniversal%7Cvice%7Cvirtue%7Cwar%7Cwealth%7Cwill%7Cwisdom%7Cworld)%5Cb">great ideas</a>" or "<a href="http://dh.crc.nd.edu/sandbox/thatcamp-2015/bin/concordance.cgi?work=##WORK##&amp;query=%5Cb%28aeschylus%7Capollonius%7Caquinas%7Carchimedes%7Caristophanes%7Caristotle%7Caugustine%7Caurelius%7Cbacon%7Cberkeley%7Cboswell%7Ccervantes%7Cchaucer%7Ccopernicus%7Cdante%7Cdarwin%7Cdescartes%7Cdostoevsky%7Cengles%7Cepictetus%7Ceuclid%7Ceuripides%7Cfaraday%7Cfielding%7Cfourier%7Cfreud%7Cgalen%7Cgalilei%7Cgibbon%7Cgilbert%7Cgoethe%7Charvey%7Chegel%7Cherodotus%7Chippocrates%7Chobbes%7Chomer%7Chume%7Chuygens%7Cjames%7Ckant%7Ckepler%7Clavoisier%7Clocke%7Clucretius%7Cmachiavelli%7Cmarx%7Cmelville%7Cmill%7Cmilton%7Cmontaigne%7Cmontesquieu%7Cnewton%7Cnicomachus%7Cpascal%7Cplato%7Cplotinus%7Cplutarch%7Cptolemy%7Crabelais%7Crousseau%7Cshakespeare%7Csmith%7Csophocles%7Cspinoza%7Csterne%7Cswift%7Ctacitus%7Cthucydides%7Ctolstoy%7Cvirgil%29%5Cb">great men</a>"
</p>
<form name='f1' action='$script' method='get' style='text-align: center'>
<input type='text' name='query' value='##QUERY##' size='30' style='font-size: x-large' />
<input type='hidden' name='work' value='##WORK##' />
<input type='submit' value='Go' style='font-size: x-large' />
##SUBFORM##
</form>
<p><a href="http://dh.crc.nd.edu/sandbox/thatcamp-2015/bin/network.cgi?q=##QUERY##&w=##WORK##">visualize results</a></p>
##LINES##
<hr style='margin-top: 2em' />
<p style='text-align: right'>
<a href='http://search.cpan.org/~emorgan/Lingua-Concordance-0.01/' style='color: silver'>Built with Lingua::Concordance</p>
</body>
</html>
EOT

}


# update subform; retain selected values
sub subform {

	my $radius = shift;
	my $sort   = shift;
	
	my $subform = <<EOF;
<br />
<!-- radius -->
Radius:
<select name="radius" onChange='javascript:document.f1.submit()' title='Length of surrounding text'>
	<option label="20" value="20" />
	<option label="30" value="30" />
	<option label="40" value="40" />
	<option label="50" value="50" />
	<option label="60" value="60" />
</select>

<!-- sort -->
Sort: <input name="sort" type="radio" value="none" onClick='javascript:document.f1.submit()' title='Order found in the text' /> None
<input name="sort" type="radio" value="left" onClick='javascript:document.f1.submit()' title='Finds phrases to the left' /> Left
<input name="sort" type="radio" value="right" onClick='javascript:document.f1.submit()' title='Finds phrases to the right' /> Right
<input name="sort" type="radio" value="match" onClick='javascript:document.f1.submit()' title='Finds word variations' /> Match
EOF

	# brute force dynamic updating; there's got to be a better way
	if    ( $radius eq '20' ) { $subform =~ s/value="20" /value="20" selected="selected" / }
	elsif ( $radius eq '30' ) { $subform =~ s/value="30" /value="30" selected="selected" / }
	elsif ( $radius eq '40' ) { $subform =~ s/value="40" /value="40" selected="selected" / }
	elsif ( $radius eq '50' ) { $subform =~ s/value="50" /value="50" selected="selected" / }
	elsif ( $radius eq '60' ) { $subform =~ s/value="60" /value="60" selected="selected" / }
	else  { $subform =~ s/value="30" /value="30" selected="selected" / }
	
	if    ( $sort eq 'none' )  { $subform =~ s/value="none" /value="none" checked="checked" / }
	elsif ( $sort eq 'left' )  { $subform =~ s/value="left" /value="left" checked="checked" / }
	elsif ( $sort eq 'right' ) { $subform =~ s/value="right" /value="right" checked="checked" / }
	elsif ( $sort eq 'match' ) { $subform =~ s/value="match" /value="match" checked="checked" / }
	else  { $subform =~ s/value="none" /value="none" checked="checked" / }
	
	# done
	return $subform;
	
}


