#!perl -w
# NAME: fgchkaircraft.pl
# AIM: Check 'data/Aircraft' folder for valid aircraft ...
# 25/06/2012 - Review, and UI improvements
# 07/12/2008 - added 'status'
# 11/7/2008 - geoff mclane - http://geoffair.net/fg
use strict;
use warnings;
use File::Basename;  # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] )
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 'lib_xml.pl' or die "Unable to load 'lib_xml.pl' Check paths in \@INC...\n";
### require 'fgutils.pl' or die "Unable to load fgutils.pl ...\n";
### require 'fgscanvc.pl' or die "Unable to load fgscanvc.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 2012-06-25";
my $load_log = 0;
my $verbosity = 0;

my $in_folder = '';
my @warnings = ();
my $tempxml = $temp_dir.$PATH_SEP.'tempxml.xml';

# OPTIONS
my $ord_byfdm = 0;
my $ord_author = 0;
my $ord_status = 0;

# DEBUG
my $debug_on = 0;
my $def_file = 'C:\FG\fgdata\Aircraft\747-200\747-200-set.xml';
my $def_dir = 'C:\FG\fgdata\Aircraft';
my $dbg_cac01 = 0;	# show information during processing ...
my $dbg_cac02 = 1;	# write a tempxml.txt file of all files processed
my $dbg_cac03 = 1;	# show FAILED folders
my $dbg_cac04 = 0;	# show warning, even when NO warnings
my $dbg_cac05 = 0;  # show entry and exit of stages

# program variables
my ($act_name,$act_dir);


##############################
### SUB ONLY

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

sub show_warnings {
	my ($dbg) = shift;
    if (@warnings) {
        prt( "\nGot ".scalar @warnings." WARNINGS ...\n" );
        foreach my $line (@warnings) {
            prt("$line\n" );
        }
        prt("\n");
    } elsif ($dbg || $dbg_cac04) {
        prt("No warnings issued.\n");
    }
}

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;
    if ($tx =~ /\n$/) {
        prt($tx);
        $tx =~ s/\n$//;
    } else {
        prt("$tx\n");
    }
    push(@warnings,$tx);
}

sub mycmp_decend_asc {
   if (${$a}[0] lt ${$b}[0]) {
      # prt( "+[".${$a}[0]."] lt [".${$b}[0]."]\n" ) if $verb3;
      return 1;
   }
   if (${$a}[0] gt ${$b}[0]) {
      # prt( "-[".${$a}[0]."] gt [".${$b}[0]."]\n" ) if $verb3;
      return -1;
   }
   # prt( "=[".${$a}[0]."] = [".${$b}[0]."]\n" ) if $verb3;
   return 0;
}

sub mycmp_ascend_asc {
   return -1 if (${$a}[0] lt ${$b}[0]);
   return 1 if (${$a}[0] gt ${$b}[0]);
   return 0;
}

sub mycmp_ascend_a5 {
   return -1 if (${$a}[5] lt ${$b}[5]);
   return 1 if (${$a}[5] gt ${$b}[5]);
   return 0;
}

sub mycmp_ascend_a4 {
   return -1 if (${$a}[4] lt ${$b}[4]);
   return 1 if (${$a}[4] gt ${$b}[4]);
   return 0;
}

sub mycmp_ascend_a3 {
    return -1 if (${$a}[3] lt ${$b}[3]);
    return 1 if (${$a}[3] gt ${$b}[3]);
    return 0;
}

