package Catalyst::Plugin::Widget::ThroughView;

=head1 NAME

Catalyst::Plugin::Widget::ThroughView - Widget rendered through L<Catalyst::View>

=cut

use Carp qw( croak );
use Moose::Role;

requires 'context';


=head1 SYNOPSIS

  package MyApp::Widget::Sample;
  use Moose;
  extends 'Catalyst::Plugin::Widget::Base';
  with    'Catalyst::Plugin::Widget::ThroughView';

  has '+view' => ( is => 'rw', default => 'MyView' );

  1;


=head1 METHODS

=head2 extension

Returns default extension for template file name. Defaults to assume '.tt'
for view inherited from L<Catalyst::View::TT>, '.tx' for
L<Catalyst::View::Xslate> descendants and '' for remainders.

=cut

has extension => ( is => 'rw', isa => 'Str', lazy => 1,
	builder => '_extension' );

# builder for 'extension'.
sub _extension {
	my ( $self ) = @_;

	$self->view_instance->isa('Catalyst::View::TT') &&
		'.tt' ||
	$self->view_instance->isa('Catalyst::View::Xslate') &&
		'.tx' ||
	'';
}


=head2 populate_stash

Fill stash with required data. Can be altered in descendants with L<Moose>
method modifiers.

=cut

sub populate_stash {
	my $self = shift;

	$self->context->stash( self => $self );
	$self->context->stash( template => $self->template )
		if $self->template;
}


=head2 render

Overriden method from L<Catalyst::Plugin::Widget::Base>.

=cut

sub render {
	my ( $self ) = @_;

	# we have to modify Moose internal storage
	local $self->context->{ stash } = {};
	local $self->context->res->{ body };

	$self->populate_stash;

	# rendering
	$self->context->forward( $self->view_instance );

	return $self->context->res->body;
}


=head2 template

Returns name of template file using for widget rendering.
Default is lower cased widget class name remaining (after word 'Widget')
with all '::' replaced with '/' and 'extension' appended.

=cut

has template => ( is => 'rw', isa => 'Str | Undef', lazy => 1,
	builder => '_template' );

# builder for 'template'.
sub _template {
	my ( $self ) = @_;

	( my $t = ref $self ) =~ s/.*::(Widget::.+)/$1/;
	$t =~ s|::|/|g;

	return lc($t) . $self->extension;
}


=head2 view

Returns L<Catalyst::View> (name or instance) for widget rendering.

=cut

has view => ( is => 'rw', isa => 'Catalyst::View | Str', required => 1 );


=head2 view_instance

Returns L<Catalyst::View> instance for widget rendering.

=cut

has view_instance => ( is => 'rw', isa => 'Catalyst::View', init_arg => undef,
	lazy => 1, builder => '_view_instance' );

# builder for 'view_instance'.
sub _view_instance {
	my $self = shift;

	ref $self->view ?
		$self->view :
		$self->context->view( $self->view ) or
	croak "No such view: '" . $self->view ."'";
}


1;