#!/usr/bin/perl use strict; use warnings; use DBI; use CGI (); use IO::All; use File::Spec; use URI::Escape; use Data::Dumper; use POSIX qw(abs ceil floor); use List::Util qw(shuffle); use Geo::Distance qw(distance_calc); #use lib ('/Users/greg/data/prog/dev/rdf/geo/lib'); use lib ('/home/greg/data/prog/dev/rdf/geo/lib'); use Location::Name; ###################################################################### my $DEGREES = 0.002; my $MAX_DEGREES = 0.15; my $MAX_COUNT = 20; my $wnprefix = 'http://xmlns.com/wordnet/1.6/'; my $base_uri = 'http://kasei.us'; #my $base_local = '/Users/greg/Sites/kasei.us'; my $base_local = '/home/greg/www'; my $templatef = File::Spec->catfile($base_local, 'templates', 'esearch.html'); ###################################################################### main(); sub main { my $template < io($templatef); my $lookup = new Location::Name; my $dbh = DBI->connect( 'DBI:mysql:database=greg', 'greg', 'nrt26ack' ); my $q = new CGI; my @places; my ($ctx, $subsel, @bind); my $args = { per_page => abs($q->param('num') || $MAX_COUNT), offset => abs($q->param('start') || 0) }; if ($q->param('lat')) { ($ctx, $subsel, @bind) = loc_search( $dbh, $args, [$q->param('lat'), $q->param('lon')] ); } elsif ($q->param('place')) { my $sth = $dbh->prepare( "SELECT * FROM geo_location WHERE INSTR(name,?) ORDER BY LOCATE(?,name)" ); $sth->execute( ($q->param('place')) x 2 ); my @places; while (my $data = $sth->fetchrow_hashref) { my $lat = $data->{'lat'}; my $lon = $data->{'lon'}; my $title = "Near " . $data->{'name'}; push(@places, [$lat, $lon, $title]); } ($ctx, $subsel, @bind) = loc_search( $dbh, $args, @places ); } elsif ($q->param('thing')) { my $thing = $q->param('thing'); ($ctx, $subsel, @bind) = thing_search( $dbh, $args, $thing ); } else { ($ctx, $subsel, @bind) = search_form(); } { # RELNAV my @relnav; if (my $url = $ctx->{ '_prevurl' }) { push(@relnav, qq{Prev}) } if ($ctx->{ '_nexturl' } or $ctx->{ '_prevurl' }) { my $page = 1 + $args->{'offset'} / $args->{'per_page'}; $page++ if ($args->{'offset'} % $args->{'per_page'}); push(@relnav, sprintf('Page %d', $page)); } if (my $url = $ctx->{ '_nexturl' }) { push(@relnav, qq{Next}) } my $relnav = join(' | ', @relnav); fill_template( 'RELNAV', $relnav ? qq{
${relnav}
} : '', \$template ); } foreach my $key (qw(SCRIPT TITLE IMAGES PEOPLE THINGS)) { fill_template( $key, exists($ctx->{ $key }) ? $ctx->{ $key } : '', \$template ); } print $q->header; print $template; } sub thing_search { my $dbh = shift; my $args = shift; my $thing = shift; my $title = $thing; $title =~ s/-\d+$//; my $ctx = { TITLE => $title, IMAGES => 'No Images Found', PEOPLE => '', THINGS => '' }; my $sth = $dbh->prepare( sprintf('SELECT t.*, i.thumbnail, i.infouri, i.description, i.thumbwidth AS width, i.thumbheight AS height FROM uri_things t, image_info i WHERE t.uri = i.uri AND t.type = ? LIMIT %d,%d', $args->{'offset'}, $args->{'per_page'}+1) ); my $subsel = sprintf("SELECT uri FROM uri_things WHERE type = ? LIMIT %d,%d", $args->{'offset'}, $args->{'per_page'}); my $wnuri = "${wnprefix}${thing}"; $sth->execute( $wnuri ); my @images; while (my $hash = $sth->fetchrow_hashref) { push(@images, $hash); } if (scalar(@images)) { if (scalar(@images) > $args->{'per_page'}) { use integer; my $start = $args->{'offset'} + $args->{'per_page'}; $ctx->{'_nexturl'} = "?thing=" . uri_escape($thing) . '&start=' . $start; $ctx->{'_nexturl'} .= "&num=" . $args->{'per_page'} unless ($args->{'per_page'} == $MAX_COUNT); } if ($args->{'offset'} > 0) { use integer; my $start = $args->{'offset'} - $args->{'per_page'}; $ctx->{'_prevurl'} = "?thing=" . uri_escape($thing); $ctx->{'_prevurl'} .= '&start=' . $start if ($start > 0); $ctx->{'_prevurl'} .= "&num=" . $args->{'per_page'} unless ($args->{'per_page'} == $MAX_COUNT); } my $html = join("\n\t", map { sprintf( q(
%s%s
), defined($_->{'infouri'}) ? $_->{'infouri'} :$_->{'uri'}, $_->{'description'}, substr($_->{'thumbnail'},length($base_uri)), $_->{'description'}, $_->{'width'}, $_->{'height'}, $_->{'description'} ) } grep { $_ } @images[0..$args->{'per_page'}-1]); $ctx->{'IMAGES'} = $html; $ctx->{'PEOPLE'} = get_people( $dbh, $subsel, $wnuri ); $ctx->{'THINGS'} = get_things( $dbh, $subsel, $wnuri ); } return ($ctx, $subsel, $wnuri); } sub loc_search { my $dbh = shift; my $args = shift; my @places = @_; my $ctx = { TITLE => '', IMAGES => 'No Images Found', PEOPLE => '', THINGS => '' }; my $sthcount = $dbh->prepare( 'SELECT COUNT(*) AS count FROM uri_location WHERE lat BETWEEN ? AND ? AND lon BETWEEN ? AND ?' ); my $sth = $dbh->prepare( sprintf("SELECT l.*, i.thumbnail, i.infouri, i.description, i.thumbwidth AS width, i.thumbheight AS height FROM uri_location l, image_info i WHERE l.uri = i.uri AND lat BETWEEN ? AND ? AND lon BETWEEN ? AND ? LIMIT %d,%d", $args->{'offset'}, $args->{'per_page'}) ); my $subsel = sprintf("SELECT uri FROM uri_location WHERE lat BETWEEN ? AND ? AND lon BETWEEN ? AND ? LIMIT %d,%d", $args->{'offset'}, $args->{'per_page'}); my (@ranges); foreach my $place (@places) { my ($lat, $lon, $title) = @{ $place }; if (not defined($title)) { my $lookup = new Location::Name; my $place = $lookup->name( $lat, $lon ); $title = $ctx->{ 'TITLE' } = "Near $place"; } # warn "Finding $title ($lat, $lon)\n"; my $maxdist; my $mult = 1; my $count = 0; while ($count < $args->{'per_page'}) { my $margin = $mult++ * $DEGREES; $maxdist = distance_calc( 'miles', 0, 0, 3*$margin, 3*$margin ); @ranges = map { $_ - $margin, $_ + $margin } ($lat, $lon); $sthcount->execute( @ranges ); ($count) = $sthcount->fetchrow_array; last if ($margin > $MAX_DEGREES); } next unless ($count); if ($count > ($args->{'offset'} + $args->{'per_page'})) { use integer; my $start = $args->{'offset'} + $args->{'per_page'}; $ctx->{'_nexturl'} = "?lat=${lat}&lon=${lon}&start=${start}"; $ctx->{'_nexturl'} .= "&num=" . $args->{'per_page'} unless ($args->{'per_page'} == $MAX_COUNT); } if ($args->{'offset'} > 0) { use integer; my $start = $args->{'offset'} - $args->{'per_page'}; $ctx->{'_prevurl'} = "?lat=${lat}&lon=${lon}"; $ctx->{'_prevurl'} .= '&start=' . $start if ($start > 0); $ctx->{'_prevurl'} .= "&num=" . $args->{'per_page'} unless ($args->{'per_page'} == $MAX_COUNT); } my @images; $sth->execute( @ranges ); while (my $hash = $sth->fetchrow_hashref) { $hash->{'dist'} = distance_calc('miles', $lon, $lat, $hash->{'lon'}, $hash->{'lat'}); unshift(@images, $hash); } @images = sort { $a->{'dist'} <=> $b->{'dist'} } grep { $_->{'dist'} <= $maxdist } @images; if (scalar(@images) > $MAX_COUNT) { splice(@images,$MAX_COUNT,scalar(@images),()); } my $html = join("\n\t", map { sprintf( q(
%s%s
), defined($_->{'infouri'}) ? $_->{'infouri'} :$_->{'uri'}, $_->{'description'}, substr($_->{'thumbnail'},length($base_uri)), $_->{'description'}, $_->{'width'}, $_->{'height'}, $_->{'description'} ) } @images); $ctx->{'TITLE'} = $title; $ctx->{'IMAGES'} = $html; $ctx->{'PEOPLE'} = get_people( $dbh, $subsel, @ranges ); $ctx->{'THINGS'} = get_things( $dbh, $subsel, @ranges ); last; } return ($ctx, $subsel, @ranges); } sub search_form { my $ctx = {}; $ctx->{'TITLE'} = 'Search'; $ctx->{'SCRIPT'} = <<"END"; END $ctx->{'IMAGES'} = <<"END";
END return $ctx; } ###################################################################### sub get_people { my $dbh = shift; my $subsel = shift; my @bind = @_; my @uris; { my $sth = $dbh->prepare( $subsel ); $sth->execute( @bind ); while (my $data = $sth->fetchrow_arrayref) { push( @uris, $data->[0] ) }; } my $sth = $dbh->prepare(<<"END"); SELECT DISTINCT(person), name FROM uri_people WHERE uri = ? END my @people; foreach my $uri (@uris) { $sth->execute($uri); while (my $data = $sth->fetchrow_hashref) { my $name = $data->{'name'}; my $url = "/people/${name}/"; $url =~ tr/ /_/; $url =~ s/'//g; push(@people, qq(
  • ${name}
  • )); } } my $people = scalar(@people) ? join("\n\t\t\t", "

    People:

    \n\t\t