package Amon2::Trigger;
use strict;
use warnings;
use parent qw/Exporter/;
use Scalar::Util ();
use if $] >= 5.009_005, 'mro';
use if $] < 5.009_005, 'MRO::Compat';

our @EXPORT = qw/add_trigger call_trigger get_trigger_code/;

sub add_trigger {
    my ($class, %args) = @_;

    if (ref $class) {
        while (my ($hook, $code) = each %args) {
            push @{$class->{_trigger}->{$hook}}, $code;
        }
    } else {
        no strict 'refs';
        while (my ($hook, $code) = each %args) {
            push @{${"${class}::_trigger"}->{$hook}}, $code;
        }
    }
}

sub call_trigger {
    my ($class, $hook, @args) = @_;
    my @code = $class->get_trigger_code($hook);
    for my $code (@code) {
        $code->($class, @args);
    }
}

sub get_trigger_code {
    my ($class, $hook) = @_;
    my @code;
    if (Scalar::Util::blessed($class)) {
        push @code, @{ $class->{_trigger}->{$hook} || [] };
        $class = ref $class;
    }
    no strict 'refs';
    my $klass = ref $class || $class;
    for (@{mro::get_linear_isa($class)}) {
        push @code, @{${"${_}::_trigger"}->{$hook} || []};
    }
    return @code;
}

1;
__END__

=head1 NAME

Amon2::Trigger - Trigger system for Amon2

=head1 SYNOPSIS

    package MyClass;
    use parent qw/Amon2::Trigger/;

    __PACKAGE__->add_trigger('Foo');
    __PACKAGE__->call_trigger('Foo');

=head1 DESCRIPTION

This is a trigger system for Amon2. You can use this class for your class using trigger system.

=head1 METHODS

=over 4

=item C<< __PACKAGE__->add_trigger($name:Str, \&code:CodeRef) >>

=item C<< $obj->add_trigger($name:Str, \&code:CodeRef) >>

You can register the callback function for the class or object.

When you register callback code on object, the callback is only registered to object, not for class.

I<Return Value>: Not defined.

=item C<< __PACKAGE__->call_trigger($name:Str); >>

=item C<< $obj->call_trigger($name:Str); >>

This method calls all callback code for $name.

I<Return Value>: Not defined.

=item C<< __PACKAGE__->get_trigger_code($name:Str) >>

=item C<< $obj->get_trigger_code($name:Str) >>

You can get all of trigger code from the class and ancestors.

=back

=head1 FAQ

=over 4

=item WHY DON'T YOU USE L<Class::Trigger>?

L<Class::Trigger> does not support get_trigger_code.

=back