src/automata@rrule@builder.erl

-module(automata@rrule@builder).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/automata/rrule/builder.gleam").
-export([builder/1, weekday/1, nth_weekday/2, with_interval/2, with_count/2, with_until_date/2, with_until_datetime/2, without_end_condition/1, with_by_day/2, with_by_month/2, with_by_month_day/2, with_by_hour/2, with_by_minute/2, build/1]).
-export_type([builder/0]).

-opaque builder() :: {builder,
        automata@rrule@validator:frequency(),
        integer(),
        automata@rrule@validator:end_condition(),
        gleam@option:option(list(automata@rrule@validator:weekday_specifier())),
        gleam@option:option(list(integer())),
        gleam@option:option(list(integer())),
        gleam@option:option(list(integer())),
        gleam@option:option(list(integer()))}.

-file("src/automata/rrule/builder.gleam", 29).
-spec builder(automata@rrule@validator:frequency()) -> builder().
builder(Frequency) ->
    {builder, Frequency, 1, forever, none, none, none, none, none}.

-file("src/automata/rrule/builder.gleam", 42).
-spec weekday(automata@schedule@ast:weekday()) -> automata@rrule@validator:weekday_specifier().
weekday(Day) ->
    {every_weekday, Day}.

-file("src/automata/rrule/builder.gleam", 46).
-spec nth_weekday(integer(), automata@schedule@ast:weekday()) -> automata@rrule@validator:weekday_specifier().
nth_weekday(Ordinal, Day) ->
    {nth_weekday, Ordinal, Day}.

-file("src/automata/rrule/builder.gleam", 53).
-spec with_interval(builder(), integer()) -> builder().
with_interval(Builder, Interval) ->
    {builder,
        erlang:element(2, Builder),
        Interval,
        erlang:element(4, Builder),
        erlang:element(5, Builder),
        erlang:element(6, Builder),
        erlang:element(7, Builder),
        erlang:element(8, Builder),
        erlang:element(9, Builder)}.

-file("src/automata/rrule/builder.gleam", 57).
-spec with_count(builder(), integer()) -> builder().
with_count(Builder, Count) ->
    {builder,
        erlang:element(2, Builder),
        erlang:element(3, Builder),
        {count, Count},
        erlang:element(5, Builder),
        erlang:element(6, Builder),
        erlang:element(7, Builder),
        erlang:element(8, Builder),
        erlang:element(9, Builder)}.

-file("src/automata/rrule/builder.gleam", 61).
-spec with_until_date(builder(), automata@schedule@ast:date()) -> builder().
with_until_date(Builder, Until) ->
    {builder,
        erlang:element(2, Builder),
        erlang:element(3, Builder),
        {until, {until_date, Until}},
        erlang:element(5, Builder),
        erlang:element(6, Builder),
        erlang:element(7, Builder),
        erlang:element(8, Builder),
        erlang:element(9, Builder)}.

-file("src/automata/rrule/builder.gleam", 65).
-spec with_until_datetime(builder(), automata@schedule@ast:date_time()) -> builder().
with_until_datetime(Builder, Until) ->
    {builder,
        erlang:element(2, Builder),
        erlang:element(3, Builder),
        {until, {until_date_time, Until}},
        erlang:element(5, Builder),
        erlang:element(6, Builder),
        erlang:element(7, Builder),
        erlang:element(8, Builder),
        erlang:element(9, Builder)}.

-file("src/automata/rrule/builder.gleam", 72).
-spec without_end_condition(builder()) -> builder().
without_end_condition(Builder) ->
    {builder,
        erlang:element(2, Builder),
        erlang:element(3, Builder),
        forever,
        erlang:element(5, Builder),
        erlang:element(6, Builder),
        erlang:element(7, Builder),
        erlang:element(8, Builder),
        erlang:element(9, Builder)}.

-file("src/automata/rrule/builder.gleam", 76).
-spec with_by_day(builder(), list(automata@rrule@validator:weekday_specifier())) -> builder().
with_by_day(Builder, Values) ->
    {builder,
        erlang:element(2, Builder),
        erlang:element(3, Builder),
        erlang:element(4, Builder),
        {some, Values},
        erlang:element(6, Builder),
        erlang:element(7, Builder),
        erlang:element(8, Builder),
        erlang:element(9, Builder)}.

