#!/usr/bin/perl -w
# NAME: runways.pl
# AIM: Given an ICAO, list the runways of that airport (if found)
use strict;
use warnings;
use File::Basename;  # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] )
use Cwd;
##use PerlIO::gzip; # FAILED TO INSTALL
use IO::Uncompress::Gunzip qw($GunzipError);
use Env qw(FG_ROOT);    # pour lire HOME FG_HOME et FG_ROOT
use Time::HiRes qw( gettimeofday tv_interval );
use Socket;
use LWP::Simple;
use Geo::METAR;
use Date::Parse;

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.3 2014-11-19";
my $load_log = 0;
my $in_icao = '';
my $verbosity = 0;
my $out_file = '';
my $add_all_runways = 0;
my $def_root = "F:\\fgdata";
$def_root = "X:\\fgdata" if (-d "X:\\fgdata");
my $FGROOT = (exists $ENV{FG_ROOT})? $FG_ROOT : $def_root;
###my $FGROOT = $def_root;
my $APTFILE = "$FGROOT/Airports/apt.dat.gz";  # le fichier contenant les aéroports
my $NAVFILE = "$FGROOT/Navaids/nav.dat.gz";   # le fichier contenant les aides à la navigation
my $aptdat = $APTFILE;

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

### program variables
my @warnings = ();
my $cwd = cwd();
my $KM2FEET = 3280.84;
my $FEET2M = 0.3048;
my $METARBASE = 'http://weather.noaa.gov/pub/data/observations/metar/stations/';
my %apt_runways = ();

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

my @runways = ();

sub fetch_url($) {	# see gettaf01.pl
	my ($url) = shift;
	prt( "Fetching: $url\n" ) if (VERB9());
	my $txt = get($url);
    my $met = '';
	if ($txt && length($txt)) {
        $met = trim_metar_txt($txt);
        #$met = trim_all($txt);
        if (length($met)) {
    		prt( "METAR: $met\n" );
        } else {
    		prt( "No METAR available for $url!\n" ) if (VERB5());
        }
	} else {
  		prt( "No METAR available for $url!\n" ) if (VERB5());
	}
    return $met;
}

sub trim_metar_txt($) {
    my $met = shift;
	$met =~ s/\n/ /gm;
	$met =~ s/\r/ /gm;
	$met =~ s/\t/ /gm;
	$met = trim_all($met);
    return $met;
}

# divide in 4 quarants
sub hdg_to_dir4($) {
    my $hdg = shift;
    my $dir = '';
    if (($hdg >= 315) && ($hdg < 45)) {
        $dir = 'N';
    } elsif (($hdg >= 45) && ($hdg < 135)) {
        $dir = 'E';
    } elsif (($hdg >= 135) && ($hdg < 225)) {
        $dir = 'S';
    } elsif (($hdg >= 225) && ($hdg < 315)) {
        $dir = 'W';
    }
    return $dir;
}

sub hdg_to_dir8($) {
    my $dir = shift;
    if (($dir >= 337.5) && ($dir < 22.5)) {
            $dir = 'N';
    } elsif (($dir >= 22.5) && ($dir < 67.5)) {
            $dir = 'NE';
    } elsif (($dir >= 67.5) && ($dir < 112.5)) {
            $dir = 'E';
    } elsif (($dir >= 112.5) && ($dir < 157.5)) {
            $dir = 'SE';
    } elsif (($dir >= 157.5) && ($dir < 202.5)) {
            $dir = 'S';
    } elsif (($dir >= 202.5) && ($dir < 247.5)) {
            $dir = 'SW';
    } elsif (($dir >= 247.5) && ($dir < 292.5)) {
            $dir = 'W';
    } elsif (($dir >= 292.5) && ($dir < 337.5)) {
            $dir = 'NW';
    }
    return $dir;
}

sub bearing_diff($$) {
    my ($b1,$b2) = @_;
    my $d = ($b1 > $b2) ? $b1 - $b2 : $b2 - $b1;
    $d = 360 - $d if ($d > 180);
    return $d;
}

# offset 10 in runway array
my %runway_surface = (
    1  => 'Asphalt',
    2  => 'Concrete',
    3  => 'Turf/grass',
    4  => 'Dirt',
    5  => 'Gravel',
    6  => 'H-Asphalt', # helepad (big 'H' in the middle).
    7  => 'H-Concrete', # helepad (big 'H' in the middle).
    8  => 'H-Turf', # helepad (big 'H' in the middle).
    9  => 'H-Dirt', # helepad (big 'H' in the middle). 
    10 => 'T-Asphalt', # taxiway - with yellow hold line across long axis (not available from WorldMaker).
    11 => 'T-Concrete', # taxiway - with yellow hold line across long axis (not available from WorldMaker).
    12 => 'Dry Lakebed', # (eg. at KEDW Edwards AFB).
    13 => 'Water' # runways (marked with bobbing buoys) for seaplane/floatplane bases (available in X-Plane 7.0 and later). 
);

