#!/perl -w
# NAME: xmltwig02.pl
# AIM: Using the XML::Twig interface, especially on VCPROJ files
# Develop some Twig functions, to see how long it takes ...
# 28/11/2007 - geoff mclane - http://geoffair.net/mperl
use strict;
use warnings;
require 'logfile.pl' or die "Unable to load logfile.pl ...\n";
# log file stuff
my ($LF);
my $pgmname = $0;
if ($pgmname =~ /\w{1}:\\.*/) {
	my @tmpsp = split(/\\/,$pgmname);
	$pgmname = $tmpsp[-1];
}
my $outfile = "temp.$pgmname.txt";
open_log($outfile);
prt( "$0 ... Hello, World ...\n" );

use XML::Twig;
use Data::Dumper;

my $do_fg = 0;
my $do_test = 0;
my $get_sources = 1;
my ($file, $grp1, $grp2, $grp3, $msg);
my $min_key = (8 + 8);

$file = 'c:\FG\18\flightgear\projects\VC8\flightgear.vcproj';
if ($do_fg) {
	$file = 'c:\FG\18\flightgear\projects\VC8\flightgear.vcproj';
	# for a VCPROJ document
	# root = VisualStudioProject
	# 2 <Configurations> each <Configuration ...>, each with multiple <Tool ...>
	# <Files> mult <Filter ...> with mult <File RelativePath="...">
	$grp1 = 'Configurations';
	$grp2 = 'Configuration';
	$grp3 = 'Tool';
} elsif ($do_test) {
	$file = 'C:/FGCVS/FlightGear/data/keyboard.xml';
	# root = PropertyList
	$grp1 = 'key';
	$grp2 = 'name';
	$grp3 = 'desc';
}

