src/automata@schedule@ast.erl

-module(automata@schedule@ast).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/automata/schedule/ast.gleam").
-export([date/3, time/3, datetime/6, valid_datetime_value/1, unsafe_assume_valid/1, try_datetime/6, try_valid_datetime/6, weekday_to_string/1, to_string/1]).
-export_type([weekday/0, date/0, time/0, date_time/0, valid_date_time/0, boundary/0, date_time_error/0]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.

-type weekday() :: monday |
    tuesday |
    wednesday |
    thursday |
    friday |
    saturday |
    sunday.

-type date() :: {date, integer(), integer(), integer()}.

-type time() :: {time, integer(), integer(), integer()}.

-type date_time() :: {date_time, date(), time()}.

-opaque valid_date_time() :: {valid_date_time, date_time()}.

-type boundary() :: {inclusive, valid_date_time()} |
    {exclusive, valid_date_time()}.

-type date_time_error() :: {invalid_date, integer(), integer(), integer()} |
    {invalid_time, integer(), integer(), integer()}.

-file("src/automata/schedule/ast.gleam", 52).
-spec date(integer(), integer(), integer()) -> date().
date(Year, Month, Day) ->
    {date, Year, Month, Day}.

-file("src/automata/schedule/ast.gleam", 56).
-spec time(integer(), integer(), integer()) -> time().
time(Hour, Minute, Second) ->
    {time, Hour, Minute, Second}.

-file("src/automata/schedule/ast.gleam", 60).
-spec datetime(integer(), integer(), integer(), integer(), integer(), integer()) -> date_time().
datetime(Year, Month, Day, Hour, Minute, Second) ->
    {date_time, {date, Year, Month, Day}, {time, Hour, Minute, Second}}.

-file("src/automata/schedule/ast.gleam", 110).
?DOC(" Recover the raw `DateTime` value from a `ValidDateTime`.\n").
-spec valid_datetime_value(valid_date_time()) -> date_time().
valid_datetime_value(Valid) ->
    erlang:element(2, Valid).

-file("src/automata/schedule/ast.gleam", 123).
?DOC(false).
-spec unsafe_assume_valid(date_time()) -> valid_date_time().
unsafe_assume_valid(Value) ->
    {valid_date_time, Value}.

-file("src/automata/schedule/ast.gleam", 131).
-spec is_valid_time_components(integer(), integer(), integer()) -> boolean().
is_valid_time_components(Hour, Minute, Second) ->
    (((((Hour >= 0) andalso (Hour =< 23)) andalso (Minute >= 0)) andalso (Minute
    =< 59))
    andalso (Second >= 0))
    andalso (Second =< 59).

-file("src/automata/schedule/ast.gleam", 170).
-spec modulo(integer(), integer()) -> integer().
modulo(Dividend, Divisor) ->
    _pipe = gleam@int:modulo(Dividend, Divisor),
    gleam@result:unwrap(_pipe, 0).

-file("src/automata/schedule/ast.gleam", 162).
-spec is_leap_year(integer()) -> boolean().
is_leap_year(Year) ->
    By_4 = modulo(Year, 4),
    By_100 = modulo(Year, 100),
    By_400 = modulo(Year, 400),
    (By_400 =:= 0) orelse ((By_4 =:= 0) andalso (By_100 /= 0)).

-file("src/automata/schedule/ast.gleam", 140).
-spec days_in_month(integer(), integer()) -> integer().
days_in_month(Year, Month) ->
    case Month of
        1 ->
            31;

        2 ->
            case is_leap_year(Year) of
                true ->
                    29;

                false ->
                    28
            end;

        3 ->
            31;

        4 ->
            30;

        5 ->
            31;

        6 ->
            30;

        7 ->
            31;

        8 ->
            31;

        9 ->
            30;

        10 ->
            31;

        11 ->
            30;

        12 ->
            31;

        _ ->
            0
    end.

-file("src/automata/schedule/ast.gleam", 127).
-spec is_valid_date_components(integer(), integer(), integer()) -> boolean().
is_valid_date_components(Year, Month, Day) ->
    (((Month >= 1) andalso (Month =< 12)) andalso (Day >= 1)) andalso (Day =< days_in_month(
        Year,
        Month
    )).

-file("src/automata/schedule/ast.gleam", 76).
?DOC(
    " Build a validated `DateTime` from raw integer components.\n"
    "\n"
    " Returns `Error(InvalidDate)` for impossible calendar dates such as\n"
    " February 30, and `Error(InvalidTime)` for clock components outside\n"
    " `00:00:00`-`23:59:59`.\n"
).
-spec try_datetime(
    integer(),
    integer(),
    integer(),
    integer(),
    integer(),
    integer()
) -> {ok, date_time()} | {error, date_time_error()}.
try_datetime(Year, Month, Day, Hour, Minute, Second) ->
    case is_valid_date_components(Year, Month, Day) of
        false ->
            {error, {invalid_date, Year, Month, Day}};

        true ->
            case is_valid_time_components(Hour, Minute, Second) of
                false ->
                    {error, {invalid_time, Hour, Minute, Second}};

                true ->
                    {ok, datetime(Year, Month, Day, Hour, Minute, Second)}
            end
    end.

-file("src/automata/schedule/ast.gleam", 95).
?DOC(" Build an opaque `ValidDateTime`, propagating validation errors.\n").
-spec try_valid_datetime(
    integer(),
    integer(),
    integer(),
    integer(),
    integer(),
    integer()
) -> {ok, valid_date_time()} | {error, date_time_error()}.
try_valid_datetime(Year, Month, Day, Hour, Minute, Second) ->
    case try_datetime(Year, Month, Day, Hour, Minute, Second) of
        {ok, Value} ->
            {ok, {valid_date_time, Value}};

        {error, Error} ->
            {error, Error}
    end.

-file("src/automata/schedule/ast.gleam", 188).
-spec weekday_to_string(weekday()) -> binary().
weekday_to_string(Weekday) ->
    case Weekday of
        monday ->
            <<"MO"/utf8>>;

        tuesday ->
            <<"TU"/utf8>>;

        wednesday ->
            <<"WE"/utf8>>;

        thursday ->
            <<"TH"/utf8>>;

        friday ->
            <<"FR"/utf8>>;

        saturday ->
            <<"SA"/utf8>>;

        sunday ->
            <<"SU"/utf8>>
    end.

-file("src/automata/schedule/ast.gleam", 200).
-spec pad2(integer()) -> binary().
pad2(Value) ->
    case Value < 10 of
        true ->
            <<"0"/utf8, (erlang:integer_to_binary(Value))/binary>>;

        false ->
            erlang:integer_to_binary(Value)
    end.

-file("src/automata/schedule/ast.gleam", 207).
-spec pad4(integer()) -> binary().
pad4(Value) ->
    case Value < 10 of
        true ->
            <<"000"/utf8, (erlang:integer_to_binary(Value))/binary>>;

        false ->
            case Value < 100 of
                true ->
                    <<"00"/utf8, (erlang:integer_to_binary(Value))/binary>>;

                false ->
                    case Value < 1000 of
                        true ->
                            <<"0"/utf8,
                                (erlang:integer_to_binary(Value))/binary>>;

                        false ->
                            erlang:integer_to_binary(Value)
                    end
            end
    end.

-file("src/automata/schedule/ast.gleam", 174).
-spec to_string(date_time()) -> binary().
to_string(Datetime) ->
    <<<<<<<<<<<<<<<<<<<<(pad4(erlang:element(2, erlang:element(2, Datetime))))/binary,
                                            "-"/utf8>>/binary,
                                        (pad2(
                                            erlang:element(
                                                3,
                                                erlang:element(2, Datetime)
                                            )
                                        ))/binary>>/binary,
                                    "-"/utf8>>/binary,
                                (pad2(
                                    erlang:element(
                                        4,
                                        erlang:element(2, Datetime)
                                    )
                                ))/binary>>/binary,
                            "T"/utf8>>/binary,
                        (pad2(erlang:element(2, erlang:element(3, Datetime))))/binary>>/binary,
                    ":"/utf8>>/binary,
                (pad2(erlang:element(3, erlang:element(3, Datetime))))/binary>>/binary,
            ":"/utf8>>/binary,
        (pad2(erlang:element(4, erlang:element(3, Datetime))))/binary>>.