sub show_hash_ref {
	my ($hr) = shift;
	my ($key, $val, $itm, $msg, $max, $i);
	my $mlen = 10;
	my $desc = '';
	my $auth = '';
	my $fdm  = '';
	my $dir  = '';
	my $txt  = '';
    my $stat = '';
    my $ord  = '';
	my $mxline = 75;
	my $mxfdm = 7;
    if ($ord_byfdm) {
        $ord = "FDM";         # @oks = sort mycmp_ascend_a4 @ok;
    } elsif ($ord_author) {
        $ord = "AUTHOR";      #@oks = sort mycmp_ascend_a3 @ok;
    } elsif ($ord_status) {
        $ord = "STATUS";      #@oks = sort mycmp_ascend_a5 @ok;
    } else {
        $ord = "Alphabetic";    #@oks = sort mycmp_ascend_asc @ok;
    }
	$key = 'OK';
	if (defined $$hr{$key}) {
		$val = $$hr{$key};
		$max = scalar @{$val};
		for ($i = 0; $i < $max; $i++) {
			$itm = $$val[$i][0];
			$fdm  = $$val[$i][4];
			$mlen = length($itm) if (length($itm) > $mlen);
			$mxfdm = length($fdm) if (length($fdm) > $mxfdm);
		}
	}

	foreach $key (keys %{$hr}) {
		$msg = '';
		$val = $$hr{$key};
		$max = scalar @{$val};
		$desc = '';
		$txt = '';
		prt( "\n$key aircraft = $max, ordered by $ord\n" );
		for ($i = 0; $i < $max; $i++) {
			$itm  = $$val[$i][0];
			$dir  = $$val[$i][1];
			$desc = $$val[$i][2];
			$auth = $$val[$i][3];
			$fdm  = $$val[$i][4];
            $stat = $$val[$i][5];
			if ($key eq 'OK') {
				$dir = '<same>' if ($itm eq $dir);
				$itm .= ' ' while (length($itm) < $mlen);
				$desc = '<none>' if (length($desc) == 0);
				$auth = '<unknown>' if (length($auth) == 0);
				$fdm  = '<def.>' if (length($fdm) == 0);
				$fdm .= ' ' while (length($fdm) < $mxfdm);
                $stat  = '<unknown>' if (length($stat) == 0);
				prt("$itm , fdm=$fdm , $stat, desc=$desc, auth=$auth, dir=$dir\n");
			} else {
				$txt .= ', ' if length($txt);
				$txt .= "[$itm]";
				if (length($txt) > $mxline) {
					$msg .= "$txt\n";
					$txt = '';
				}
			}
		}
		if ($key eq 'FAILED') {
			if ($dbg_cac03) {
				$msg .= $txt if length($txt);
				prt( "No Aircraft/folder/<aircraft>-set.xml file found in ...\n" );
				prt( "$msg\n" );
			}
		}
		prt( "$key listed $max by $ord\n" );
	}
}

sub process_folder {
    my ($ff, $setfiles, $aircraft) = @_;
    my ($df, $setfil, $air, @dfiles);
    if ( opendir( DIR, $ff) ) {
        @dfiles = readdir(DIR);
        close DIR;
        foreach $df (@dfiles) {
            next if (($df eq '.') || ($df eq '..'));
            next if ($df eq 'CVS');
            $setfil = $ff . "\\" . $df;
            if (-d $setfil) {
                # skip directories, OR
                process_folder( $setfil, $setfiles, $aircraft );
            } elsif ($df =~ /^(.+)-set.xml$/) {
                $air = $1;		# got an <aircraft>-set.xml file
                push(@$aircraft,$air);
                push(@$setfiles,$setfil);
            }
        }
    }
}

