-module(automata@rrule@evaluator).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/automata/rrule/evaluator.gleam").
-export([day_matches/2, next_time_on_day/3, first_time_on_day/2, next_occurrence/3, matches/2, yielded_before/2]).
-export_type([nth_scope/0, occurrence/0]).
-type nth_scope() :: month_scope | year_scope.
-type occurrence() :: {occurrence, integer(), integer()}.
-file("src/automata/rrule/evaluator.gleam", 102).
-spec date_to_datetime(automata@schedule@ast:date()) -> automata@schedule@ast:date_time().
date_to_datetime(Date) ->
{date_time, Date, {time, 23, 59, 59}}.
-file("src/automata/rrule/evaluator.gleam", 90).
-spec within_until(
automata@rrule@validator:end_condition(),
automata@schedule@ast:date_time()
) -> boolean().
within_until(End_condition, At) ->
case End_condition of
{until, Until} ->
case Until of
{until_date, Date} ->
automata@internal@calendar:less_or_equal(
At,
date_to_datetime(Date)
);
{until_date_time, Limit} ->
automata@internal@calendar:less_or_equal(At, Limit)
end;
_ ->
true
end.
-file("src/automata/rrule/evaluator.gleam", 183).
-spec month_day_matches(
gleam@option:option(list(integer())),
automata@schedule@ast:date()
) -> boolean().
month_day_matches(Values, Date) ->
case Values of
none ->
true;
{some, Items} ->
Maximum = automata@internal@calendar:days_in_month(
erlang:element(2, Date),
erlang:element(3, Date)
),
gleam@list:any(Items, fun(Item) -> case Item > 0 of
true ->
Item =:= erlang:element(4, Date);
false ->
((Maximum + Item) + 1) =:= erlang:element(4, Date)
end end)
end.
-file("src/automata/rrule/evaluator.gleam", 261).
-spec nth_scope(automata@rrule@normalize:r_rule_plan()) -> nth_scope().
nth_scope(Plan) ->
case {erlang:element(3, Plan), erlang:element(7, Plan)} of
{yearly, none} ->
year_scope;
{_, _} ->
month_scope
end.
-file("src/automata/rrule/evaluator.gleam", 276).
-spec weekday_occurrences_in_month_loop(
automata@schedule@ast:weekday(),
integer(),
integer(),
integer(),
list(occurrence())
) -> list(occurrence()).
weekday_occurrences_in_month_loop(Weekday, Year, Month, Day, Acc) ->
Maximum = automata@internal@calendar:days_in_month(Year, Month),
case Day > Maximum of
true ->
lists:reverse(Acc);
false ->
Datetime = {date_time, {date, Year, Month, Day}, {time, 0, 0, 0}},
case automata@internal@calendar:weekday(Datetime) =:= Weekday of
true ->
weekday_occurrences_in_month_loop(
Weekday,
Year,
Month,
Day + 1,
[{occurrence, Month, Day} | Acc]
);
false ->
weekday_occurrences_in_month_loop(
Weekday,
Year,
Month,
Day + 1,
Acc
)
end
end.
-file("src/automata/rrule/evaluator.gleam", 268).
-spec weekday_occurrences_in_month(
automata@schedule@ast:weekday(),
integer(),
integer()
) -> list(occurrence()).
weekday_occurrences_in_month(Weekday, Year, Month) ->
weekday_occurrences_in_month_loop(Weekday, Year, Month, 1, []).
-file("src/automata/rrule/evaluator.gleam", 310).
-spec weekday_occurrences_in_year_loop(
automata@schedule@ast:weekday(),
integer(),
integer(),
list(occurrence())
) -> list(occurrence()).
weekday_occurrences_in_year_loop(Weekday, Year, Month, Acc) ->
case Month > 12 of
true ->
lists:reverse(Acc);
false ->
Month_occurrences = weekday_occurrences_in_month(
Weekday,
Year,
Month
),
weekday_occurrences_in_year_loop(
Weekday,
Year,
Month + 1,
gleam@list:fold(
Month_occurrences,
Acc,
fun(Carry, Item) -> [Item | Carry] end
)
)
end.
-file("src/automata/rrule/evaluator.gleam", 306).
-spec weekday_occurrences_in_year(automata@schedule@ast:weekday(), integer()) -> list(occurrence()).
weekday_occurrences_in_year(Weekday, Year) ->
weekday_occurrences_in_year_loop(Weekday, Year, 1, []).
-file("src/automata/rrule/evaluator.gleam", 227).
-spec nth_weekday_matches(
automata@rrule@normalize:r_rule_plan(),
integer(),
automata@schedule@ast:weekday(),
automata@schedule@ast:date()
) -> boolean().
nth_weekday_matches(Plan, Ordinal, Weekday, Date) ->
Occurrences = case nth_scope(Plan) of
year_scope ->
weekday_occurrences_in_year(Weekday, erlang:element(2, Date));
month_scope ->
weekday_occurrences_in_month(
Weekday,
erlang:element(2, Date),
erlang:element(3, Date)
)
end,
case Ordinal > 0 of
true ->
case gleam@list:drop(Occurrences, Ordinal - 1) of
[Match | _] ->
(erlang:element(2, Match) =:= erlang:element(3, Date))
andalso (erlang:element(3, Match) =:= erlang:element(
4,
Date
));
[] ->
false
end;
false ->
case gleam@list:drop(lists:reverse(Occurrences), (0 - Ordinal) - 1) of
[Match@1 | _] ->
(erlang:element(2, Match@1) =:= erlang:element(3, Date))
andalso (erlang:element(3, Match@1) =:= erlang:element(
4,
Date
));
[] ->
false
end
end.
-file("src/automata/rrule/evaluator.gleam", 214).
-spec weekday_specifier_matches(
automata@rrule@normalize:r_rule_plan(),
automata@rrule@validator:weekday_specifier(),
automata@schedule@ast:weekday(),
automata@schedule@ast:date()
) -> boolean().
weekday_specifier_matches(Plan, Specifier, Actual, Date) ->
case Specifier of
{every_weekday, Expected} ->
Expected =:= Actual;
{nth_weekday, Ordinal, Expected@1} ->
(Expected@1 =:= Actual) andalso nth_weekday_matches(
Plan,
Ordinal,
Expected@1,
Date
)
end.
-file("src/automata/rrule/evaluator.gleam", 198).
-spec weekday_matches(
automata@rrule@normalize:r_rule_plan(),
gleam@option:option(list(automata@rrule@validator:weekday_specifier())),
automata@schedule@ast:date_time()
) -> boolean().
weekday_matches(Plan, Values, At) ->
case Values of
none ->
true;
{some, Items} ->
Actual = automata@internal@calendar:weekday(At),
gleam@list:any(
Items,
fun(Item) ->
weekday_specifier_matches(
Plan,
Item,
Actual,
erlang:element(2, At)
)
end
)
end.
-file("src/automata/rrule/evaluator.gleam", 52).
-spec day_matches(
automata@rrule@normalize:r_rule_plan(),
automata@schedule@ast:date()
) -> boolean().
day_matches(Plan, Date) ->
Datetime = {date_time, Date, {time, 0, 0, 0}},
Month_match = case erlang:element(7, Plan) of
none ->
true;
{some, Values} ->
gleam@list:any(
Values,
fun(Item) -> Item =:= erlang:element(3, Date) end
)
end,
Month_day_match = month_day_matches(erlang:element(8, Plan), Date),
Weekday_match = weekday_matches(Plan, erlang:element(6, Plan), Datetime),
Month_match andalso case {erlang:element(8, Plan), erlang:element(6, Plan)} of
{{some, _}, {some, _}} ->
Month_day_match andalso Weekday_match;
{{some, _}, none} ->
Month_day_match;
{none, {some, _}} ->
Weekday_match;
{none, none} ->
true
end.
-file("src/automata/rrule/evaluator.gleam", 351).
-spec find_minute(
integer(),
list(integer()),
automata@schedule@ast:date(),
integer(),
automata@schedule@ast:date_time()
) -> gleam@option:option(automata@schedule@ast:date_time()).
find_minute(Hour, Minutes, Date, Second, Search) ->
case Minutes of
[] ->
none;
[Minute | Rest] ->
Candidate = {date_time, Date, {time, Hour, Minute, Second}},
case automata@internal@calendar:less_than(Candidate, Search) of
true ->
find_minute(Hour, Rest, Date, Second, Search);
false ->
{some, Candidate}
end
end.
-file("src/automata/rrule/evaluator.gleam", 330).
-spec find_time(
list(integer()),
list(integer()),
automata@schedule@ast:date(),
integer(),
automata@schedule@ast:date_time()
) -> gleam@option:option(automata@schedule@ast:date_time()).
find_time(Hours, Minutes, Date, Second, Search) ->
case Hours of
[] ->
none;
[Hour | Rest_hours] ->
case Hour < erlang:element(2, erlang:element(3, Search)) of
true ->
find_time(Rest_hours, Minutes, Date, Second, Search);
false ->
case find_minute(Hour, Minutes, Date, Second, Search) of
{some, Found} ->
{some, Found};
none ->
find_time(Rest_hours, Minutes, Date, Second, Search)
end
end
end.
-file("src/automata/rrule/evaluator.gleam", 44).
-spec next_time_on_day(
automata@rrule@normalize:r_rule_plan(),
automata@schedule@ast:date(),
automata@schedule@ast:date_time()
) -> gleam@option:option(automata@schedule@ast:date_time()).
next_time_on_day(Plan, Date, Search) ->
find_time(
erlang:element(9, Plan),
erlang:element(10, Plan),
Date,
erlang:element(11, Plan),
Search
).
-file("src/automata/rrule/evaluator.gleam", 371).
-spec list_first(list(integer())) -> integer().
list_first(Values) ->
case Values of
[First | _] ->
First;
[] ->
0
end.
-file("src/automata/rrule/evaluator.gleam", 33).
-spec first_time_on_day(
automata@rrule@normalize:r_rule_plan(),
automata@schedule@ast:date()
) -> automata@schedule@ast:date_time().
first_time_on_day(Plan, Date) ->
{date_time,
Date,
{time,
list_first(erlang:element(9, Plan)),
list_first(erlang:element(10, Plan)),
erlang:element(11, Plan)}}.
-file("src/automata/rrule/evaluator.gleam", 386).
-spec months_between(
automata@schedule@ast:date_time(),
automata@schedule@ast:date_time()
) -> integer().
months_between(From, To) ->
((erlang:element(2, erlang:element(2, To)) * 12) + erlang:element(
3,
erlang:element(2, To)
))
- ((erlang:element(2, erlang:element(2, From)) * 12) + erlang:element(
3,
erlang:element(2, From)
)).
-file("src/automata/rrule/evaluator.gleam", 398).
-spec weekday_offset(automata@schedule@ast:weekday()) -> integer().
weekday_offset(Day) ->
case Day of
monday ->
0;
tuesday ->
1;
wednesday ->
2;
thursday ->
3;
friday ->
4;
saturday ->
5;
sunday ->
6
end.
-file("src/automata/rrule/evaluator.gleam", 391).
-spec start_of_week(automata@schedule@ast:date_time()) -> automata@schedule@ast:date_time().
start_of_week(Datetime) ->
automata@internal@calendar:add_days(
{date_time, erlang:element(2, Datetime), {time, 0, 0, 0}},
0 - weekday_offset(automata@internal@calendar:weekday(Datetime))
).
-file("src/automata/rrule/evaluator.gleam", 428).
-spec days_before_month_loop(integer(), integer(), integer(), integer()) -> integer().
days_before_month_loop(Year, Target, Month, Acc) ->
case Month >= Target of
true ->
Acc;
false ->
days_before_month_loop(
Year,
Target,
Month + 1,
Acc + automata@internal@calendar:days_in_month(Year, Month)
)
end.
-file("src/automata/rrule/evaluator.gleam", 424).
-spec days_before_month(integer(), integer()) -> integer().
days_before_month(Year, Month) ->
days_before_month_loop(Year, Month, 1, 0).
-file("src/automata/rrule/evaluator.gleam", 441).
-spec modulo(integer(), integer()) -> integer().
modulo(Dividend, Divisor) ->
case gleam@int:modulo(Dividend, Divisor) of
{ok, Result} ->
Result;
{error, _} ->
0
end.
-file("src/automata/rrule/evaluator.gleam", 448).
-spec quotient(integer(), integer()) -> integer().
quotient(Dividend, Divisor) ->
case gleam@int:divide(Dividend, Divisor) of
{ok, Result} ->
Result;
{error, _} ->
0
end.
-file("src/automata/rrule/evaluator.gleam", 416).
-spec days_before_year(integer()) -> integer().
days_before_year(Year) ->
Previous = Year - 1,
(((Previous * 365) + quotient(Previous, 4)) - quotient(Previous, 100)) + quotient(
Previous,
400
).
-file("src/automata/rrule/evaluator.gleam", 410).
-spec days_since_epoch(automata@schedule@ast:date()) -> integer().
days_since_epoch(Date) ->
(days_before_year(erlang:element(2, Date)) + days_before_month(
erlang:element(2, Date),
erlang:element(3, Date)
))
+ erlang:element(4, Date).
-file("src/automata/rrule/evaluator.gleam", 378).
-spec days_between(
automata@schedule@ast:date_time(),
automata@schedule@ast:date_time()
) -> integer().
days_between(From, To) ->
days_since_epoch(erlang:element(2, To)) - days_since_epoch(
erlang:element(2, From)
).
-file("src/automata/rrule/evaluator.gleam", 382).
-spec weeks_between(
automata@schedule@ast:date_time(),
automata@schedule@ast:date_time()
) -> integer().
weeks_between(From, To) ->
quotient(days_between(start_of_week(From), start_of_week(To)), 7).
-file("src/automata/rrule/evaluator.gleam", 78).
-spec aligned(
automata@rrule@normalize:r_rule_plan(),
automata@schedule@ast:date_time()
) -> boolean().
aligned(Plan, At) ->
case erlang:element(3, Plan) of
daily ->
modulo(
days_between(erlang:element(2, Plan), At),
erlang:element(4, Plan)
)
=:= 0;
weekly ->
modulo(
weeks_between(erlang:element(2, Plan), At),
erlang:element(4, Plan)
)
=:= 0;
monthly ->
modulo(
months_between(erlang:element(2, Plan), At),
erlang:element(4, Plan)
)
=:= 0;
yearly ->
modulo(
erlang:element(2, erlang:element(2, At)) - erlang:element(
2,
erlang:element(2, erlang:element(2, Plan))
),
erlang:element(4, Plan)
)
=:= 0
end.
-file("src/automata/rrule/evaluator.gleam", 70).
-spec base_match(
automata@rrule@normalize:r_rule_plan(),
automata@schedule@ast:date_time()
) -> boolean().
base_match(Plan, At) ->
(((aligned(Plan, At) andalso day_matches(Plan, erlang:element(2, At)))
andalso gleam@list:any(
erlang:element(9, Plan),
fun(Hour) -> Hour =:= erlang:element(2, erlang:element(3, At)) end
))
andalso gleam@list:any(
erlang:element(10, Plan),
fun(Minute) -> Minute =:= erlang:element(3, erlang:element(3, At)) end
))
andalso (erlang:element(4, erlang:element(3, At)) =:= erlang:element(
11,
Plan
)).
-file("src/automata/rrule/evaluator.gleam", 137).
-spec next_occurrence(
automata@rrule@normalize:r_rule_plan(),
automata@schedule@ast:date_time(),
integer()
) -> gleam@option:option(automata@schedule@ast:date_time()).
next_occurrence(Plan, Search, Guard) ->
case Guard > 4000000 of
true ->
none;
false ->
Start = case automata@internal@calendar:less_than(
Search,
erlang:element(2, Plan)
) of
true ->
erlang:element(2, Plan);
false ->
Search
end,
case within_until(erlang:element(5, Plan), Start) of
false ->
none;
true ->
case day_matches(Plan, erlang:element(2, Start)) andalso aligned(
Plan,
Start
) of
true ->
case next_time_on_day(
Plan,
erlang:element(2, Start),
Start
) of
{some, Found} ->
case within_until(
erlang:element(5, Plan),
Found
) of
true ->
{some, Found};
false ->
none
end;
none ->
next_occurrence(
Plan,
automata@internal@calendar:next_day(
Start
),
Guard + 1
)
end;
false ->
next_occurrence(
Plan,
automata@internal@calendar:next_day(Start),
Guard + 1
)
end
end
end.
-file("src/automata/rrule/evaluator.gleam", 106).
-spec occurrence_index(
automata@rrule@normalize:r_rule_plan(),
automata@schedule@ast:date_time(),
integer(),
automata@schedule@ast:date_time()
) -> integer().
occurrence_index(Plan, Target, Count, Search) ->
case next_occurrence(Plan, Search, 0) of
none ->
Count;
{some, Found} ->
case automata@internal@calendar:compare(Found, Target) of
lt ->
occurrence_index(
Plan,
Target,
Count + 1,
automata@internal@calendar:add_seconds(Found, 1)
);
eq ->
Count + 1;
gt ->
Count
end
end.
-file("src/automata/rrule/evaluator.gleam", 13).
-spec matches(
automata@rrule@normalize:r_rule_plan(),
automata@schedule@ast:date_time()
) -> boolean().
matches(Plan, At) ->
case automata@internal@calendar:less_than(At, erlang:element(2, Plan)) of
true ->
false;
false ->
case within_until(erlang:element(5, Plan), At) of
false ->
false;
true ->
case base_match(Plan, At) of
false ->
false;
true ->
case erlang:element(5, Plan) of
{count, Limit} ->
occurrence_index(
Plan,
At,
0,
erlang:element(2, Plan)
)
=< Limit;
_ ->
true
end
end
end
end.
-file("src/automata/rrule/evaluator.gleam", 129).
-spec yielded_before(
automata@rrule@normalize:r_rule_plan(),
automata@schedule@ast:date_time()
) -> integer().
yielded_before(Plan, Cursor) ->
case automata@internal@calendar:less_than(Cursor, erlang:element(2, Plan)) of
true ->
0;
false ->
occurrence_index(
Plan,
automata@internal@calendar:add_seconds(Cursor, -1),
0,
erlang:element(2, Plan)
)
end.