src/qrkit@content.erl

-module(qrkit@content).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/qrkit/content.gleam").
-export([url/1, vcard/0, with_name/2, with_phone/2, with_email/2, with_url/2, with_organization/2, with_title/2, with_address/2, sms/2, geo/2, phone/1, event/3, with_location/2, with_description/2, with_all_day/2, wifi/4, email/3, vcard_to_string/1, event_to_string/1]).
-export_type([wifi_security/0, v_card/0, calendar_event/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.

?MODULEDOC(" Domain-specific helpers that produce QR-ready payload strings.\n").

-type wifi_security() :: open | wep | wpa | wpa2 | wpa3.

-opaque v_card() :: {v_card,
        gleam@option:option(binary()),
        gleam@option:option(binary()),
        gleam@option:option(binary()),
        gleam@option:option(binary()),
        gleam@option:option(binary()),
        gleam@option:option(binary()),
        gleam@option:option(binary())}.

-opaque calendar_event() :: {calendar_event,
        binary(),
        integer(),
        integer(),
        gleam@option:option(binary()),
        gleam@option:option(binary()),
        boolean()}.

-file("src/qrkit/content.gleam", 11).
?DOC(" Return a URL payload unchanged.\n").
-spec url(binary()) -> binary().
url(Href) ->
    Href.

-file("src/qrkit/content.gleam", 57).
?DOC(" Create an empty vCard builder.\n").
-spec vcard() -> v_card().
vcard() ->
    {v_card, none, none, none, none, none, none, none}.

-file("src/qrkit/content.gleam", 62).
?DOC(" Set the display name.\n").
-spec with_name(v_card(), binary()) -> v_card().
with_name(Card, Name) ->
    {v_card, _, Phone, Email, Url, Organization, Title, Address} = Card,
    {v_card, {some, Name}, Phone, Email, Url, Organization, Title, Address}.

-file("src/qrkit/content.gleam", 68).
?DOC(" Set the phone number.\n").
-spec with_phone(v_card(), binary()) -> v_card().
with_phone(Card, Phone) ->
    {v_card, Name, _, Email, Url, Organization, Title, Address} = Card,
    {v_card, Name, {some, Phone}, Email, Url, Organization, Title, Address}.

-file("src/qrkit/content.gleam", 74).
?DOC(" Set the e-mail address.\n").
-spec with_email(v_card(), binary()) -> v_card().
with_email(Card, Email) ->
    {v_card, Name, Phone, _, Url, Organization, Title, Address} = Card,
    {v_card, Name, Phone, {some, Email}, Url, Organization, Title, Address}.

-file("src/qrkit/content.gleam", 80).
?DOC(" Set the URL field.\n").
-spec with_url(v_card(), binary()) -> v_card().
with_url(Card, Url) ->
    {v_card, Name, Phone, Email, _, Organization, Title, Address} = Card,
    {v_card, Name, Phone, Email, {some, Url}, Organization, Title, Address}.

-file("src/qrkit/content.gleam", 86).
?DOC(" Set the organization field.\n").
-spec with_organization(v_card(), binary()) -> v_card().
with_organization(Card, Org) ->
    {v_card, Name, Phone, Email, Url, _, Title, Address} = Card,
    {v_card, Name, Phone, Email, Url, {some, Org}, Title, Address}.

-file("src/qrkit/content.gleam", 92).
?DOC(" Set the title field.\n").
-spec with_title(v_card(), binary()) -> v_card().
with_title(Card, Title) ->
    {v_card, Name, Phone, Email, Url, Organization, _, Address} = Card,
    {v_card, Name, Phone, Email, Url, Organization, {some, Title}, Address}.

-file("src/qrkit/content.gleam", 98).
?DOC(" Set the address field.\n").
-spec with_address(v_card(), binary()) -> v_card().
with_address(Card, Address) ->
    {v_card, Name, Phone, Email, Url, Organization, Title, _} = Card,
    {v_card, Name, Phone, Email, Url, Organization, Title, {some, Address}}.

-file("src/qrkit/content.gleam", 138).
?DOC(" Build an SMS payload.\n").
-spec sms(binary(), binary()) -> binary().
sms(To, Body) ->
    <<<<<<"SMSTO:"/utf8, To/binary>>/binary, ":"/utf8>>/binary, Body/binary>>.

-file("src/qrkit/content.gleam", 143).
?DOC(" Build a geo URI.\n").
-spec geo(float(), float()) -> binary().
geo(Latitude, Longitude) ->
    <<<<<<"geo:"/utf8, (gleam_stdlib:float_to_string(Latitude))/binary>>/binary,
            ","/utf8>>/binary,
        (gleam_stdlib:float_to_string(Longitude))/binary>>.

-file("src/qrkit/content.gleam", 148).
?DOC(" Build a phone URI.\n").
-spec phone(binary()) -> binary().
phone(Number) ->
    <<"tel:"/utf8, Number/binary>>.

-file("src/qrkit/content.gleam", 164).
?DOC(" Create a calendar event payload builder.\n").
-spec event(binary(), integer(), integer()) -> calendar_event().
event(Title, Start_unix, End_unix) ->
    {calendar_event, Title, Start_unix, End_unix, none, none, false}.

-file("src/qrkit/content.gleam", 173).
?DOC(" Set the event location.\n").
-spec with_location(calendar_event(), binary()) -> calendar_event().
with_location(Event, Loc) ->
    {calendar_event, Title, Start_unix, End_unix, _, Description, All_day} = Event,
    {calendar_event,
        Title,
        Start_unix,
        End_unix,
        {some, Loc},
        Description,
        All_day}.

-file("src/qrkit/content.gleam", 180).
?DOC(" Set the event description.\n").
-spec with_description(calendar_event(), binary()) -> calendar_event().
with_description(Event, Desc) ->
    {calendar_event, Title, Start_unix, End_unix, Location, _, All_day} = Event,
    {calendar_event,
        Title,
        Start_unix,
        End_unix,
        Location,
        {some, Desc},
        All_day}.

-file("src/qrkit/content.gleam", 186).
?DOC(" Toggle all-day rendering.\n").
-spec with_all_day(calendar_event(), boolean()) -> calendar_event().
with_all_day(Event, All_day) ->
    {calendar_event, Title, Start_unix, End_unix, Location, Description, _} = Event,
    {calendar_event,
        Title,
        Start_unix,
        End_unix,
        Location,
        Description,
        All_day}.

-file("src/qrkit/content.gleam", 222).
-spec wifi_security_name(wifi_security()) -> binary().
wifi_security_name(Security) ->
    case Security of
        open ->
            <<"nopass"/utf8>>;

        wep ->
            <<"WEP"/utf8>>;

        wpa ->
            <<"WPA"/utf8>>;

        wpa2 ->
            <<"WPA2"/utf8>>;

        wpa3 ->
            <<"WPA3"/utf8>>
    end.

-file("src/qrkit/content.gleam", 232).
-spec escape_wifi(binary()) -> binary().
escape_wifi(Value) ->
    _pipe = Value,
    _pipe@1 = gleam@string:replace(_pipe, <<"\\"/utf8>>, <<"\\\\"/utf8>>),
    _pipe@2 = gleam@string:replace(_pipe@1, <<";"/utf8>>, <<"\\;"/utf8>>),
    _pipe@3 = gleam@string:replace(_pipe@2, <<","/utf8>>, <<"\\,"/utf8>>),
    _pipe@4 = gleam@string:replace(_pipe@3, <<":"/utf8>>, <<"\\:"/utf8>>),
    gleam@string:replace(_pipe@4, <<"\""/utf8>>, <<"\\\""/utf8>>).

-file("src/qrkit/content.gleam", 24).
?DOC(" Build a WiFi payload string.\n").
-spec wifi(binary(), binary(), wifi_security(), boolean()) -> binary().
wifi(Ssid, Password, Security, Hidden) ->
    Base = <<<<<<<<<<<<"WIFI:T:"/utf8, (wifi_security_name(Security))/binary>>/binary,
                        ";S:"/utf8>>/binary,
                    (escape_wifi(Ssid))/binary>>/binary,
                ";P:"/utf8>>/binary,
            (escape_wifi(Password))/binary>>/binary,
        ";"/utf8>>,
    case Hidden of
        true ->
            <<Base/binary, "H:true;;"/utf8>>;

        false ->
            <<Base/binary, ";"/utf8>>
    end.

-file("src/qrkit/content.gleam", 244).
-spec option_line_with(
    binary(),
    gleam@option:option(binary()),
    fun((binary()) -> binary())
) -> gleam@option:option(binary()).
option_line_with(Key, Value, Escape) ->
    case Value of
        {some, Value@1} ->
            {some,
                <<<<Key/binary, ":"/utf8>>/binary, (Escape(Value@1))/binary>>};

        none ->
            none
    end.

-file("src/qrkit/content.gleam", 255).
-spec present_lines(list(gleam@option:option(binary())), list(binary())) -> list(binary()).
present_lines(Lines, Acc) ->
    case Lines of
        [] ->
            lists:reverse(Acc);

        [{some, Line} | Rest] ->
            present_lines(Rest, [Line | Acc]);

        [none | Rest@1] ->
            present_lines(Rest@1, Acc)
    end.

-file("src/qrkit/content.gleam", 263).
-spec percent_encode(binary()) -> binary().
percent_encode(Value) ->
    gleam_stdlib:percent_encode(Value).

-file("src/qrkit/content.gleam", 124).
?DOC(" Build a `mailto:` payload.\n").
-spec email(binary(), binary(), binary()) -> binary().
email(To, Subject, Body) ->
    <<<<<<<<<<"mailto:"/utf8, To/binary>>/binary, "?subject="/utf8>>/binary,
                (percent_encode(Subject))/binary>>/binary,
            "&body="/utf8>>/binary,
        (percent_encode(Body))/binary>>.

-file("src/qrkit/content.gleam", 267).
-spec escape_vcard(binary()) -> binary().
escape_vcard(Value) ->
    _pipe = Value,
    _pipe@1 = gleam@string:replace(_pipe, <<"\\"/utf8>>, <<"\\\\"/utf8>>),
    _pipe@2 = gleam@string:replace(_pipe@1, <<"\n"/utf8>>, <<"\\n"/utf8>>),
    _pipe@3 = gleam@string:replace(_pipe@2, <<","/utf8>>, <<"\\,"/utf8>>),
    gleam@string:replace(_pipe@3, <<";"/utf8>>, <<"\\;"/utf8>>).

-file("src/qrkit/content.gleam", 104).
?DOC(" Render the vCard as a text payload.\n").
-spec vcard_to_string(v_card()) -> binary().
vcard_to_string(Card) ->
    {v_card, Name, Phone, Email, Url, Organization, Title, Address} = Card,
    _pipe = [{some, <<"BEGIN:VCARD"/utf8>>},
        {some, <<"VERSION:3.0"/utf8>>},
        option_line_with(<<"N"/utf8>>, Name, fun escape_vcard/1),
        option_line_with(<<"FN"/utf8>>, Name, fun escape_vcard/1),
        option_line_with(<<"ORG"/utf8>>, Organization, fun escape_vcard/1),
        option_line_with(<<"TITLE"/utf8>>, Title, fun escape_vcard/1),
        option_line_with(<<"TEL"/utf8>>, Phone, fun escape_vcard/1),
        option_line_with(<<"EMAIL"/utf8>>, Email, fun escape_vcard/1),
        option_line_with(<<"URL"/utf8>>, Url, fun escape_vcard/1),
        option_line_with(<<"ADR"/utf8>>, Address, fun escape_vcard/1),
        {some, <<"END:VCARD"/utf8>>}],
    _pipe@1 = present_lines(_pipe, []),
    gleam@string:join(_pipe@1, <<"\n"/utf8>>).

-file("src/qrkit/content.gleam", 275).
-spec escape_ical(binary()) -> binary().
escape_ical(Value) ->
    _pipe = Value,
    _pipe@1 = gleam@string:replace(_pipe, <<"\\"/utf8>>, <<"\\\\"/utf8>>),
    _pipe@2 = gleam@string:replace(_pipe@1, <<"\n"/utf8>>, <<"\\n"/utf8>>),
    _pipe@3 = gleam@string:replace(_pipe@2, <<","/utf8>>, <<"\\,"/utf8>>),
    gleam@string:replace(_pipe@3, <<";"/utf8>>, <<"\\;"/utf8>>).

-file("src/qrkit/content.gleam", 309).
-spec civil_from_days(integer()) -> {integer(), integer(), integer()}.
civil_from_days(Days) ->
    Z = Days + 719468,
    Era = Z div 146097,
    Doe = Z - (Era * 146097),
    Yoe = (((Doe - (Doe div 1460)) + (Doe div 36524)) - (Doe div 146096)) div 365,
    Y = Yoe + (Era * 400),
    Doy = Doe - (((365 * Yoe) + (Yoe div 4)) - (Yoe div 100)),
    Mp = ((5 * Doy) + 2) div 153,
    Day = (Doy - (((153 * Mp) + 2) div 5)) + 1,
    Month = Mp + case Mp < 10 of
        true ->
            3;

        false ->
            -9
    end,
    Year = Y + case Month =< 2 of
        true ->
            1;

        false ->
            0
    end,
    {Year, Month, Day}.

-file("src/qrkit/content.gleam", 299).
-spec unix_to_utc(integer()) -> {integer(),
    integer(),
    integer(),
    integer(),
    integer(),
    integer()}.
unix_to_utc(Unix) ->
    Days = Unix div 86400,
    Seconds_of_day = Unix rem 86400,
    {Year, Month, Day} = civil_from_days(Days),
    Hour = Seconds_of_day div 3600,
    Minute = (Seconds_of_day rem 3600) div 60,
    Second = Seconds_of_day rem 60,
    {Year, Month, Day, Hour, Minute, Second}.

-file("src/qrkit/content.gleam", 333).
-spec pad(integer(), integer()) -> binary().
pad(Value, Width) ->
    Text = erlang:integer_to_binary(Value),
    Zeros = Width - string:length(Text),
    case Zeros =< 0 of
        true ->
            Text;

        false ->
            <<(gleam@string:repeat(<<"0"/utf8>>, Zeros))/binary, Text/binary>>
    end.

-file("src/qrkit/content.gleam", 283).
-spec format_datetime(integer(), boolean()) -> binary().
format_datetime(Unix, All_day) ->
    {Year, Month, Day, Hour, Minute, Second} = unix_to_utc(Unix),
    case All_day of
        true ->
            <<<<(pad(Year, 4))/binary, (pad(Month, 2))/binary>>/binary,
                (pad(Day, 2))/binary>>;

        false ->
            <<<<<<<<<<<<<<(pad(Year, 4))/binary, (pad(Month, 2))/binary>>/binary,
                                    (pad(Day, 2))/binary>>/binary,
                                "T"/utf8>>/binary,
                            (pad(Hour, 2))/binary>>/binary,
                        (pad(Minute, 2))/binary>>/binary,
                    (pad(Second, 2))/binary>>/binary,
                "Z"/utf8>>
    end.

-file("src/qrkit/content.gleam", 193).
?DOC(" Render a calendar event as an iCalendar payload.\n").
-spec event_to_string(calendar_event()) -> binary().
event_to_string(Event) ->
    {calendar_event,
        Title,
        Start_unix,
        End_unix,
        Location,
        Description,
        All_day} = Event,
    Start_value = format_datetime(Start_unix, All_day),
    End_value = format_datetime(End_unix, All_day),
    Start_key = case All_day of
        true ->
            <<"DTSTART;VALUE=DATE"/utf8>>;

        false ->
            <<"DTSTART"/utf8>>
    end,
    End_key = case All_day of
        true ->
            <<"DTEND;VALUE=DATE"/utf8>>;

        false ->
            <<"DTEND"/utf8>>
    end,
    _pipe = [{some, <<"BEGIN:VCALENDAR"/utf8>>},
        {some, <<"VERSION:2.0"/utf8>>},
        {some, <<"BEGIN:VEVENT"/utf8>>},
        {some, <<"SUMMARY:"/utf8, (escape_ical(Title))/binary>>},
        {some, <<<<Start_key/binary, ":"/utf8>>/binary, Start_value/binary>>},
        {some, <<<<End_key/binary, ":"/utf8>>/binary, End_value/binary>>},
        option_line_with(<<"LOCATION"/utf8>>, Location, fun escape_ical/1),
        option_line_with(<<"DESCRIPTION"/utf8>>, Description, fun escape_ical/1),
        {some, <<"END:VEVENT"/utf8>>},
        {some, <<"END:VCALENDAR"/utf8>>}],
    _pipe@1 = present_lines(_pipe, []),
    gleam@string:join(_pipe@1, <<"\n"/utf8>>).