sub get_metar_wind() {
    my $file = $perl_dir."\\temp.$in_icao.TXT";
    my $url = $METARBASE.$in_icao.".TXT";
    my $met = fetch_url($url);
    my %rwys = ();
    if (length($met)) {
        $met = trim_metar_txt($met);
        my $m = new Geo::METAR;
        $m->metar($met);
        ##my @arr = keys(%{$m});
        # WIND_DIR_DEG  = 280
        # WIND_DIR_ENG  = West
        # WIND_KTS      = 03 kt 3.5 mph
        if (defined ${$m}{'WIND_DIR_DEG'}) {
            my $degs = ${$m}{'WIND_DIR_DEG'};
            $degs = trim_all($degs);
            if ($degs =~ /^\d+$/) {
                prt(sprintf("Wind: %d degrees",$degs));
                my $wdir = hdg_to_dir4($degs);
                my $wdir8 = hdg_to_dir8($degs);
                if ($wdir eq $wdir8) {
                    prt(" ($wdir8)");
                } else {
                    prt(" ($wdir-$wdir8)");
                }
                if (defined ${$m}{WIND_KTS}) {
                    my $kts = ${$m}{WIND_KTS};
                    prt(", at $kts knots");
                }
                prt("\n");

                my $rcnt = scalar @runways;
                my ($ra);
                my ($rlen,$hdg,$rlet1,$rlet2,$hdgr,$surf);
                my ($rdir1,$rdir2,$i,$fnd);
                if ($rcnt) {
                    ##              0      1     2     3      4    5
                    #push(@runways,[$rlet1,$hdg,$rlet2,$hdgr,$rlen,$surf);
                    for ($i = 0; $i < $rcnt; $i++) {
                        # little choice - just choose end closes into wind
                        $ra = $runways[$i];
                        $rlet1 = ${$ra}[0];
                        $hdg   = ${$ra}[1];
                        $rlet2 = ${$ra}[2];
                        $hdgr  = ${$ra}[3];
                        $rlen  = ${$ra}[4];
                        $surf  = ${$ra}[5];
                        $surf =  $runway_surface{$surf} if (defined $runway_surface{$surf});

                        $rdir1 = hdg_to_dir8($hdg);
                        $rdir2 = hdg_to_dir8($hdgr);
                        if ($wdir8 eq $rdir1) {
                            $hdg = int($hdg + 0.5);
                            prt("Rwy: $rlet1 ($hdg)");
                            if (! defined $rwys{$rlet1}) {
                                prt(" $rlen ft. $surf");
                            }
                            prt("\n");
                            $rwys{$rlet1} = 1;
                            $rwys{$rlet2} = 1;
                            $fnd++;
                        } elsif ($wdir8 eq $rdir2) {
                            $hdgr = int($hdgr + 0.5);
                            prt("Rwy: $rlet2 ($hdgr)");
                            if (! defined $rwys{$rlet2}) {
                                prt(" $rlen ft. $surf");
                            }
                            prt("\n");
                            $rwys{$rlet1} = 1;
                            $rwys{$rlet2} = 1;
                            $fnd++;
                        }
                    }
                    if (!$fnd) {
                        for ($i = 0; $i < $rcnt; $i++) {
                            # little choice - just choose end closes into wind
                            $ra = $runways[$i];
                            $rlet1 = ${$ra}[0];
                            $hdg   = ${$ra}[1];
                            $rlet2 = ${$ra}[2];
                            $hdgr  = ${$ra}[3];
                            $rlen  = ${$ra}[4];
                            $surf  = ${$ra}[5];
                            $surf =  $runway_surface{$surf} if (defined $runway_surface{$surf});
                            $rdir1 = hdg_to_dir4($hdg);
                            $rdir2 = hdg_to_dir4($hdgr);
                            if ($wdir eq $rdir1) {
                                $hdg = int($hdg + 0.5);
                                prt("rwy: $rlet1 ($hdg)");
                                if (! defined $rwys{$rlet1}) {
                                    prt(" $rlen ft. $surf");
                                }
                                prt("\n");
                                $rwys{$rlet1} = 1;
                                $rwys{$rlet2} = 1;
                                $fnd++;
                            } elsif ($wdir eq $rdir2) {
                                $hdgr = int($hdgr + 0.5);
                                prt("rwy: $rlet2 ($hdgr)");
                                if (! defined $rwys{$rlet2}) {
                                    prt(" $rlen ft. $surf");
                                }
                                prt("\n");
                                $rwys{$rlet1} = 1;
                                $rwys{$rlet2} = 1;
                                $fnd++;
                            }
                        }
                    }
                    if (!$fnd) {
                        if ($add_all_runways) {
                            for ($i = 0; $i < $rcnt; $i++) {
                                # no choice - show all
                                $ra = $runways[$i];
                                $rlet1 = ${$ra}[0];
                                $hdg   = ${$ra}[1];
                                $rlet2 = ${$ra}[2];
                                $hdgr  = ${$ra}[3];
                                $rlen  = ${$ra}[4];
                                $surf  = ${$ra}[5];
                                $surf =  $runway_surface{$surf} if (defined $runway_surface{$surf});

                                $rdir1 = hdg_to_dir4($hdg);
                                $rdir2 = hdg_to_dir4($hdgr);
                                if ($wdir eq $rdir1) {
                                    #prt(", rwy: $rlet1 ($hdg)");
                                } elsif ($wdir eq $rdir2) {
                                    #prt(", rwy: $rlet2 ($hdgr)");
                                } else {
                                    $rdir1 = hdg_to_dir8($hdg);
                                    $rdir2 = hdg_to_dir8($hdgr);
                                    if ($wdir8 eq $rdir1) {
                                        #prt(", rwy: $rlet1 ($hdg)");
                                    } elsif ($wdir8 eq $rdir2) {
                                        #prt(", rwy: $rlet2 ($hdgr)");
                                    } else {
                                        # cross wind
                                        $hdg = int($hdg + 0.5);
                                        $hdgr = int($hdgr + 0.5);
                                        prt("RWY: $rlet1 ($hdg) or $rlet2 ($hdgr)");
                                        if (! defined $rwys{$rlet1}) {
                                            prt(" $rlen ft. $surf");
                                        }
                                        prt("\n");
                                        $rwys{$rlet1} = 1;
                                        $rwys{$rlet2} = 1;
                                    }
                                }
                            }
                        } else {
                            prt("no rwy matching! ");
                            my $min_d = 360;
                            my $min_i = 0;
                            my $min_12 = 0;
                            my ($d);
                            for ($i = 0; $i < $rcnt; $i++) {
                                $ra = $runways[$i];
                                $rlet1 = ${$ra}[0];
                                $hdg   = ${$ra}[1];
                                $rlet2 = ${$ra}[2];
                                $hdgr  = ${$ra}[3];
                                $d = bearing_diff($degs,$hdg);
                                if ($d < $min_d) {
                                    $min_d = $d;
                                    $min_i = $i;
                                    $min_12 = 1;
                                }
                                $d = bearing_diff($degs,$hdgr);
                                if ($d < $min_d) {
                                    $min_d = $d;
                                    $min_i = $i;
                                    $min_12 = 2;
                                }
                            }
                            $i = $min_i;
                            $ra = $runways[$i];
                            $rlet1 = ${$ra}[0];
                            $hdg   = ${$ra}[1];
                            $rlet2 = ${$ra}[2];
                            $hdgr  = ${$ra}[3];
                            $rdir1 = hdg_to_dir8($hdg);
                            $rdir2 = hdg_to_dir8($hdgr);
                            if ($min_12 == 1) {
                                $hdg = int($hdg + 0.5);
                                prt("closest $rlet1 $rdir1 $hdg ");
                            } else {
                                $hdgr = int($hdgr + 0.5);
                                prt("closest $rlet2 $rdir2 $hdgr ");
                            }
                            prt("\n");

                            if (VERB1()) {
                                my %dupes = ();
                                for ($i = 0; $i < $rcnt; $i++) {
                                    # no choice - show all
                                    $ra = $runways[$i];
                                    $rlet1 = ${$ra}[0];
                                    $hdg   = ${$ra}[1];
                                    $rlet2 = ${$ra}[2];
                                    $hdgr  = ${$ra}[3];
                                    $rdir1 = hdg_to_dir4($hdg);
                                    $rdir2 = hdg_to_dir4($hdgr);
                                    if (!defined $dupes{$rdir1}) {
                                        $hdg = int($hdg + 0.5);
                                        prt("$rlet1 $hdg $rdir1 ");
                                        $dupes{$rdir1} = 1;
                                    }
                                    if (!defined $dupes{$rdir2}) {
                                        $hdgr = int($hdgr + 0.5);
                                        prt("$rlet2 $hdgr $rdir2 ");
                                        $dupes{$rdir2} = 1;
                                    }
                                    $hdg   = ${$ra}[1];
                                    $hdgr  = ${$ra}[3];
                                    $rdir1 = hdg_to_dir8($hdg);
                                    $rdir2 = hdg_to_dir8($hdgr);
                                    if (!defined $dupes{$rdir1}) {
                                        $hdg = int($hdg + 0.5);
                                        prt("$rlet1 $hdg $rdir1 ");
                                        $dupes{$rdir1} = 1;
                                    }
                                    if (!defined $dupes{$rdir2}) {
                                        $hdgr = int($hdgr + 0.5);
                                        prt("$rlet2 $hdgr $rdir2 ");
                                        $dupes{$rdir2} = 1;
                                    }
                                }
                                prt("\n");
                            }
                        }
                    }
                }
            } else {
                prt("Wind: $degs NN\n");
            }
            #prt("\n");
        }
    } else {
        prt("Failed to get $url!\n") if (VERB9());
    }
}

