#!/usr/bin/perl -w
# NAME: vcprojlist02.pl
# AIM: Parse a vcxproj file, showwing information
# see earlier vcprojlist.pl for a pevious attempt
# 26/08/2013 geoff mclane http://geoffair.net/mperl
use strict;
use warnings;
use File::Basename;  # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] )
use XML::Simple;
use Data::Dumper;
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";
# 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 $in_file = '';
my $verbosity = 0;
my $out_file = '';
my $indent = "\t";

# ### DEBUG ###
my $debug_on = 1;
my $def_file = 'C:\FG\18\build-osg\src\osgPlugins\png\osgdb_png.vcxproj';

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

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

# string reference
# SCALAR ARRAY HASH CODE REF GLOB LVALUE FORMAT IO VSTRING Regexp

# ItemGroup [ARRAY]
# xmlns []
# Import [ARRAY]
# ImportGroup [ARRAY]
# PropertyGroup [ARRAY]
# DefaultTargets []
# ToolsVersion []
# ItemDefinitionGroup [ARRAY]
sub process_ref_array($$$$);
sub process_ref_hash($$$);

sub show_ref_array($$) {
    my ($key,$val) = @_;
    my ($acnt,$ky2,$ref2);
    $acnt = scalar @{$val};
    # out a single line list
    prt("$key [ARRAY] $acnt: ");
    foreach $ky2 (@{$val}) {
        $ref2 = ref($ky2);
        if (length($ref2)) {
            prt("[$ref2] ");
        } else {
            prt("V[$ky2] ");
        }
    }
    prt("\n");
}

sub show_ref_hash($$$) {
    my ($ind,$ky2,$rvals) = @_;
    my $dnout = 0;
    my ($ky3,$val3,$ref3);
    foreach $ky3 (keys %{$ky2}) {
        $val3 = ${$ky2}{$ky3};
        $ref3 = ref($val3);
        if (length($ref3)) {
            if (VERB5()) {
                prt($ind."$ky3 [$ref3] ");
                $dnout++;
            }
        } else {
            if (VERB9()) {
                prt($ind."$ky3 V[$val3] ");
                $dnout++;
            }
        }
    }
    prt("\n") if ($dnout);
}

sub process_ref_hash($$$) {
    my ($ind,$ky2,$rvals) = @_;
    my ($ky3,$val3,$ref3);
    show_ref_hash($ind,$ky2,$rvals) if (VERB5());
    foreach $ky3 (keys %{$ky2}) {
        $val3 = ${$ky2}{$ky3};
        $ref3 = ref($val3);
        if (length($ref3)) {
            if ($ref3 eq 'HASH') {
                push(@{$rvals},[$ky3,"[$ref3]",$ind]);
                process_ref_hash($ind.$indent,$val3,$rvals);
            } elsif ($ref3 eq 'ARRAY') {
                push(@{$rvals},[$ky3,"[$ref3]",$ind]);
                process_ref_array($ind.$indent,$ky3,$val3,$rvals);
            } else {
                prtw("WARNING: $ky3 SKIPPED [$ref3] - FIX ME!\n");
            }
        } else {
            push(@{$rvals},[$ky3,$val3,$ind]);
        }
    }

}


sub process_ref_array($$$$) {
    my ($ind,$key,$val,$rvals) = @_;
    show_ref_array($key,$val) if (VERB5());
    my ($ky2,$ref,$ref2,$dnout,$ky3,$val3,$ref3);
    foreach $ky2 (@{$val}) {
        $ref2 = ref($ky2);
        if (length($ref2)) {
            if ($ref2 eq 'HASH') {
                push(@{$rvals},["processing","[$ref2]",$ind]);
                process_ref_hash($ind.$indent,$ky2,$rvals);
            } else {
                prtw("WARNING: SKIPPED [$ref2] - FIX ME!\n");
            }
        }
    }
}


# ClCompile [HASH]
#  PreprocessorDefinitions = string;string;... eg WIN32;_WINDOWS;_DEBUG;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;OSG_CPP_EXCEPTIONS_AVAILABLE;CMAKE_INTDIR=\"Debug\";osgdb_png_EXPORTS;%(PreprocessorDefinitions)
#  AdditionalIncludeDirectories = string eg C:/FG/18/OpenSceneGraph-3.1.5/include;C:/FG/18/build-osg/include;C:/FG/18/3rdParty/include;%(AdditionalIncludeDirectories)
# Link [HASH]
#  AdditionalDependencies eg kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;..\..\..\lib\OpenThreadsd.lib;..\..\..\lib\osgd.lib;..\..\..\lib\osgDBd.lib;..\..\..\lib\osgUtild.lib;C:\FG\18\3rdParty\lib\libpng.lib;C:\FG\18\3rdParty\lib\zlibd.lib;opengl32.lib;..\..\..\lib\osgd.lib;..\..\..\lib\OpenThreadsd.lib;opengl32.lib
#  SubSystem = Console
#  Include = ..\..\..\..\OpenSceneGraph-3.1.5\src\osgPlugins\png\ReaderWriterPNG.cpp
#  Include = ..\..\..\PlatformSpecifics\Windows\OpenSceneGraphVersionInfo.rc
my %skip_defs = (
    'NDEBUG' => 1,
    '_WINDOWS' => 2
    );