if ($do_fg || $do_test) {
	my $twig = XML::Twig->new();

	$twig->set_pretty_print( 'indented');

	$twig->parsefile($file);

	my $root = $twig->root;
	#prt( Dumper($root) );
	if ($do_fg) {
		prt( "Getting $grp1 array ..." );
		my @configs = $root->children($grp1);
		prt( " Count = ".scalar @configs."\n" );
		my $cnt = 0;
		foreach my $conf (@configs) {
			$cnt++;
			prt( "$cnt <$grp1>\n" );
			#prt( $conf->sprint );
			#prt( "\n" );
			my @cfgs = $conf->children($grp2);
			foreach my $cnf (@cfgs) {
				# <Configuration ConfigurationType="1" IntermediateDirectory="Debug" Name="Debug|Win32" OutputDirectory="Debug">
				$msg = "Name = " . $cnf->att('Name');
				my @tools = $cnf->children('Tool');
				$msg .= " Tool cnt ".scalar @tools;
				#prt( $cnf->sprint );
				prt( "$msg\n" );
				my $show = 0;
				foreach my $tl (@tools) {
					$msg = $tl->att('Name');
					$show = 0;
					if ($msg eq 'VCCLCompilerTool') {
						# <Tool Name="VCCLCompilerTool"
						# AdditionalIncludeDirectories="../../../;$(ProgramFiles)/OpenThreads/include;$(ProgramFiles)/OpenSceneGraph/include;../../../Simgear;../../src;../../src/include;../../src/input;../../src/FDM/JSBSim;../../../3rdparty/include" 
						# BasicRuntimeChecks="3" 
						# DebugInformationFormat="4" 
						# Detect64BitPortabilityProblems="false" 
						# MinimalRebuild="true" 
						# Optimization="0" 
						# PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;ENABLE_THREADS;HAVE_CONFIG_H;_CRT_SECURE_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX" 
						# RuntimeLibrary="3" 
						# UsePrecompiledHeader="0" 
						# WarningLevel="3"/>
						$msg .= ' RT = '.$tl->att('RuntimeLibrary');
						$msg .= ' I = '.$tl->att('AdditionalIncludeDirectories');
						$msg .= ' PP = '.$tl->att('PreprocessorDefinitions');
						$show = 1;
					} elsif ($msg eq "VCLinkerTool") {
						# <Tool Name="VCLinkerTool"
						# AdditionalDependencies="FlightgearLib.lib Simgear.lib fnt.lib js.lib net.lib psl.lib puAux.lib pui.lib pw.lib sg.lib sl.lib ul.lib osgDBd.lib osgGAd.lib osgViewerd.lib osgUtild.lib osgParticled.lib osgTextd.lib osgd.lib OpenThreadsd.lib libjpeg.lib pthreadvc2.lib Alut.lib openal32.lib glu32.lib opengl32.lib winmm.lib zlib1.lib wsock32.lib advapi32.lib comdlg32.lib shell32.lib user32.lib" 
						# AdditionalLibraryDirectories="&quot;FG$(IntDir)&quot;;$(ProgramFiles)/OpenThreads/lib;$(ProgramFiles)/OpenSceneGraph/lib;../../../plib/;&quot;../../../Simgear/Projects/VC8/$(IntDir)&quot;;../../../3rdParty/lib" 
						# FixedBaseAddress="1" 
						# GenerateDebugInformation="true" 
						# IgnoreDefaultLibraryNames="libcmt.lib" 
						# LargeAddressAware="2" 
						# LinkIncremental="2" 
						# SubSystem="2" 
						# TargetMachine="1"/>
						$msg .= " AD = ".$tl->att('AdditionalDependencies');
						$msg .= " AP = ".$tl->att('AdditionalLibraryDirectories');
						$show = 1;
					}
					prt( "$msg\n" ) if ($show);
				}
			}
		}
		my @files = $root->children("Files");
		prt( "Files Count = ".scalar @files."\n" );
		foreach my $file (@files) {
			my @filts = $file->children('Filter');
			prt( "Filt Count = ".scalar @filts."\n" );
			foreach my $filt (@filts) {
				#prt( $filt->sprint );
				$msg = "Group: ".$filt->att('Name');
				$msg .= " Filter: " . $filt->att('Filter');
				my @fils = $filt->children('File');
				$msg .= " File Count = ".scalar @fils;
				prt( "$msg\n" );
				foreach my $fil (@fils) {
					$msg = " ". $fil->att('RelativePath');
					#prt( $fil->sprint );
					prt( "$msg\n" );
				}
			}
		}
		prt( "Done list ...\n" );
	} elsif ($do_test) {
		foreach my $species ($root->children($grp1)) {
			$msg = "$grp1: ".$species->first_child_text($grp2)." ";
			$msg .= "n=".$species->att('n');
			while (length($msg) < $min_key) {
				$msg .= " ";
			}
		#    print ' (' . $species->att('key') . ') ';
			$msg .= ' (';
			$msg .= "$grp3: ".$species->first_child_text($grp3);
		#    print $species->first_child('conservation')->att('status');
			$msg .= ')';
			prt( "$msg\n" );
		}
		prt( "Done list ...\n" );
	}
}

prt( "File [$file] has RUNTIMES:\n" );
prt( get_xml_runtime($file)."\n" );
if ($get_sources) {
	my @groups = get_xml_groups($file);
	foreach my $gp (@groups) {
		my @csrcs = get_xml_sources($file, $gp, 0);
		my $filter = get_xml_filter($file, $gp);
		prt( "Group: $gp ... ".scalar @csrcs." files ...Filter=$filter\n" );
		prt( " ".join("\n",@csrcs)."\n" );
	}
}
my @inc_dirs = get_xml_include_dirs($file);
prt( "AdditionalIncludeDirectories are -\n" );
prt( join("\n",@inc_dirs)."\n" );
my @pre_items = get_xml_pre_definitions($file);
prt( "PreprocessorDefinitions are -\n" );
prt( join("\n",@pre_items)."\n" );
#$twig->set_pretty_print( 'indented');
#$twig->print;

close_log($outfile,1);
exit(0);

