#  Copyright (c) 2018
#  Charles Jordan (Hokkaido University, Sapporo, Japan),
#  Michael Joswig, Lars Kastner (Technische Universitaet Berlin, Germany)
# 
#  This program is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by the
#  Free Software Foundation; either version 3, or (at your option) any
#  later version: http://www.gnu.org/licenses/gpl.txt.
# 
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#-------------------------------------------------------------------------------

use strict;
use Cwd;
use Config;
use File::Path;

use vars '$root', '%ConfigFlags';
my ($targets_file, $config_file);
($targets_file, $root, $config_file)=@ARGV;

unless (@ARGV==3 && -f $config_file && -d $root) {
   die "usage: $0 BUILD_ROOT/targets.ninja PROJECT_TOP BUILD_ROOT/config.ninja\n";
}

do "$root/support/install_utils.pl";
die $@ if $@;

# for file in src{,-reg,-mp}/*.cc; do perl bla.pl `basename $file .cc`; done > support/deps.txt
my %deps;
open my $depfile, "<","$root/support/deps.txt" or die "no deps!";
while (<$depfile>) {
   next if /^\s*$/;
   my ($target,$dep) = split(": ",$_);
   chomp $dep;
   $deps{$target} = [split(" ",$dep)];
}

my $buildroot=dirname($config_file);
%ConfigFlags=load_config_file($config_file, $root);

my $core_mode=!exists $ConfigFlags{extroot};
my $srcroot= $core_mode ? $root : $ConfigFlags{extroot};
my $srcrootname= $core_mode ? '${root}' : '${extroot}';
my $DeveloperMode=-d "$srcroot/.git";


open(my $out_file, ">$targets_file") or die "Cannot write to $targets_file.";

# Ompi is handled by appending the string "_ompi" to the rule of the
# rules.ninja file. For the regular TOPCOM files we do not want to build with
# mpic{c,xx}.
my $mpi = "";
my @all = ();

# If cdd was misconfigured or isn't present, we have a workaround ready.
my $nocdd = $ConfigFlags{CXXFLAGS} =~ m/-DNO_CDD/;
my @omit_cdd = ();

foreach my $file (glob "$srcroot/lib-src*/*.cc"){
   # If there is no cdd, omit files from "lib-src-reg"
   if($nocdd){
      if($file !~ m/lib-src-reg\/.*\.cc/){
         process_cc_file($file, '${builddir}', $out_file, $mpi);
      } else {
         my ($fn) = $file =~ m/lib-src-reg\/(.*)\.cc/;
         push @omit_cdd, $fn;
      }
   } else {
      process_cc_file($file, '${builddir}', $out_file, $mpi);
   }
}

foreach my $file (glob "$srcroot/src{,-reg}/*.cc"){
   process_cc_file($file, '${builddir}', $out_file);
   push @all, process_binary_file($file, '${builddir}', $out_file, $mpi);
}

if(defined $ConfigFlags{MPICXX}){
   # From here on we build mptopcom, so activate mpi option.
   $mpi = "_mpi";

   foreach my $file (glob "$srcroot/src-mp/*.{c,cc}"){
      process_cc_file($file, '${builddir}', $out_file, $mpi);
   }

   push @all, process_binary_file("$srcroot/src-mp/mptopcom.cc", '${builddir}', $out_file, $mpi);
}

if(defined $ConfigFlags{MPIRUN}){
   my $mpirun = $ConfigFlags{MPIRUN};
   push @all, "bin/mpirun";
   print $out_file "build bin/mpirun: symlink $mpirun\n\n";
}

print $out_file <<"---";
build always: phony
build \$root/lib-src-ReverseSearch/version.hh: update_version | always

build install: install_core || all
build all: phony \$root/lib-src-ReverseSearch/version.hh | @all
default all
---

close($out_file);

exit 0;

###############################################################################
###############################################################################

sub process_binary_file {
   my($src_file, $out_dir, $out_file, $mpi) = @_;
   my $subdir = $src_file;
   my ($src_name, $obj_name)=basename($src_file, "(?:cc|cpp|C)");
   $subdir =~ s/\/$src_name//;
   $subdir =~ s/^\Q$srcroot\E\///;
   my $libfiles = join(" ",map {"\${builddir}/$_"} @{$deps{$subdir."/".$obj_name}});

   # If there is no cdd, dependencies on lib-src-reg are removed and for the
   # RegularityCheck rerouted to our RegularityCheckCache.
   if($nocdd){
      if($libfiles =~ m/RegularityCheck\.o/){
         $libfiles =~ s/\$\{builddir\}\/lib-src-ReverseSearch\/RegularityCheckCache\.o//;
         $libfiles =~ s/\$\{builddir\}\/lib-src-reg\/RegularityCheck\.o/\$\{builddir\}\/lib-src-ReverseSearch\/RegularityCheckCache\.o/;
      }
      for my $fn (@omit_cdd){
         $libfiles =~ s/\$\{builddir\}\/lib-src-reg\/$fn\.o//;
      }
   }
   # Bypass complete.

   my $in=$out_dir."/".$subdir."/".$obj_name.".o ".$libfiles." ";
   
   $obj_name="$out_dir/bin/$obj_name";
   print $out_file
      "build $obj_name : binary$mpi $in";
   print $out_file "\n\n";
   return $obj_name;
}

sub process_cc_file {
   my($src_file, $out_dir, $out_file, $mpi) = @_;
   my $subdir = $src_file;
   my ($src_name, $obj_name)=basename($src_file, "(?:c|cc|cpp|C)");
   $subdir =~ s/\/$src_name//;
   $src_file =~ s/^\Q$srcroot\E/$srcrootname/;
   $subdir =~ s/^\Q$srcroot\E\///;
   $obj_name="$out_dir/$subdir/$obj_name.o";
   my $xx = "";
   unless ($src_file =~ /\.c$/) {
      $xx = "xx";
   }
   
   print $out_file
      "build $obj_name : c${xx}compile$mpi $src_file";
   if($obj_name =~ m/mptopcom1?\.o$/){
      print $out_file
         " | \$root/lib-src-ReverseSearch/version.hh";
   }
   print $out_file "\n\n";
}


# Local Variables:
# cperl-indent-level:3
# indent-tabs-mode:nil
# End:
