#!/usr/bin/perl -w
# NAME: cmpapfreqs.pl
# AIM: Give two apt.dat files, collect and compare frequencies listed for each airport
# handle 850 and 1000 apt.dat formats
use strict;
use warnings;
use File::Basename;  # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] )
use Cwd;
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";
require 'fg_wsg84.pl' or die "Unable to load fg_wsg84.pl ...\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.1 2013-03-17";
my $load_log = 0;
my $ap_file1 = 'C:\FG\fgdata\Airports\apt.dat.gz';
my $ap_file2 = 'D:\FG\xplane\1000\apt.dat';
my $verbosity = 0;
my $out_file = '';

# ### DEBUG ###
my $debug_on = 0;
my $def_file = 'def_file';

### program variables
my @warnings = ();
my $cwd = cwd();

my $max_lat_len = 0;
my $max_lon_len = 0;
my $max_alt_len = 0;
my $max_nam_len = 0;

my $bgntm = time();

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);
    my $secs = time() - $bgntm;
    prt("Ran for $secs seconds...\n");
    close_log($outfile,$load_log);
    exit($val);
}


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

sub process_in_file($) {
    my ($inf) = @_;
    if (! open INF, "<$inf") {
        pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); 
    }
    my @lines = <INF>;
    close INF;
    my $lncnt = scalar @lines;
    prt("Processing $lncnt lines, from [$inf]...\n");
    my ($line,$inc,$lnn);
    $lnn = 0;
    foreach $line (@lines) {
        chomp $line;
        $lnn++;
        if ($line =~ /\s*#\s*include\s+(.+)$/) {
            $inc = $1;
            prt("$lnn: $inc\n");
        }
    }
}
# versions line
# 12345678901234567890123456789012345678901234567890123456789012345678901
# 1000 Version - data cycle 2012.08,  build 20121293,  metadata AptXP1000
sub load_ap_file($$$) {
    my ($file,$rv,$rl) = @_;
    prt("Loading file $file... ");
    if ($file =~ /\.gz$/) {
        open IF, "gzip -d -c $file|" or pgm_exit(1, "ERROR: CAN NOT OPEN $file ... $!\n" );
    } else {
        open IF, "<$file" or pgm_exit(1, "ERROR: CAN NOT OPEN $file ... $!\n" );
    }
    my @lines = <IF>;
    close IF;
    my $cnt = scalar @lines;
    prt("got $cnt lines...\n");
    pgm_exit(1,"Invalid apt.dat file... too few lines...\n") if ($cnt < 4);
    my $line = $lines[1];
    chomp $line;
    if ($line =~ /^(\d+)\s+Version\s+/) {
        ${$rv} = $1;
        prt("Version $1\n");
    } else {
        pgm_exit(1,"Invalid apt.dat file... no version line...\n");
    }
    $line = substr($line,0,69);
    prt("$line\n");
    ${$rl} = $line;
    return \@lines;
}

sub in_world_range($$) {
    my ($lat,$lon) = @_;
    if (($lat <= 90)&&
        ($lat >= -90)&&
        ($lon <= 180)&&
        ($lon >= -180)) {
        return 1;
    }
    return 0;
}

# sort per ASCII in 2nd column - ICAO
sub mycmp_ascend_a1 {
   return -1 if (${$a}[1] lt ${$b}[1]);
   return  1 if (${$a}[1] gt ${$b}[1]);
   return  0;
}

# types of airport - of course some are mix, but 
my $land_type  = 1;
my $heli_type  = 2;  # has a '[H]' in name
my $sea_type   = 4;  # has a '[S]' in name
my $aband_type = 8;  # has a '[X]' in name