my %off2name2 = (
    0 => 'ATIS',
    1 => 'UNICOM',
    2 => 'CLR',
    3 => 'GRD',
    4 => 'TWR',
    5 => 'APP',
    6 => 'DEP'
);


# 12345678901234567890123456
# -37.60451900,-122.38223600
sub get_ll_stg($$) {
    my ($lat,$lon) = @_;
    my $stg = sprintf("%.8f,%.8f",$lat,$lon);
    $stg .= ' ' while (length($stg) < 26);
    return $stg;
}

my @apt = ();
#                   0     1      2      3      4      5      6       7     8
# push(@g_navaids, [$typ, $nlat, $nlon, $nalt, $nfrq, $nrng, $nfrq2, $nid, $name, 0, 0, 0, 0] );
my @g_navaids = ();
my %nav_types = (
    2 => 'NDB',
    3 => 'VOR',
    4 => 'ILS',
    5 => 'LOC',
    6 => 'GS',
    7 => 'OM',
    8 => 'MM',
    9 => 'IM',
    12 => 'VDME',
    13 => 'NDME'
    );

sub search_nav_data() {
    my $icao = $in_icao;
    my $max = scalar @g_navaids;
    my ($i,$ra,$nid,$name,$typ,$nfrq,$msg);
    my ($nlat,$nlon,$nalt,$nrng,$line,@arr,$rlets,$rhdg);
    prt("Searching $max navaids for ICAO $icao\n") if (VERB5());
    my %freq = ();
    # $apt_runways{$rlet1} = $hdg;
    # $apt_runways{$rlet2} = $hdgr;

    #          ILS  37.60451900,-122.38223600    10 ft. 108.90  18 nm. ISIA KSFO 19L ILS-cat-I
    my $hdr = "typ  latitude    longitude       alt ft.  freq.  range  id   name";
    for ($i = 0; $i < $max; $i++) {
        $ra = $g_navaids[$i];
        $typ = ${$ra}[0];
        next if (($typ == 6)||($typ == 7)||($typ == 8)||($typ == 9)); # skip GS and Markers
        $nid = ${$ra}[7];
        $name = ${$ra}[8];
        if ($name =~ /^$icao/) { # ($nid eq $icao) {
            @arr = split(/\s+/,$name);
            $nfrq = ${$ra}[4];
            next if (defined $freq{$nfrq});
            $freq{$nfrq} = 1;
            $nlat = ${$ra}[1];
            $nlon = ${$ra}[2];
            $nalt = ${$ra}[3];
            $nrng = ${$ra}[5];
            $msg = '';
            if ($typ == 4) { # ILS
                $rlets = $arr[1];
                if (defined $apt_runways{$rlets}) {
                    $rhdg = $apt_runways{$rlets};
                    $rhdg = int($rhdg + 0.5);
                    $msg = "b=$rhdg";
                }
            }

            # display
            # ILS  37.60451900,-122.38223600   10 ft. 108.90  18 nm. ISIA KSFO 19L ILS-cat-I
            # prt(join(" ",@{$ra})."\n");
            $typ = $nav_types{$typ} if (defined $nav_types{$typ});
            $typ .= ' ' while (length($typ) < 4);
            $nid .= ' ' while (length($nid) < 4);
            $line = "$typ ";
            $line .= get_ll_stg($nlat,$nlon);
            $line .= sprintf(" %4d ft. ",$nalt);
            $line .= sprintf("%6.2f",$nfrq / 100);
            $line .= sprintf(" %3d nm.",$nrng);
            $line .= " $nid $name $msg";
            prt("$hdr\n") if (length($hdr));
            $hdr = '';
            prt("$line\n");
        }
    }
}

