package Make::Target;

use strict;
use warnings;
## no critic (ValuesAndExpressions::ProhibitConstantPragma)
use constant DEBUG => $ENV{MAKE_DEBUG};
## use critic

our $VERSION = '2.009';

# Intermediate 'target' package
# There is an instance of this for each 'target' that apears on
# the left hand side of a rule i.e. for each thing that can be made.
sub new {
    my ( $class, $name, $info ) = @_;
    return bless {
        NAME       => $name,    # name of thing
        MAKEFILE   => $info,    # Makefile context
        RULES      => [],
        RULE_TYPE  => undef,    # undef, :, ::
        HAS_RECIPE => undef,    # undef, boolean
        Pass       => 0,        # Used to determine if 'done' this sweep
    }, $class;
}

sub date {
    my $self = shift;
    my $info = $self->Info;
    return $info->date( $self->Name );
}

sub phony {
    my $self = shift;
    return $self->Info->phony( $self->Name );
}

sub has_recipe {
    my ($self) = @_;
    return $self->{HAS_RECIPE} if defined $self->{HAS_RECIPE};
    ## no critic (BuiltinFunctions::RequireBlockGrep)
    return $self->{HAS_RECIPE} = grep @{ $_->recipe }, @{ $self->{RULES} };
    ## use critic
}

sub rules {
    my ($self) = @_;
    if ( !$self->phony && !$self->has_recipe ) {
        my $rule = $self->Info->patrule( $self->Name, $self->{RULE_TYPE} || ':' );
        DEBUG and print STDERR "Implicit rule (", $self->Name, "): @{ $rule ? $rule->prereqs : ['none'] }\n";
        $self->add_rule($rule) if $rule;
    }
    return $self->{RULES};
}

sub add_rule {
    my ( $self, $rule ) = @_;
    my $new_kind = $rule->kind;
    my $kind     = $self->{RULE_TYPE} ||= $new_kind;
    die "Target '$self->{NAME}' had '$kind' but tried to add '$new_kind'"
        if $kind ne $new_kind;
    $self->{HAS_RECIPE} ||= undef;    # reset if was no or unknown
    return push @{ shift->{RULES} }, $rule;
}

sub Name {
    return shift->{NAME};
}

sub Base {
    my $name = shift->{NAME};
    $name =~ s/\.[^.]+$//;
    return $name;
}

sub Info {
    return shift->{MAKEFILE};
}

sub done {
    my $self = shift;
    my $pass = $self->Info->pass;
    return 1 if ( $self->{Pass} == $pass );
    $self->{Pass} = $pass;
    return 0;
}

# as part of "out of date" processing, if any child is remade, I need too
sub recurse {
    my ( $self, $method ) = @_;
    return if $self->done;
    my $info = $self->Info;
    my @results;
    DEBUG and print STDERR "Build " . $self->Name, "\n";
    foreach my $rule ( @{ $self->rules } ) {
        ## no critic (BuiltinFunctions::RequireBlockMap)
        push @results, map $info->target($_)->recurse($method), @{ $rule->prereqs };
        ## use critic
        push @results, $rule->$method($self);
    }
    return @results;
}

1;