The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Form::Toolkit::Field;
$Form::Toolkit::Field::VERSION = '0.007';
use Class::Load;
use Moose -traits => 'Form::Toolkit::Meta::Class::Trait::HasShortClass';
use Moose::Util qw/apply_all_roles/;

use Class::Load;

with qw(MooseX::Clone);

__PACKAGE__->meta->short_class('GenericField');

=head1 NAME

Form::Toolkit::Field - A field for JCOM::Form s

=cut

has 'form' => ( isa => 'Form::Toolkit::Form' , is => 'ro' , weak_ref => 1 , required => 1 );

has 'name' => ( isa => 'Str' , is => 'ro' , required => 1 , traits => [ 'Clone' ]);
has 'help' => ( isa => 'Str', is => 'rw', traits => [ 'Clone' ]);
has 'placeholder' => ( isa => 'Str', is => 'rw' , traits => [ 'Clone' ]);

has 'label' => ( isa => 'Str', is => 'rw' , required => 1 , default => '' ,  traits => [ 'Clone' ]);
has 'value' => ( is => 'rw' , clearer => 'clear_value' , traits => [ 'Clone' ]);

has 'errors' => ( isa => 'ArrayRef[Str]' , is => 'rw' , default => sub{ [] } , required => 1 , traits => [ 'Clone' ] );

=head2 id

Returns a unique id of this field in the space of all forms in the process.

Usage:

  my $id = $this->id();

=cut

sub id{
  my ($self) = @_;
  return $self->form()->meta()->id().'_'.$self->name();
}

=head2 fast_clone

Returns a fast clone of this field.

=cut

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

  my $new = bless { %$self } , Scalar::Util::blessed($self);
  $new->value($self->value_clone());
  return $new;
}

=head2 value_clone

Returns a shallow clone of the contained value (can be undef)

=cut

sub value_clone{
  my ($self) = @_;
  return $self->value();
}

=head2 value_struct

Returns the string value of this field.

=cut

sub value_struct{
  my ($self) = @_;
  unless( defined $self->value() ){
    return undef;
  }
  return $self->value().'';
}

=head2 set_placeholder

Chainable placeholder(..);

Placeholder. This is an extra hint, like an example of what to enter
for users. Very useful for HMTL5 interfaces.

=cut

sub set_placeholder{
  my ($self, $placeholder) = @_;
  $self->placeholder($placeholder);
  return $self;
}

=head2 set_help

Chainable help() method.

=cut

sub set_help{
  my ($self, $help) = @_;
  $self->help($help);
  return $self;
}

=head2 set_label

Chainable label method.

=cut

sub set_label{
  my ($self , $label) = @_;
  $self->label($label);
  return $self;
}

=head2 add_error

Adds an error string to this field.

=cut

sub add_error{
  my ($self , $err_str) = @_;
  push @{$self->errors()} , $err_str;
}

=head2 has_errors

Returns the number of errors in this form.

=cut

sub has_errors{
  my ($self) = @_;
  return scalar(@{$self->errors()});
}

=head2 validate

Does nothing. Can be extended by roles.

=cut

sub validate{}

=head2 clear

Resets this field value and errors

=cut

sub clear{
  my ($self) = @_;
  $self->errors([]);
  $self->clear_value();
}

=head2 add_role

Adds a Subrole of L<Form::Toolkit::FieldRole> or a custom defined FormRole.
Additionnaly, you can provide new parameters if the role you're applying
requires some mandatory attributes.

Returns the field so you can chain calls.

Usage:

 $this->add_role('Mandatory')
         ->add_role('+My::App::FieldRole::Whatever');
           ->add_role('RegExpMatch', { regexp_match => qr/^[A-Z]+$/ });

=cut

sub add_role{
  my ($self, $role, $new_args) = @_;
  $new_args //= {};

  if( $role =~ /^\+/ ){
    $role =~ s/^\+//;
  }else{
    $role = 'Form::Toolkit::FieldRole::'.$role;
  }

  ## Maintain important meta attributes.
  my $short_class = $self->meta->short_class();

  ##apply_all_roles($self , $role );

  ## This is better, as apply can be used to add new arguments
  ## See http://search.cpan.org/~ether/Moose-2.0801/lib/Moose/Role.pm#APPLYING_ROLES
  Class::Load::load_class( $role );
  $role->meta->apply($self, rebless_params => $new_args );

  ## Maintain important meta attributes.
  $self->meta->short_class($short_class);
  return $self;
}

=head2 roles_names

Returns an array of Roles this field implements.

=cut

sub roles_names{
  my ($self) = @_;
  return  map{ $_->name() } $self->meta->calculate_all_roles_with_inheritance();
}

=head2 does_role

Returns true if this field does the given role.

Usage:

  if( $this->does_role('Mandatory') ){
    ...
  }


  if( $this->does_role('+My::Specific::Role') ){
    ...
  }

=cut

sub does_role{
  my ($self , $role) = @_;
  if( $role =~ /^\+/ ){
    $role =~ s/^\+//;
  }else{
    $role = 'Form::Toolkit::FieldRole::'.$role;
  }
  return $self->does($role);
}

=head2 short_class

Accessor shortcut for meta short class.

Usage:

 $this->short_class();

=cut

sub short_class{
  my ($self) = @_;
  return $self->meta->short_class();
}

#__PACKAGE__->meta->make_immutable();
1;