sub load_nav_data() {
    my $t1 = [gettimeofday];
	prt("\n[v5] Loading $NAVFILE file ...\n") if (VERB5());
	die "ERROR: Can NOT stat '$NAVFILE'!\n" if ( !( -f $NAVFILE) );
	open NIF, "gzip -d -c $NAVFILE|" or die "ERROR: CAN NOT OPEN $NAVFILE...$!...\n";
	my @nav_lines = <NIF>;
	close NIF;
    my $elap = secs_HHMMSS( tv_interval( $t1, [gettimeofday] ) );
    prt("[v5] Got ".scalar @nav_lines." lines in $elap...\n") if (VERB5());
    my ($line,@arr,$nc,$i,$len);
    my ($typ,$nlat,$nlon,$nalt,$nfrq,$nrng,$nfrq2,$nid,$name);

    foreach $line (@nav_lines) {
        chomp $line;
		$line = trim_all($line);
        $len = length($line);
        next if ($line =~ /\s+Version\s+/i);
        next if ($line =~ /^I/);
        next if ($len == 0);
		# 0   1 (lat)   2 (lon)     3(alt) 4(feq)  5(rng)     6    7   8++
		# 2   38.087769 -077.324919  284     396    25     0.000   APH  A P Hill NDB
		# 3   57.103719  009.995578   57   11670   100     1.000   AAL  Aalborg VORTAC
		# 4   39.980911 -075.877814  660   10850    18     281.662 IMQS 40N 29 ILS-cat-I
		# 4  -09.458922  147.231225  128   11010    18     148.650 IWG  AYPY 14L ILS-cat-I
		# 5   40.034606 -079.023281 2272   10870    18     236.086 ISOZ 2G9 24 LOC
		# 5   67.018506 -050.682072  165   10955    18      61.600 ISF  BGSF 10 LOC
		# 6   39.977294 -075.860275  655   10850    10  300281.205 ---  40N 29 GS
		# 6  -09.432703  147.216444  128   11010    10  302148.785 ---  AYPY 14L GS
		# 7   39.960719 -075.750778  660       0     0     281.205 ---  40N 29 OM
		# 7  -09.376150  147.176867  146       0     0     148.785 JSN  AYPY 14L OM
		# 8  -09.421875  147.208331   91       0     0     148.785 MM   AYPY 14L MM
		# 8  -09.461050  147.232544  146       0     0     328.777 PY   AYPY 32R MM
		# 9   65.609444 -018.052222   32       0     0      22.093 ---  BIAR 01 IM
		# 9   08.425319  004.475597 1126       0     0      49.252 IL   DNIL 05 IM
		# 12 -09.432703  147.216444   11   11010    18       0.000 IWG  AYPY 14L DME-ILS
		# 12 -09.449222  147.226589   11   10950    18       0.000 IBB  AYPY 32R DME-ILS
		@arr = split(/\s+/,$line);
		$nc = scalar @arr;
		$typ = $arr[0];
        last if ($typ == 99);
        if ($nc < 8) {
            prt("Type: [$typ] - Handle this line [$line] - count = $nc...\n");
            pgm_exit(1,"ERROR: FIX ME FIRST!\n");
        }
        $nlat  = $arr[1];
        $nlon  = $arr[2];
        $nalt  = $arr[3];
        $nfrq  = $arr[4];
        $nrng  = $arr[5];
        $nfrq2 = $arr[6];
        $nid   = $arr[7];
        $name  = '';
        for ($i = 8; $i < $nc; $i++) {
            $name .= ' ' if length($name);
            $name .= $arr[$i];
        }
        #                 0     1      2      3      4      5      6       7     8
        push(@g_navaids, [$typ, $nlat, $nlon, $nalt, $nfrq, $nrng, $nfrq2, $nid, $name, 0, 0, 0, 0] );
    }
    $elap = secs_HHMMSS( tv_interval( $t1, [gettimeofday] ) );
    prt("[v5] Got ".scalar @g_navaids." navaids in $elap...\n") if (VERB5());
}


