#!/usr/bin/perl -w
# NAME: fgms-log.pl
# AIM: Read a fgms log, and produce tracker information...
# 28/06/2012 - Initial cut
use strict;
use warnings;
use File::Basename;  # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] )
use Cwd;
use Time::HiRes qw(gettimeofday tv_interval);       # provide more accurate timings
use Date::Calc qw(Week_of_Year);
use Time::gmtime;
use Time::Local;
use JSON;   # use JASON::XS;
my $os = $^O;
my $perl_dir = '/home/geoff/bin';
my $PATH_SEP = '/';
my $temp_dir = '/tmp';
if ($os =~ /win/i) {
    $perl_dir = 'C:\GTools\perl';
    $temp_dir = $perl_dir;
    $PATH_SEP = "\\";
}
unshift(@INC, $perl_dir);
require 'lib_utils.pl' or die "Unable to load 'lib_utils.pl' Check paths in \@INC...\n";
# log file stuff
our ($LF);
my $pgmname = $0;
if ($pgmname =~ /(\\|\/)/) {
    my @tmpsp = split(/(\\|\/)/,$pgmname);
    $pgmname = $tmpsp[-1];
}
my $outfile = $temp_dir.$PATH_SEP."temp.$pgmname.txt";
open_log($outfile);

# user variables
my $VERS = "0.0.2 2012-07-17";
##my $VERS = "0.0.1 2012-06-28";
my $load_log = 0;
my $in_file = '';
my $verbosity = 0;
my $out_json = '';
my $show_not_in_alist = 0;
my $extend_active_tm = 1;
my $issue_warnings = 1;
my $max_col_count = 4;
my $write_html = 0;

my $filter_by_minsecs = 1;  # FILTER - do NOT show pilots with less time thant this
my $min_secs = 60 * 10;  # ten minutes is minimum, else NOT counted

my $out_path = 'C:\Users\user\Downloads\logs\temp2';

sub sort_results8($$$$$$$$); # ($rpth,$rpah,$rplh,$rath,$raph,$rperlh,$rph,$rah)
sub output_json6($$$$$$); # ($rperlh,$rph,$rah,$out_comb,$out_air,$out_pilot)

my $debug_on = 1;
my $def_file = 'C:\Users\user\Downloads\logs\fgms_curr.log';
my $def_file2 = 'C:\Users\user\Downloads\logs\fgms_006.log';
my $def_out = $temp_dir.$PATH_SEP."temp.$pgmname.json";

my $temp_air = $temp_dir.$PATH_SEP."tempair.json";
my $temp_pilot = $temp_dir.$PATH_SEP."temppilot.json";

### program variables
my @warnings = ();
my $cwd = cwd();
my @in_files = ();
my $html = '';
my $html_out = $temp_dir.$PATH_SEP."temp.$pgmname.htm";

sub test_time() {
    #my $weekNumber = POSIX::strftime("%V", gmtime time);
    # sec, min, hour, mday, mon, year, wday, yday, and isdst.
    my $tm = gmtime(time());
    #my $m = sprintf( "%04d/%02d/%02d", $tm->year() + 1900, $tm->mon() + 1, $tm->mday());
    my $year = $tm->year() + 1900;
    my $month = $tm->mon() + 1;
    my $day = $tm->mday();
    my ($week,$ayear) = Week_of_Year($year,$month,$day); 
    prt("Is week $week of $ayear\n");
    exit(1);
}

sub VERB1() { return $verbosity >= 1; }
sub VERB2() { return $verbosity >= 2; }
sub VERB5() { return $verbosity >= 5; }
sub VERB9() { return $verbosity >= 9; }

sub show_warnings($) {
    my ($val) = @_;
    if (@warnings) {
        prt( "\nGot ".scalar @warnings." WARNINGS...\n" );
        foreach my $itm (@warnings) {
           prt("$itm\n");
        }
        prt("\n");
    } else {
        prt( "\nNo warnings issued.\n\n" ) if (VERB9());
    }
}

sub pgm_exit($$) {
    my ($val,$msg) = @_;
    if (length($msg)) {
        $msg .= "\n" if (!($msg =~ /\n$/));
        prt($msg);
    }
    show_warnings($val);
    close_log($outfile,$load_log);
    exit($val);
}


sub prtw($) {
   my ($tx) = shift;
   $tx =~ s/\n$//;
   prt("$tx\n");
   push(@warnings,$tx);
}

sub get_top_link() {
    my $top = <<EOF;
<p align="center"><a href="#top">top</a></p>
EOF
    return $top;
}

sub parse_time_string($$) {
    my ($time,$ra) = @_;
    if ($time =~ /^(\d{2})\.(\d{2})\.(\d{4})\s+(\d{2}):(\d{2}):(\d{2})\s*$/) {
        ${$ra}[0] = $1; # $day = $1;
        ${$ra}[1] = $2; # $mth = $2;
        ${$ra}[2] = $3; # $yrs = $3;
        ${$ra}[3] = $4; # $hrs = $4;
        ${$ra}[4] = $5; # $min = $5;
        ${$ra}[5] = $6; # $sec = $6;
        return 1;
    }
    return 0;
}

sub secs_to_DAYS_HHMMSS($) {
    my ($secs) = @_;
    my ($mins,$hour,$days);
    $mins = int($secs / 60);
    $secs = $secs - ($mins * 60);
    $hour = int($mins / 60);
    $mins = $mins - ($hour * 60);
    $days = int($hour / 24);
    $hour = $hour - ($days * 24);
    my $tm = sprintf("%3d %02d:%02d:%02d",$days, $hour, $mins, $secs);
    return $tm;
}

sub modify_callsign($) {
    my $cs = shift;
    $cs = uc($cs);
    my $len = length($cs);
    return 'ANON' if ($len == 0);
    my ($i,$ch);
    my $ncs = '';
    for ($i = 0; $i < $len; $i++) {
        $ch = substr($cs,$i,1);
        next if ($ch eq '_');
        next if ( !($ch =~ /\w/) );
        $ncs .= $ch;
    }
    $len = length($ncs);
    return 'ANON' if ($len == 0);
    $ncs = substr($ncs,0,7) if ($len > 7);
    return $ncs;
}

sub by_time {
    return -1 if (${$a}[0] > ${$b}[0]);
    return  1 if (${$a}[0] < ${$b}[0]);
    return 0;
}

my $write_month_files = 1;
my $write_week_files = 1;

sub get_time_stamp($$) {
    my ($time,$rts) = @_;
    my ($day,$mth,$yrs,$hrs,$min,$sec);
    if ($time =~ /^(\d{2})\.(\d{2})\.(\d{4})\s+(\d{2}):(\d{2}):(\d{2})\s*$/) {
        $day = $1;
        $mth = $2;
        $yrs = $3;
        $hrs = $4;
        $min = $5;
        $sec = $6;
        # my $timestamp = timegm($sec,$min,$hrd,$day,$mth-1,$yrs);
        ${$rts} = timelocal($sec,$min,$hrs,$day,$mth-1,$yrs);
        return 1;
    }
    return 0;
}

sub extend_active_times($$$$$$) {
    my ($rparams,$rpth,$rpah,$rplh,$rath,$raph) = @_;
    my $curr_time = ${$rparams}{'CURR_TIME'};
    my $sort = ${$rparams}{'CURR_PERIOD'};  # 0 = all, 1 = month, 2 = week
    ###my ($day,$mth,$yrs,$hrs,$min,$sec);
    my $ractive = ${$rparams}{'CURR_ACTIVE'};
    my $acnt = 0;
    my ($timestamp);
    if (get_time_stamp($curr_time,\$timestamp)) {
        my ($rperlh,$rph,$rah);
        if ($sort == 0) {
            $rperlh = ${$rparams}{'H_PERL_SCALAR'};
            $rph = ${$rperlh}{'pilots'};
            $rah = ${$rperlh}{'aircraft'};
            $acnt = scalar keys(%{$ractive});
        } elsif ($sort == 1) {
            $rperlh = ${$rparams}{'M_PERL_SCALAR'};
            $rph = ${$rperlh}{'pilots'};
            $rah = ${$rperlh}{'aircraft'};
            $acnt = scalar keys(%{$ractive});
        } elsif ($sort == 2) {
            $rperlh = ${$rparams}{'W_PERL_SCALAR'};
            $rph = ${$rperlh}{'pilots'};
            $rah = ${$rperlh}{'aircraft'};
            $acnt = scalar keys(%{$ractive});
        }
        if ($acnt) {
            my ($add,$pilot,$tm,$ts,$ac,$ra,$cnt,$rh);
            foreach $pilot (keys (%{$ractive})) {
                $ra = ${$ractive}{$pilot};
                $ac = ${$ra}[0];    # get aircraft in use
                $tm = ${$ra}[1];    # get begin time
                if (get_time_stamp($tm,\$ts)) {
                    $add = $timestamp - $ts;    # get amount to add
                    if ($add > 0) {
                        $cnt = 0;
                        if (defined ${$rpth}{$pilot}) {
                            ${$rpth}{$pilot} += $add;  # add the time
                            $cnt++;
                        }
                        if (defined ${$rpah}{$pilot}) {
                            $rh = ${$rpah}{$pilot}; # get aircraft used by this pilot
                            if (defined ${$rh}{$ac}) {
                                ${$rh}{$ac} += $add;    # add the time
                                $cnt++;
                            }
                        }
                        if (defined ${$rath}{$ac}) {
                            ${$rath}{$ac} += $add; # add the time
                            $cnt++;
                        }
#                        if (defined ${$raph}{$ac}) {
#                            $rh = ${$raph}{$ac};
#                            if (defined ${$rh}{$pilot}) {
#                                ${$rh}{$pilot} += $add; # add the time - THIS IS AN AIRCRAFT
#                                $cnt++;
#                            }
#                        }

                        prt("For pilot [$pilot], in [$ac], add $add secs [$cnt]\n") if (VERB9());
                    } elsif ($add < 0) {
                        prtw("WARNING: timestamp diff [$curr_time] and [$tm] is NEGATIVE! [$add] [$timestamp] [$ts]\n");
                    }
                } else {
                    prtw("WARNING: Failed to get time stamp from [$tm]!\n");
                }
            }
        }
    } else {
        prtw("WARNING: Failed to get time stamp from [$curr_time]!\n");
    }
}

sub extend_times_of_active($$) {
    my ($rparams,$sort) = @_;
    ${$rparams}{'CURR_PERIOD'} = $sort;
    my ($rpth,$rpah,$rplh,$rath,$raph,$rperlh,$rph,$rah);
    if ($sort == 0) {
        $rpth = ${$rparams}{'H_PILOT_TIME'};
        $rpah = ${$rparams}{'H_PILOT_AIR'};
        $rplh = ${$rparams}{'H_PILOT_LAST'};
        $rath = ${$rparams}{'H_AIR_TIME'};
        $raph = ${$rparams}{'H_AIR_PILOT'};
        $rperlh = ${$rparams}{'H_PERL_SCALAR'};
        $rph = ${$rperlh}{'pilots'};
        $rah = ${$rperlh}{'aircraft'};
        extend_active_times($rparams,$rpth,$rpah,$rplh,$rath,$raph);
    } elsif ($sort == 1) {
        $rpth = ${$rparams}{'M_PILOT_TIME'};
        $rpah = ${$rparams}{'M_PILOT_AIR'};
        $rplh = ${$rparams}{'M_PILOT_LAST'};
        $rath = ${$rparams}{'M_AIR_TIME'};
        $raph = ${$rparams}{'M_AIR_PILOT'};
        $rperlh = ${$rparams}{'M_PERL_SCALAR'};
        $rph = ${$rperlh}{'pilots'};
        $rah = ${$rperlh}{'aircraft'};
        extend_active_times($rparams,$rpth,$rpah,$rplh,$rath,$raph);
    } elsif ($sort == 2) {
        $rpth = ${$rparams}{'W_PILOT_TIME'};
        $rpah = ${$rparams}{'W_PILOT_AIR'};
        $rplh = ${$rparams}{'W_PILOT_LAST'};
        $rath = ${$rparams}{'W_AIR_TIME'};
        $raph = ${$rparams}{'W_AIR_PILOT'};
        $rperlh = ${$rparams}{'W_PERL_SCALAR'};
        $rph = ${$rperlh}{'pilots'};
        $rah = ${$rperlh}{'aircraft'};
        extend_active_times($rparams,$rpth,$rpah,$rplh,$rath,$raph);
    }
}

sub add_html_pilot_times($$) {
    my ($rh,$cap) = @_;
    my ($pilot,$sec,$wrap,$i,$cnt,$split,$tsecs);
    my %h = ();
    my @pilot_time = ();
    $tsecs = 0;
    foreach $pilot (keys %{$rh}) {
        $sec = ${$rh}{$pilot};
        next if ($filter_by_minsecs && ($sec <= $min_secs));
        push(@pilot_time, [$sec, $pilot]);
        $tsecs += $sec;
    }
    @pilot_time = sort by_time @pilot_time;
    $cnt = scalar @pilot_time;
    $html .= "<table align=\"center\">\n";
    $html .= "<caption><b>$cap - $cnt pilots - ";
    $html .= "total time ".secs_to_DAYS_HHMMSS($tsecs);
    $html .= "</b></caption>\n";
    $wrap = 0;
    $split = "<td>&nbsp;|&nbsp;</td>";
    for ($i = 0; $i < $cnt; $i++) {
        $sec    = $pilot_time[$i][0];
        $pilot  = $pilot_time[$i][1];
        $html .= "<tr>\n" if ($wrap == 0);
        $html .= "<td>$pilot</td><td align=\"right\">";
        $html .= secs_to_DAYS_HHMMSS($sec);
        $html .= "</td>";
        $wrap++;
        if ($wrap == $max_col_count) {
             $html .= "\n</tr>\n";
             $wrap = 0;
        } else {
            $html .= $split;
        }
    }
    if ($wrap) {
        while ($wrap < $max_col_count) {
            $html .= "<td>&nbsp</td><td align=\"right\">&nbsp;</td>";
            $wrap++;
            if ($wrap != $max_col_count) {
                $html .= $split;
            }
        }
        $html .= "\n</tr>\n";
    }
    $html .= "</table>\n";
    $html .= get_top_link();
}


