use v6;
use WorkdayCalendar;
use TimeOfDay;
class Schedule {
subset DaysInWeek of Str where <Mon Tue Wed Thu Fri Sat Sun>;
subset WeeksInMonth of Int where 1..5;
subset DaysInMonth of Int where 1..31;
subset MonthsInYear of Int where <Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec>;
subset TimeOut of Int where $_ > 0;
has DateTime $.present is rw = DateTime.now;
has Str $.id;
has TimeOfDay @.time is rw;
has DaysInWeek @.weekdays is rw;
has WeeksInMonth @.ordinal is rw; #--- Ordinal weekday modifier: 1st monday of the month, 5th friday of the month (last)
has DaysInMonth @.monthdays is rw;
has MonthsInYear @.months is rw;
has TimeOut $.timeout is rw;
has WorkdayCalendar $.calendar;
has DateTime $!next-instants is rw;
has Bool $.recover-lost-events = False;
has Bool $.advance-lost-events = False;
#method future-events(DateTime $from = now, DateTime $until = $from + (60*60*24)*(30*3) ) {
method future-events {
#--- If the months are not populated, means "every month"
@.months = <Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec> if @.months.elems == 0;
my Str @whole_schedule =
(
(
(
('MNTH=' X~ (@.months.elems == 0) ?? '' !! @.months)
X~
(';ORDN=' X~ (@.ordinal.elems == 0) ?? '' !! @.ordinal)
)
X~
(';MDAY=' X~ (@.monthdays.elems == 0) ?? '' !! @.monthdays)
)
X~
(';WDAY=' X~ (@.weekdays.elems == 0) ?? '' !! @.weekdays)
)
X~
(';TIME=' X~ (@.time.elems == 0) ?? '' !! @.time) #--- hlighter?
;
my %event_spec;
my Int $index = 0;
for @whole_schedule -> $event {
my @event_data = split /';'/, $event;
for @event_data -> $data {
my (Str $type, Str $value) = split '=', $data;
if $value ne '' {
my %ev;
%ev{$type} = $value;
%event_spec{$index} = %ev;
say $index ~ %ev.perl ~ "===>" ~ %event_spec.perl;
} # This is a workaround until (%h<a><b> = x) is implemented on rakudo
}
$index++;
}
say %event_spec.perl; exit;
#TODO: Clean %event_spec of invalid dates
for %event_spec.keys -> $index {
say ">>event " ~ $index;
my %e = %event_spec{$index};
say %e.perl;
#--- Validating event specification
try {
if defined %e{'ORDN'} && defined %e{'MDAY'} {
warn "ERROR: Can't specify an ordinal weekday modifier and a week-number at the same time.";
}
if defined %e{'WDAY'} && defined %e{'MDAY'} {
warn "ERROR: Can't specify a monthday and a weekday at the same time.";
}
if !defined %e{'TIME'} {
warn "ERROR: A time specification is needed";
}
CATCH {
note "ERROR: event specification flawed";
next;
}
}
#--- Combos
if defined %e{'ORDN'} && defined %e{'WDAY'} {
#--- Find the Nth corresponding Weekday of the month
my $month_number = self.__month-name-to-number( %e{'MHTN'} );
say ">>> $month_number";
my $start = Date.new(
$.present.year ~ '-' ~ $month_number.fmt('%02d') ~ '-01' #'T ~ $.present.hour ~ ':' ~ $.present.minute ~ ':' ~ $.present.second ~ 'Z'
);
my $weekdays_found = 0;
my Date $current_day = $start;
say "dow $current_day.day-of-week";
for (1..$start.days-in-month) -> $day_in_month {
my $current_day = $current_day.succ;
my %wd = enum <Mon Tue Wed Thu Fri Sat Sun>;
$weekdays_found++ if $current_day.day-of-week == %e{'WDAY'};
last if $weekdays_found == %e{'ORDN'};
}
#--- $current_day is the day we are looking for now.
}
my ($hour, $minute, $second) = (0,0,0);
($hour, $minute, $second) = split ':', %event_spec{$index}{'TIME'};
my $event = DateTime.new(
hour=>$hour.Int, minute=>$minute.Int, second=>$second.Int
);
}
return %event_spec;
}
method next-instant(DateTime $from = now) {
my Workdate $start_date .= new($from, $.calendar);
my TimeOfDay $start_time = TimeOfDay.new(
hour => $from.hour,
minute => $from.minute,
second => $from.second
)
}
method when-next(DateTime $from = now) {
}
method when-previous(DateTime $from = now) {
}
method __month-name-to-number($month_name) {
my $month_number = 0;
for <Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec> {
$month_number++;
last if $_ eq $month_name;
}
return $month_number;
}
}