package MasonX::Plugin::Catalyst::ImportStash;

use strict;
use warnings;

use base qw(HTML::Mason::Plugin);

sub start_request_hook {
  my ($self, $context) = @_;
  my ( $m, $args ) = @{ $context };

  #FIXME: respect in_package config var
  my $c = $HTML::Mason::Commands::c;

  # get (another!) copy of the stash
  my @sargs = %{ $c->stash };

  # prepare the notes we will use during this request
  $m->notes( '_mxp_cis_stash', \@sargs );
  $m->notes( '_mxp_cis_modified_comps', {} )
	 unless defined $m->notes( '_mxp_cis_modified_comps' );

}

sub start_component_hook {
  my ($self, $context) = @_;
  my ( $m, $comp, $args ) = @{ $context };

  #FIXME: respect in_package config var
  my $c = $HTML::Mason::Commands::c;

  # ignore subcomponents
  return if $comp->is_subcomp;

  # the current component in the call chain already
  # knows about the stash
  return if exists $m->{wrapper_index}->{$comp->comp_id};

  # do nothing if the resp. conponent isn't
  # interested in named arguments
  return unless %{ $comp->declared_args };

  my $sargs = $m->notes( '_mxp_cis_stash' );

  # mark this component so we can restore the arg list later on
  $m->notes( '_mxp_cis_modified_comps' )->{$comp} = 1;

  unshift @{ $args }, @{ $sargs };

}

sub end_component_hook {
  my ($self, $context) = @_;

  my ( $m, $comp, $args ) = @{ $context };

  #FIXME: respect in_package config var
  my $c = $HTML::Mason::Commands::c;

  # fetch and unset components modification status from
  # request notes, return if there is nothing to do
  delete $m->notes( '_mxp_cis_modified_comps' )->{$comp}
	 or return;

  my $sargs = $m->notes( '_mxp_cis_stash' );

  # remove stash from argument list (this is fatal if a component
  # has mucked around with the aliased @_ while also using named
  # arguments, but anyone doing this doesn't deserve better)
  splice @$args, 0, scalar @$sargs;

}

sub end_request_hook {
  my ($self, $context) = @_;
  my $m = $context->request;
  # in theory these should die with the current request, but I
  # still want to unset them explicitly here to avoid potential
  # circular references
  $m->notes( '_mxp_cis_stash', undef );
  $m->notes( '_mxp_cis_modified_comps', undef )
}

1;

__END__

=head1 NAME

MasonX::Plugin::Catalyst::ImportStash - Import the stash in all comps

=head1 SYNOPIS

To be written when the interface settles down ...

=head1 CAVEATS

Do not use named parameters in conjunction with modifying @_ in your
components. Not that this needed to be mentioned, $deity kills a
kitten everytime you do so, anyways.

=head1 AUTHORS

Sebastian Willert

=cut