sub do_end_week($) {
    my $rparams = shift;
    my $iret = 0;
    my $r_last_week = ${$rparams}{'R_LAST_WEEK'};
    my $last_week = ${$r_last_week};
    my $curr_time = ${$rparams}{'CURR_TIME'};
    if ($write_week_files && ($last_week != -1)) {
        # results for week
        my $rwpth = ${$rparams}{'W_PILOT_TIME'};
        my $rwpah = ${$rparams}{'W_PILOT_AIR'};
        my $rwplh = ${$rparams}{'W_PILOT_LAST'};
        my $rwath = ${$rparams}{'W_AIR_TIME'};
        my $rwaph = ${$rparams}{'W_AIR_PILOT'};
        my $ractive = ${$rparams}{'CURR_ACTIVE'};
        my $acnt = scalar keys(%{$ractive});
        my ($out_comb,$out_air,$out_pilot);
        my ($pilot,$ac,$rh);
        my $rwperlh = ${$rparams}{'W_PERL_SCALAR'};
        my $rwph = ${$rwperlh}{'pilots'};
        my $rwah = ${$rwperlh}{'aircraft'};
        if (check_total_times($rwpth,$rwath)) {
            $iret = 1;
            prt("Do end week $last_week [$curr_time] - $acnt still active\n");
            extend_times_of_active($rparams,2) if ($acnt && $extend_active_tm);
            sort_results8($rwpth,$rwpah,$rwplh,$rwath,$rwaph,$rwperlh,$rwph,$rwah);
            $out_comb = $out_path.$PATH_SEP."combined.w$last_week.json";
            $out_air  = $out_path.$PATH_SEP."aircraft.w$last_week.json";
            $out_pilot = $out_path.$PATH_SEP."pilots.w$last_week.json";
            output_json6($rwperlh,$rwph,$rwah,$out_comb,$out_air,$out_pilot);
            add_html_pilot_times($rwpth,"for week $last_week") if ($write_html);
            foreach $pilot (keys %{$rwpth}) {
                ${$rwpth}{$pilot} = 0;  # clear the time
                if (defined ${$rwpah}{$pilot}) {
                    $rh = ${$rwpah}{$pilot}; # get aircraft used by this pilot
                    foreach $ac (keys %{$rh}) {
                        ${$rh}{$ac} = 0;    # clear time
                    }
                }
            }
            foreach $ac (keys %{$rwath}) {
                ${$rwath}{$ac} = 0; # clear any time
                #if (defined ${$rwaph}{$ac}) {
                #    $rh = ${$rwaph}{$ac};
                #    foreach $pilot (keys %{$rh}) {
                #        ${$rh}{$pilot} = 0; # clear time
                #    }
                #}
            }

            %{$rwperlh} = ();
            #%{$rwph} = ();
            #%{$rwah} = ();
            my %hw1 = ();
            my %hw2 = ();
            ${$rwperlh}{'pilots'} = \%hw1;
            ${$rwperlh}{'aircraft'} = \%hw2;
        } else {
            prt("No results for end week $last_week - $acnt still active\n");
        }
    }
    return $iret;
}


sub do_end_month($) {
    my $rparams = shift;
    my $iret = 0;
    my $r_last_month = ${$rparams}{'R_LAST_MONTH'};
    my $last_month = ${$r_last_month};
    my $curr_time = ${$rparams}{'CURR_TIME'};
    if ($write_month_files && ($last_month != -1)) {
        my ($out_comb,$out_air,$out_pilot);
        my ($pilot,$ac,$rh);
        my $ractive = ${$rparams}{'CURR_ACTIVE'};
        my $acnt = scalar keys(%{$ractive});
        # sort and write the MONTH list
        # results for month
        my $rmpth = ${$rparams}{'M_PILOT_TIME'};
        my $rmpah = ${$rparams}{'M_PILOT_AIR'};
        my $rmplh = ${$rparams}{'M_PILOT_LAST'};
        my $rmath = ${$rparams}{'M_AIR_TIME'};
        my $rmaph = ${$rparams}{'M_AIR_PILOT'};
        my $rmperlh = ${$rparams}{'M_PERL_SCALAR'};
        my $rmph = ${$rmperlh}{'pilots'};
        my $rmah = ${$rmperlh}{'aircraft'};
        if (check_total_times($rmpth,$rmath)) {
            $iret = 1;
            prt("Do end month $last_month [$curr_time] - $acnt still active\n");
            extend_times_of_active($rparams,1) if ($acnt && $extend_active_tm);
            sort_results8($rmpth,$rmpah,$rmplh,$rmath,$rmaph,$rmperlh,$rmph,$rmah);
            $out_comb = $out_path.$PATH_SEP."combined.m$last_month.json";
            $out_air  = $out_path.$PATH_SEP."aircraft.m$last_month.json";
            $out_pilot = $out_path.$PATH_SEP."pilots.m$last_month.json";
            output_json6($rmperlh,$rmph,$rmah,$out_comb,$out_air,$out_pilot);
            foreach $pilot (keys %{$rmpth}) {
                ${$rmpth}{$pilot} = 0;  # clear the time
                if (defined ${$rmpah}{$pilot}) {
                    $rh = ${$rmpah}{$pilot}; # get aircraft used by this pilot
                    foreach $ac (keys %{$rh}) {
                        ${$rh}{$ac} = 0;    # clear time
                    }
                }
            }
            foreach $ac (keys %{$rmath}) {
                ${$rmath}{$ac} = 0; # clear any time
                #if (defined ${$rmaph}{$ac}) {
                #    $rh = ${$rmaph}{$ac};
                #    foreach $pilot (keys %{$rh}) {
                #        ${$rh}{$pilot} = 0; # clear time
                #    }
                #}
            }
            %{$rmperlh} = ();
            my %hm1 = ();
            my %hm2 = ();
            ${$rmperlh}{'pilots'} = \%hm1;
            ${$rmperlh}{'aircraft'} = \%hm2;
        } else {
            prt("No results for end month $last_month - $acnt still active\n");
        }
    }
    return $iret;
}

# 12345678901234567890
# 04.06.2012 08:08:56 New REMOTE Client: Isnar mpserver01:5000 (Aircraft/777-300/Models/777-300ER.xml) current clients: 1 max: 1
# 04.06.2012 08:09:14 TTL exceeded, dropping pilot BR-RIC@mpserver01  after 11 seconds.  Usage #packets in: 1 forwarded: 0 out: 0. Current clients: 17 max: 18
# process_in_file($in_file, $rpth, $rpah, $rplh, $rath, $raph);
## sub process_in_file($$$$$$) {
##    my ($inf, $rpth, $rpah, $rplh, $rath, $raph) = @_;
sub process_in_file($) {
    my $rparams = shift;
    my $inf = ${$rparams}{'CURRENT_FILE'};
    if (! open INF, "<$inf") {
        pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); 
    }
    my @lines = <INF>;
    close INF;
    my $lncnt = scalar @lines;
    my $ractive = ${$rparams}{'CURR_ACTIVE'};
    my $acnt = scalar keys(%{$ractive});
    prt("Processing $lncnt lines, from [$inf]... $acnt active pilots\n");

    # combined
    my $rpth  = ${$rparams}{'H_PILOT_TIME'};
    my $rpah  = ${$rparams}{'H_PILOT_AIR'};
    my $rplh  = ${$rparams}{'H_PILOT_LAST'};
    my $rath  = ${$rparams}{'H_AIR_TIME'};
    my $raph  = ${$rparams}{'H_AIR_PILOT'};
    my $rptbh = ${$rparams}{'H_PILOT_BEGIN'};

    # results for month
    my $rmpth = ${$rparams}{'M_PILOT_TIME'};
    my $rmpah = ${$rparams}{'M_PILOT_AIR'};
    my $rmplh = ${$rparams}{'M_PILOT_LAST'};
    my $rmath = ${$rparams}{'M_AIR_TIME'};
    my $rmaph = ${$rparams}{'M_AIR_PILOT'};
    my $rmptbh = ${$rparams}{'M_PILOT_BEGIN'};

    # results for week
    my $rwpth = ${$rparams}{'W_PILOT_TIME'};
    my $rwpah = ${$rparams}{'W_PILOT_AIR'};
    my $rwplh = ${$rparams}{'W_PILOT_LAST'};
    my $rwath = ${$rparams}{'W_AIR_TIME'};
    my $rwaph = ${$rparams}{'W_AIR_PILOT'};
    my $rwptbh = ${$rparams}{'W_PILOT_BEGIN'};

    my $r_clients = ${$rparams}{'R_CLIENTS'};
    my $r_max_clients = ${$rparams}{'R_MAX_CLIENTS'};
    my $r_last_week = ${$rparams}{'R_LAST_WEEK'};
    my $r_last_month = ${$rparams}{'R_LAST_MONTH'};
    my $clients = ${$r_clients};
    my $max_clients = ${$r_max_clients};
    my ($line,$inc,$lnn);
    my ($time,$info,$join);
    my ($day,$mth,$yrs,$hrs,$min,$sec);
    my ($pilot,$serv,$port,$air,$left,$type);
    my ($rh,$ac,@arr,$cnt);
    my ($week,$year);
    my $last_week = ${$r_last_week};
    my $last_month = ${$r_last_month};
    my $prev_time = ${$rparams}{'CURR_PREV_TIME'};
    $lnn = 0;
    my $jcnt = 0;
    my $ecnt = 0;
    my $jmcnt = 0;
    my $jwcnt = 0;
    my $emcnt = 0;
    my $ewcnt = 0;
    $time = '';
    foreach $line (@lines) {
        chomp $line;
        $lnn++;
        $prev_time = $time;
        $time = substr($line,0,19);
        $info = substr($line,20);
        $type = 0;
        $pilot = 'ANON2';
        if ($time =~ /^(\d{2})\.(\d{2})\.(\d{4})\s+(\d{2}):(\d{2}):(\d{2})\s*$/) {
            $day = $1;
            $mth = $2;
            $yrs = $3;
            $hrs = $4;
            $min = $5;
            $sec = $6;
            ${$rparams}{'PREV_TIME'} = ${$rparams}{'CURR_TIME'};
            ${$rparams}{'CURR_TIME'} = $time;
            ($week,$year) = Week_of_Year($yrs,$mth,$day);
            if ($last_month != $mth) {  # sort and write the MONTH list
                if ($write_month_files && ($last_month != -1)) {
                    if (do_end_month($rparams)) {
                        $jmcnt = 0;
                        $emcnt = 0;
                    }
                }
                $acnt = scalar keys(%{$ractive});
                prt("Got new month $mth [$time] - $acnt still active\n");
                $last_month = $mth;
                ${$r_last_month} = $last_month;
            }
            if ($last_week != $week) {  # sort and write WEEK list
                if ($write_week_files && ($last_week != -1)) {
                    if (do_end_week($rparams)) {
                        $jwcnt = 0;
                        $ewcnt = 0;
                    }
                }
                $acnt = scalar keys(%{$ractive});
                prt("Got new week $week [$time] - $acnt still active\n");
                $last_week = $week;
                ${$r_last_week} = $last_week;
            }
            #              1234567890123456789
            if ($info =~ /^New REMOTE Client: /) {
                # New REMOTE Client: Isnar mpserver01:5000 (Aircraft/777-300/Models/777-300ER.xml) current clients: 1 max: 1
                $join = substr($info,19);
                ### if ($join =~ /^([-\.\s\w]+)\s+mpserver(\d{2}):(\d{4})\s+\((.+)\)\s+/) {
                if ($join =~ /^(.+)\s+mpserver(\d{2}):(\d{4})\s+\((.*)\)\s+/) {
                    $pilot = $1;
                    $serv  = $2;
                    $port  = $3;
                    $air   = $4;
                    $type = 1;
                } else {
                    prt("$lnn: join [$info] FAILED\n");
                }
            } elsif ($info =~ /^New LOCAL Client: /) {
                # 123456789012345678
                # New LOCAL Client: GA007 83.202.38.240:5000 (Aircraft/c172p/Models/c172p.xml) current clients: 27 max: 30
                $join = substr($info,18);
                ###if ($join =~ /^(.+)\s+mpserver(\d{2}):(\d{4})\s+\((.*)\)\s+/) {
                if ($join =~ /^(.+)\s+(.+):(\d+)\s+\((.*)\)\s+/) {
                    $pilot = $1;
                    $serv  = $2;
                    $port  = $3;
                    $air   = $4;
                    $type = 2;
                } else {
                    prtw("WARNING: $lnn: join [$info] FAILED\n");
                }
            } elsif ($info =~ /^TTL exceeded, dropping pilot /) {
                # 12345678901234567890123456789
                # TTL exceeded, dropping pilot BR-NVS@mpserver01  after 79 seconds.  Usage #packets in: 27 forwarded: 0 out: 0. Current clients: 18 max: 19
                $left = substr($info,29);
                if ($left =~ /^(.+)\@mpserver(\d{2})\s+after\s+(\d+)\s+seconds/) {
                    $pilot = $1;
                    $serv  = $2;
                    $sec   = $3;
                    $type = 3;
                } elsif ($left =~ /^(.+)\@LOCAL\s+after\s+(\d+)\s+seconds/) {
                    $pilot = $1;
                    $sec   = $2;
                    $type = 4;
                } else {
                    if ($issue_warnings) {
                        prtw("WARNING:$lnn: left [$left] FAILED\n");
                    } else {
                        prt("$lnn: left [$left] FAILED\n");
                    }
                }
            } else {
                if ($info =~ /^\#/) {
                    if ($info =~ /^\#\s+This\s+is\s+(.+)$/) {
                        my $sn = $1;
                        # my @as = ();
                        # if (parse_time_string($prev_time,\@as))
                        # ${$rparams}{'START_STOP_TIMES'} = \%start_stop;
                        my $rth = ${$rparams}{'START_STOP_TIMES'};
                        if (length($prev_time)) {
                            ${$rth}{$prev_time} = "stopped $sn";
                        }
                        ${$rth}{$time} = "started $sn";
                    } elsif ($info =~ /Main server started!/) {
                        $clients = 0;   # on server start, clear all clients
                    }
                } elsif ($info =~ /Main server started!/) {
                    $clients = 0;
                } elsif ($info =~ /^Got STAT file /) {
                    # Got STAT file /tmp/fgms_stat
                } elsif ($info =~ /^Pilots (\d+)$/) {
                } elsif ($info =~ /^Total: Packets /) {
                    # Total: Packets 0 BL=0 INV=0 UR=0 PD=0 Telnet 0
                } elsif ($info =~ /^Since: Packets /) {
                    # Since: Packets 0 BL=0 INV=0 UR=0 PD=0 Telnet 0
                } elsif ($info =~ /^Got EXIT file : /) {
                    # Got EXIT file : /tmp/fgms_exit
                } elsif ($info =~ /^FG_SERVER::Done/) {
                    # FG_SERVER::Done() - exiting
                    $clients = 0;   # on EXIT, clear all clients
                } else {
                    if ($issue_warnings) {
                        prtw("WARNING:$lnn: uncased [$info]\n");
                    } else {
                        prt("$lnn: uncased [$info]\n");
                    }
                }
            }
        } else {
            if ($issue_warnings) {
                prtw("WARNING:$lnn: [$time] time regex FAILED\n");
            } else {
                prt("$lnn: [$time] time regex FAILED\n");
            }
        }
        if ($type) {
            $pilot = modify_callsign($pilot);
            if (($type == 1)||($type == 2)) {
                # JOINING PLAYER
                if (length($air) && ($air =~ /\W+/)) {
                    @arr = split("/",$air);
                    $air = $arr[-1];
                    if ($air =~ /^(.+)\.xml$/) {
                        $ac = $1;
                    } elsif ($air =~ /^(.+)\.ac$/) {
                        $ac = $1;
                    } else {
                        $ac = 'Unlisted';
                        prtw("WARNING: Regex no aircraft from [$join]\n");
                    }
                } else {
                    $ac = '<blank>';
                    # no warning about a BLANK
                    # prtw("WARNING: No aircraft from [$join]\n");
                }

                ${$ractive}{$pilot} = [$ac,$time]; # add to active list by pilot [$ac,$time]
                ${$rparams}{'JOINED_CNT'}++;
                $jcnt++;
                $jmcnt++;
                $jwcnt++;
                # add to MASTER LIST
                # ==================
                ${$rpth}{$pilot} = 0 if (! defined ${$rpth}{$pilot});
                ${$rpah}{$pilot} = {} if (! defined ${$rpah}{$pilot});
                ${$rath}{$ac} = 0 if (! defined ${$rath}{$ac});
                $rh = ${$rpah}{$pilot};
                ${$rh}{$ac} = 0 if (! defined ${$rh}{$ac} );
                ${$rplh}{$pilot} = $ac;
                ${$rptbh}{$pilot} = $time;  # time flight began
                ${$raph}{$ac} = {} if (! defined ${$raph}{$ac});
                $rh = ${$raph}{$ac};
                ${$rh}{$pilot} = $ac;

                # add to MONTH LIST
                # ==================
                if ($write_month_files) {
                    ${$rmpth}{$pilot} = 0 if (! defined ${$rmpth}{$pilot});
                    ${$rmpah}{$pilot} = {} if (! defined ${$rmpah}{$pilot});
                    ${$rmath}{$ac} = 0 if (! defined ${$rmath}{$ac});
                    $rh = ${$rmpah}{$pilot};
                    ${$rh}{$ac} = 0 if (! defined ${$rh}{$ac} );
                    ${$rmplh}{$pilot} = $ac;
                    ${$rmptbh}{$pilot} = $time;  # time flight began
                    ${$rmaph}{$ac} = {} if (! defined ${$rmaph}{$ac});
                    $rh = ${$rmaph}{$ac};
                    ${$rh}{$pilot} = $ac;
                }

                # add to WEEK LIST
                # ==================
                if ($write_week_files) {
                    ${$rwpth}{$pilot} = 0 if (! defined ${$rwpth}{$pilot});
                    ${$rwpah}{$pilot} = {} if (! defined ${$rwpah}{$pilot});
                    ${$rwath}{$ac} = 0 if (! defined ${$rwath}{$ac});
                    $rh = ${$rwpah}{$pilot};
                    ${$rh}{$ac} = 0 if (! defined ${$rh}{$ac} );
                    ${$rwplh}{$pilot} = $ac;    # store current AIRCRAFT
                    ${$rwptbh}{$pilot} = $time;  # time flight began
                    ${$rwaph}{$ac} = {} if (! defined ${$rwaph}{$ac});
                    $rh = ${$rwaph}{$ac};
                    ${$rh}{$pilot} = $ac;
                }
                $clients++;
                $max_clients = $clients if ($clients > $max_clients);
            } elsif (($type == 3)||($type == 4)) {
                # EXPIRED PLAYER
                ${$rparams}{'EXPIRED_CNT'}++; # expired counter
                $ecnt++;
                $emcnt++;
                $ewcnt++;
                if (defined ${$ractive}{$pilot}) {
                    delete ${$ractive}{$pilot}; # take pilot OUT of active list
                } else {
                    prtw("WARNING:$lnn: Pilot [$pilot] expired, but NOT in active list!\n") if ($show_not_in_alist || VERB9());
                }

                # close for MASTER list
                if (defined ${$rpth}{$pilot}) {
                    ${$rpth}{$pilot} += $sec; # accumulatet time for pilot
                } else {
                    prtw("WARNING:$lnn: Dropping undefined pilot! [$info]\n");
                }
                if (defined ${$rpah}{$pilot} && defined ${$rplh}{$pilot}) {
                    $ac = ${$rplh}{$pilot}; # get a/c [s]he joined with
                    $rh = ${$rpah}{$pilot};
                    if (defined ${$rh}{$ac}) {
                        ${$rh}{$ac} += $sec;    # accumulate time in this aircraft for this pilot
                    } else {
                        prtw("WARNING: Aircraft [$ac] was not defined in pilot [$pilot] ref hash!\n");
                        ${$rh}{$ac} = $sec;     # well set the time
                    }
                    if (defined ${$rath}{$ac}) {
                        ${$rath}{$ac} += $sec;
                    } else {
                        prtw("WARNING: Aircraft [$ac] was not defined in aircraft ref hash!\n");
                        ${$rath}{$ac} = $sec;
                    }
                } else {
                    prtw("WARNING: pilot [$pilot] not defined in aircraft or last hashes!\n");
                }

                # close for MONTH list
                if ($write_month_files) {
                    if (defined ${$rmpth}{$pilot}) {
                        ${$rmpth}{$pilot} += $sec;
                    } else {
                        prtw("WARNING:$lnn:M: Dropping undefined pilot! [$info]\n");
                    }
                    if (defined ${$rmpah}{$pilot} && defined ${$rmplh}{$pilot}) {
                        $ac = ${$rmplh}{$pilot};
                        $rh = ${$rmpah}{$pilot};
                        if (defined ${$rh}{$ac}) {
                            ${$rh}{$ac} += $sec;
                        } else {
                            prtw("WARNING:M: Aircraft [$ac] was not defined in pilot [$pilot] ref hash!\n");
                            ${$rh}{$ac} = $sec;
                        }
                        if (defined ${$rmath}{$ac}) {
                            ${$rmath}{$ac} += $sec;
                        } else {
                            prtw("WARNING:M: Aircraft [$ac] was not defined in aircraft ref hash!\n");
                            ${$rmath}{$ac} = $sec;
                        }
                    } else {
                        prtw("WARNING:M: pilot [$pilot] not defined in aircraft or last hashes!\n");
                    }
                }

                # close for WEEK list
                if ($write_week_files) {
                    if (defined ${$rwpth}{$pilot}) {
                        ${$rwpth}{$pilot} += $sec;
                    } else {
                        prtw("WARNING:$lnn:W: Dropping undefined pilot! [$info]\n");
                    }
                    if (defined ${$rwpah}{$pilot} && defined ${$rwplh}{$pilot}) {
                        $ac = ${$rwplh}{$pilot};    # get last AIRCRAFT by pilot
                        $rh = ${$rwpah}{$pilot};
                        if (defined ${$rh}{$ac}) {
                            ${$rh}{$ac} += $sec;
                        } else {
                            # prtw("WARNING:W: Aircraft [$ac] was not defined in pilot [$pilot] ref hash!\n");
                            ${$rh}{$ac} = $sec;
                        }
                        if (defined ${$rwath}{$ac}) {
                            ${$rwath}{$ac} += $sec;
                        } else {
                            prtw("WARNING:W: Aircraft [$ac] was not defined in aircraft ref hash!\n");
                            ${$rwath}{$ac} = $sec;
                        }
                        # prt("Added $sec to aircraft [$ac], under pilot [$pilot]\n");
                    } else {
                        prtw("WARNING:W: pilot [$pilot] not defined in aircraft or last hashes!\n");
                    }
                }
                if ($clients) {
                    $clients--;
                } else {
                    if ($issue_warnings) {
                        prtw("WARNING:$lnn: Dropped pilot [$pilot] [$ac] but none in server!\n");
                    } else {
                        prt("$lnn: Dropped pilot [$pilot] [$ac] but none in server!\n");
                    }
                }
            }
        }
    }

    my $tecnt = ${$rparams}{'EXPIRED_CNT'};
    my $tjcnt = ${$rparams}{'JOINED_CNT'};
    prt("Done $lncnt lines, from [$inf]... Total/In file  $tjcnt/$jcnt joined, $tecnt/$ecnt expired\n");
    prt("Have $clients pilots now, had max of $max_clients at one time\n");
    # update counters
    ${$r_clients} = $clients;
    ${$r_max_clients} = $max_clients;
    ${$r_last_week} = $last_week;
    ${$r_last_month} = $last_month;
    ${$rparams}{'CURR_PREV_TIME'} = $prev_time;
}