sub get_xml_runtime {
	my ($fil) = shift;
	my $t = XML::Twig->new();
	$t->parsefile($fil);
	my $rt = $t->root;
	my @configs = $rt->children('Configurations');
	my $msg = '';
	foreach my $conf (@configs) {
		my @cfgs = $conf->children('Configuration');
		foreach my $cnf (@cfgs) {
			# <Configuration ConfigurationType="1" IntermediateDirectory="Debug" Name="Debug|Win32" OutputDirectory="Debug">
			$msg .= "*" if (length($msg));
			$msg .= $cnf->att('Name');
			$msg .= '|';
			$msg .= $cnf->att('IntermediateDirectory');
			$msg .= '|';
			$msg .= $cnf->att('OutputDirectory');
			# THIS WORKS from: http://www.xmltwig.com/xmltwig/quick_ref.html
			#my $attrs = $cnf->atts;	# get a HASH reference to the attributes
			#prt( "Got ".scalar keys(%{$attrs})." keys ...\n" );
			#foreach my $key (keys %{$attrs}) {
			#	prt("$key = ".${$attrs}{$key}."\n" );
			#}
			my @tools = $cnf->children('Tool');
			foreach my $tl (@tools) {
				my $tn = $tl->att('Name');
				if ($tn eq 'VCCLCompilerTool') {
					$msg .= '|'.$tl->att('RuntimeLibrary');
					last;
				}
			}
		}
	}
	return $msg;
}

sub get_xml_include_dirs {
	my ($fil) = shift;
	my $t = XML::Twig->new();
	$t->parsefile($fil);
	my $rt = $t->root;
	my @configs = $rt->children('Configurations');
	my @ret = ();
	my $msg = '';
	foreach my $conf (@configs) {
		my @cfgs = $conf->children('Configuration');
		foreach my $cnf (@cfgs) {
			# <Configuration ConfigurationType="1" IntermediateDirectory="Debug" Name="Debug|Win32" OutputDirectory="Debug">
			$msg = $cnf->att('Name');
			#$msg .= $cnf->att('IntermediateDirectory');
			#$msg .= '|';
			#$msg .= $cnf->att('OutputDirectory');
			# THIS WORKS from: http://www.xmltwig.com/xmltwig/quick_ref.html
			#my $attrs = $cnf->atts;	# get a HASH reference to the attributes
			#prt( "Got ".scalar keys(%{$attrs})." keys ...\n" );
			#foreach my $key (keys %{$attrs}) {
			#	prt("$key = ".${$attrs}{$key}."\n" );
			#}
			my @tools = $cnf->children('Tool');
			foreach my $tl (@tools) {
				my $tn = $tl->att('Name');
				if ($tn eq 'VCCLCompilerTool') {
					#<Tool
					# Name="VCCLCompilerTool"
					# AdditionalIncludeDirectories="../../../;$(ProgramFiles)/OpenThreads/include;$(ProgramFiles)/OpenSceneGraph/include;../../../Simgear;../../src;../../src/include;../../src/input;../../src/FDM/JSBSim;../../../3rdparty/include"
					# PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;ENABLE_THREADS;HAVE_CONFIG_H;_CRT_SECURE_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;_USE_MATH_DEFINES;NOMINMAX"
					# StringPooling="true"
					# RuntimeLibrary="2"
					# UsePrecompiledHeader="0"
					# WarningLevel="3"
					# Detect64BitPortabilityProblems="false"
					# DebugInformationFormat="3"/>
					$msg .= '|'.$tl->att('AdditionalIncludeDirectories');
					push(@ret,$msg);
					last;
				}
			}
		}
	}
	return @ret;
}