sub show_apt() {
    my $icao = $in_icao;
    my ($i,$max,$ra,$typ,$line,@arr);

    my ($aalt,$actl,$abld,$anam,$rfa);
    my ($rlat1,$rlon1,$rlat2,$rlon2,$rlat,$rlon);
    my ($rlen,$hdg,$az2,$res,$s,$rlet1,$rlet2,$hdgr,$rwid,$surf);
    my ($alat,$alon,$tmp);
    my %freqs = ();
    my $glat = 0;
    my $glon = 0;
    my $rwcnt = 0;
    my $gottwr = 0;
    $max = scalar @apt;
    if (!$max) {
        prt("No airport to show...\n");
        return;
    }
    for ($i = 0; $i < $max; $i++) {
        $ra = $apt[$i];
        ###prt(join(" ",@{$ra})."\n");
        $typ = ${$ra}[0];
        if ($typ == 1) {
            $aalt = ${$ra}[1];
            $actl = ${$ra}[2]; # control tower
            $abld = ${$ra}[3]; # buildings
            #$icao = ${$ra}[4];
            $anam = join(' ', splice(@{$ra},5));
        } elsif ($typ == 14) {
            # Tower viewpoints Example Usage 
            # 14          Identifies this as a data line for a tower viewpoint (code 14).Only a single tower viewpoint is permitted. 
            # 35.047005   Latitude (in decimal degrees) of the viewpoint. 
            # -106.608162 Longitude (in decimal degrees) of the viewpoint. 
            # 100         Height (in feet) above ground level of viewpoint. 
            # 1           Flag to indicate if a control tower object should be drawn at this location in X-Plane.  0=no tower, 1=draw tower. 
            # Tower viewpoint Name of this viewpoint 
            $gottwr = 1;
            $alat = ${$ra}[1];
            $alon = ${$ra}[2];
        } elsif ($typ == 10) {
            # @runways reference
            # 0   1=lat      2=lon      3=s 4=hdg  5=len 6=offsets 7=stopway 8=wid 9=lights 10=surf 11 12 13   14 15
            # 10  36.962213  127.031071 14x 131.52  8208 1595.0620 0000.0000 150   321321   1       0  3  0.25 0  0300.0300
            # 11=shoulder 12=marks 13=smooth 14=signs 15=GS angles
            # 0           3        0.25      0        0300.0300
            $rlet1 = ${$ra}[3];
            $rlet1 =~ /(..)(.)/;
            $rlet2 = ($1 > 18) ? $1 - 18 : $1 + 18;
            $rlet2 = "0".$rlet2 if ($rlet2 < 10);
            if ($2) {
                $rlet2 .= 'L' if ($2 eq 'R');
                $rlet2 .= 'R' if ($2 eq 'L');
                $rlet2 .= 'C' if ($2 eq 'C');
            }
            $hdg   = ${$ra}[4];
            $hdgr  = $hdg + 180;
            $hdgr -= 360 if ($hdgr >= 360);
            $rlen = ${$ra}[5];  # length, in feet
            $rlat = ${$ra}[1];
            $rlon = ${$ra}[2];
            $glat += $rlat;
            $glon += $rlon;
            $rwcnt++;
            $surf = ${$ra}[10];  # add surface type
            fg_geo_direct_wgs_84( $rlat, $rlon, $hdg , ($rlen * $FEET2M), \$rlat1, \$rlon1, \$az2 );
            fg_geo_direct_wgs_84( $rlat, $rlon, $hdgr, ($rlen * $FEET2M), \$rlat2, \$rlon2, \$az2 );

            push(@runways,[$rlet1,$hdg,$rlet2,$hdgr,$rlen,$surf]);
            $apt_runways{$rlet1} = $hdg;
            $apt_runways{$rlet2} = $hdgr;

            # build display
            $rlet1 .= ' ' while (length($rlet1) < 3);
            $rlet2 .= ' ' while (length($rlet2) < 3);
            $hdg = int($hdg + 0.5);
            $hdgr = int($hdgr + 0.5);
            $line = "$rlet1 ".get_ll_stg($rlat1,$rlon1);
            $line .= " $rlet2 ".get_ll_stg($rlat2,$rlon2);
            $line .= " b=$hdg/$az2 l=$rlen ft";
            if (defined $runway_surface{$surf}) {
                $line .= " (".$runway_surface{$surf}.")";
            }
            prt("$line\n");
        } elsif ($typ == 100) {
            # 10L: 37.62872250,-122.39342127 28R: 37.61351918,-122.35716907 b=118/298 l=11870 ft (Asphalt)  
            # 10R: 37.62527727,-122.39074787 28L: 37.61169441,-122.35837447 b=118/298 l=10601 ft (Asphalt)
            # 01R: 37.60620279,-122.38114713 19L: 37.62781186,-122.36681630 b=28/208 l=8896 ft (Asphalt)
            # 01L: 37.60897310,-122.38223043 19R: 37.62719258,-122.37015433 b=28/208 l=7500 ft (Asphalt)
            $rwid  = ${$ra}[1];  # WIDTH in meters? NOT SHOWN
            $surf  = ${$ra}[2];  # add surface type
            $rlet1 = ${$ra}[8];
            $rlat1 = ${$ra}[9];  # $of_lat1
            $rlon1 = ${$ra}[10]; # $of_lon1
            $rlet2 = ${$ra}[17];
            $rlat2 = ${$ra}[18]; # $of_lat2
            $rlon2 = ${$ra}[19]; # $of_lon2
            $rlat = ($rlat1 + $rlat2) / 2;
            $rlon = ($rlon1 + $rlon2) / 2;
            $glat += $rlat;
            $glon += $rlon;
            $rwcnt++;
            $res = fg_geo_inverse_wgs_84($rlat1, $rlon1, $rlat2, $rlon2, \$hdg, \$az2, \$s);
            $hdgr = $az2;
            $rlen = int(($s / 1000) * $KM2FEET );    # runway length, in feet
            #              0      1     2     3      4    5
            push(@runways,[$rlet1,$hdg,$rlet2,$hdgr,$rlen,$surf]);
            $apt_runways{$rlet1} = $hdg;
            $apt_runways{$rlet2} = $hdgr;

            # build display
            # runway markings - magnetic azimuth of the centerline
            $rlet1 .= ' ' while (length($rlet1) < 3);
            $rlet2 .= ' ' while (length($rlet2) < 3);
            $hdg = int($hdg + 0.5);
            $hdgr = int($hdgr + 0.5);
            $line = "$rlet1 ".get_ll_stg($rlat1,$rlon1);
            $line .= " $rlet2 ".get_ll_stg($rlat2,$rlon2);
            $line .= " b=$hdg/$hdgr l=$rlen ft";
            if (defined $runway_surface{$surf}) {
                $line .= " (".$runway_surface{$surf}.")";
            }
            prt("$line\n");
        } elsif (($typ >= 50) && ($typ <= 56)) {
            $typ -= 50;
            $typ = $off2name2{$typ};
            $freqs{$typ} = [] if (!defined $freqs{$typ});
            $rfa = $freqs{$typ};
            push(@{$rfa}, (${$ra}[1] / 100));
        }
    }
    my $max_line = 100;
    @arr = sort keys %freqs;
    $line = "frqs: ";
    foreach $typ (@arr) {
        $line .= "$typ: ";
        $rfa = $freqs{$typ};
        $tmp = join(" ",@{$rfa}).' ';
        if (length($line.$tmp) > $max_line) {
            prt("$line\n");
            $line = "      ";
        }
        $line .= $tmp;
    }
    prt("$line\n");
    get_metar_wind();
    load_nav_data();
    search_nav_data();
    $line = "$icao $anam ";
    if ($gottwr) {
        $line .= "twr: ".get_ll_stg($alat,$alon).' ';
    } elsif ($rwcnt) {
        $alat = $glat / $rwcnt;
        $alon = $glon / $rwcnt;
        $line .= "rc: ".get_ll_stg($alat,$alon).' ';
    }
    $line .= "$aalt ft. ";
    prt("$line\n");
}