sub output_json6($$$$$$) {
    my ($rperlh,$rph,$rah,$out_comb,$out_air,$out_pilot) = @_;

    my ($msg,$n,$d);
    my $acnt = scalar keys(%{$rah});
    my $pcnt = scalar keys(%{$rph});
    if (($pcnt == 0)&&($acnt == 0)) {
        prt("No JSON written due to ZERO pilots and aircraft!\n");
        return;
    }

    $msg = '';
    my $json = JSON::XS->new->pretty(1)->encode($rperlh);
    if ($out_comb && length($out_comb)) {
        write2file($json."\n",$out_comb);
        prt("Comined JSON written to [$out_comb]\n") if (VERB9());
        ($n,$d) = fileparse($out_comb);
        $msg .= "$n ";
    } else {
        prt("No OUTPUT file given! Use -o file\n");
        prt("\n$json\n");
    }

    if ($out_air && length($out_air)) {
        my %ah = ();
        $ah{'aircraft'} = $rah;
        $json = JSON::XS->new->pretty(1)->encode(\%ah);
        write2file($json,$out_air);
        prt("Aircraft JSON written to [$out_air]\n") if (VERB9());
        ($n,$d) = fileparse($out_comb);
        $msg .= "$n ";
    }

    if ($out_pilot && length($out_pilot)) {
        my %ph = ();
        $ph{'pilots'} = $rph;
        $json = JSON::XS->new->pretty(1)->encode(\%ph);
        write2file($json,$out_pilot);
        prt("Pilots JSON written to [$out_pilot]\n") if (VERB9());
        ($n,$d) = fileparse($out_comb);
        $msg .= "$n ";
    }
    if (length($msg)) {
        prt("Written JSON files $msg\n");
    } else {
        prt("NO JSON files written!\n");
    }
}