-file("src/automata/rrule/builder.gleam", 83).
-spec with_by_month(builder(), list(integer())) -> builder().
with_by_month(Builder, Values) ->
    {builder,
        erlang:element(2, Builder),
        erlang:element(3, Builder),
        erlang:element(4, Builder),
        erlang:element(5, Builder),
        {some, Values},
        erlang:element(7, Builder),
        erlang:element(8, Builder),
        erlang:element(9, Builder)}.

-file("src/automata/rrule/builder.gleam", 87).
-spec with_by_month_day(builder(), list(integer())) -> builder().
with_by_month_day(Builder, Values) ->
    {builder,
        erlang:element(2, Builder),
        erlang:element(3, Builder),
        erlang:element(4, Builder),
        erlang:element(5, Builder),
        erlang:element(6, Builder),
        {some, Values},
        erlang:element(8, Builder),
        erlang:element(9, Builder)}.

-file("src/automata/rrule/builder.gleam", 91).
-spec with_by_hour(builder(), list(integer())) -> builder().
with_by_hour(Builder, Values) ->
    {builder,
        erlang:element(2, Builder),
        erlang:element(3, Builder),
        erlang:element(4, Builder),
        erlang:element(5, Builder),
        erlang:element(6, Builder),
        erlang:element(7, Builder),
        {some, Values},
        erlang:element(9, Builder)}.

-file("src/automata/rrule/builder.gleam", 95).
-spec with_by_minute(builder(), list(integer())) -> builder().
with_by_minute(Builder, Values) ->
    {builder,
        erlang:element(2, Builder),
        erlang:element(3, Builder),
        erlang:element(4, Builder),
        erlang:element(5, Builder),
        erlang:element(6, Builder),
        erlang:element(7, Builder),
        erlang:element(8, Builder),
        {some, Values}}.

-file("src/automata/rrule/builder.gleam", 138).
-spec validate_interval(integer()) -> {ok, nil} |
    {error, automata@rrule@validator:validation_error()}.
validate_interval(Interval) ->
    case Interval > 0 of
        true ->
            {ok, nil};

        false ->
            {error, {must_be_positive, interval_part, Interval}}
    end.

-file("src/automata/rrule/builder.gleam", 149).
-spec validate_end_condition(automata@rrule@validator:end_condition()) -> {ok,
        nil} |
    {error, automata@rrule@validator:validation_error()}.
validate_end_condition(End_condition) ->
    case End_condition of
        {count, Count} ->
            case Count > 0 of
                true ->
                    {ok, nil};

                false ->
                    {error, {must_be_positive, count_part, Count}}
            end;

        _ ->
            {ok, nil}
    end.

-file("src/automata/rrule/builder.gleam", 166).
-spec validate_optional_list(
    gleam@option:option(list(any())),
    automata@rrule@validator:rule_part()
) -> {ok, nil} | {error, automata@rrule@validator:validation_error()}.
validate_optional_list(Values, Part) ->
    case Values of
        none ->
            {ok, nil};

        {some, []} ->
            {error, {invalid_list, Part, <<""/utf8>>}};

        {some, _} ->
            {ok, nil}
    end.

-file("src/automata/rrule/builder.gleam", 203).
-spec translate_parser_error(automata@rrule@parser:parse_error()) -> automata@rrule@validator:validation_error().
translate_parser_error(Error) ->
    case Error of
        {invalid_rule, Value} ->
            {invalid_part_value, freq_part, Value};

        {invalid_part_syntax, Value@1} ->
            {invalid_part_value, freq_part, Value@1};

        {empty_part, Value@2} ->
            {invalid_part_value, freq_part, Value@2}
    end.

-file("src/automata/rrule/builder.gleam", 237).
-spec append_int_part(
    list(binary()),
    binary(),
    gleam@option:option(list(integer()))
) -> list(binary()).
append_int_part(Parts, Name, Values) ->
    case Values of
        none ->
            Parts;

        {some, Items} ->
            lists:append(
                Parts,
                [<<<<Name/binary, "="/utf8>>/binary,
                        (gleam@string:join(
                            gleam@list:map(
                                Items,
                                fun erlang:integer_to_binary/1
                            ),
                            <<","/utf8>>
                        ))/binary>>]
            )
    end.