sub process_810_lines($) {
    my $ra = shift;
    my ($i,$lncnt,$line,@arr,$acnt,$type,$lnn,$apt,$len,@arr2);
    my ($aalt,$actl,$abld,$icao,$name,$alat,$alon,$glat,$glon);
    my ($rlat,$rlon,$rwyt,$rwycn,$ftyp,$cfrq,$frqn,$add,$rwycnt,$atyp);
    $lncnt = scalar @{$ra};
    prt("Process $lncnt lines in 810 format...\n");
    $lnn = 2;
    $apt = '';
    my @airports = ();
    my @runways = ();
    my @waterways = ();
    my @heliways = ();
    my @freqs = ();
    $glat = 0;
    $glon = 0;
    my $twrcount = 0;
    my $wscount = 0;
    my $freqcount = 0;
    for ($i = 2; $i < $lncnt; $i++) {
        $lnn++;
        $line = ${$ra}[$i];
        chomp $line;
        $line = trim_all($line);
        $len = length($line);
        next if ($len == 0);
        @arr = split(/\s+/,$line);
        $acnt = scalar @arr;
        $type = $arr[0];
        if ( !($type =~ /^\d+$/) ) {
            prt("WHAT IS THIS [$line]!\n");
            next;
        }
        if ($type == 99) {
            prt("$lnn: Last line...\n");
            last;
        }
        # 810 format
        if (($type == 1)||($type == 16)||($type == 17)) {	# start with 1, 16, 17
            # 0  1   2 3 4     
            # 17 126 0 0 EH0001 [H] VU medisch centrum
            # ID ALT C B NAME++
            if (length($apt)) {
                # deal with the previous airport
                @arr2 = split(/\s+/,$apt);
                $aalt = $arr2[1]; # Airport (general) ALTITUDE AMSL
                $actl = $arr2[2]; # control tower
                $abld = $arr2[3]; # buildings
                $icao = $arr2[4]; # ICAO
                $rwyt = $arr2[5];
                $name = join(' ', splice(@arr2,5)); # Name
                # decide if HELI OR SEAPLANE
                $atyp = $land_type;
                if ($name =~ /\[H\]/) {
                    @heliways = @runways;
                    @runways = ();
                    $atyp = $heli_type;
                } elsif ($name =~ /\[S\]/) {
                    @waterways = @runways;
                    @runways = ();
                    $atyp = $sea_type;
                }
                if ($name =~ /\[X\]/) {
                    $atyp |= $aband_type;
                }
                my @ra = @runways;
                my @wa = @waterways;
                my @ha = @heliways;
                my @fa = @freqs;
                $alat = 0;
                $alon = 0;
                my %info = ();
                $info{twrcount}  = $twrcount;
                $info{wscount}   = $wscount;
                $info{freqcount} = $freqcount;
                if ($rwycnt > 0) {
                    $alat = $glat / $rwycnt;
                    $alon = $glat / $rwycnt;
                } else {
                    prtw("WARNING: $lnn: Ap with NO runways!\n$apt\n");
                }
                #                0      1      2      3      4      5     6     7     8     9  10     11
                push(@airports, [$aalt, $icao, $name, $alat, $alon, \@ra, \@wa, \@ha, \@fa, 0, $atyp, \%info ]);
                # set up minimum display sizes
                $len = length($aalt);
                $max_alt_len = $len if ($len > $max_alt_len);
                $len = length($alat);
                $max_lat_len = $len if ($len > $max_lat_len);
                $len = length($alon);
                $max_lon_len = $len if ($len > $max_lon_len);
                $len = length($name);
                $max_nam_len = $len if ($len > $max_nam_len);
            }
            # start a NEW airport
            $apt = $line;
            @runways = ();  # clear RUNWAY list
            @waterways = ();
            @heliways = ();
            @freqs = (); # clear frequencies
            $glat = 0;
            $glon = 0;
            $rwycnt = 0;
            $twrcount = 0;
            $wscount = 0;
            $freqcount = 0;
        } elsif ($type == 10) {  # 810 format
            # 10  36.962213  127.031071 14x 131.52  8208 1595.0620 0000.0000   150 321321  1 0 3 0.25 0 0300.0300
            # 10  36.969145  127.020106 xxx 221.51   329 0.0 0.0    75 161161  1 0 0 0.25 0 
            $rlat = $arr[1];
            $rlon = $arr[2];
            $rwyt = $arr[3]; # text 'xxx'=taxiway, 'H1x'=heleport, else a runway
            ###prt( "$line [$rlat, $rlon]\n" );
            if ( $rwyt ne "xxx" ) {
                # $rwyt =~ s/x//g;    # remove trailing 'x'
                $glat += $rlat;
                $glon += $rlon;
                push(@runways, \@arr);
                $rwycnt++;
            }
        ###} elsif ($line =~ /^5(\d+)\s+/) {
        } elsif (($type >= 50)&&($type <= 56)) {
            # frequencies
            $ftyp = $type - 50;
            $cfrq = $arr[1];
            $frqn = $arr[2];
            $add = 0;
            if ($ftyp == 0) {
                $add = 1; # ATIS
            } elsif ($ftyp == 1) {
                $add = 1; # Unicom
            } elsif ($ftyp == 2) {
                $add = 1; # clearance
            } elsif ($ftyp == 3) {
                $add = 1; # ground
            } elsif ($ftyp == 4) {
                $add = 1; # tower
            } elsif ($ftyp == 5) {
                $add = 1; # approach
            } elsif ($ftyp == 6) {
                $add = 1; # departure
            } else {
                pgm_exit(1,"Unknown [$line]\n");
            }
            if ($add) {
                #push(@freqs, \@arr); # save the freq array
                push(@freqs, [@arr]); # save the freq array
                $freqcount++;
            } else {
                pgm_exit(1, "WHAT IS THIS [5$ftyp $cfrq $frqn] [$line]\n FIX ME!!!");
            }
        } elsif ($type == 14) {
            # tower location
            # 14  52.911007  156.878342    0 0 Tower Viewpoint
            $twrcount++;
        } elsif ($type == 15) {
            # ramp startup
        } elsif ($type == 18) {
            # Airport light beacon
        } elsif ($type == 19) {
            # Airport windsock
            # 19  52.911030  156.851840 1 WS
            $wscount++;
        } else {
            prt("FIX ME - LINE UNCASED $type\n");
            prt("$line\n");
            pgm_exit(1,"");
        }
        # 810 format
    }
    # get LAST
    if (length($apt)) {
        # deal with the previous airport
        @arr2 = split(/\s+/,$apt);
        $aalt = $arr2[1]; # Airport (general) ALTITUDE AMSL
        $actl = $arr2[2]; # control tower
        $abld = $arr2[3]; # buildings
        $icao = $arr2[4]; # ICAO
        $name = join(' ', splice(@arr2,5)); # Name
        # decide if HELI OR SEAPLANE
        $atyp = $land_type;
        if ($name =~ /\[H\]/) {
            @heliways = @runways;
            @runways = ();
            $atyp = $heli_type;
        } elsif ($name =~ /\[S\]/) {
            @waterways = @runways;
            @runways = ();
            $atyp = $sea_type;
        }
        if ($name =~ /\[X\]/) {
            $atyp |= $aband_type;
        }
        $alat = 0;
        $alon = 0;
        if ($rwycnt > 0) {
            $alat = $glat / $rwycnt;
            $alon = $glat / $rwycnt;
        } else {
            prtw("WARNING: $lnn: Ap with NO runways!\n$apt\n");
        }
        my @ra = @runways;
        my @wa = @waterways;
        my @ha = @heliways;
        my @fa = @freqs;
        my %info = ();
        $info{twrcount}  = $twrcount;
        $info{wscount}   = $wscount;
        $info{freqcount} = $freqcount;
        #                0      1      2      3      4      5     6     7     8     9  10     11
        push(@airports, [$aalt, $icao, $name, $alat, $alon, \@ra, \@wa, \@ha, \@fa, 0, $atyp, \%info ]);
        # set up minimum display sizes
        $len = length($aalt);
        $max_alt_len = $len if ($len > $max_alt_len);
        $len = length($alat);
        $max_lat_len = $len if ($len > $max_lat_len);
        $len = length($alon);
        $max_lon_len = $len if ($len > $max_lon_len);
        $len = length($name);
        $max_nam_len = $len if ($len > $max_nam_len);
    }
    @airports = sort mycmp_ascend_a1 @airports;
    $aalt = scalar @airports;
    prt("Collected $aalt airports...\n");
    my %h = ();
    $h{form} = 810;
    $h{apts} = \@airports;
    return \%h;
}