sub find_icao($) {
    my $icao = shift;
    my $t1 = [gettimeofday];
    my ($ver,@arr,$typ,$line,$max,$add,$i,$ra);
    my $gotapt = 0;
    if ($os =~ /win/i) {
        $aptdat = path_u2d($aptdat);
    } else {
        $aptdat = path_d2u($aptdat);
    }
    if ( ! -f $aptdat ) {
        prt("Can NOT 'stat' $aptdat!\n");
        prt("Versify the root folder $FGROOT\n");
        prt("or use the option -a apt-file\n");
        prt("or modify the script ver line 39/40\n");
        pgm_exit(1,"");
    }
    prt("Opening file $aptdat...\n") if (VERB9());
    ##open( APT, "gzip -d -c $aptdat|" ) or mydie( "ERROR: CAN NOT OPEN $aptdat...$!...\n" );
    ##open( APT, ":gzip", $aptdat ) or mydie( "ERROR: CAN NOT OPEN $aptdat...$!...\n" );
    my $APT = IO::Uncompress::Gunzip->new( $aptdat )
        or mydie( "ERROR: CAN NOT OPEN $aptdat...$!...\n" );
    while (<$APT>) {
        chomp;
        if (/^(\d+)\s+Version\s+/) {
            $ver = $1;
            last;
        }
    }
    if ($ver) {
        prt("Searching file $aptdat, version $ver... moment...\n") if (VERB1());
    } else {
        close $APT;
        prt("Failed to find version in $aptdat!\n");
        pgm_exit(1,"");
    }
    while ($line = <$APT>) {
        chomp $line;
        next if ($line =~ /^\s*$/);
        @arr = split(/\s+/,$line);
        $typ = $arr[0];
        last if ($typ == 99);
        if ($typ == 1) {
            if ($arr[4] eq $icao) {
                $gotapt = 1;
                prt(join(" ",@arr)."\n") if (VERB9());
                my @a1 = @arr;
                push(@apt,\@a1);
                while ($line = <$APT>) {
                    chomp $line;
                    next if ($line =~ /^\s*$/);
                    @arr = split(/\s+/,$line);
                    $typ = $arr[0];
                    last if ($typ == 1);
                    last if ($typ == 99);
                    $add = 0;
                    if ($typ == 10) {
                        if ($arr[3] ne 'xxx') {
                            $add = 1;
                        }
                    } elsif ($typ == 14) {
                        $add = 1;
                    } elsif ($typ == 100) {
                        $add = 1;
                    } elsif (($typ >= 50) && ($typ <= 56)) {
                        $add = 1;
                    }
                    if ($add) {
                        my @a2 = @arr;
                        push(@apt,\@a2);
                    }
                }
                last;
            }
        }
    }
    $i = $.;
    close $APT;
    $max = scalar @apt;
    my $elap = secs_HHMMSS( tv_interval( $t1, [gettimeofday] ) );
    prt("Found $max airport components... $i lines in $elap\n") if (VERB2());
    if (!$gotapt) {
        prt("Failed to find airport $icao!\n");
        return;
    }
    show_apt();
}

