new renamed viewports
[catagits/Reaction.git] / lib / Reaction / UI / ViewPort / Field / .ToDo / TimeRange.pm
1 package Reaction::UI::ViewPort::Field::TimeRange;
2
3 use Reaction::Class;
4 use Reaction::Types::DateTime;
5 use DateTime;
6 use DateTime::SpanSet;
7 use Time::ParseDate ();
8
9 class TimeRange is 'Reaction::UI::ViewPort::InterfaceModel::Field', which {
10
11   has '+value' => (isa => 'DateTime::SpanSet');
12
13   #has '+layout' => (default => 'timerange');
14
15   has value_string =>
16     (isa => 'Str',  is => 'rw', lazy_fail => 1, trigger_adopt('value_string'));
17
18   has delete_label => (
19     isa => 'Str', is => 'rw', required => 1, default => sub { 'Delete' },
20   );
21
22   has parent => (
23     isa => 'Reaction::UI::ViewPort::TimeRangeCollection',
24     is => 'ro',
25     required => 1,
26     is_weak_ref => 1
27   );
28
29   implements _build_value_string => as {
30     my $self = shift;
31     #return '' unless $self->has_value;
32     #return $self->value_string;
33   };
34
35   implements value_array => as {
36     my $self = shift;
37     return split(',', $self->value_string);
38   };
39
40   implements adopt_value_string => as {
41     my ($self) = @_;
42     my @values = $self->value_array;
43     for my $idx (0 .. 3) { # last value is repeat
44       if (length $values[$idx]) {
45         my ($epoch) = Time::ParseDate::parsedate($values[$idx], UK => 1);
46         $values[$idx] = DateTime->from_epoch( epoch => $epoch );
47       }
48     }
49     $self->value($self->range_to_spanset(@values));
50   };
51
52   implements range_to_spanset => as {
53     my ($self, $time_from, $time_to, $repeat_from, $repeat_to, $pattern) = @_;
54     my $spanset = DateTime::SpanSet->empty_set;
55     if (!$pattern || $pattern eq 'none') {
56       my $span = DateTime::Span->from_datetimes(
57                    start => $time_from, end => $time_to
58                  );
59       $spanset = $spanset->union( $span );
60     } else {
61       my $duration = $time_to - $time_from;
62       my %args = ( days => $time_from->day + 2,
63                   hours => $time_from->hour,
64                 minutes => $time_from->minute,
65                 seconds => $time_from->second );
66
67       delete $args{'days'} if ($pattern eq 'daily');
68       delete @args{qw/hours days/} if ($pattern eq 'hourly');
69       $args{'days'} = $time_from->day if ($pattern eq 'monthly');
70       my $start_set = DateTime::Event::Recurrence->$pattern( %args );
71       my $iter = $start_set->iterator( start => $repeat_from, end => $repeat_to );
72       while ( my $dt = $iter->next ) {
73         my $endtime = $dt + $duration;
74         my $new_span = DateTime::Span->from_datetimes(
75                          start => $dt,
76                          end => $endtime
77                        );
78         $spanset = $spanset->union( $new_span );
79       }
80     }
81     return $spanset;
82   };
83
84   implements delete => as {
85     my ($self) = @_;
86     $self->parent->remove_range_vp($self);
87   };
88
89   override accept_events => sub { ('value_string', 'delete', super()) };
90
91 };
92
93 1;
94
95 =head1 NAME
96
97 Reaction::UI::ViewPort::Field::TimeRange
98
99 =head1 SYNOPSIS
100
101 =head1 DESCRIPTION
102
103 =head1 METHODS
104
105 =head2 value
106
107   Accessor for a L<DateTime::SpanSet> object.
108
109 =head2 value_string
110
111   Returns: Encoded range string representing the value.
112
113 =head2 value_array
114
115   Returns: Arrayref of the elements of C<value_string>.
116
117 =head2 parent
118
119   L<Reaction::UI::ViewPort::TimeRangeCollection> object.
120
121 =head2 range_to_spanset
122
123   Arguments: $self, $time_from, $time_to, $repeat_from, $repeat_to, $pattern
124   where $time_from, $time_to, $repeat_from, $repeat_to are L<DateTime>
125   objects, and $pattern is a L<DateTime::Event::Recurrence> method name
126
127   Returns: $spanset
128
129 =head2 delete
130
131   Removes TimeRange from C<parent> collection.
132
133 =head2 delete_label
134
135   Label for the delete option. Default: 'Delete'.
136
137 =head1 SEE ALSO
138
139 =head2 L<Reaction::UI::ViewPort::Field>
140
141 =head2 L<Reaction::UI::ViewPort::TimeRangeCollection>
142
143 =head1 AUTHORS
144
145 See L<Reaction::Class> for authors.
146
147 =head1 LICENSE
148
149 See L<Reaction::Class> for the license.
150
151 =cut