-file("src/automata/rrule/builder.gleam", 273).
-spec weekday_to_string(automata@schedule@ast:weekday()) -> binary().
weekday_to_string(Day) ->
    case Day 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/rrule/builder.gleam", 186).
-spec check_weekday_items(list(automata@rrule@validator:weekday_specifier())) -> {ok,
        nil} |
    {error, automata@rrule@validator:validation_error()}.
check_weekday_items(Items) ->
    case Items of
        [] ->
            {ok, nil};

        [Item | Rest] ->
            case Item of
                {nth_weekday, 0, Day} ->
                    {error,
                        {invalid_part_value,
                            by_day_part,
                            <<"0"/utf8, (weekday_to_string(Day))/binary>>}};

                _ ->
                    check_weekday_items(Rest)
            end
    end.

-file("src/automata/rrule/builder.gleam", 177).
-spec validate_weekday_specifiers(
    gleam@option:option(list(automata@rrule@validator:weekday_specifier()))
) -> {ok, nil} | {error, automata@rrule@validator:validation_error()}.
validate_weekday_specifiers(Values) ->
    case Values of
        none ->
            {ok, nil};

        {some, Items} ->
            check_weekday_items(Items)
    end.

-file("src/automata/rrule/builder.gleam", 115).
-spec validate_inputs(builder()) -> {ok, nil} |
    {error, automata@rrule@validator:validation_error()}.
validate_inputs(Builder) ->
    gleam@result:'try'(
        validate_interval(erlang:element(3, Builder)),
        fun(_) ->
            gleam@result:'try'(
                validate_end_condition(erlang:element(4, Builder)),
                fun(_) ->
                    gleam@result:'try'(
                        validate_optional_list(
                            erlang:element(5, Builder),
                            by_day_part
                        ),
                        fun(_) ->
                            gleam@result:'try'(
                                validate_weekday_specifiers(
                                    erlang:element(5, Builder)
                                ),
                                fun(_) ->
                                    gleam@result:'try'(
                                        validate_optional_list(
                                            erlang:element(6, Builder),
                                            by_month_part
                                        ),
                                        fun(_) ->
                                            gleam@result:'try'(
                                                validate_optional_list(
                                                    erlang:element(7, Builder),
                                                    by_month_day_part
                                                ),
                                                fun(_) ->
                                                    gleam@result:'try'(
                                                        validate_optional_list(
                                                            erlang:element(
                                                                8,
                                                                Builder
                                                            ),
                                                            by_hour_part
                                                        ),
                                                        fun(_) ->
                                                            validate_optional_list(
                                                                erlang:element(
                                                                    9,
                                                                    Builder
                                                                ),
                                                                by_minute_part
                                                            )
                                                        end
                                                    )
                                                end
                                            )
                                        end
                                    )
                                end
                            )
                        end
                    )
                end
            )
        end
    ).

-file("src/automata/rrule/builder.gleam", 265).
-spec weekday_specifier_to_string(automata@rrule@validator:weekday_specifier()) -> binary().
weekday_specifier_to_string(Specifier) ->
    case Specifier of
        {every_weekday, Day} ->
            weekday_to_string(Day);

        {nth_weekday, Ordinal, Day@1} ->
            <<(erlang:integer_to_binary(Ordinal))/binary,
                (weekday_to_string(Day@1))/binary>>
    end.

-file("src/automata/rrule/builder.gleam", 251).
-spec append_weekday_part(
    list(binary()),
    gleam@option:option(list(automata@rrule@validator:weekday_specifier()))
) -> list(binary()).
append_weekday_part(Parts, Values) ->
    case Values of
        none ->
            Parts;

        {some, Items} ->
            lists:append(
                Parts,
                [<<"BYDAY="/utf8,
                        (gleam@string:join(
                            gleam@list:map(
                                Items,
                                fun weekday_specifier_to_string/1
                            ),
                            <<","/utf8>>
                        ))/binary>>]
            )
    end.

