#   PreProcessor 0.1
#   by Csaba Peterfalvi
#   peterfalvi.web.elte.hu
#   09-12-2011

######################################################################################################################
#   General File PreProcessor
#   ((w)perl) preprocessor.pl CommentCharacter JobFile
#   See documentation.

#   keywords: file IO, regular expressions, string matching, string manipulation, PC independent, subroutine, rewriting file in place


# use strict;

# points to preprocessor_subs.pl
@parts = split(/\\/,$0);
$temp=$0 . 'preprocessor_subs.pl';
$temp=~s/$parts[-1]//;
require $temp;


$CommentChar = shift @ARGV;
$JobFile = shift @ARGV;
$JobFile=~s/\//\\/g;

open($in, '<', $JobFile) or die ("$JobFile not found.\n");

@parts = split(/\\/,$JobFile);
$Path=$JobFile;
$Path=~s/\\$parts[-1]//;
$SPC_PATH=$Path;

#####################################################################################
# SubRoutines

sub SlurpFile($){
	my $filename = shift;
	open F, "< $filename" or return "";
	local $/ = undef;           # Read entire file at once
	my $contents = <F>;         # Return file as one single `line'
	close F;
	return $contents;
}

sub ReplaceVars($\@$$){
	my($myfile)=shift;
	my(@Defs)=@{(shift)};
	my($Path)=shift;
	my($CommentChar)=shift;
	my $VarNames='my(';
	my(@VarDefs)=();
	my $temp;

	while ($myfile =~ m/\n$CommentChar#VAR_(\w+?) *= *""(.*?)""/gs){
		$VarNames=$VarNames.'$VAR_'.$1.',';
		$temp='$VAR_'.$1.'=\''.$2.'\';';
		$temp=~s/\n$CommentChar/\n/g;
		$temp=subs($temp,$Path);
		push(@VarDefs,"$temp");};
	
	$VarNames=~s/.$//;
	$VarNames=$VarNames.');';
	eval $VarNames;
	foreach my $VarDefs(@VarDefs){eval $VarDefs;};

	foreach my $Defs(@Defs){
		$temp='$myfile=~'.$Defs.';';
		eval $temp;}
	
	return $myfile;
}

#####################################################################################
# Gathers the files with jobs to do from the JobFile...

@JobWPP=();@JobUD=();@JobUD2=();@JobUDO=();@JobUDO2=();
while(<$in>){
	chomp($_);
	if(m/^$CommentChar#WRITEPP: *"(.+)"/){
		$temp=subs($1,$Path);
		push(@JobWPP,"$temp");}
	elsif(m/^$CommentChar#UPDATE: +"([^>]+)"/){
		$temp=subs($1,$Path);
		push(@JobUD,"$temp");
		if(m/>>> +(.+)/){
			$temp=subs($1,$Path);
			push(@JobUD2,"$temp");}
		else{push(@JobUD2,"");};}
	elsif(m/^$CommentChar#UPDATEON: +(\w+) +"([^>]+)"/){
		$CurrentComputerName=$ENV{COMPUTERNAME};
		$UpdatedOnComputerName=$1;
		if ($UpdatedOnComputerName ne $CurrentComputerName){
			$temp=subs($2,$Path);
			push(@JobUDO,"$temp");
			if(m/>>> +(.+)/){
				$temp=subs($1,$Path);
				push(@JobUDO2,"$temp");}
			else{push(@JobUDO2,"");};};};}
close($in);

#####################################################################################
# Carries out the changes in the files set by the #UPDATEON commands in the JobFile...