sub process_1000_lines($) {
    my $ra = shift;
    my ($i,$lncnt,$line,@arr,$acnt,$type,$lnn,$apt,$len,@arr2);
    my ($aalt,$actl,$abld,$icao,$name,$alat,$alon,$glat,$glon);
    my ($rlat1,$rlon1,$rlat2,$rlon2,$rlat,$rlon);
    my ($rwycnt,$wwcnt,$helicnt);
    my ($ftyp,$cfrq,$frqn,$add,$rwyt,$atyp);
    $lncnt = scalar @{$ra};
    prt("Process $lncnt lines in 1000 format...\n");
    $lnn = 2;
    $apt = '';
    my @airports = ();
    my @runways = ();
    my @waterways = ();
    my @heliways = ();
    my @freqs = ();
    my $twrcount = 0;
    my $wscount = 0;
    my $freqcount = 0;
    for ($i = 2; $i < $lncnt; $i++) {
        $lnn++;
        $line = ${$ra}[$i];
        chomp $line;
        next if ((length($line) == 0)||($line =~ /^\s+$/));
        @arr = split(/\s+/,$line);
        $acnt = scalar @arr;
        $type = $arr[0];
        if ( !($type =~ /^\d+$/) ) {
            prt("WHAT IS THIS [$line]!\n");
            next;
        }
        if ($type == 99) {
            prt("$lnn: Last line...\n");
            last;
        }
        # 1000 format
        if (($type == 1)||($type == 16)||($type == 17)) {	# start with 1, 16, 17
            # 0  1   2 3 4     
            # 17 126 0 0 EH0001 [H] VU medisch centrum
            # ID ALT C B NAME++
            if (length($apt)) {
                # deal with the previous airport
                @arr2 = split(/\s+/,$apt);
                $aalt = $arr2[1]; # Airport (general) ALTITUDE AMSL
                $actl = $arr2[2]; # control tower
                $abld = $arr2[3]; # buildings
                $icao = $arr2[4]; # ICAO
                $name = join(' ', splice(@arr2,5)); # Name
                $alat = 0;
                $alon = 0;
                $rwycnt += $wwcnt;
                $rwycnt += $helicnt;
                if ($rwycnt > 0) {
                    $alat = $glat / $rwycnt;
                    $alon = $glat / $rwycnt;
                } else {
                    prtw("WARNING: $lnn: Ap with NO runways!\n$apt\n");
                }
                # decide if HELI OR SEAPLANE
                $atyp = $land_type;
                if ($name =~ /\[H\]/) {
                    $atyp = $heli_type;
                } elsif ($name =~ /\[S\]/) {
                    $atyp = $sea_type;
                }
                if ($name =~ /\[X\]/) {
                    $atyp |= $aband_type;
                }
                my @ra = @runways;
                my @wa = @waterways;
                my @ha = @heliways;
                my @fa = @freqs;
                my %info = ();
                $info{twrcount}  = $twrcount;
                $info{wscount}   = $wscount;
                $info{freqcount} = $freqcount;
                #                0      1      2      3      4      5     6     7     8     9  10     11
                push(@airports, [$aalt, $icao, $name, $alat, $alon, \@ra, \@wa, \@ha, \@fa, 0, $atyp, \%info ]);
                # set up minimum display sizes
                $len = length($aalt);
                $max_alt_len = $len if ($len > $max_alt_len);
                $len = length($alat);
                $max_lat_len = $len if ($len > $max_lat_len);
                $len = length($alon);
                $max_lon_len = $len if ($len > $max_lon_len);
                $len = length($name);
                $max_nam_len = $len if ($len > $max_nam_len);
            }
            # start a NEW airport
            $apt = $line;
            @runways = ();  # clear RUNWAY list
            @freqs = (); # clear frequencies
            $glat = 0;
            $glon = 0;
            $rwycnt = 0;
            $wwcnt = 0;
            $helicnt = 0;
            $twrcount = 0;
            $wscount = 0;
            $freqcount = 0;
        } elsif ($type == 10) {
            # 10  36.962213  127.031071 14x 131.52  8208 1595.0620 0000.0000   150 321321  1 0 3 0.25 0 0300.0300
            # 10  36.969145  127.020106 xxx 221.51   329 0.0 0.0    75 161161  1 0 0 0.25 0 
            $rlat = $arr[1];
            $rlon = $arr[2];
            $rwyt = $arr[3]; # text 'xxx'=taxiway, 'H1x'=heleport, else a runway
            ###prt( "$line [$rlat, $rlon]\n" );
            if ( $rwyt ne "xxx" ) {
                # $rwyt =~ s/x//g;    # remove trailing 'x'
                $glat += $rlat;
                $glon += $rlon;
                push(@runways, \@arr);
                $rwycnt++;
            }
        } elsif ($type == 100) {
            #  0   1     2 3 4    5 6 7 8   9            10            11    12   13 14 15 16 17  18           19           20     21   22 23 24 25
            #  100 29.87 3 0 0.00 0 0 0 16  -24.20505300 151.89156100  0.00  0.00 1  0  0  0  34  -24.19732300 151.88585300 0.00   0.00 1  0  0  0
            #  100 29.87 1 0 0.15 0 2 1 13L 47.53801700  -122.30746100 73.15 0.00 2  0  0  1  31R 47.52919200 -122.30000000 110.95 0.00 2  0  0  1

            $rlat1 = $arr[9];  # $of_lat1
            $rlon1 = $arr[10]; # $of_lon1
            $rlat2 = $arr[18]; # $of_lat2
            $rlon2 = $arr[19]; # $of_lon2
            $rlat = ($rlat1 + $rlat2) / 2;
            $rlon = ($rlon1 + $rlon2) / 2;
            ###prt( "$line [$rlat, $rlon]\n" );
            $glat += $rlat;
            $glon += $rlon;
            my @a2 = @arr;
            push(@runways, \@a2);
            $rwycnt++;
        } elsif ($type == 101) {	# Water runways
            # 0   1      2 3  4           5             6  7           8
            # 101 243.84 0 16 29.27763293 -089.35826258 34 29.26458929 -089.35340410
            # 101 22.86  0 07 29.12988952 -089.39561501 25 29.13389936 -089.38060001
            # prt("$.: $line\n");
            $rlat1 = $arr[4];
            $rlon1 = $arr[5];
            $rlat2 = $arr[7];
            $rlon2 = $arr[8];
            $rlat = sprintf("%.8f",(($rlat1 + $rlat2) / 2));
            $rlon = sprintf("%.8f",(($rlon1 + $rlon2) / 2));
            if (!in_world_range($rlat,$rlon)) {
                prtw( "WARNING: $.: $line [$rlat, $rlon] NOT IN WORLD\n" );
                next;
            }
            $glat += $rlat;
            $glon += $rlon;
            my @a2 = @arr;
            push(@waterways, \@a2);
            $wwcnt++;
        } elsif ($type == 102) {	# Heliport
            # my $heli =   '102'; # Helipad
            # 0   1  2           3            4      5     6     7 8 9 10   11
            # 102 H2 52.48160046 013.39580674 355.00 18.90 18.90 2 0 0 0.00 0
            # 102 H3 52.48071507 013.39937648 2.64   13.11 13.11 1 0 0 0.00 0
            # prt("$.: $line\n");
            $rlat = sprintf("%.8f",$arr[2]);
            $rlon = sprintf("%.8f",$arr[3]);
            if (!in_world_range($rlat,$rlon)) {
                prtw( "WARNING: $.: $line [$rlat, $rlon] NOT IN WORLD\n" );
                next;
            }
            $glat += $rlat;
            $glon += $rlon;
            my @a2 = @arr;
            push(@heliways, \@a2);
            $helicnt++;
        } elsif (($type >= 50)&&($type <= 56)) {
            # frequencies
            $ftyp = $type - 50;
            $cfrq = $arr[1];
            $frqn = $arr[2];
            $add = 0;
            if ($ftyp == 0) {
                $add = 1; # ATIS
            } elsif ($ftyp == 1) {
                $add = 1; # Unicom
            } elsif ($ftyp == 2) {
                $add = 1; # clearance
            } elsif ($ftyp == 3) {
                $add = 1; # ground
            } elsif ($ftyp == 4) {
                $add = 1; # tower
            } elsif ($ftyp == 5) {
                $add = 1; # approach
            } elsif ($ftyp == 6) {
                $add = 1; # departure
            } else {
                pgm_exit(1,"Unknown [$line]\n");
            }
            if ($add) {
                ##push(@freqs, \@arr); # save the freq array
                push(@freqs, [@arr]); # save the freq array
                $freqcount++;
            } else {
                pgm_exit(1, "WHAT IS THIS [5$ftyp $cfrq $frqn] [$line]\n FIX ME!!!");
            }
        } elsif ($type == 110) {
            # 110 Pavement (taxiway or ramp) header Must form a closed loop
        } elsif ($type == 120) {
            # 120 Linear feature (painted line or light string) header Can form closed loop or simple string
        } elsif ($type == 130) {
            # 130 Airport boundary header Must form a closed loop
        } elsif ($type == 111) {
            # 111 Node All nodes can also include a “style” (line or lights)
        } elsif ($type == 112) {
            # 112 Node with Bezier control point Bezier control points define smooth curves
        } elsif ($type == 113) {
            # 113 Node with implicit close of loop Implied join to first node in chain
        } elsif ($type == 114) {
            # 114 Node with Bezier control point, with implicit close of loop Implied join to first node in chain
        } elsif ($type == 115) {
            # 115 Node terminating a string (no close loop) No “styles” used
        } elsif ($type == 116) {
            # 116 Node with Bezier control point, terminating a string (no close loop) No “styles” used
        } elsif ($type == 14) {
            # 14 Airport viewpoint One or none for each airport - TOWER?
            $twrcount++;
        } elsif ($type == 15) {
            # 15   Aeroplane startup location *** Convert these to new row code 1300 ***
        } elsif ($type == 18) {
            # 18 Airport light beacon One or none for each airport
        } elsif ($type == 19) {
            # 19 Windsock Zero, one or many for each airport
            $wscount++;
        } elsif ($type == 20) {
            # 20 Taxiway sign (inc. runway distance-remaining signs) Zero, one or many for each airport
        } elsif ($type == 21) {
            # 21 Lighting object (VASI, PAPI, Wig-Wag, etc.) Zero, one or many for each airport
        } elsif (($type >= 1000)&&($type <= 1004)) {
            # 1000 Airport traffic flow Zero, one or many for an airport. Used if following rules met (rules of same type are ORed together, rules of a different type are ANDed together to). First flow to pass all rules is used.
            # 1001 Traffic flow wind rule One or many for a flow. Multiple rules of same type “ORed”
            # 1002 Traffic flow minimum ceiling rule Zero or one rule for each flow
            # 1003 Traffic flow minimum visibility rule Zero or one rule for each flow
            # 1004 Traffic flow time rule One or many for a flow. Multiple rules of same type “ORed”
        } elsif (($type >= 1100)&&($type <= 1101)) {
            # 1100 Runway-in-use arrival/departure constraints First constraint met is used. Sequence matters
            # 1101 VFR traffic pattern Zero or one pattern for each traffic flow
        } elsif (($type >= 1200)&&($type <= 1204)) {
            # 1200 Header indicating that taxi route network data follows
            # 1201 Taxi route network node Sequencing is arbitrary. Must be part of one or more edges
            # 1202 Taxi route network edge Must connect two nodes
            # 1204 Taxi route edge active zone Can refer to up to 4 runway ends
        } elsif ($type == 1300) {
            # 1300 Airport location Not explicitly connected to taxi route network
        } else {
            prt("FIX ME - LINE UNCASED $type\n");
            prt("$line\n");
            pgm_exit(1,"");
        }
        # 1000 format
    }
    # get LAST
    if (length($apt)) {
        # deal with the previous airport
        @arr2 = split(/\s+/,$apt);
        $aalt = $arr2[1]; # Airport (general) ALTITUDE AMSL
        $actl = $arr2[2]; # control tower
        $abld = $arr2[3]; # buildings
        $icao = $arr2[4]; # ICAO
        $name = join(' ', splice(@arr2,5)); # Name
        $alat = 0;
        $alon = 0;
        $rwycnt += $wwcnt;
        $rwycnt += $helicnt;
        if ($rwycnt > 0) {
            $alat = $glat / $rwycnt;
            $alon = $glat / $rwycnt;
        } else {
            prtw("WARNING: $lnn: Ap with NO runways!\n$apt\n");
        }
        # decide if HELI OR SEAPLANE
        $atyp = $land_type;
        if ($name =~ /\[H\]/) {
            $atyp = $heli_type;
        } elsif ($name =~ /\[S\]/) {
            $atyp = $sea_type;
        }
        if ($name =~ /\[X\]/) {
            $atyp |= $aband_type;
        }
        my @ra = @runways;
        my @wa = @waterways;
        my @ha = @heliways;
        my @fa = @freqs;
        my %info = ();
        $info{twrcount}  = $twrcount;
        $info{wscount}   = $wscount;
        $info{freqcount} = $freqcount;
        #                0      1      2      3      4      5     6     7     8     9  10     11
        push(@airports, [$aalt, $icao, $name, $alat, $alon, \@ra, \@wa, \@ha, \@fa, 0, $atyp, \%info ]);
        # set up minimum display sizes
        $len = length($aalt);
        $max_alt_len = $len if ($len > $max_alt_len);
        $len = length($alat);
        $max_lat_len = $len if ($len > $max_lat_len);
        $len = length($alon);
        $max_lon_len = $len if ($len > $max_lon_len);
        $len = length($name);
        $max_nam_len = $len if ($len > $max_nam_len);
    }
    @airports = sort mycmp_ascend_a1 @airports;
    $aalt = scalar @airports;
    prt("Collected $aalt airports...\n");
    my %h = ();
    $h{form} = 1000;
    $h{apts} = \@airports;
    return \%h;
}