sub output_json($) {
    my $rparams = shift;
    my $rperlh = ${$rparams}{'H_PERL_SCALAR'};
    my $rph = ${$rperlh}{'pilots'};
    my $rah = ${$rperlh}{'aircraft'};

    my $out_comb  = ${$rparams}{'FILE_COMBINED'};
    my $out_air   = ${$rparams}{'FILE_ARICRAFT'};
    my $out_pilot = ${$rparams}{'FILE_PILOTS'};
    output_json6($rperlh,$rph,$rah,$out_comb,$out_air,$out_pilot);
}

sub check_total_times($$) {
    my ($rpth,$rath) = @_;
    my ($pcnt,$acnt,$ttp,$tta,$ttp2,$tta2,@arr,$sec,$pilot,$ac,$pcnt2,$acnt2);
    $pcnt2 = 0;
    $acnt2 = 0;
    $ttp = 0;
    $ttp2 = 0;
    @arr = keys(%{$rpth});
    $pcnt = scalar @arr;
    foreach $pilot (@arr) {
        $sec = ${$rpth}{$pilot};
        $ttp += $sec;
        next if ($filter_by_minsecs && ($sec <= $min_secs));
        $ttp2 += $sec;
        $pcnt2++;
    }
    $tta = 0;
    $tta2 = 0;
    @arr = keys(%{$rath});
    $acnt = scalar @arr;
    foreach $ac (@arr) {
        $sec = ${$rath}{$ac};
        $tta += $sec;
        next if ($filter_by_minsecs && ($sec <= $min_secs));
        $tta2 += $sec;
        $acnt2++;
    }
    if ($filter_by_minsecs) {
        prt("pilots $pcnt, tot $ttp, filt $ttp2 - aircraft $acnt, tot $tta, filt $tta2, filt. by $min_secs min.secs flown\n");
    } else {
        prt("pilots $pcnt, tot $ttp - aircraft $acnt, tot $tta.\n");
    }
    return ($pcnt2 + $acnt2);
}

sub sort_results8($$$$$$$$) {
    my ($rpth,$rpah,$rplh,$rath,$raph,$rperlh,$rph,$rah) = @_;

    prt("\n");
    my ($pilot,$sec,$cnt,@arr);
    my ($rh,$ac,$min);
    my ($tm,$i,$msg,$sec2,$tm2,$len);
    my ($i2,$cnt2,$rh2,$msg2);
    my ($cnt3,$cnt4,$tsecs,$tloads);
    my ($dpilot,$dac);
    my (@arr3);
    my @pilots_time = ();
    my @air_times = ();

    ####################################################
    ### List 1 - Pilots and the aircraft flown
    ####################################################
    @arr = sort keys(%{$rpth});
    $cnt2 = scalar @arr;
    $msg = "Had $cnt2 pilots... ";
    foreach $pilot (@arr) {
        $sec = ${$rpth}{$pilot};
        next if ($filter_by_minsecs && ($sec <= $min_secs));
        push(@pilots_time, [$sec, $pilot]);
        $tm = secs_to_DAYS_HHMMSS($sec);
        $pilot .= ' ' while (length($pilot) < 7);
    }
    $cnt = scalar @pilots_time;
    if ($filter_by_minsecs) {
        $msg .= "but only $cnt greater than min.secs $min_secs";
    }
    prt("$msg\n");
    @pilots_time = sort by_time @pilots_time;
    $cnt3 = 0;
    for ($i = 0; $i < $cnt; $i++) {
        $sec = $pilots_time[$i][0];
        $pilot = $pilots_time[$i][1];
        $msg = "a/c unknown";
        $cnt2 = 0;
        if (defined ${$rpah}{$pilot}) {
            $rh = ${$rpah}{$pilot}; # get aircraft used by this pilot
            $msg = '';
            @arr = ();
            $tloads = 0;
            foreach $ac (keys %{$rh}) {
                $sec2 = ${$rh}{$ac};
                $tloads++;
                next if ($filter_by_minsecs && ($sec2 <= $min_secs));
                push(@arr, [$sec2,$ac]);
            }
            @arr = sort by_time @arr;
            $cnt2 = scalar @arr;
            @arr3 = ();
            $tsecs = 0;
            for ($i2 = 0; $i2 < $cnt2; $i2++) {
                $sec2 = $arr[$i2][0];
                $ac   = $arr[$i2][1];
                my %h2 = ();
                $h2{'aircraft'} = $ac;
                $h2{'time'} = $sec2;
                push(@arr3,\%h2);
                $tsecs += $sec2;
                $tm2 = secs_to_DAYS_HHMMSS($sec2);
                $msg .= ", " if (length($msg));
                $msg .= "$ac $tm2";
            }
            #foreach $ac (sort keys %{$rh}) {
            #    $sec2 = ${$rh}{$ac};
            #    $tm2 = secs_to_DAYS_HHMMSS($sec2);
            #    $msg .= ", " if (length($msg));
            #    $msg .= "$ac $tm2";
            #}
        }
        $tm = secs_to_DAYS_HHMMSS($sec);
        $dpilot = $pilot;
        $dpilot .= ' ' while (length($dpilot) < 7);
        if ($cnt2) {    # only show if a/c flown above min.secs
            prt("Pilot: $dpilot $tm $msg\n") if (VERB5());
            ${$rph}{$pilot}{'total_time'} = $tsecs;
            ${$rph}{$pilot}{'total_connected'} = $sec;
            ${$rph}{$pilot}{'total_aircraft'} = $cnt2;
            ${$rph}{$pilot}{'total_loads'} = $tloads;
            ###${$rph}{$pilot}{'aircraft'} = [ @arr ];
            ${$rph}{$pilot}{'aircraft'} = [ @arr3 ];   # add in a label
            $cnt3++;
        }
    }
    @arr = keys(%{$rpth});
    $cnt2 = scalar @arr;
    prt("Shown $cnt3 of $cnt2 pilots, and the aircraft flown...\n");
    #============================================================

    #############################################################
    ### List 2 - Aircraft flown, and by whom
    #############################################################
    @arr = sort keys(%{$rath});
    $cnt2 = scalar @arr;
    $msg = "They used $cnt2 different aircraft... ";
    $min = 0;
    foreach $ac (@arr) {
        $sec = ${$rath}{$ac};
        next if ($filter_by_minsecs && ($sec <= $min_secs));
        push(@air_times, [$sec,$ac]);
        $len = length($ac);
        $min = $len if ($len > $min);
    }

    @air_times = sort by_time @air_times;
    $cnt = scalar @air_times;
    if ($cnt < $cnt2) {
        $msg .= "but only $cnt flown above $min_secs min. secs...";
    }
    prt("\n$msg\n");
    $cnt4 = 0;
    for ($i = 0; $i < $cnt; $i++) {
        $sec = $air_times[$i][0];
        $ac = $air_times[$i][1];
        $msg = "pilots unknown";
        $msg2 = '';
        $cnt3 = 0;
        if ( defined ${$raph}{$ac} ) {
            $rh = ${$raph}{$ac};
            $cnt2 = scalar keys(%{$rh});
            $msg2 = "By $cnt2 pilots - ";
            $msg = '';
            # this gives us a list of pilots who flew this aircraft
            #foreach $pilot (keys %{$rh}) {
            #    # now to get his/her TIME in this a/c
            #    $msg .= ", " if (length($msg));
            #    $msg .= $pilot;
            #    if (defined ${$rpah}{$pilot}) {
            #        $rh2 = ${$rpah}{$pilot}; # get aircraft used by this pilot
            #        if (defined ${$rh2}{$ac}) {
            #            $sec2 = ${$rh2}{$ac};
            #            $tm2 = secs_to_DAYS_HHMMSS($sec2);
            #            $msg .= " $tm2";
            #        }
            #    }
            #}
            # but it shuld be by TIME also
            @arr = ();
            $tloads = 0;
            foreach $pilot (keys %{$rh}) {
                if (defined ${$rpah}{$pilot}) {
                    $rh2 = ${$rpah}{$pilot}; # get aircraft used by this pilot
                    if (defined ${$rh2}{$ac}) {
                        $sec2 = ${$rh2}{$ac};
                        $tloads++;
                        next if ($filter_by_minsecs && ($sec2 <= $min_secs));
                        push(@arr,[$sec2,$pilot]);
                    }
                }
            }
            @arr = sort by_time @arr;
            $cnt2 = scalar @arr;
            @arr3 = ();
            $tsecs = 0;
            for ($i2 = 0; $i2 < $cnt2; $i2++) {
                $sec2  = $arr[$i2][0];
                $pilot = $arr[$i2][1];
                my %h3 = ();
                $h3{'pilot'} = $pilot;
                $h3{'time'} = $sec2;
                $tsecs += $sec2;
                $tm2 = secs_to_DAYS_HHMMSS($sec2);
                $msg .= ", " if (length($msg));
                $cnt3++;
                $msg .= "$cnt3: $pilot $tm2";
                push(@arr3,\%h3);
            }
        }
        $tm = secs_to_DAYS_HHMMSS($sec);
        $dac = $ac;
        $dac .= ' ' while (length($dac) < $min);
        if ($cnt3) {
            prt("$dac $tm $msg2 $msg\n") if (VERB5());
            ${$rah}{$ac}{'total_time'} = $tsecs;    # seconds flown, if above min_secs
            ${$rah}{$ac}{'total_connected'} = $sec; # total of ALL connections
            ${$rah}{$ac}{'total_pilots'} = $cnt3; 
            ${$rah}{$ac}{'total_loads'} = $tloads;  # total times this aircraft seen
            #${$rah}{$ac}{'pilots'} = [ @arr ];
            ${$rah}{$ac}{'pilots'} = [ @arr3 ];
            $cnt4++;
        }
    }
    @arr = sort keys(%{$rath});
    $cnt2 = scalar @arr;
    prt("Shown $cnt4 of $cnt2 aircraft, and the pilots who flew them, both in time order.\n");

    #########################################################
    ### Any other lists???
    #########################################################
    
}

sub sort_results($) {
    my $rparams = shift;
    my $rpth = ${$rparams}{'H_PILOT_TIME'};
    my $rpah = ${$rparams}{'H_PILOT_AIR'};
    my $rplh = ${$rparams}{'H_PILOT_LAST'};
    my $rath = ${$rparams}{'H_AIR_TIME'};
    my $raph = ${$rparams}{'H_AIR_PILOT'};

    my $rperlh = ${$rparams}{'H_PERL_SCALAR'};
    my $rph = ${$rperlh}{'pilots'};
    my $rah = ${$rperlh}{'aircraft'};

    my $ractive = ${$rparams}{'CURR_ACTIVE'};
    my $acnt = scalar keys(%{$ractive});
    extend_times_of_active($rparams,0) if ($acnt && $extend_active_tm);
    sort_results8($rpth,$rpah,$rplh,$rath,$raph,$rperlh,$rph,$rah);
}

sub set_month_hashes($) {
    my $rparams = shift;
    my %m_pilot_time = ();
    my %m_pilot_air = ();
    my %m_pilot_last = ();
    my %m_pilot_begin = ();
    my %m_ac_time = ();
    my %m_ac_pilot = ();
    my %m_perl_scalar = ();
    my $rmpth   = \%m_pilot_time;
    my $rmpah   = \%m_pilot_air;
    my $rmplh   = \%m_pilot_last;
    my $rmath   = \%m_ac_time;
    my $rmaph   = \%m_ac_pilot;
    my $rmptbh  = \%m_pilot_begin;
    ${$rparams}{'M_PILOT_TIME'}  = $rmpth;
    ${$rparams}{'M_PILOT_AIR'}   = $rmpah;
    ${$rparams}{'M_PILOT_LAST'}  = $rmplh;
    ${$rparams}{'M_AIR_TIME'}    = $rmath;
    ${$rparams}{'M_AIR_PILOT'}   = $rmaph;
    ${$rparams}{'M_PILOT_BEGIN'} = $rmptbh;

    my $rmperlh = \%m_perl_scalar;
    my %mph = ();
    my %mah = ();
    ${$rmperlh}{'pilots'}    = \%mph;
    ${$rmperlh}{'aircraft'} = \%mah;
    ${$rparams}{'M_PERL_SCALAR'} = $rmperlh;
}

sub set_week_hashes($) {
    my $rparams = shift;
    my %w_pilot_time = ();
    my %w_pilot_air = ();
    my %w_pilot_last = ();
    my %w_pilot_begin = ();
    my %w_ac_time = ();
    my %w_ac_pilot = ();
    my %w_perl_scalar = ();
    my $rwpth   = \%w_pilot_time;
    my $rwpah   = \%w_pilot_air;
    my $rwplh   = \%w_pilot_last;
    my $rwath   = \%w_ac_time;
    my $rwaph   = \%w_ac_pilot;
    my $rwptbh  = \%w_pilot_begin;

    ${$rparams}{'W_PILOT_TIME'}  = $rwpth;
    ${$rparams}{'W_PILOT_AIR'}   = $rwpah;
    ${$rparams}{'W_PILOT_LAST'}  = $rwplh;
    ${$rparams}{'W_AIR_TIME'}    = $rwath;
    ${$rparams}{'W_AIR_PILOT'}   = $rwaph;
    ${$rparams}{'W_PILOT_BEGIN'} = $rwptbh;

    my $rwperlh = \%w_perl_scalar;
    my %wph = ();
    my %wah = ();
    ${$rwperlh}{'pilots'}    = \%wph;
    ${$rwperlh}{'aircraft'} = \%wah;
    ${$rparams}{'W_PERL_SCALAR'} = $rwperlh;

}

