package App::ArduinoBuilder::DepCheck;

use strict;
use warnings;
use utf8;

use Exporter 'import';
use File::Basename;
use File::Spec::Functions;
use Log::Any::Simple ':default';

our @EXPORT_OK = qw(check_dep);

# Returns true if the target needs to be rebuilt.
sub check_dep {
  my ($source, $target) = @_;
  fatal "Can’t find source file: ${source}" unless -f $source;
  my $source_time = -M _;  # Note: this is negated mtime due to a weird Perl quirk.
  unless (-f $target) {
    trace "Rebuilding ${source} because ${target} does not exist";
    return 1;
  }
  # In some error situation a 0 byte .o file is written, let’s assume that a valid output is
  # never empty (which would not be true in the general case for a build system).
  if (-z _) {
    trace "Rebuilding ${source} because ${target} is empty";
    return 1;
  }
  my $target_time = -M _;
  if ($source_time < $target_time) {
    trace "Rebuilding ${source} because of ${target}";
    return 1;
  }

  my $d_file = catfile(dirname($target), basename($source).'.d');
  unless (-f $d_file) {
    warning "Dependency file does not exist: ${d_file}";
    return 0;  # We assume that there is no other dependency.
  }
  if ($source_time < -M _) {
    trace "Rebuilding ${source} because it’s newer than dependency file ${d_file}";
    return 1;
  }

  # If we don’ use the crlf layer our regex can fail on Cygwin when reading
  # files generated by a Windows toolchain.
  # BUG: one line of the dependency file can contain several file names,
  # separated by spaces (but we need to catch spaces in the name of files too).
  open my $fh, '<:crlf', $d_file or fatal "Can’t open dependency file '${d_file}': $!";
  my $l = <$fh>;
  # We force a space after the colon to avoid matching $1 to C in C:\foo\...
  if ($l !~ m/^\s*(.*?)\s*:\s+(.*?)?\s*\\?$/) {
    error "Can’t parse dependency file: ${d_file}";
    debug "Unparsable line: $l";
    return 1;
  }
  # we could test that rel2abs($1) eq rel2abs($target)
    if ($2 && -M $1 < $target_time) {
      trace "Rebuilding ${source} because of ${2}";
      return 1;
    }

  while (my $l = <$fh>) {
    if ($l !~ m/^\s*(.*?)?\s*\\?$/) {
      error "Can’t parse dependency file: ${d_file}";
      debug "Unparsable line: $l";
      return 1;
    }
    if ($1 && -M $1 < $target_time) {
      trace "Rebuilding ${source} because of ${1}";
      return 1;
    }
  }
  trace "Not rebuilding ${target}, it is up-to-date";
  close $fh;
  return 0;
}

1;