# Like
# 50 10820 ATIS
# 53 11950 DESIDERIO GND
# 54 12250 DESIDERIO TWR
# 55 12790 OSAN APP/DEP
my %off2name = (
    0 => 'ATIS',
    1 => 'Unicom',
    2 => 'Clearance',
    3 => 'Ground',
    4 => 'Tower',
    5 => 'Approach',
    6 => 'Departure'
);

my %off2sname = (
    50 => 'ATIS',
    51 => 'Unicom',
    52 => 'CLR',
    53 => 'GND',
    54 => 'TWR',
    55 => 'APP',
    56 => 'DEP'
);


# compare the frequencies show by a particular ICAO value
my %compared_icao = ();

sub compare_freq_ra($$$$) {
    my ($ra1,$ra2,$rni2,$rni1) = @_;
    my ($aalt,$icao,$name,$alat,$alon,$rra,$rwa,$rha,$rfa);
    my ($aalt2,$icao2,$name2,$alat2,$alon2,$rra2,$rwa2,$rha2,$rfa2);
    $aalt = ${$ra1}[0];
    $icao = ${$ra1}[1];
    $name = ${$ra1}[2];
    $alat = ${$ra1}[3];
    $alon = ${$ra1}[4];
    $rra  = ${$ra1}[5];
    $rwa  = ${$ra1}[6];
    $rha  = ${$ra1}[7];
    $rfa  = ${$ra1}[8];

    $aalt2 = ${$ra2}[0];
    $icao2 = ${$ra2}[1];
    $name2 = ${$ra2}[2];
    $alat2 = ${$ra2}[3];
    $alon2 = ${$ra2}[4];
    $rra2  = ${$ra2}[5];
    $rwa2  = ${$ra2}[6];
    $rha2  = ${$ra2}[7];
    $rfa2  = ${$ra2}[8];

    my $fcnt1 = scalar @{$rfa};
    my $fcnt2 = scalar @{$rfa2};
    my ($i,$j);
    my ($type,$type2,$freq,$freq2,$fnd);
    my @nfin2 = ();
    my @nfin1 = ();
    for ($i = 0; $i < $fcnt1; $i++) {
        $type = ${$rfa}[$i][0];
        $freq = ${$rfa}[$i][1];
        $fnd = 0;
        for ($j = 0; $j < $fcnt2; $j++) {
            $type2 = ${$rfa2}[$j][0];
            $freq2 = ${$rfa2}[$j][1];
            if (($type == $type2)&&($freq == $freq2)) {
                $fnd = 1;
                last;
            }
        }
        if (!$fnd) {
            push(@nfin2,$i);
            push(@{$rni2}, $i);
        }
    }
    for ($i = 0; $i < $fcnt2; $i++) {
        $type = ${$rfa2}[$i][0];
        $freq = ${$rfa2}[$i][1];
        $fnd = 0;
        for ($j = 0; $j < $fcnt1; $j++) {
            $type2 = ${$rfa}[$j][0];
            $freq2 = ${$rfa}[$j][1];
            if (($type == $type2)&&($freq == $freq2)) {
                $fnd = 1;
                last;
            }
        }
        if (!$fnd) {
            push(@nfin1,$i);
            push(@{$rni1}, $i);
        }
    }
    my $cnt1 = scalar @nfin2;
    my $cnt2 = scalar @nfin1;
    my ($acnt,$afcnt,$dname);
    if ($cnt1) {
        $icao .= ' ' while (length($icao) < 4);
        #$alat = ' '.$alat while (length($alat) < $max_lat_len);
        #$alon = ' '.$alon while (length($alon) < $max_lon_len);
        #$aalt = ' '.$aalt while (length($aalt) < $max_alt_len);
        $dname = $name;
        $dname .= ' ' while (length($dname) < $max_nam_len);
        $acnt  = sprintf("%2d",$cnt1);
        $afcnt = sprintf("%2d",$fcnt1);
        prt("$icao $dname has $acnt of $afcnt 1NOTin2 ");
        foreach $i (@nfin2) {
            $type = ${$rfa}[$i][0];
            $freq = ${$rfa}[$i][1];
            $type = $off2sname{$type} if (defined $off2sname{$type});
            prt("$type $freq ");
            push(@{$rni2},$i);  # NOT found in 2
        }
        prt("\n");
    }
    if ($cnt2) {
        if ($cnt1) {
            $icao2 = ' ' x 4;
            if ($name eq $name2) {
                $name2 = ' ' x $max_nam_len;
            } else {
                $name2 .= ' ' while (length($name2) < $max_nam_len);
            }
        } else {
            $icao2 .= ' ' while (length($icao2) < 4);
            #$alat = ' '.$alat while (length($alat) < $max_lat_len);
            #$alon = ' '.$alon while (length($alon) < $max_lon_len);
            #$aalt = ' '.$aalt while (length($aalt) < $max_alt_len);
            $name2 .= ' ' while (length($name2) < $max_nam_len);
        }
        $acnt  = sprintf("%2d",$cnt2);
        $afcnt = sprintf("%2d",$fcnt2);
        prt("$icao2 $name2 has $acnt of $afcnt 2NOTin1 ");
        foreach $i (@nfin1) {
            $type = ${$rfa2}[$i][0];
            $freq = ${$rfa2}[$i][1];
            $type = $off2sname{$type} if (defined $off2sname{$type});
            prt("$type $freq ");
            push(@{$rni1},$i);
        }
        prt("\n");
    }
    return ($cnt1 + $cnt2);
}