# ${$rparams}{'START_STOP_TIMES'} = \%start_stop;
sub show_start_stop($) {
    my $rparams = shift;
    my $rth = ${$rparams}{'START_STOP_TIMES'};
    my @arr = keys(%{$rth});
    my ($key,$val,$cnt,$ts,$k,$pkey,$msg,$pval,$tcnt);
    $cnt = scalar @arr;
    prt("Display of $cnt starts/stops of the server...\n");
    my %h = ();
    foreach $key (@arr) {
        $val = ${$rth}{$key};
        if (get_time_stamp($key,\$ts)) {
            $h{$ts} = $key;
        } else {
            prtw("WARNING: Time string [$key] did NOT yield a timestamp!\n");
        }
    }
    @arr = sort keys(%h);
    $ts = 0;
    $pval = '';
    $cnt = scalar @arr;
    $tcnt = 0;
    my $add_html = ($write_html && $cnt) ? 1 : 0;
    if ($add_html) {
        $html .= "<table align=\"center\">\n";
        $html .= "<caption><b>Server running times<b></caption>\n";
    }
    foreach $k (@arr) {
        $tcnt++;
        $key = $h{$k};
        $val = ${$rth}{$key};
        $msg = '';
        if (($val =~ /stopped\s+/)&&($pval =~ /started\s+/)&&($ts > 0)) {
            $msg = " ran for ".secs_to_DAYS_HHMMSS($k - $ts);
        } elsif (($tcnt == $cnt)&&($val =~ /started\s+/)) {
            $msg = " running for ".secs_to_DAYS_HHMMSS(time() - $k);
        }
        prt("$key $val $msg\n");
        $ts = $k;   # keep previous
        $pval = $val;
        if ($add_html) {
            $html .= "<tr><td>$key</td><td>$val</td><td>$msg</td></tr>\n";
        }
    }
    if ($add_html) {
        $html .= "</table>\n";
        $html .= get_top_link();
    }
}

sub get_header() {
    my $head = <<EOF;
<html>
<head>
<title>fgms log info</title>
</head>
<body>
<a name="top" id="top"></a>
<h1 align="center">Analysis of fgms logs</h1>
<p>A simple analysis of fgms logged data. Callsigns have been modified to only include
alpha-numeric characters, and shown in uppercase. Flying time less than about 10 
minutes have been discarded. Pilots active at the end of the period have had their 
time extended to the end of that period. Table listings are ordered by time.
</p>

EOF
    return $head;
}

sub get_tail() {
    my $tail = <<EOF;
</body>
</html>

EOF
    return $tail;
}

sub write_html() {
    return if (length($html) == 0);
    my $txt = get_header();
    $txt .= $html;
    $txt .= get_tail();
    write2file($txt,$html_out);
    prt("HTML text written to [$html_out]\n");
}

sub process_in_files() {
    my $begin = [ gettimeofday ];
    my %pilot_time = ();
    my %pilot_air = ();
    my %pilot_last = ();
    my %pilot_begin = ();
    my %ac_time = ();
    my %ac_pilot = ();
    my %perl_scalar = ();

    my $rpth = \%pilot_time;
    my $rpah = \%pilot_air;
    my $rplh = \%pilot_last;
    my $rath = \%ac_time;
    my $raph = \%ac_pilot;
    my $rptbh = \%pilot_begin;

    my $rperlh = \%perl_scalar;
    my %ph = ();
    my %ah = ();
    ${$rperlh}{'pilots'} = \%ph;
    ${$rperlh}{'aircraft'} = \%ah;

    my %hash = ();
    my $rparams = \%hash;
    my $clients = 0;
    my $max_clients = 0;
    my $last_week = -1;
    my $last_month = -1;

    ${$rparams}{'H_PILOT_TIME'}  = $rpth;
    ${$rparams}{'H_PILOT_AIR'}   = $rpah;
    ${$rparams}{'H_PILOT_LAST'}  = $rplh;
    ${$rparams}{'H_AIR_TIME'}    = $rath;
    ${$rparams}{'H_AIR_PILOT'}   = $raph;
    ${$rparams}{'H_PILOT_BEGIN'} = $rptbh;

    my %active_pilots = ();
    my $ractive = \%active_pilots;  # by pilot [$ac,$time]
    ${$rparams}{'CURR_ACTIVE'} = $ractive;

    ${$rparams}{'H_PERL_SCALAR'} = $rperlh;

    set_month_hashes($rparams);
    set_week_hashes($rparams);

    ${$rparams}{'R_CLIENTS'} = \$clients;
    ${$rparams}{'R_MAX_CLIENTS'} = \$max_clients;
    ${$rparams}{'R_LAST_WEEK'} = \$last_week;
    ${$rparams}{'R_LAST_MONTH'} = \$last_month;
    ${$rparams}{'JOINED_CNT'} = 0;
    ${$rparams}{'EXPIRED_CNT'} = 0;
    ${$rparams}{'CURR_EVENT'} = "main";
    ${$rparams}{'CURR_TIME'} = '';
    ${$rparams}{'PREV_TIME'} = '';

    ${$rparams}{'CURR_PREV_TIME'} = '';
    my %start_stop = ();
    ${$rparams}{'START_STOP_TIMES'} = \%start_stop;

    foreach $in_file (@in_files) {
        ${$rparams}{'CURRENT_FILE'} = $in_file;
        ###process_in_file($in_file, $rpth, $rpah, $rplh, $rath, $raph);
        process_in_file($rparams);
    }

    do_end_week($rparams);
    do_end_month($rparams);

    my $end = [ gettimeofday ];
    sort_results($rparams);

    ${$rparams}{'FILE_COMBINED'} = $out_path.'\combined.json';
    ${$rparams}{'FILE_ARICRAFT'} = $out_path.'\aircraft.json';
    ${$rparams}{'FILE_PILOTS'}   = $out_path.'\pilots.json';
    output_json($rparams);

    show_start_stop($rparams);
    write_html();
    my $interval = tv_interval( $begin, $end );
    prt("Log read took $interval seconds ...\n");

}

########################################
### MAIN ###
### test_time();
parse_args(@ARGV);
###process_in_file($in_file);
process_in_files();

pgm_exit(0,"");
########################################
sub give_help {
    prt("$pgmname: version $VERS\n");
    prt("Usage: $pgmname [options] in-file\n");
    prt("Options:\n");
    prt(" --help  (-h or -?) = This help, and exit 0.\n");
    prt(" --verb[n]     (-v) = Bump [or set] verbosity. def=$verbosity\n");
    prt(" --load        (-l) = Load LOG at end. ($outfile)\n");
    prt(" --out <file>  (-o) = Write output to this file.\n");
}

sub need_arg {
    my ($arg,@av) = @_;
    pgm_exit(1,"ERROR: [$arg] must have a following argument!\n") if (!@av);
}

sub parse_args {
    my (@av) = @_;
    my ($arg,$sarg);
    while (@av) {
        $arg = $av[0];
        if ($arg =~ /^-/) {
            $sarg = substr($arg,1);
            $sarg = substr($sarg,1) while ($sarg =~ /^-/);
            if (($sarg =~ /^h/i)||($sarg eq '?')) {
                give_help();
                pgm_exit(0,"Help exit(0)");
            } elsif ($sarg =~ /^v/) {
                if ($sarg =~ /^v.*(\d+)$/) {
                    $verbosity = $1;
                } else {
                    while ($sarg =~ /^v/) {
                        $verbosity++;
                        $sarg = substr($sarg,1);
                    }
                }
                prt("Verbosity = $verbosity\n") if (VERB1());
            } elsif ($sarg =~ /^l/) {
                $load_log = 1;
                prt("Set to load log at end.\n") if (VERB1());
            } elsif ($sarg =~ /^o/) {
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                $out_json = $sarg;
                prt("Set out file to [$out_json].\n") if (VERB1());
            } else {
                pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n");
            }
        } else {
            $in_file = $arg;
            push(@in_files,$in_file);
            prt("Add to input [$in_file]\n") if (VERB1());
        }
        shift @av;
    }

    if ((length($in_file) ==  0) && $debug_on) {
        $in_file = $def_file;
        push(@in_files,$def_file2);
        push(@in_files,$in_file);
        prt("Set DEFAULT input to [$in_file]\n");
        $load_log = 2;
    }
    if ((length($out_json) == 0) && $debug_on) {
        $out_json = $def_out;
    }
    if (length($in_file) ==  0) {
        pgm_exit(1,"ERROR: No input files found in command!\n");
    }
    if (! -f $in_file) {
        pgm_exit(1,"ERROR: Unable to find in file [$in_file]! Check name, location...\n");
    }
}

# eof - fgms-log.pl