sub process_set_file($$$) {
    my ($setfil,$rok,$air) = @_;
    my $desc = '';
    my $auth = '';
	my $fdm  = '';
    my $status = '';
    my %lnmap = ();
	my ($lnnum, $xln, @attribs, %atthash, $tag);
    my %hash = ();
    ($act_name,$act_dir) = fileparse($setfil);
    $air = $act_name;
    $air =~ s/-set.xml$//;
	prt("Processing $setfil file...\n") if (VERB5());
	if (open INF, "<$setfil") {
        my @lines = <INF>;
		close INF;
        my $xlncnt = scalar @lines;
		@lines = xml_array_to_lines(\%lnmap, @lines); # this re-lines the array
		my $lncnt = scalar @lines;
        if ($dbg_cac02) {	# this is really ONLY FOR DEBUG
            append2file( "\n$setfil\n",$tempxml );
            append2file( join("\n",@lines),$tempxml );
            append2file( "\n",$tempxml );
            prt("Written $lncnt xml lines to [$tempxml]\n") if (VERB9());
        }
        my $inpl = 0;
        my $insim = 0;
        my $indesc = 0;
        my $inauth = 0;
        my $infdm = 0;
        my $instatus = 0;
        my $lnnum = 0;
        my ($line);
        foreach $line (@lines) {
            $lnnum++;
            $xln = $lnmap{$lnnum};
            @attribs = space_split($line);	# split on 'space', but honour quoted text
            $tag = $attribs[0];
            prt("$xln: tag [$tag] line [$line]\n") if ($dbg_cac05);
            if ($tag && length($tag)) {
                if ($inpl) {
                    if ($tag =~ /^<\/PropertyList/) {
                        $inpl = 0;
                    } elsif ($insim) {
                        if ($indesc) {
                            if ($tag =~ /^<\/description>/) {
                                $indesc = 0;
                                prt("$xln: End description\n") if ($dbg_cac05);
                            } else {
                                $desc .= ' ' if length($desc);
                                $desc .= $line;
                            }
                        } elsif ($inauth) {
                            if ($tag =~ /^<\/author>/) {
                                $inauth = 0;
                            } else {
                                $auth .= ' ' if length($auth);
                                $auth .= $line;
                            }
                        } elsif ($infdm) {
                            if ($tag =~ /^<\/flight-model>/) {
                                $infdm = 0;
                            } else {
                                $fdm .= ' ' if length($fdm);
                                $fdm .= $line;
                            }
                        } elsif ($instatus) {
                            if ($tag =~ /^<\/status>/) {
                                $instatus = 0;
                            } else {
                                $status .= ' ' if length($status);
                                $status .= $line;
                            }
                        } else {
                            if ($tag =~ /^<\/sim>/) {
                                $insim = 0;
                                prt("$xln: End sim\n") if ($dbg_cac05);
                            } elsif ($tag =~ /^<description>/) {
                                $indesc = 1;
                                prt("$xln: Bgn description\n") if ($dbg_cac05);
                            } elsif ($tag =~ /^<author>/) {
                                $inauth = 1;
                            } elsif ($tag =~ /^<flight-model>/) {
                                $infdm = 1;
                            } elsif ($tag =~ /^<status>/) {
                                $instatus = 1;
                            }
                        }
                    } elsif (($tag =~ /^<sim>/)||($tag =~ /^<sim\b/)) {
                        $insim = 1;
                        prt("$xln: Bgn sim\n") if ($dbg_cac05);
                    }
                } elsif ($tag =~ /^<PropertyList/) {
                    %atthash = array_2_hash_on_equals(@attribs);
                    $inpl = 1;
                    prt("$xln: Bgn PropertyList\n") if ($dbg_cac05);
                }
            }
        }
    } else {
        prtw( "WARNING: Failed to open $setfil ...\n" );
    }
    # note the $air may NOT be the directory name
    #              0     1        2      3      4     5
    push(@{$rok}, [$air, $setfil, $desc, $auth, $fdm, $status]);
    ###$hash{'OK'} = [@oks];
    $hash{'OK'} = $rok;
	return %hash;

}

