The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use strict;
use warnings;
use Test::More;

use_ok( 'HTML::FormHandler::Field::Repeatable' );
use_ok( 'HTML::FormHandler::Field::Repeatable::Instance' );

{
   package Repeatable::Form;
   use HTML::FormHandler::Moose;
   extends 'HTML::FormHandler';

   has_field 'my_test';
   has_field 'addresses' => ( type => 'Repeatable', auto_id => 1 );
   has_field 'addresses.street';
   has_field 'addresses.city';
   has_field 'addresses.country';
   has_field 'addresses.sector' => ( type => 'Select' );

   sub options_addresses_sector
   {
      [ 1 => 'East',
        2 => 'West',
        3 => 'South'
      ]
   }

}

my $form = Repeatable::Form->new;

ok( $form, 'created hasmany form');

$form = Repeatable::Form->new;
ok( $form->field('addresses')->has_fields, 'created form again with fields');

# empty form, creating new record
$form->process( params => {} );
ok( $form->field('addresses')->field('0')->field('city'), 'empty field exists' );
is( $form->field('addresses')->field('0')->field('sector')->num_options, 3, 'right number of options');

my $init_object = {
   addresses => [
      {
         street => 'First Street',
         city => 'Prime City',
         country => 'Utopia',
         id => 0,
      },
      {
         street => 'Second Street',
         city => 'Secondary City',
         country => 'Graustark',
         id => 1,
      },
      {
         street => 'Third Street',
         city => 'Tertiary City',
         country => 'Atlantis',
         id => 2,
      }
   ],
};

$form = Repeatable::Form->new( init_object => $init_object );
ok( $form, 'created form from initial object' );

# add in fields in form not in init_object
$init_object->{my_test} = undef;
$init_object->{addresses}->[0]->{sector} = undef;
$init_object->{addresses}->[1]->{sector} = undef;
$init_object->{addresses}->[2]->{sector} = undef;
is_deeply( $form->values, $init_object, 'get values back out' );
delete $init_object->{my_test};
is_deeply( $form->field('addresses')->value, $init_object->{addresses}, 'hasmany field value');
is_deeply( $form->field('addresses')->field('0')->value, $init_object->{addresses}->[0],
    'instance field value' );
is( $form->field('addresses')->field('0')->field('sector')->num_options, 3, 'right number of options');
is( $form->field('addresses')->field('0')->field('city')->value, 'Prime City',
    'compound subfield value');

my $fif = {
   'addresses.0.street' => 'First Street',
   'addresses.0.city' => 'Prime City',
   'addresses.0.country' => 'Utopia',
   'addresses.0.id' => '0',
   'addresses.0.sector' => '',
   'addresses.1.street' => 'Second Street',
   'addresses.1.city' => 'Secondary City',
   'addresses.1.country' => 'Graustark',
   'addresses.1.id' => '1',
   'addresses.1.sector' => '',
   'addresses.2.street' => 'Third Street',
   'addresses.2.city' => 'Tertiary City',
   'addresses.2.country' => 'Atlantis',
   'addresses.2.id' => '2',
   'addresses.2.sector' => '',
   'my_test' => '',
};
is_deeply( $form->fif, $fif, 'get fill in form');
$fif->{'addresses.0.city'} = 'Primary City';
$fif->{'addresses.2.country'} = 'Grand Fenwick';
delete $fif->{my_test};
$form->clear;
$form->process($fif);
ok($form->validated, 'validate fif');
$fif->{my_test} = '';
is_deeply( $form->fif, $fif, 'still get right fif');
$init_object->{addresses}->[0]->{city} = 'Primary City';
$init_object->{addresses}->[2]->{country} = 'Grand Fenwick';
is_deeply( $form->values, $init_object, 'still get right values');

$fif = {
   'addresses.0.street' => 'First Street',
   'addresses.0.city' => 'Prime City',
   'addresses.0.country' => 'Utopia',
   'addresses.0.id' => '0',
   'addresses.0.sector' => undef,
   'addresses.2.street' => 'Third Street',
   'addresses.2.city' => 'Tertiary City',
   'addresses.2.country' => 'Atlantis',
   'addresses.2.id' => '2',
   'addresses.2.sector' => undef,
};

$form->process($fif);

ok( $form->validated, 'form validated' );
is( $form->field('addresses')->num_fields, 2, 'right number of fields');

$fif = {
   'addresses.0.street' => 'Main Street',
   'addresses.0.city' => 'Prime City',
   'addresses.0.country' => 'Utopia',
   'addresses.0.id' => '0',
   'addresses.0.sector' => undef,
};

ok( $form->process($fif), 'process a single repeatable element');
is( $form->field('addresses')->field('0')->field('street')->value, 'Main Street', 'get value');
is( $form->field('addresses')->field('0')->field('sector')->num_options, 3, 'right number of options');

my $values = {
   'addresses' => [
      {
         'city' => 'Prime City',
         'country' => 'Utopia',
         'id' => 0,
         'street' => 'Main Street',
         'sector' => undef,
      },
   ],
};
is_deeply( $form->values, $values, 'get right values' );

my $no_repeat = {
   my_test => 'test'
};
$form->process( $no_repeat );
is_deeply( $form->value()->{addresses}, [],  'Addresses deleted not in params' );

$form->process({});
ok( exists $form->value->{addresses}[0], 'Addresses are back' );
is( $form->field('addresses')->field('0')->field('sector')->num_options, 3, 'right number of options');
$form->clear_init_object;
$form->process( { my_test => 'test' } );
is_deeply( $form->value()->{addresses}, [], 'Addresses deleted' );

{
    package Test::User::Repeatable;
    use HTML::FormHandler::Moose;
    extends 'HTML::FormHandler';

    has_field 'user_name';
    has_field 'occupation';
    has_field 'employers' => ( type => 'Repeatable' );
    has_field 'employers.employer_id' => ( type => 'PrimaryKey' );
    has_field 'employers.name';
    has_field 'employers.address';
}
$form = Test::User::Repeatable->new;
my $unemployed_params = {
   user_name => "No Employer",
   occupation => "Unemployed",
   'employers.0.employer_id' => '', # empty string
   'employers.0.name' => '',
   'employers.0.address' => ''
};
$form->process( $unemployed_params);
ok( $form->validated, "User with empty employer validates" );
is_deeply( $form->value, { employers => [], user_name => 'No Employer', occupation => 'Unemployed' },
    'creates right value for empty repeatable' );
is_deeply( $form->fif, $unemployed_params, 'right fif for empty repeatable' );


# following tests Duration in a Repeatable, with no other subfield
{
    package Form::RepeatableCompound;

    use HTML::FormHandler::Moose;
    extends 'HTML::FormHandler';

    has_field timeslots => (type => 'Repeatable');

    has_field 'timeslots.duration' => (type => 'Duration');
    has_field 'timeslots.duration.hours' => (type => 'Integer');
    has_field 'timeslots.duration.minutes' => (type => 'Integer');
}

$form = Form::RepeatableCompound->new;
my $params = {
    'timeslots.0.id' => 'zero',
    'timeslots.0.duration.hours' => 10,
    'timeslots.0.duration.minutes' => 12,
    'timeslots.1.id' => 'one',
    'timeslots.1.duration.hours' => 2,
    'timeslots.1.duration.minutes' => 1,
};

$form->process( params => $params );
ok( $form->validated, 'form validated' );
my $value = $form->value;
my $dur0 = DateTime::Duration->new( hours => 10, minutes => 12 );
is( $value->{timeslots}->[0]->{duration}->in_units('minutes'), $dur0->in_units('minutes'), 'got same duration' );

done_testing;