sub get_xml_pre_definitions {
	my ($fil) = shift;
	my $t = XML::Twig->new();
	$t->parsefile($fil);
	my $rt = $t->root;
	my @configs = $rt->children('Configurations');
	my @ret = ();
	my $msg = '';
	foreach my $conf (@configs) {
		my @cfgs = $conf->children('Configuration');
		foreach my $cnf (@cfgs) {
			# <Configuration ConfigurationType="1" IntermediateDirectory="Debug" Name="Debug|Win32" OutputDirectory="Debug">
			$msg = $cnf->att('Name');
			#$msg .= $cnf->att('IntermediateDirectory');
			#$msg .= '|';
			#$msg .= $cnf->att('OutputDirectory');
			# THIS WORKS from: http://www.xmltwig.com/xmltwig/quick_ref.html
			#my $attrs = $cnf->atts;	# get a HASH reference to the attributes
			#prt( "Got ".scalar keys(%{$attrs})." keys ...\n" );
			#foreach my $key (keys %{$attrs}) {
			#	prt("$key = ".${$attrs}{$key}."\n" );
			#}
			my @tools = $cnf->children('Tool');
			foreach my $tl (@tools) {
				my $tn = $tl->att('Name');
				if ($tn eq 'VCCLCompilerTool') {
					#<Tool
					# Name="VCCLCompilerTool"
					# AdditionalIncludeDirectories="../../../;$(ProgramFiles)/OpenThreads/include;$(ProgramFiles)/OpenSceneGraph/include;../../../Simgear;../../src;../../src/include;../../src/input;../../src/FDM/JSBSim;../../../3rdparty/include"
					# PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;ENABLE_THREADS;HAVE_CONFIG_H;_CRT_SECURE_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;_USE_MATH_DEFINES;NOMINMAX"
					# StringPooling="true"
					# RuntimeLibrary="2"
					# UsePrecompiledHeader="0"
					# WarningLevel="3"
					# Detect64BitPortabilityProblems="false"
					# DebugInformationFormat="3"/>
					$msg .= '|'.$tl->att('PreprocessorDefinitions');
					push(@ret,$msg);
					last;
				}
			}
		}
	}
	return @ret;
}


sub get_xml_sources {
	my ($fil, $typ, $dbg) = @_;
	prt( "Seeking [$typ] in $fil ...\n" ) if ($dbg);
	my $t = XML::Twig->new();
	$t->parsefile($fil);
	my $rt = $t->root;
	my @rfiles = ();
	my @files = $rt->children("Files");
	#prt( "Got ".scalar @files." Files items ...\n" );
	foreach my $file (@files) {
		my @filts = $file->children('Filter');
		prt( "Got ".scalar @filts." Filter items ...\n" ) if ($dbg);
		foreach my $filt (@filts) {
			my $gn = $filt->att('Name');
			prt( "FN = $gn\n" ) if ($dbg);
			if ($gn eq $typ) {
				my @fils = $filt->children('File');
				prt( "Got ".scalar @fils." File items ...\n" ) if ($dbg);
				foreach my $fil (@fils) {
					push(@rfiles,$fil->att('RelativePath'));
				}
				last;
			}
		}
	}
	return @rfiles;
}

sub get_xml_groups {
	my ($fil) = shift;
	my $t = XML::Twig->new();
	$t->parsefile($fil);
	my $rt = $t->root;
	my @rfiles = ();
	my @files = $rt->children("Files");
	foreach my $file (@files) {
		my @filts = $file->children('Filter');
		foreach my $filt (@filts) {
			my $gn = $filt->att('Name');
			push(@rfiles,$gn);
		}
	}
	return @rfiles;
}

sub get_xml_filter {
	my ($fil, $typ) = @_;
	my $t = XML::Twig->new();
	$t->parsefile($fil);
	my $rt = $t->root;
	my @files = $rt->children("Files");
	my $filter = '';
	foreach my $file (@files) {
		my @filts = $file->children('Filter');
		foreach my $filt (@filts) {
			# <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
			my $gn = $filt->att('Name');
			##prt( "Comparing [$gn] with $typ \n" );
			if ($gn eq $typ) {
				$filter = $filt->att('Filter');
				##prt( "Got filter [$filter] with $typ \n" );
				last;
			}
		}
	}
	return $filter;
}


# eof - xmltwig02.pl