sub gen_dirs() {
    my $dir = 360;
    my $inc = 22.5;
    my $max = $dir + $inc;
    $max -= 360 if ($max > 350);
    prt("\tif ((\$dir >= ".($dir - $inc).") && (\$dir < ".$max.")) {\n");
    prt("\t\t\$dir = 'N';\n");
    $dir += $inc;
    $dir -= 360 if ($dir >= 360);
    $max = $dir + (2 *$inc);
    $max -= 360 if ($max > 350);
    prt("\t} elsif ((\$dir >= ".$dir.") && (\$dir < ".$max.")) {\n");
    prt("\t\t\$dir = 'NE';\n");
    $dir += 2 * $inc;
    $dir -= 360 if ($dir >= 360);
    $max = $dir + (2 * $inc);
    $max -= 360 if ($max > 350);
    prt("\t} elsif ((\$dir >= ".$dir.") && (\$dir < ".$max.")) {\n");
    prt("\t\t\$dir = 'E';\n");
    $dir += 2 * $inc;
    $dir -= 360 if ($dir >= 360);
    $max = $dir + (2 * $inc);
    $max -= 360 if ($max > 350);
    prt("\t} elsif ((\$dir >= ".$dir.") && (\$dir < ".$max.")) {\n");
    prt("\t\t\$dir = 'SE';\n");
    $dir += 2 * $inc;
    $dir -= 360 if ($dir >= 360);
    $max = $dir + (2 * $inc);
    $max -= 360 if ($max > 350);
    prt("\t} elsif ((\$dir >= ".$dir.") && (\$dir < ".$max.")) {\n");
    prt("\t\t\$dir = 'S';\n");
    $dir += 2 * $inc;
    $dir -= 360 if ($dir >= 360);
    $max = $dir + (2 * $inc);
    $max -= 360 if ($max > 350);
    prt("\t} elsif ((\$dir >= ".$dir.") && (\$dir < ".$max.")) {\n");
    prt("\t\t\$dir = 'SW';\n");
    $dir += 2 * $inc;
    $dir -= 360 if ($dir >= 360);
    $max = $dir + (2 * $inc);
    $max -= 360 if ($max > 350);
    prt("\t} elsif ((\$dir >= ".$dir.") && (\$dir < ".$max.")) {\n");
    prt("\t\t\$dir = 'W';\n");
    $dir += 2 * $inc;
    $dir -= 360 if ($dir >= 360);
    $max = $dir + (2 * $inc);
    $max -= 360 if ($max > 350);
    prt("\t} elsif ((\$dir >= ".$dir.") && (\$dir < ".$max.")) {\n");
    prt("\t\t\$dir = 'NW';\n");
    $dir += $inc;
    $dir -= 360 if ($dir >= 360);
    exit(1);
}