$NJobUDO=-1;
foreach $JobUDO(@JobUDO){
	@Defs=();
	$NJobUDO++;

	$temp = 'copy ' . $JobUDO . ' ' . $JobUDO . '.ppbckp';
	system($temp);

	$myfile=SlurpFile($JobUDO);
	if($myfile eq ""){
		print "WARNING: $JobUDO could not be accessed for reading.\n\n";
		next;}

	while ($myfile =~ m/\n$CommentChar#DEFON.*?= *""(.*?)""/g){
		subv($1);
		push(@Defs,"$1");}

	$myfile=ReplaceVars($myfile,@Defs,$Path,$CommentChar);
	
	print "Updating $JobUDO on ".$ENV{COMPUTERNAME}."...\n\n";
	
	open($out, '>', $JobUDO);
	print $out "$myfile";
	close($out);

	system($JobUDO2[$NJobUDO]);
}

# Resets the ComputerName in the #UPDATEON items in the JobFile...
$JobUDO=@JobUDO;
if($JobUDO>0){

	open($in, '+<', $JobFile);

	@pplines = <$in>;
	$NLine=-1;
	foreach $pplines(@pplines){
		$NLine++;

		if($pplines=~/^$CommentChar#UPDATEON: *(\w+)/){

			$UpdatedOnComputerName=$1;
			if ($UpdatedOnComputerName ne $CurrentComputerName){
				$pplines[$NLine]=~s/$UpdatedOnComputerName/$CurrentComputerName/;};};}

	seek($in,0,0);
	print $in @pplines;
	truncate($in,tell($in));
	close($in);
}

#####################################################################################
# Carries out the changes in the files set by the #UPDATE commands in the JobFile...

$NJobUD=-1;
foreach $JobUD(@JobUD){
	@Defs=();
	$NJobUD++;

	$myfile=SlurpFile($JobUD);
	if($myfile eq ""){
		print "WARNING: $JobUD could not be accessed for reading.\n\n";
		next;}

	$myfile_old=$myfile;

	while ($myfile =~ m/\n$CommentChar#DEF(.*?)= *""(.*?)""/g){
		if(!($1=~m/^ON/)){
			subv($2);
			push(@Defs,"$2");};};

	$myfile=ReplaceVars($myfile,@Defs,$Path,$CommentChar);

	if($myfile_old ne $myfile){
		$temp = 'copy ' . $JobUD . ' ' . $JobUD . '.ppbckp';
		system($temp);
	
		print "Updating $JobUD...\n\n";

		open($out, '>', $JobUD);
		print $out "$myfile";
		close($out);

		system($JobUD2[$NJobUD]);}
}

#####################################################################################
# Carries out the changes in the files set by the #WRITEPP commands in the JobFile...

foreach $JobWPP(@JobWPP){

	$myfile=SlurpFile($JobWPP);
	if($myfile eq ""){
		print "WARNING: $JobWPP could not be accessed for reading.\n\n";
		next;}

	$JobWPP=~s/(\.\w+)$/_pp$1/;
	open($out, '>', $JobWPP);
	
	print "Writing $JobWPP...\n\n";

	$myfile2=$myfile;
	while ($myfile =~ m/\n$CommentChar#(VAR_\w+?) *= *"".(.*?).""/gs){
		$temp1='\$'.$1;
		$temp2=subs($2,$Path);
		$temp2=~s/\n$CommentChar/\n/g;
		$myfile2=~s/$temp1/$temp2/g;};

	open($out, '>', $JobWPP);
	print $out "$myfile2";
	close($out);
}


# This is the obsolate line-by-line version, also with the old syntax.
# Carries out the changes in the files set by the #WRITEPP commands in the JobFile...
# %csere=();
# foreach $JobWPP(@JobWPP){
	# open($in, '<', $JobWPP) or $in=0;
	# if($in==0){
		# print "WARNING: $JobWPP not found.\n\n";
		# next;}
	
	# $JobWPP=~s/(\.\w+)$/_pp$1/;
	# open($out, '>', $JobWPP);
	
	# print "Processing $JobWPP...\n\n";
	
	# while(<$in>){
		# $outline=$_;
		# foreach $key (keys %csere){$outline=~s/#$key/$csere{$key}/g;}
		# if(m/\n$CommentChar#(\w+)=""(.+)""/){
			# $csere{$1}=subs($2,$Path);};
		# print $out "$outline";}

	# close($out);
	# close($in);
# }
