fix ann filtering
[spider.git] / perl / Spot.pm
index 74e4e27a753ed2f640630f922036729575011537..420025e6ed8f0d1445f5fd8ec5cfc85e1ce9a275 100644 (file)
@@ -16,20 +16,30 @@ use DXLog;
 use Julian;
 use Prefix;
 use DXDupe;
+use Data::Dumper;
 
 use strict;
-use vars qw($fp $maxspots $defaultspots $maxdays $dirprefix $duplth $dupage $filterdef);
+
+use vars qw($VERSION $BRANCH);
+$VERSION = sprintf( "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/ );
+$BRANCH = sprintf( "%d.%03d", q$Revision$ =~ /\d+\.\d+\.(\d+)\.(\d+)/ ) || 0;
+$main::build += $VERSION;
+$main::branch += $BRANCH;
+
+use vars qw($fp $statp $maxspots $defaultspots $maxdays $dirprefix $duplth $dupage $filterdef);
 
 $fp = undef;
+$statp = undef;
 $maxspots = 50;                                        # maximum spots to return
 $defaultspots = 10;                            # normal number of spots to return
-$maxdays = 365;                                        # normal maximum no of days to go back
+$maxdays = 100;                                # normal maximum no of days to go back
 $dirprefix = "spots";
 $duplth = 20;                                  # the length of text to use in the deduping
 $dupage = 3*3600;               # the length of time to hold spot dups
 $filterdef = bless ([
                          # tag, sort, field, priv, special parser 
                          ['freq', 'r', 0, 0, \&decodefreq],
+                         ['on', 'r', 0, 0, \&decodefreq],
                          ['call', 'c', 1],
                          ['info', 't', 3],
                          ['by', 'c', 4],
@@ -87,6 +97,7 @@ sub init
 {
        mkdir "$dirprefix", 0777 if !-e "$dirprefix";
        $fp = DXLog::new($dirprefix, "dat", 'd');
+       $statp = DXLog::new($dirprefix, "bys", 'd');
 }
 
 sub prefix
@@ -94,20 +105,20 @@ sub prefix
        return $fp->{prefix};
 }
 
-# add a spot to the data file (call as Spot::add)
-sub add
+# fix up the full spot data from the basic spot data
+sub prepare
 {
-       my @spot = @_;                          # $freq, $call, $t, $comment, $spotter = @_
-       my @out = @spot[0..4];      # just up to the spotter
+       # $freq, $call, $t, $comment, $spotter = @_
+       my @out = @_[0..4];      # just up to the spotter
 
        # normalise frequency
-       $spot[0] = sprintf "%.f", $spot[0];
+       $_[0] = sprintf "%.1f", $_[0];
   
        # remove ssids if present on spotter
        $out[4] =~ s/-\d+$//o;
 
        # remove leading and trailing spaces
-       $spot[3] = unpad($spot[3]);
+       $_[3] = unpad($_[3]);
        
        # add the 'dxcc' country on the end for both spotted and spotter, then the cluster call
        my @dxcc = Prefix::extract($out[1]);
@@ -120,17 +131,16 @@ sub add
        my $spotter_itu = (@dxcc > 0 ) ? $dxcc[1]->itu() : 0;
        my $spotter_cq = (@dxcc > 0 ) ? $dxcc[1]->cq() : 0;
        push @out, $spotter_dxcc;
-       push @out, $spot[5];
-
-       my $buf = join("\^", @out);
-
-       # compare dates to see whether need to open another save file (remember, redefining $fp 
-       # automagically closes the output file (if any)). 
-       $fp->writeunix($out[2], $buf);
-  
+       push @out, $_[5];
        return (@out, $spotted_itu, $spotted_cq, $spotter_itu, $spotter_cq);
 }
 
+sub add
+{
+       my $buf = join("\^", @_[0..7]);
+       $fp->writeunix($_[2], $buf);
+}
+
 # search the spot database for records based on the field no and an expression
 # this returns a set of references to the spots
 #
@@ -164,14 +174,15 @@ sub search
        my $ref;
        my $i;
        my $count;
-       my @today = Julian::unixtoj(time());
-       my @fromdate;
-       my @todate;
+       my $today = Julian::Day->new(time());
+       my $fromdate;
+       my $todate;
 
        $dayfrom = 0 if !$dayfrom;
-       $dayto = $maxdays if !$dayto;
-       @fromdate = Julian::sub(@today, $dayfrom);
-       @todate = Julian::sub(@fromdate, $dayto);
+       $dayto = $maxdays unless $dayto;
+       $dayto = $dayfrom + $maxdays if $dayto < $dayfrom;
+       $fromdate = $today->sub($dayfrom);
+       $todate = $fromdate->sub($dayto);
        $from = 0 unless $from;
        $to = $defaultspots unless $to;
        $hint = $hint ? "next unless $hint" : "";
@@ -182,7 +193,7 @@ sub search
        $expr =~ s/\$f(\d)/\$ref->[$1]/g; # swap the letter n for the correct field name
        #  $expr =~ s/\$f(\d)/\$spots[$1]/g;               # swap the letter n for the correct field name
   
-       dbg("search", "expr='$expr', spotno=$from-$to, day=$dayfrom-$dayto\n");
+       dbg("hint='$hint', expr='$expr', spotno=$from-$to, day=$dayfrom-$dayto\n") if isdbg('search');
   
        # build up eval to execute
        $eval = qq(
@@ -207,11 +218,11 @@ sub search
        $fp->close;                                     # close any open files
 
        for ($i = $count = 0; $i < $maxdays; ++$i) {    # look thru $maxdays worth of files only
-               my @now = Julian::sub(@fromdate, $i); # but you can pick which $maxdays worth
-               last if Julian::cmp(@now, @todate) <= 0;         
+               my $now = $fromdate->sub($i); # but you can pick which $maxdays worth
+               last if $now->cmp($todate) <= 0;         
        
                my @spots = ();
-               my $fh = $fp->open(@now); # get the next file
+               my $fh = $fp->open($now); # get the next file
                if ($fh) {
                        my $in;
                        eval $eval;                     # do the search on this file
@@ -229,6 +240,7 @@ sub ftor
        my ($a, $b) = @_;
        return undef unless $a < $b;
        $b--;
+       my $d = $b - $a;
        my @a = split //, $a;
        my @b = split //, $b;
        my $out;
@@ -238,12 +250,14 @@ sub ftor
        while (@b) {
                my $aa = shift @a;
                my $bb = shift @b;
-               if ($aa eq $bb) {
+               if (@b < (length $d) - 1) {
+                       $out .= '\\d';
+               } elsif ($aa eq $bb) {
                        $out .= $aa;
                } elsif ($aa < $bb) {
                        $out .= "[$aa-$bb]";
                } else {
-                       $out .= "[$bb-$aa]";
+                       $out .= "[0-$bb$aa-9]";
                }
        }
        return $out;
@@ -272,11 +286,11 @@ sub formatl
 #
 # return all the spots from a day's file as an array of references
 # the parameter passed is a julian day
-sub readfile
+sub readfile($)
 {
        my @spots;
        
-       my $fh = $fp->open(@_); 
+       my $fh = $fp->open(shift); 
        if ($fh) {
                my $in;
                while (<$fh>) {
@@ -297,17 +311,105 @@ sub dup
  
        $freq = sprintf "%.1f", $freq;       # normalise frequency
        chomp $text;
+       $text =~ s/\%([0-9A-F][0-9A-F])/chr(hex($1))/eg;
        $text = substr($text, 0, $duplth) if length $text > $duplth; 
        unpad($text);
+       $text = pack("C*", map {$_ & 127} unpack("C*", $text));
        $text =~ s/[^a-zA-Z0-9]//g;
+       for (0,60,120,180,240,300) {
+               my $dt = $d - $_;
+               my $dupkey = "X$freq|$call|$dt|\L$text";
+               return 1 if DXDupe::find($dupkey);
+       }
        my $dupkey = "X$freq|$call|$d|\L$text";
-       return DXDupe::check($dupkey, $main::systime+$dupage);
+       DXDupe::add($dupkey, $main::systime+$dupage);
+       return 0;
 }
 
 sub listdups
 {
        return DXDupe::listdups('X', $dupage, @_);
 }
+
+sub genstats($)
+{
+       my $date = shift;
+       my $in = $fp->open($date);
+       my $out = $statp->open($date, 'w');
+       my @freq = (
+                               [0, Bands::get_freq('160m')],
+                               [1, Bands::get_freq('80m')],
+                               [2, Bands::get_freq('40m')],
+                               [3, Bands::get_freq('30m')],
+                               [4, Bands::get_freq('20m')],
+                               [5, Bands::get_freq('17m')],
+                               [6, Bands::get_freq('15m')],
+                               [7, Bands::get_freq('12m')],
+                               [8, Bands::get_freq('10m')],
+                               [9, Bands::get_freq('6m')],
+                               [10, Bands::get_freq('4m')],
+                               [11, Bands::get_freq('2m')],
+                               [12, Bands::get_freq('70cm')],
+                               [13, Bands::get_freq('13cm')],
+                               [14, Bands::get_freq('9cm')],
+                               [15, Bands::get_freq('6cm')],
+                               [16, Bands::get_freq('3cm')],
+                               [17, Bands::get_freq('12mm')],
+                               [18, Bands::get_freq('6cm')],
+                          );
+       my %list;
+       my @tot;
+       
+       if ($in && $out) {
+               while (<$in>) {
+                       chomp;
+                       my ($freq, $by, $dxcc) = (split /\^/)[0,4,6];
+                       my $ref = $list{$by} || [0, $dxcc];
+                       for (@freq) {
+                               if ($freq >= $_->[1] && $freq <= $_->[2]) {
+                                       $$ref[$_->[0]+2]++;
+                                       $tot[$_->[0]+2]++;
+                                       $$ref[0]++;
+                                       $tot[0]++;
+                                       $list{$by} = $ref;
+                                       last;
+                               }
+                       }
+               }
+
+               my $i;
+               for ($i = 0; $i < @freq+2; $i++) {
+                       $tot[$i] ||= 0;
+               }
+               $out->write(join('^', 'TOTALS', @tot) . "\n");
+
+               for (sort {$list{$b}->[0] <=> $list{$a}->[0]} keys %list) {
+                       my $ref = $list{$_};
+                       my $call = $_;
+                       for ($i = 0; $i < @freq+2; ++$i) {
+                               $ref->[$i] ||= 0;
+                       }
+                       $out->write(join('^', $call, @$ref) . "\n");
+               }
+               $out->close;
+       }
+}
+
+# return true if the stat file is newer than than the spot file
+sub checkstats($)
+{
+       my $date = shift;
+       my $in = $fp->mtime($date);
+       my $out = $statp->mtime($date);
+       return defined $out && defined $in && $out >= $in;
+}
+
+# daily processing
+sub daily
+{
+       my $date = Julian::Day->new($main::systime)->sub(1);
+       genstats($date) unless checkstats($date);
+}
 1;