-file("src/automata/rrule/builder.gleam", 285).
-spec frequency_to_string(automata@rrule@validator:frequency()) -> binary().
frequency_to_string(Frequency) ->
    case Frequency of
        daily ->
            <<"DAILY"/utf8>>;

        weekly ->
            <<"WEEKLY"/utf8>>;

        monthly ->
            <<"MONTHLY"/utf8>>;

        yearly ->
            <<"YEARLY"/utf8>>
    end.

-file("src/automata/rrule/builder.gleam", 314).
-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/rrule/builder.gleam", 321).
-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/rrule/builder.gleam", 301).
-spec date_to_string(automata@schedule@ast:date()) -> binary().
date_to_string(Date) ->
    <<<<(pad4(erlang:element(2, Date)))/binary,
            (pad2(erlang:element(3, Date)))/binary>>/binary,
        (pad2(erlang:element(4, Date)))/binary>>.

-file("src/automata/rrule/builder.gleam", 305).
-spec datetime_to_string(automata@schedule@ast:date_time()) -> binary().
datetime_to_string(Datetime) ->
    <<<<<<<<<<(date_to_string(erlang:element(2, Datetime)))/binary, "T"/utf8>>/binary,
                    (pad2(erlang:element(2, erlang:element(3, Datetime))))/binary>>/binary,
                (pad2(erlang:element(3, erlang:element(3, Datetime))))/binary>>/binary,
            (pad2(erlang:element(4, erlang:element(3, Datetime))))/binary>>/binary,
        "Z"/utf8>>.

-file("src/automata/rrule/builder.gleam", 294).
-spec until_to_string(automata@rrule@validator:until()) -> binary().
until_to_string(Until) ->
    case Until of
        {until_date, Date} ->
            date_to_string(Date);

        {until_date_time, Datetime} ->
            datetime_to_string(Datetime)
    end.

-file("src/automata/rrule/builder.gleam", 214).
-spec render(builder()) -> binary().
render(Builder) ->
    Parts = [<<"FREQ="/utf8,
            (frequency_to_string(erlang:element(2, Builder)))/binary>>],
    Parts@1 = case erlang:element(4, Builder) of
        forever ->
            Parts;

        {count, Count} ->
            lists:append(
                Parts,
                [<<"COUNT="/utf8, (erlang:integer_to_binary(Count))/binary>>]
            );

        {until, Until} ->
            lists:append(
                Parts,
                [<<"UNTIL="/utf8, (until_to_string(Until))/binary>>]
            )
    end,
    Parts@2 = case erlang:element(3, Builder) =:= 1 of
        true ->
            Parts@1;

        false ->
            lists:append(
                Parts@1,
                [<<"INTERVAL="/utf8,
                        (erlang:integer_to_binary(erlang:element(3, Builder)))/binary>>]
            )
    end,
    Parts@3 = append_weekday_part(Parts@2, erlang:element(5, Builder)),
    Parts@4 = append_int_part(
        Parts@3,
        <<"BYMONTH"/utf8>>,
        erlang:element(6, Builder)
    ),
    Parts@5 = append_int_part(
        Parts@4,
        <<"BYMONTHDAY"/utf8>>,
        erlang:element(7, Builder)
    ),
    Parts@6 = append_int_part(
        Parts@5,
        <<"BYHOUR"/utf8>>,
        erlang:element(8, Builder)
    ),
    Parts@7 = append_int_part(
        Parts@6,
        <<"BYMINUTE"/utf8>>,
        erlang:element(9, Builder)
    ),
    gleam@string:join(Parts@7, <<";"/utf8>>).

-file("src/automata/rrule/builder.gleam", 99).
-spec build(builder()) -> {ok, automata@rrule@validator:valid_r_rule()} |
    {error, automata@rrule@validator:validation_error()}.
build(Builder) ->
    case validate_inputs(Builder) of
        {error, Error} ->
            {error, Error};

        {ok, _} ->
            Rendered = render(Builder),
            case automata@rrule@parser:parse(Rendered) of
                {ok, Raw} ->
                    automata@rrule@validator:validate(Raw);

                {error, Error@1} ->
                    {error, translate_parser_error(Error@1)}
            end
    end.