#     my %h = ();
#    $h{form} = 810;
#    $h{apts} = @airports;
#    return \%h;

sub compare_ap_ref_hashs($$) {
    my ($apth1,$apth2) = @_;
    if ((!defined ${$apth1}{form})||(!defined ${$apth1}{apts})) {
        prtw("WARNING: ref hash 1 does not have 'form' or 'apts'\n");
        return;
    }
    if ((!defined ${$apth2}{form})||(!defined ${$apth2}{apts})) {
        prtw("WARNING: ref hash 2 does not have 'form' or 'apts'\n");
        return;
    }
    # ready to party with data
    my ($apt1,$apt2,$form1,$form2);

    $form1 = ${$apth1}{form};
    $apt1  = ${$apth1}{apts};
    $form2 = ${$apth2}{form};
    $apt2  = ${$apth2}{apts};

    my $acnt1 = scalar @{$apt1};
    my $acnt2 = scalar @{$apt2};
    ##                0      1      2      3      4      5     6     7     8     9  10     11
    #push(@airports, [$aalt, $icao, $name, $alat, $alon, \@ra, \@wa, \@ha, \@fa, 0, $atyp, \%info ]);
    my ($i,$j,$fnd,$aalt,$icao,$name,$alat,$alon,$rra,$rwa,$rha,$rfa,$atyp);
    my ($aalt2,$icao2,$name2,$alat2,$alon2,$rra2,$rwa2,$rha2,$rfa2,$atyp2);
    my ($ra1,$ra2,$msg,$mat2,$rih,$rih2);
    my @nfin2 = ();
    my @nfin1 = ();
    my $diff_cnt = 0;
    my $same_cnt = 0;
    my $miss_cnt = 0;
    my $miss_cnt2 = 0;
    my @fnotin2 = ();
    my @fnotin1 = ();
    my $apnotwr = 0;
    my $apnows  = 0;
    my $apnofrq = 0;
    my $apnotwr2 = 0;
    my $apnows2  = 0;
    my $apnofrq2 = 0;
    my $helini2 = 0;
    my $seani2 = 0;
    my $helini1 = 0;
    my $seani1 = 0;
    # ============================================================
    # first compare
    prt("\nComparing $acnt1 with $acnt2 airports...\n");
    for ($i = 0; $i < $acnt1; $i++) {
        $ra1  = ${$apt1}[$i];
        $aalt = ${$apt1}[$i][0];
        $icao = ${$apt1}[$i][1];
        $name = ${$apt1}[$i][2];
        $alat = ${$apt1}[$i][3];
        $alon = ${$apt1}[$i][4];
        $rra  = ${$apt1}[$i][5];
        $rwa  = ${$apt1}[$i][6];
        $rha  = ${$apt1}[$i][7];
        $rfa  = ${$apt1}[$i][8];
        # 9  used for cross referencing
        $atyp = ${$apt1}[$i][10];   # land, heli, sea OR abandoned
        $rih  = ${$apt1}[$i][11];   # contains twrcount, wscount, freqcount
        $fnd = 0;
        for ($j = 0; $j < $acnt2; $j++) {
            $mat2  = ${$apt2}[$j][9];
            next if ($mat2 > 0);
            $icao2 = ${$apt2}[$j][1];
            if ($icao eq $icao2) {
                $fnd = 1;
                $ra2 = ${$apt2}[$j];
                $aalt2 = ${$apt2}[$j][0];
                #$icao2 = ${$apt2}[$j][1];
                $name2 = ${$apt2}[$j][2];
                $alat2 = ${$apt2}[$j][3];
                $alon2 = ${$apt2}[$j][4];
                $rra2  = ${$apt2}[$j][5];
                $rwa2  = ${$apt2}[$j][6];
                $rha2  = ${$apt2}[$j][7];
                $rfa2  = ${$apt2}[$j][8];
                # 9  used for cross referencing
                ${$apt1}[$i][9] = $j + 1;   # matched
                ${$apt2}[$j][9] = $i + 1;   # matched
                $atyp2 = ${$apt2}[$j][10];   # land, heli, sea OR abandoned
                $rih2  = ${$apt2}[$j][11];   # contains twrcount, wscount, freqcount
                last;
            }
        }
        if ($fnd) {
            if (!defined $compared_icao{$icao}) {
                $compared_icao{$icao} = 1;
                if (compare_freq_ra($ra1,$ra2,\@fnotin2,\@fnotin1)) {
                    $diff_cnt++;
                } else {
                    $same_cnt++;
                }
            }
        } else {
            $helini2++ if ($atyp & $heli_type);
            $seani2++ if ($atyp & $sea_type);;
            $icao .= ' ' while (length($icao) < 4);
            $alat = ' '.$alat while (length($alat) < $max_lat_len);
            $alon = ' '.$alon while (length($alon) < $max_lon_len);
            $aalt = ' '.$aalt while (length($aalt) < $max_alt_len);
            $name .= ' ' while (length($name) < $max_nam_len);
            $msg = "$icao $alat $alon $aalt $name";
            #prt("$msg NOT found in 2\n");
            push(@nfin1,$msg);
            $miss_cnt++;
        }
        $apnotwr++ if (${$rih}{twrcount} == 0);
        $apnows++ if (${$rih}{wscount} == 0);
        $apnofrq++ if (${$rih}{freqcount} == 0);
    }
    # ============================================================
    # second compare - compare 1 with 2
    prt("\nComparing $acnt2 with $acnt1 airports...\n");
    for ($i = 0; $i < $acnt2; $i++) {
        $ra2  = ${$apt2}[$i];
        $aalt = ${$apt2}[$i][0];
        $icao = ${$apt2}[$i][1];
        $name = ${$apt2}[$i][2];
        $alat = ${$apt2}[$i][3];
        $alon = ${$apt2}[$i][4];
        $rra  = ${$apt2}[$i][5];
        $rwa  = ${$apt2}[$i][6];
        $rha  = ${$apt2}[$i][7];
        $rfa  = ${$apt2}[$i][8];
        $mat2 = ${$apt2}[$i][9];
        $atyp = ${$apt2}[$i][10];   # land, heli, sea OR abandoned
        $rih2 = ${$apt2}[$i][11];   # contains twrcount, wscount, freqcount
        $apnotwr2++ if (${$rih2}{twrcount} == 0);
        $apnows2++ if (${$rih2}{wscount} == 0);
        $apnofrq2++ if (${$rih2}{freqcount} == 0);
        next if ($mat2);
        $fnd = 0;
        for ($j = 0; $j < $acnt1; $j++) {
            $icao2 = ${$apt1}[$j][1];
            if ($icao eq $icao2) {
                $fnd = 1;
                $ra2 = ${$apt1}[$j];
                $aalt2 = ${$apt1}[$j][0];
                #$icao2 = ${$apt1}[$j][1];
                $name2 = ${$apt1}[$j][2];
                $alat2 = ${$apt1}[$j][3];
                $alon2 = ${$apt1}[$j][4];
                $rra2  = ${$apt1}[$j][5];
                $rwa2  = ${$apt1}[$j][6];
                $rha2  = ${$apt1}[$j][7];
                $rfa2  = ${$apt1}[$j][8];
                $atyp2 = ${$apt1}[$j][10];   # land, heli, sea OR abandoned
                last;
            }
        }
        if ($fnd) {
            if (!defined $compared_icao{$icao}) {
                $compared_icao{$icao} = 1;
                if (compare_freq_ra($ra1,$ra2,\@fnotin2,\@fnotin1)) {
                    $diff_cnt++;
                } else {
                    $same_cnt++;
                }
            }
        } else {
            $helini1++ if ($atyp & $heli_type);
            $seani1++ if ($atyp & $sea_type);;
            $icao .= ' ' while (length($icao) < 4);
            $alat = ' '.$alat while (length($alat) < $max_lat_len);
            $alon = ' '.$alon while (length($alon) < $max_lon_len);
            $aalt = ' '.$aalt while (length($aalt) < $max_alt_len);
            $name .= ' ' while (length($name) < $max_nam_len);
            $msg = "$icao $alat $alon $aalt $name";
            #prt("$msg NOT found in 2\n");
            push(@nfin1,$msg);
            $miss_cnt2++;
        }
    }
    $fnd = scalar @nfin2;
    prt("Have $fnd of $acnt1 NOT found in 2, heli $helini2, sea $seani2\n");
    if ($fnd) {
        prt(join("\n",@nfin2)."\n");
    }
    $fnd = scalar @nfin1;
    prt("Have $fnd of $acnt2 NOT found in 1, heli $helini1, sea $seani1\n");
    if ($fnd) {
        prt(join("\n",@nfin1)."\n");
    }
    $fnd = scalar @fnotin2;
    if ($fnd) {
        prt("Found $fnd cases of frequencies not in 2\n");
    }
    $fnd = scalar @fnotin1;
    if ($fnd) {
        prt("Found $fnd cases of frequencies not in 1\n");
    }
    prt("In comparing $acnt1 with $acnt2 airports... same $same_cnt, diff $diff_cnt, miss 1IN2 $miss_cnt, miss 2IN1 $miss_cnt2\n");
    prt("$acnt1 AP1 no twr $apnotwr, ws $apnows, f $apnofrq, $acnt2 AP2 no twr $apnotwr2, ws $apnows2, f $apnofrq2\n");
    $fnd = scalar @nfin2;
    prt("Have $fnd of $acnt1 $ap_file1 airports NOT found in 2, heli $helini2, sea $seani2\n");
    $fnd = scalar @nfin1;
    prt("Have $fnd of $acnt2 $ap_file2 airports NOT found in 1, heli $helini1, sea $seani1\n");
}