sub process_aircraft_folder {
	my ($inf) = shift;
	my @ok = ();
	my @failed = ();
	my %hash = ();
	my (@dfiles, $df);
	my (@setfiles, @aircraft, $i, $setcnt);
	prt( "Processing $inf folder ...\n" );
	write2file( "Processing $inf folder ...\n",$tempxml ) if ($dbg_cac02);
	my $dotcnt = 0;
	my $mxdots = 70;
    my ($fl,$ff,$air,$setfil);
	if ( opendir( DIR, $inf ) ) {
		my @files = readdir(DIR);
		closedir DIR;
		# maybe get all the ???-set.xml files ...
		foreach $fl (@files) {
			next if (($fl eq '.') || ($fl eq '..'));
			next if ($fl eq 'CVS');
			$ff = $inf . "\\" . $fl;
			$setcnt = 0;
			$air = $fl;
			if (-d $ff) {
				# maybe the FOLDER contains ???-set.xml file(s) ...
				@setfiles = ();
				@aircraft = ();
				$setcnt = 0;
                process_folder( $ff, \@setfiles, \@aircraft );
                $setcnt = scalar @setfiles;
				if ($setcnt) {
					if ($dbg_cac01) {
						prt( "$fl = ok\n" );
					} else {
						prt( '.' );
						$dotcnt++;
						if ($dotcnt > $mxdots) {
							prt("\n");
							$dotcnt = 0;
						}
					}
					for ($i = 0; $i < $setcnt; $i++) {
						$air    = $aircraft[$i];
						$setfil = $setfiles[$i];
                        process_set_file($setfil,\@ok,$air);
					}
				} else {
					prt( "$fl = NOT FOUND $setfil\n" ) if ($dbg_cac01);
                    #               0   1    2   3   4   5
					#push(@failed, [$fl, $fl, $desc, $auth, $fdm, $status]);
					push(@failed, [$fl, $fl, "", "", "", ""]);
				}
			}
		}
		prt("\n") if (!$dbg_cac01 && $dotcnt);
	} else {
		prtw( "ERROR: Unable to open $inf ...\n" );
	}
	$hash{'FAILED'} = [ @failed ];
	my @oks = ();
    if ($ord_byfdm) {
        @oks = sort mycmp_ascend_a4 @ok;
    } elsif ($ord_author) {
        @oks = sort mycmp_ascend_a3 @ok;
    } elsif ($ord_status) {
        @oks = sort mycmp_ascend_a5 @ok;
    } else {    # default alphabetic
        @oks = sort mycmp_ascend_asc @ok;
    }

	$hash{'OK'}     = [ @oks ];
	return %hash;
}

# MAIN
############################################################

parse_args(@ARGV);

$| = 1;		# set no print output buffering
my %h = ();
if (-d $in_folder) {
    %h = process_aircraft_folder($in_folder);    # get LIST from ALL <aircraft>-set.xml files
} elsif (-f $in_folder) {
    my @a = ();
    if ($dbg_cac02) {
    	write2file( "Processing $in_folder file...\n",$tempxml );
        prt("Writting xml to $tempxml\n");
    }
    %h = process_set_file($in_folder,\@a,$in_folder);
}

show_hash_ref( \%h );	# output the list

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,$msg);
    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_xml = $sarg;
            #    prt("Set out file to [$out_xml].\n") if (VERB1());
            } elsif ($sarg =~ /^s/) {
                need_arg(@av);
                shift @av;
                $sarg = $av[0];

                if ($sarg eq 'fdm') {
                    $ord_byfdm = 1;
                } elsif ($sarg eq 'author') {
                    $ord_author = 1;
                } elsif ($sarg eq 'status') {
                    $ord_status = 1;
                } else {
                    pgm_exit(1,"ERROR: Sort order can only be fdm|author|status, NOT [$sarg]\n");
                }
                prt("Set SORT order per [$sarg]\n") if (VERB1());
            } else {
                pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n");
            }
        } else {
            if (-d $arg) {
                $in_folder = $arg;
                prt("Set input to [$in_folder]\n") if (VERB1());
            } elsif (-f $arg) {
                $in_folder = $arg;
                prt("Set input to [$in_folder]\n") if (VERB1());
            } else {
                pgm_exit(1,"ERROR: Input [$arg] is neither folder, nor file!\n");
            }
        }
        shift @av;
    }

    if ((length($in_folder) ==  0) && $debug_on) {
        #$in_folder = $def_file;
        $in_folder = $def_dir;
        prt("Set DEFAULT input to [$in_folder]\n");
        $load_log = 2;
    }
    if (length($in_folder) ==  0) {
        pgm_exit(1,"ERROR: No input folder found in command!\n");
    }
    if ((! -d $in_folder) && (! -f $in_folder)) {
        pgm_exit(1,"ERROR: Unable to find in folder or file [$in_folder]! Check name, location...\n");
    }
}

sub give_help {
    prt("$pgmname: version $VERS\n");
    prt("Usage: $pgmname [options] in-folder\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(" --sort ord    (-s) = Sort order. Options are fdm|author|status. Default is alphabetic.\n");
    #prt(" --out <file>  (-o) = Write output to this file.\n");
}


# eof - fgchkaircraft.pl