my @skip_libs = qw( advapi32.lib comdlg32.lib gdi32.lib kernel32.lib ole32.lib oleaut32.lib opengl32.lib shell32.lib user32.lib uuid.lib winspool.lib );

sub in_skip_libs($) {
    my $lib = lc(shift);
    my ($tmp);
    foreach $tmp (@skip_libs) {
        return 1 if ($tmp eq $lib);
    }
    return 0;
}

sub show_value_collected($) {
    my $ra = shift;
    my $cnt = scalar @{$ra};
    prt("\nGot $cnt values...\n");
    my ($i,$key,$val,$ind,$msg,@arr,$tmp);
    my %sources = ();
    my %prepro = ();
    my %incdirs = ();
    my %libs = ();
    for ($i = 0; $i < $cnt; $i++) {
        $key = ${$ra}[$i][0];
        $val = ${$ra}[$i][1];
        $ind = ${$ra}[$i][2];
        if ($val =~ /^\[.+\]$/) {
            $msg = $ind."$key $val";
        } else {
            $msg = $ind."$key = $val";
            if ($key eq 'PreprocessorDefinitions') {
                @arr = split(";",$val);
                foreach $tmp (@arr) {
                    next if ($tmp =~ /^\%/);
                    next if ($tmp =~ /^CMAKE_INTDIR/);
                    next if (defined $skip_defs{$tmp});
                    $prepro{$tmp} = 1;
                }
            } elsif ($key eq 'AdditionalIncludeDirectories') {
                @arr = split(";",$val);
                foreach $tmp (@arr) {
                    next if ($tmp =~ /^\%/);
                    $incdirs{$tmp} = 1;
                }
            } elsif ($key eq 'AdditionalDependencies') {
                @arr = split(";",$val);
                foreach $tmp (@arr) {
                    next if ($tmp =~ /^\%/);
                    next if (in_skip_libs($tmp));
                    $libs{$tmp} = 1;
                }
            } elsif ($key eq 'Include') {
                @arr = split(";",$val);
                foreach $tmp (@arr) {
                    next if ($tmp =~ /^\%/);
                    next if ($tmp =~ /CMakeLists.txt$/);
                    next if ($tmp =~ /\.vcxproj$/);
                    next if ($tmp =~ /\|Win32$/);
                    $sources{$tmp} = 1;
                }
            }
        }
    }
    @arr = sort keys %prepro;
    prt("Defs: ".join(" ",@arr)."\n");
    @arr = sort keys %incdirs;
    prt("Incs: ".join(" ",@arr)."\n");
    @arr = sort keys %libs;
    prt("Libs: ".join(" ",@arr)."\n");
    @arr = sort keys %sources;
    prt("Srcs: ".join(" ",@arr)."\n");
}

sub process_in_file($) {
    my ($inf) = @_;
    my $xml = XMLin($inf);
    ##prt(Dumper($xml));
    my @values = ();
    my ($i,$key,$val,$ref,$acnt,$ky2,$val2,$ref2,$ind,$cnt,$ky3,$val3,$ref3,$hdr,$dnout);
    $ind = '';
    foreach $key (keys %{$xml}) {
        $val = ${$xml}{$key};
        $ref = ref($val);
        if (length($ref)) {
            if ($ref eq 'ARRAY') {
                push(@values,[$key,"[$ref]",$ind]);
                process_ref_array($ind,$key,$val,\@values);
            } else {
                prtw("WARNING: $key [$ref] SKIPPED -FIX ME!\n");
            }
        } else {
            prt("$key V[$val]\n") if (VERB9());
            push(@values,[$key,$val,$ind]);
        }
    }

    show_value_collected(\@values);
    $load_log = 1;
}

#########################################
### MAIN ###
parse_args(@ARGV);
process_in_file($in_file);
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 {
            $in_file = $arg;
            prt("Set input to [$in_file]\n") if (VERB1());
        }
        shift @av;
    }

    if ($debug_on) {
        prtw("WARNING: DEBUG is ON!\n");
        if ((length($in_file) ==  0) && $debug_on) {
            $in_file = $def_file;
            prt("Set DEFAULT input to [$in_file]\n");
        }
    }
    if (length($in_file) ==  0) {
        pgm_exit(1,"ERROR: No input files found in command!\n");
    }
    if (! -f $in_file) {
        pgm_exit(1,"ERROR: Unable to find in file [$in_file]! Check name, location...\n");
    }
}

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 - template.pl