#########################################
### MAIN ###
### gen_dirs();
parse_args(@ARGV);
find_icao($in_icao);
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);
    my $verb = VERB2();
    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);
                    }
                }
                $verb = VERB2();
                prt("Verbosity = $verbosity\n") if ($verb);
            } elsif ($sarg =~ /^l/) {
                if ($sarg =~ /^ll/) {
                    $load_log = 2;
                } else {
                    $load_log = 1;
                }
                prt("Set to load log at end. ($load_log)\n") if ($verb);
            } elsif ($sarg =~ /^o/) {
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                $out_file = $sarg;
                prt("Set out file to [$out_file].\n") if ($verb);
            } else {
                pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n");
            }
        } else {
            $in_icao = $arg;
            prt("Set input to [$in_icao]\n") if ($verb);
        }
        shift @av;
    }

    if ($debug_on) {
        prtw("WARNING: DEBUG is ON!\n");
        if (length($in_icao) ==  0) {
            $in_icao = $def_file;
            prt("Set DEFAULT input to [$in_icao]\n");
        }
    }
    if (length($in_icao) ==  0) {
        pgm_exit(1,"ERROR: No input ICAO found in command!\n");
    }
}

sub give_help {
    prt("$pgmname: version $VERS\n");
    prt("Usage: $pgmname [options] in-icao\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");
    prt(" Givan an ICAO, will search $APTFILE, ");
    if (-f $APTFILE) {
        prt("ok,\n");
    } else {
        prt("NOT FOUND!\n");
    }
    prt("and list the runways for that airport\n");

}

# eof - template.pl