sub load_ap_files() {
    my ($v1,$v2,$ln1,$ln2);
    my $ra1 = load_ap_file($ap_file1,\$v1,\$ln1);
    my ($raph1,$raph2);
    if ($v1 == 810) {
        $raph1 = process_810_lines($ra1);
    } elsif ($v1 == 1000) {
        $raph1 = process_1000_lines($ra1);
    } else {
        pgm_exit(1,"ERROR: Uncoded version [$v1]\n");
    }
    my $ra2 = load_ap_file($ap_file2,\$v2,\$ln2);
    if ($v2 == 810) {
        $raph2 = process_810_lines($ra2);
    } elsif ($v2 == 1000) {
        $raph2 = process_1000_lines($ra2);
    } else {
        pgm_exit(1,"ERROR: Unknown version [$v2]\n");
    }
    compare_ap_ref_hashs($raph1,$raph2);
}


#########################################
### MAIN ###
parse_args(@ARGV);
load_ap_files();
#process_in_file($in_file);
$load_log = 1;
pgm_exit(0,"");
########################################

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/) {
                if ($sarg =~ /^ll/) {
                    $load_log = 2;
                } else {
                    $load_log = 1;
                }
                prt("Set to load log at end. ($load_log)\n") if (VERB1());
            } elsif ($sarg =~ /^o/) {
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                $out_file = $sarg;
                prt("Set out file to [$out_file].\n") if (VERB1());
            } else {
                pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n");
            }
        } else {
            pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n");
        }
        shift @av;
    }

    if ($debug_on) {
        prtw("WARNING: DEBUG is ON!\n");
    }
    pgm_exit(1,"ERROR: Can NOT locate $ap_file1!\n") if (! -f $ap_file1);
    pgm_exit(1,"ERROR: Can NOT locate $ap_file2!\n") if (! -f $ap_file2);
}

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");
}

# eof - cmpapfreq.pl
