src/qrkit@internal@micro.erl

-module(qrkit@internal@micro).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/qrkit/internal/micro.gleam").
-export([version/1, width/1, height/1, rows/1, mask/1, data_capacity_bits/2, ec_codewords/2, data_codewords/2, symbol_size/1, encode/4]).
-export_type([encoded/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(false).

-opaque encoded() :: {encoded,
        integer(),
        integer(),
        integer(),
        integer(),
        list(list(boolean()))}.

-file("src/qrkit/internal/micro.gleam", 32).
?DOC(false).
-spec version(encoded()) -> integer().
version(Encoded) ->
    {encoded, Version, _, _, _, _} = Encoded,
    Version.

-file("src/qrkit/internal/micro.gleam", 37).
?DOC(false).
-spec width(encoded()) -> integer().
width(Encoded) ->
    {encoded, _, Width, _, _, _} = Encoded,
    Width.

-file("src/qrkit/internal/micro.gleam", 42).
?DOC(false).
-spec height(encoded()) -> integer().
height(Encoded) ->
    {encoded, _, _, Height, _, _} = Encoded,
    Height.

-file("src/qrkit/internal/micro.gleam", 47).
?DOC(false).
-spec rows(encoded()) -> list(list(boolean())).
rows(Encoded) ->
    {encoded, _, _, _, _, Rows} = Encoded,
    Rows.

-file("src/qrkit/internal/micro.gleam", 52).
?DOC(false).
-spec mask(encoded()) -> integer().
mask(Encoded) ->
    {encoded, _, _, _, Mask, _} = Encoded,
    Mask.

-file("src/qrkit/internal/micro.gleam", 177).
?DOC(false).
-spec mode_name(qrkit@types:mode()) -> binary().
mode_name(Selected_mode) ->
    case Selected_mode of
        numeric ->
            <<"Numeric"/utf8>>;

        alphanumeric ->
            <<"Alphanumeric"/utf8>>;

        byte ->
            <<"Byte"/utf8>>;

        kanji ->
            <<"Kanji"/utf8>>
    end.

-file("src/qrkit/internal/micro.gleam", 247).
?DOC(false).
-spec validate_ecc(qrkit@types:error_correction()) -> {ok, nil} |
    {error, qrkit@error:encode_error()}.
validate_ecc(Ecc) ->
    case Ecc of
        low ->
            {ok, nil};

        medium ->
            {ok, nil};

        quartile ->
            {ok, nil};

        _ ->
            {error,
                {incompatible_options,
                    <<"Micro QR does not support the High error correction level"/utf8>>}}
    end.

-file("src/qrkit/internal/micro.gleam", 275).
?DOC(false).
-spec classify_char(binary()) -> qrkit@types:mode().
classify_char(Char) ->
    case qrkit@internal@mode:is_numeric_char(Char) of
        true ->
            numeric;

        false ->
            case qrkit@internal@mode:is_alphanumeric_char(Char) of
                true ->
                    alphanumeric;

                false ->
                    case qrkit@internal@mode:is_kanji_char(Char) of
                        true ->
                            kanji;

                        false ->
                            byte
                    end
            end
    end.

-file("src/qrkit/internal/micro.gleam", 290).
?DOC(false).
-spec refine_mode(qrkit@types:mode(), qrkit@types:mode()) -> qrkit@types:mode().
refine_mode(Current, Next) ->
    case {Current, Next} of
        {byte, _} ->
            byte;

        {_, byte} ->
            byte;

        {kanji, _} ->
            byte;

        {_, kanji} ->
            byte;

        {alphanumeric, numeric} ->
            alphanumeric;

        {numeric, alphanumeric} ->
            alphanumeric;

        {_, _} ->
            Next
    end.

-file("src/qrkit/internal/micro.gleam", 267).
?DOC(false).
-spec detect_uniform_mode(list(binary()), qrkit@types:mode()) -> qrkit@types:mode().
detect_uniform_mode(Chars, Best) ->
    case Chars of
        [] ->
            Best;

        [Char | Rest] ->
            detect_uniform_mode(Rest, refine_mode(Best, classify_char(Char)))
    end.

-file("src/qrkit/internal/micro.gleam", 257).
?DOC(false).
-spec select_mode(binary(), qrkit@types:mode_preference()) -> {ok,
        qrkit@types:mode()} |
    {error, qrkit@error:encode_error()}.
select_mode(Text, Preference) ->
    case Preference of
        force_byte ->
            {ok, byte};

        auto ->
            {ok,
                detect_uniform_mode(
                    qrkit@internal@util:characters(Text),
                    numeric
                )}
    end.

-file("src/qrkit/internal/micro.gleam", 355).
?DOC(false).
-spec mode_supported(qrkit@types:mode(), integer()) -> boolean().
mode_supported(Selected_mode, Version) ->
    case {Version, Selected_mode} of
        {1, numeric} ->
            true;

        {1, _} ->
            false;

        {2, numeric} ->
            true;

        {2, alphanumeric} ->
            true;

        {2, _} ->
            false;

        {_, _} ->
            true
    end.

-file("src/qrkit/internal/micro.gleam", 365).
?DOC(false).
-spec mode_indicator_bits(integer()) -> integer().
mode_indicator_bits(Version) ->
    Version - 1.

-file("src/qrkit/internal/micro.gleam", 369).
?DOC(false).
-spec mode_indicator_value(qrkit@types:mode()) -> integer().
mode_indicator_value(Selected_mode) ->
    case Selected_mode of
        numeric ->
            0;

        alphanumeric ->
            1;

        byte ->
            2;

        kanji ->
            3
    end.

-file("src/qrkit/internal/micro.gleam", 431).
?DOC(false).
-spec append_mode_indicator(
    qrkit@internal@bitstream:bit_stream(),
    qrkit@types:mode(),
    integer()
) -> qrkit@internal@bitstream:bit_stream().
append_mode_indicator(Stream, Selected_mode, Version) ->
    Bits = mode_indicator_bits(Version),
    case Bits of
        0 ->
            Stream;

        _ ->
            qrkit@internal@bitstream:append_bits(
                Stream,
                mode_indicator_value(Selected_mode),
                Bits
            )
    end.

-file("src/qrkit/internal/micro.gleam", 444).
?DOC(false).
-spec terminator_size(integer(), integer()) -> integer().
terminator_size(Version, Remaining) ->
    Target = (Version * 2) + 1,
    case Remaining < Target of
        true ->
            Remaining;

        false ->
            Target
    end.

-file("src/qrkit/internal/micro.gleam", 465).
?DOC(false).
-spec pad_alternating(
    qrkit@internal@bitstream:bit_stream(),
    integer(),
    integer()
) -> qrkit@internal@bitstream:bit_stream().
pad_alternating(Stream, Target_bytes, Index) ->
    Current_bytes = erlang:length(qrkit@internal@bitstream:to_byte_list(Stream)),
    case Current_bytes >= Target_bytes of
        true ->
            Stream;

        false ->
            Byte = case (Index rem 2) =:= 0 of
                true ->
                    16#EC;

                false ->
                    16#11
            end,
            pad_alternating(
                qrkit@internal@bitstream:append_byte(Stream, Byte),
                Target_bytes,
                Index + 1
            )
    end.

-file("src/qrkit/internal/micro.gleam", 511).
?DOC(false).
-spec has_half_codeword(integer(), qrkit@types:error_correction()) -> boolean().
has_half_codeword(Version, Ecc) ->
    case {Version, Ecc} of
        {1, low} ->
            true;

        {3, low} ->
            true;

        {3, medium} ->
            true;

        {_, _} ->
            false
    end.

-file("src/qrkit/internal/micro.gleam", 576).
?DOC(false).
-spec reserve_format_info(qrkit@internal@matrix:matrix(), integer()) -> qrkit@internal@matrix:matrix().
reserve_format_info(Target, _) ->
    Horizontal = begin
        _pipe = qrkit@internal@util:range(1, 8),
        gleam@list:fold(
            _pipe,
            Target,
            fun(Acc, Col) ->
                qrkit@internal@matrix:set(Acc, 8, Col, false, true)
            end
        )
    end,
    _pipe@1 = qrkit@internal@util:range(1, 7),
    gleam@list:fold(
        _pipe@1,
        Horizontal,
        fun(Acc@1, Row) ->
            qrkit@internal@matrix:set(Acc@1, Row, 8, false, true)
        end
    ).

-file("src/qrkit/internal/micro.gleam", 647).
?DOC(false).
-spec power_of_two(integer()) -> integer().
power_of_two(Index) ->
    case Index =< 0 of
        true ->
            1;

        false ->
            2 * power_of_two(Index - 1)
    end.

-file("src/qrkit/internal/micro.gleam", 643).
?DOC(false).
-spec bit_at(integer(), integer()) -> boolean().
bit_at(Value, Index) ->
    ((case power_of_two(Index) of
        0 -> 0;
        Gleam@denominator -> Value div Gleam@denominator
    end) rem 2) =:= 1.

-file("src/qrkit/internal/micro.gleam", 627).
?DOC(false).
-spec append_byte_bits(integer(), integer(), integer(), list(boolean())) -> list(boolean()).
append_byte_bits(Byte, Bit_position, Remaining, Acc) ->
    case Remaining =< 0 of
        true ->
            Acc;

        false ->
            append_byte_bits(
                Byte,
                Bit_position - 1,
                Remaining - 1,
                [bit_at(Byte, Bit_position) | Acc]
            )
    end.

-file("src/qrkit/internal/micro.gleam", 605).
?DOC(false).
-spec codewords_to_bits(
    list(integer()),
    integer(),
    boolean(),
    integer(),
    list(boolean())
) -> list(boolean()).
codewords_to_bits(Codewords, Data_count, Half_codeword, Index, Acc) ->
    case Codewords of
        [] ->
            lists:reverse(Acc);

        [Byte | Rest] ->
            Bit_count = case Half_codeword andalso ((Index + 1) =:= Data_count) of
                true ->
                    4;

                false ->
                    8
            end,
            Next_acc = append_byte_bits(Byte, 7, Bit_count, Acc),
            codewords_to_bits(
                Rest,
                Data_count,
                Half_codeword,
                Index + 1,
                Next_acc
            )
    end.

-file("src/qrkit/internal/micro.gleam", 695).
?DOC(false).
-spec maybe_take(
    qrkit@internal@matrix:matrix(),
    integer(),
    integer(),
    list({integer(), integer()})
) -> list({integer(), integer()}).
maybe_take(Target, Row, Col, Acc) ->
    case Col < 0 of
        true ->
            Acc;

        false ->
            case qrkit@internal@matrix:is_reserved(Target, Row, Col) of
                true ->
                    Acc;

                false ->
                    [{Row, Col} | Acc]
            end
    end.

-file("src/qrkit/internal/micro.gleam", 679).
?DOC(false).
-spec scan_column_pair(
    qrkit@internal@matrix:matrix(),
    integer(),
    integer(),
    integer(),
    list({integer(), integer()})
) -> {list({integer(), integer()}), integer(), integer()}.
scan_column_pair(Target, Col, Row, Inc, Acc) ->
    With_right = maybe_take(Target, Row, Col, Acc),
    With_both = maybe_take(Target, Row, Col - 1, With_right),
    Next_row = Row + Inc,
    case (Next_row < 0) orelse (Next_row >= qrkit@internal@matrix:height(Target)) of
        true ->
            {With_both, Row, 0 - Inc};

        false ->
            scan_column_pair(Target, Col, Next_row, Inc, With_both)
    end.

-file("src/qrkit/internal/micro.gleam", 662).
?DOC(false).
-spec do_data_positions(
    qrkit@internal@matrix:matrix(),
    integer(),
    integer(),
    integer(),
    list({integer(), integer()})
) -> list({integer(), integer()}).
do_data_positions(Target, Col, Row, Inc, Acc) ->
    case Col =< 0 of
        true ->
            lists:reverse(Acc);

        false ->
            {Next_acc, Last_row, Next_inc} = scan_column_pair(
                Target,
                Col,
                Row,
                Inc,
                Acc
            ),
            do_data_positions(Target, Col - 2, Last_row, Next_inc, Next_acc)
    end.

-file("src/qrkit/internal/micro.gleam", 654).
?DOC(false).
-spec data_positions(qrkit@internal@matrix:matrix(), integer(), integer()) -> list({integer(),
    integer()}).
data_positions(Target, Col, Row) ->
    do_data_positions(Target, Col, Row, -1, []).

-file("src/qrkit/internal/micro.gleam", 711).
?DOC(false).
-spec write_bits(
    qrkit@internal@matrix:matrix(),
    list({integer(), integer()}),
    list(boolean())
) -> qrkit@internal@matrix:matrix().
write_bits(Target, Positions, Bits) ->
    case {Positions, Bits} of
        {[{Row, Col} | Rest_positions], [Bit | Rest_bits]} ->
            write_bits(
                qrkit@internal@matrix:set(Target, Row, Col, Bit, false),
                Rest_positions,
                Rest_bits
            );

        {_, _} ->
            Target
    end.

-file("src/qrkit/internal/micro.gleam", 810).
?DOC(false).
-spec micro_mask_at(integer(), integer(), integer()) -> boolean().
micro_mask_at(Mask, Row, Col) ->
    case Mask of
        0 ->
            (Row rem 2) =:= 0;

        1 ->
            (((Row div 2) + (Col div 3)) rem 2) =:= 0;

        2 ->
            ((((Row * Col) rem 2) + ((Row * Col) rem 3)) rem 2) =:= 0;

        _ ->
            ((((Row + Col) rem 2) + ((Row * Col) rem 3)) rem 2) =:= 0
    end.

-file("src/qrkit/internal/micro.gleam", 784).
?DOC(false).
-spec do_apply_mask(
    qrkit@internal@matrix:matrix(),
    integer(),
    integer(),
    integer()
) -> qrkit@internal@matrix:matrix().
do_apply_mask(Target, Mask, Row, Col) ->
    case Row >= qrkit@internal@matrix:height(Target) of
        true ->
            Target;

        false ->
            case Col >= qrkit@internal@matrix:width(Target) of
                true ->
                    do_apply_mask(Target, Mask, Row + 1, 0);

                false ->
                    case qrkit@internal@matrix:is_reserved(Target, Row, Col) of
                        true ->
                            do_apply_mask(Target, Mask, Row, Col + 1);

                        false ->
                            do_apply_mask(
                                qrkit@internal@matrix:'xor'(
                                    Target,
                                    Row,
                                    Col,
                                    micro_mask_at(Mask, Row, Col)
                                ),
                                Mask,
                                Row,
                                Col + 1
                            )
                    end
            end
    end.

-file("src/qrkit/internal/micro.gleam", 780).
?DOC(false).
-spec apply_mask(qrkit@internal@matrix:matrix(), integer()) -> qrkit@internal@matrix:matrix().
apply_mask(Target, Mask) ->
    do_apply_mask(Target, Mask, 0, 0).

-file("src/qrkit/internal/micro.gleam", 847).
?DOC(false).
-spec do_count_dark_edge(
    qrkit@internal@matrix:matrix(),
    integer(),
    integer(),
    integer(),
    boolean(),
    integer()
) -> integer().
do_count_dark_edge(Target, Axis, Current, To, Vertical, Acc) ->
    case Current > To of
        true ->
            Acc;

        false ->
            Dark = case Vertical of
                true ->
                    qrkit@internal@matrix:get(Target, Current, Axis);

                false ->
                    qrkit@internal@matrix:get(Target, Axis, Current)
            end,
            Next_acc = case Dark of
                true ->
                    Acc + 1;

                false ->
                    Acc
            end,
            do_count_dark_edge(
                Target,
                Axis,
                Current + 1,
                To,
                Vertical,
                Next_acc
            )
    end.

-file("src/qrkit/internal/micro.gleam", 837).
?DOC(false).
-spec count_dark_edge(
    qrkit@internal@matrix:matrix(),
    integer(),
    integer(),
    integer(),
    boolean()
) -> integer().
count_dark_edge(Target, Axis, From, To, Vertical) ->
    do_count_dark_edge(Target, Axis, From, To, Vertical, 0).

-file("src/qrkit/internal/micro.gleam", 822).
?DOC(false).
-spec micro_penalty(qrkit@internal@matrix:matrix(), integer()) -> integer().
micro_penalty(Target, Size) ->
    Last = Size - 1,
    Dark_right = count_dark_edge(Target, Last, 1, Last, true),
    Dark_bottom = count_dark_edge(Target, 1, Last, Last, false),
    High = case Dark_right >= Dark_bottom of
        true ->
            Dark_right;

        false ->
            Dark_bottom
    end,
    Low = case Dark_right >= Dark_bottom of
        true ->
            Dark_bottom;

        false ->
            Dark_right
    end,
    (Low * 16) + High.

-file("src/qrkit/internal/micro.gleam", 882).
?DOC(false).
-spec place_horizontal_format(qrkit@internal@matrix:matrix(), integer()) -> qrkit@internal@matrix:matrix().
place_horizontal_format(Target, Bits) ->
    _pipe = qrkit@internal@util:range(0, 7),
    gleam@list:fold(
        _pipe,
        Target,
        fun(Acc, Index) ->
            Col = Index + 1,
            Dark = bit_at(Bits, 14 - Index),
            qrkit@internal@matrix:set(Acc, 8, Col, Dark, true)
        end
    ).

-file("src/qrkit/internal/micro.gleam", 891).
?DOC(false).
-spec place_vertical_format(qrkit@internal@matrix:matrix(), integer()) -> qrkit@internal@matrix:matrix().
place_vertical_format(Target, Bits) ->
    _pipe = qrkit@internal@util:range(0, 6),
    gleam@list:fold(
        _pipe,
        Target,
        fun(Acc, Index) ->
            Row = 7 - Index,
            Dark = bit_at(Bits, 6 - Index),
            qrkit@internal@matrix:set(Acc, Row, 8, Dark, true)
        end
    ).

-file("src/qrkit/internal/micro.gleam", 929).
?DOC(false).
-spec int_to_str(integer()) -> binary().
int_to_str(Value) ->
    case Value of
        1 ->
            <<"1"/utf8>>;

        2 ->
            <<"2"/utf8>>;

        3 ->
            <<"3"/utf8>>;

        4 ->
            <<"4"/utf8>>;

        _ ->
            <<"?"/utf8>>
    end.

-file("src/qrkit/internal/micro.gleam", 195).
?DOC(false).
-spec data_capacity_bits(integer(), qrkit@types:error_correction()) -> {ok,
        integer()} |
    {error, qrkit@error:encode_error()}.
data_capacity_bits(Version, Ecc) ->
    case {Version, Ecc} of
        {1, low} ->
            {ok, 20};

        {2, low} ->
            {ok, 40};

        {2, medium} ->
            {ok, 32};

        {3, low} ->
            {ok, 84};

        {3, medium} ->
            {ok, 68};

        {4, low} ->
            {ok, 128};

        {4, medium} ->
            {ok, 112};

        {4, quartile} ->
            {ok, 80};

        {_, _} ->
            {error,
                {incompatible_options,
                    <<<<"Micro QR M"/utf8, (int_to_str(Version))/binary>>/binary,
                        " does not support the requested error correction level"/utf8>>}}
    end.

-file("src/qrkit/internal/micro.gleam", 218).
?DOC(false).
-spec ec_codewords(integer(), qrkit@types:error_correction()) -> {ok, integer()} |
    {error, qrkit@error:encode_error()}.
ec_codewords(Version, Ecc) ->
    case {Version, Ecc} of
        {1, low} ->
            {ok, 2};

        {2, low} ->
            {ok, 5};

        {2, medium} ->
            {ok, 6};

        {3, low} ->
            {ok, 6};

        {3, medium} ->
            {ok, 8};

        {4, low} ->
            {ok, 8};

        {4, medium} ->
            {ok, 10};

        {4, quartile} ->
            {ok, 14};

        {_, _} ->
            {error,
                {incompatible_options,
                    <<<<"Micro QR M"/utf8, (int_to_str(Version))/binary>>/binary,
                        " does not support the requested error correction level"/utf8>>}}
    end.

-file("src/qrkit/internal/micro.gleam", 378).
?DOC(false).
-spec char_count_bits_for_mode(qrkit@types:mode(), integer()) -> {ok, integer()} |
    {error, qrkit@error:encode_error()}.
char_count_bits_for_mode(Selected_mode, Version) ->
    case {Version, Selected_mode} of
        {1, numeric} ->
            {ok, 3};

        {2, numeric} ->
            {ok, 4};

        {2, alphanumeric} ->
            {ok, 3};

        {3, numeric} ->
            {ok, 5};

        {3, alphanumeric} ->
            {ok, 4};

        {3, byte} ->
            {ok, 4};

        {3, kanji} ->
            {ok, 3};

        {4, numeric} ->
            {ok, 6};

        {4, alphanumeric} ->
            {ok, 5};

        {4, byte} ->
            {ok, 5};

        {4, kanji} ->
            {ok, 4};

        {_, _} ->
            {error,
                {incompatible_options,
                    <<"Mode is not supported by Micro QR M"/utf8,
                        (int_to_str(Version))/binary>>}}
    end.

-file("src/qrkit/internal/micro.gleam", 333).
?DOC(false).
-spec encoded_bits(binary(), qrkit@types:mode(), integer()) -> {ok, integer()} |
    {error, qrkit@error:encode_error()}.
encoded_bits(Text, Selected_mode, Version) ->
    Mode_bits_count = mode_indicator_bits(Version),
    case mode_supported(Selected_mode, Version) of
        false ->
            {error,
                {incompatible_options,
                    <<"Mode not supported by Micro QR M"/utf8,
                        (int_to_str(Version))/binary>>}};

        true ->
            case char_count_bits_for_mode(Selected_mode, Version) of
                {error, Error} ->
                    {error, Error};

                {ok, Count_bits} ->
                    Data_bits = qrkit@internal@mode:data_bits_length(
                        Text,
                        Selected_mode
                    ),
                    {ok, (Mode_bits_count + Count_bits) + Data_bits}
            end
    end.

-file("src/qrkit/internal/micro.gleam", 146).
?DOC(false).
-spec check_version(
    binary(),
    qrkit@types:mode(),
    qrkit@types:error_correction(),
    integer()
) -> {ok, integer()} | {error, qrkit@error:encode_error()}.
check_version(Text, Selected_mode, Ecc, Candidate) ->
    case mode_supported(Selected_mode, Candidate) of
        false ->
            {error,
                {incompatible_options,
                    <<<<<<<<"Micro QR M"/utf8, (int_to_str(Candidate))/binary>>/binary,
                                " does not support the "/utf8>>/binary,
                            (mode_name(Selected_mode))/binary>>/binary,
                        " mode"/utf8>>}};

        true ->
            case data_capacity_bits(Candidate, Ecc) of
                {error, Error} ->
                    {error, Error};

                {ok, Capacity} ->
                    case encoded_bits(Text, Selected_mode, Candidate) of
                        {error, Error@1} ->
                            {error, Error@1};

                        {ok, Required} ->
                            case Required =< Capacity of
                                true ->
                                    {ok, Candidate};

                                false ->
                                    {error,
                                        {data_exceeds_capacity,
                                            Required,
                                            Capacity}}
                            end
                    end
            end
    end.

-file("src/qrkit/internal/micro.gleam", 490).
?DOC(false).
-spec data_codewords(integer(), qrkit@types:error_correction()) -> {ok,
        integer()} |
    {error, qrkit@error:encode_error()}.
data_codewords(Version, Ecc) ->
    case data_capacity_bits(Version, Ecc) of
        {ok, Bits} ->
            {ok, (Bits + 7) div 8};

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

-file("src/qrkit/internal/micro.gleam", 452).
?DOC(false).
-spec pad_to_capacity(
    qrkit@internal@bitstream:bit_stream(),
    integer(),
    qrkit@types:error_correction()
) -> qrkit@internal@bitstream:bit_stream().
pad_to_capacity(Stream, Version, Ecc) ->
    Aligned = qrkit@internal@bitstream:pad_to_byte_boundary(Stream),
    Data_bytes_count = case data_codewords(Version, Ecc) of
        {ok, Value} ->
            Value;

        {error, _} ->
            0
    end,
    pad_alternating(Aligned, Data_bytes_count, 0).

-file("src/qrkit/internal/micro.gleam", 500).
?DOC(false).
-spec compute_ec(list(integer()), integer(), qrkit@types:error_correction()) -> {ok,
        list(integer())} |
    {error, qrkit@error:encode_error()}.
compute_ec(Data, Version, Ecc) ->
    case ec_codewords(Version, Ecc) of
        {ok, Degree} ->
            {ok, qrkit@internal@reed_solomon:encode(Data, Degree)};

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

-file("src/qrkit/internal/micro.gleam", 588).
?DOC(false).
-spec place_codewords(
    qrkit@internal@matrix:matrix(),
    list(integer()),
    integer(),
    qrkit@types:error_correction()
) -> qrkit@internal@matrix:matrix().
place_codewords(Target, Codewords, Version, Ecc) ->
    Half = has_half_codeword(Version, Ecc),
    Data_count = case data_codewords(Version, Ecc) of
        {ok, Value} ->
            Value;

        {error, _} ->
            0
    end,
    Bits = codewords_to_bits(Codewords, Data_count, Half, 0, []),
    Positions = data_positions(
        Target,
        qrkit@internal@matrix:width(Target) - 1,
        qrkit@internal@matrix:height(Target) - 1
    ),
    write_bits(Target, Positions, Bits).

-file("src/qrkit/internal/micro.gleam", 910).
?DOC(false).
-spec symbol_number(integer(), qrkit@types:error_correction()) -> {ok,
        integer()} |
    {error, qrkit@error:encode_error()}.
symbol_number(Version, Ecc) ->
    case {Version, Ecc} of
        {1, low} ->
            {ok, 0};

        {2, low} ->
            {ok, 1};

        {2, medium} ->
            {ok, 2};

        {3, low} ->
            {ok, 3};

        {3, medium} ->
            {ok, 4};

        {4, low} ->
            {ok, 5};

        {4, medium} ->
            {ok, 6};

        {4, quartile} ->
            {ok, 7};

        {_, _} ->
            {error,
                {incompatible_options,
                    <<<<"Micro QR M"/utf8, (int_to_str(Version))/binary>>/binary,
                        " does not support the requested error correction level"/utf8>>}}
    end.

-file("src/qrkit/internal/micro.gleam", 939).
?DOC(false).
-spec result_try(
    {ok, DZL} | {error, qrkit@error:encode_error()},
    fun((DZL) -> {ok, DZO} | {error, qrkit@error:encode_error()})
) -> {ok, DZO} | {error, qrkit@error:encode_error()}.
result_try(Result, Callback) ->
    case Result of
        {ok, Value} ->
            Callback(Value);

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

-file("src/qrkit/internal/micro.gleam", 401).
?DOC(false).
-spec create_codewords(
    binary(),
    qrkit@types:mode(),
    qrkit@types:error_correction(),
    integer()
) -> {ok, list(integer())} | {error, qrkit@error:encode_error()}.
create_codewords(Text, Selected_mode, Ecc, Version) ->
    result_try(
        data_capacity_bits(Version, Ecc),
        fun(Capacity) ->
            result_try(
                char_count_bits_for_mode(Selected_mode, Version),
                fun(Count_bits) ->
                    Count_value = qrkit@internal@mode:character_count(
                        Text,
                        Selected_mode
                    ),
                    result_try(
                        qrkit@internal@mode:encode(Text, Selected_mode, 0),
                        fun(Payload) ->
                            Stream = begin
                                _pipe = qrkit@internal@bitstream:new(),
                                _pipe@1 = append_mode_indicator(
                                    _pipe,
                                    Selected_mode,
                                    Version
                                ),
                                _pipe@2 = qrkit@internal@bitstream:append_bits(
                                    _pipe@1,
                                    Count_value,
                                    Count_bits
                                ),
                                qrkit@internal@bitstream:append_bytes(
                                    _pipe@2,
                                    Payload
                                )
                            end,
                            Total_bits = qrkit@internal@bitstream:length_bits(
                                Stream
                            ),
                            case Total_bits > Capacity of
                                true ->
                                    {error,
                                        {data_exceeds_capacity,
                                            Total_bits,
                                            Capacity}};

                                false ->
                                    Terminator_bits = terminator_size(
                                        Version,
                                        Capacity - Total_bits
                                    ),
                                    With_terminator = qrkit@internal@bitstream:append_bits(
                                        Stream,
                                        0,
                                        Terminator_bits
                                    ),
                                    Padded = pad_to_capacity(
                                        With_terminator,
                                        Version,
                                        Ecc
                                    ),
                                    result_try(
                                        {ok,
                                            qrkit@internal@bitstream:to_byte_list(
                                                Padded
                                            )},
                                        fun(Data_bytes) ->
                                            result_try(
                                                compute_ec(
                                                    Data_bytes,
                                                    Version,
                                                    Ecc
                                                ),
                                                fun(Ec_bytes) ->
                                                    {ok,
                                                        lists:append(
                                                            Data_bytes,
                                                            Ec_bytes
                                                        )}
                                                end
                                            )
                                        end
                                    )
                            end
                        end
                    )
                end
            )
        end
    ).

-file("src/qrkit/internal/micro.gleam", 549).
?DOC(false).
-spec draw_finder_module(qrkit@internal@matrix:matrix(), integer(), integer()) -> qrkit@internal@matrix:matrix().
draw_finder_module(Target, Row, Col) ->
    Dark = case (Row =:= 7) orelse (Col =:= 7) of
        true ->
            false;

        false ->
            ((((Row =:= 0) orelse (Row =:= (7 - 1))) orelse (Col =:= 0)) orelse (Col
            =:= (7 - 1)))
            orelse ((((Row >= 2) andalso (Row =< 4)) andalso (Col >= 2)) andalso (Col
            =< 4))
    end,
    qrkit@internal@matrix:set(Target, Row, Col, Dark, true).

-file("src/qrkit/internal/micro.gleam", 541).
?DOC(false).
-spec draw_finder(qrkit@internal@matrix:matrix(), integer()) -> qrkit@internal@matrix:matrix().
draw_finder(Target, _) ->
    _pipe = qrkit@internal@util:range(0, 7),
    gleam@list:fold(
        _pipe,
        Target,
        fun(Acc, Row) -> _pipe@1 = qrkit@internal@util:range(0, 7),
            gleam@list:fold(
                _pipe@1,
                Acc,
                fun(Acc2, Col) -> draw_finder_module(Acc2, Row, Col) end
            ) end
    ).

-file("src/qrkit/internal/micro.gleam", 566).
?DOC(false).
-spec draw_timing(qrkit@internal@matrix:matrix(), integer()) -> qrkit@internal@matrix:matrix().
draw_timing(Target, Size) ->
    _pipe = qrkit@internal@util:range(7 + 1, Size - 1),
    gleam@list:fold(
        _pipe,
        Target,
        fun(Acc, Index) ->
            Dark = (Index rem 2) =:= 0,
            _pipe@1 = Acc,
            _pipe@2 = qrkit@internal@matrix:set(_pipe@1, 0, Index, Dark, true),
            qrkit@internal@matrix:set(_pipe@2, Index, 0, Dark, true)
        end
    ).

-file("src/qrkit/internal/micro.gleam", 187).
?DOC(false).
-spec symbol_size(integer()) -> {ok, integer()} |
    {error, qrkit@error:encode_error()}.
symbol_size(Version) ->
    case (Version >= 1) andalso (Version =< 4) of
        true ->
            {ok, (Version * 2) + 9};

        false ->
            {error, {invalid_version, Version}}
    end.

-file("src/qrkit/internal/micro.gleam", 240).
?DOC(false).
-spec validate_version(integer()) -> {ok, nil} |
    {error, qrkit@error:encode_error()}.
validate_version(Version) ->
    case (Version >= 1) andalso (Version =< 4) of
        true ->
            {ok, nil};

        false ->
            {error, {invalid_version, Version}}
    end.

-file("src/qrkit/internal/micro.gleam", 114).
?DOC(false).
-spec validate_requested(gleam@option:option(integer())) -> {ok, nil} |
    {error, qrkit@error:encode_error()}.
validate_requested(Requested_version) ->
    case Requested_version of
        none ->
            {ok, nil};

        {some, Value} ->
            validate_version(Value)
    end.

-file("src/qrkit/internal/micro.gleam", 302).
?DOC(false).
-spec do_find_version(
    binary(),
    qrkit@types:mode(),
    qrkit@types:error_correction(),
    integer()
) -> {ok, integer()} | {error, qrkit@error:encode_error()}.
do_find_version(Text, Selected_mode, Ecc, Candidate) ->
    case Candidate > 4 of
        true ->
            {error, {data_exceeds_capacity, 0, 0}};

        false ->
            case mode_supported(Selected_mode, Candidate) of
                false ->
                    do_find_version(Text, Selected_mode, Ecc, Candidate + 1);

                true ->
                    case data_capacity_bits(Candidate, Ecc) of
                        {error, _} ->
                            do_find_version(
                                Text,
                                Selected_mode,
                                Ecc,
                                Candidate + 1
                            );

                        {ok, Capacity} ->
                            case encoded_bits(Text, Selected_mode, Candidate) of
                                {error, _} ->
                                    do_find_version(
                                        Text,
                                        Selected_mode,
                                        Ecc,
                                        Candidate + 1
                                    );

                                {ok, Required} ->
                                    case Required =< Capacity of
                                        true ->
                                            {ok, Candidate};

                                        false ->
                                            do_find_version(
                                                Text,
                                                Selected_mode,
                                                Ecc,
                                                Candidate + 1
                                            )
                                    end
                            end
                    end
            end
    end.

-file("src/qrkit/internal/micro.gleam", 131).
?DOC(false).
-spec resolve_version(
    binary(),
    qrkit@types:mode(),
    qrkit@types:error_correction(),
    gleam@option:option(integer())
) -> {ok, integer()} | {error, qrkit@error:encode_error()}.
resolve_version(Text, Selected_mode, Ecc, Requested_version) ->
    case Requested_version of
        none ->
            do_find_version(Text, Selected_mode, Ecc, 1);

        {some, N} ->
            check_version(Text, Selected_mode, Ecc, N)
    end.

-file("src/qrkit/internal/micro.gleam", 900).
?DOC(false).
-spec format_bits(integer(), qrkit@types:error_correction(), integer()) -> integer().
format_bits(Version, Ecc, Mask) ->
    case symbol_number(Version, Ecc) of
        {ok, Number} ->
            Index = (Number * 4) + Mask,
            qrkit@internal@util:at_or(
                [16#4445,
                    16#4172,
                    16#4E2B,
                    16#4B1C,
                    16#55AE,
                    16#5099,
                    16#5FC0,
                    16#5AF7,
                    16#6793,
                    16#62A4,
                    16#6DFD,
                    16#68CA,
                    16#7678,
                    16#734F,
                    16#7C16,
                    16#7921,
                    16#06DE,
                    16#03E9,
                    16#0CB0,
                    16#0987,
                    16#1735,
                    16#1202,
                    16#1D5B,
                    16#186C,
                    16#2508,
                    16#203F,
                    16#2F66,
                    16#2A51,
                    16#34E3,
                    16#31D4,
                    16#3E8D,
                    16#3BBA],
                Index,
                16#4445
            );

        {error, _} ->
            16#4445
    end.

-file("src/qrkit/internal/micro.gleam", 871).
?DOC(false).
-spec place_format_info(
    qrkit@internal@matrix:matrix(),
    integer(),
    qrkit@types:error_correction(),
    integer()
) -> qrkit@internal@matrix:matrix().
place_format_info(Target, Version, Ecc, Mask) ->
    Bits = format_bits(Version, Ecc, Mask),
    Horizontal = place_horizontal_format(Target, Bits),
    place_vertical_format(Horizontal, Bits).

-file("src/qrkit/internal/micro.gleam", 736).
?DOC(false).
-spec do_choose_mask(
    qrkit@internal@matrix:matrix(),
    integer(),
    qrkit@types:error_correction(),
    integer(),
    integer(),
    integer(),
    qrkit@internal@matrix:matrix(),
    integer()
) -> {integer(), qrkit@internal@matrix:matrix()}.
do_choose_mask(
    Target,
    Version,
    Ecc,
    Size,
    Candidate,
    Best_mask,
    Best_matrix,
    Best_score
) ->
    case Candidate > 3 of
        true ->
            {Best_mask, Best_matrix};

        false ->
            With_data = apply_mask(Target, Candidate),
            Placed = place_format_info(With_data, Version, Ecc, Candidate),
            Score = micro_penalty(Placed, Size),
            case (Best_score < 0) orelse (Score > Best_score) of
                true ->
                    do_choose_mask(
                        Target,
                        Version,
                        Ecc,
                        Size,
                        Candidate + 1,
                        Candidate,
                        Placed,
                        Score
                    );

                false ->
                    do_choose_mask(
                        Target,
                        Version,
                        Ecc,
                        Size,
                        Candidate + 1,
                        Best_mask,
                        Best_matrix,
                        Best_score
                    )
            end
    end.

-file("src/qrkit/internal/micro.gleam", 727).
?DOC(false).
-spec choose_best_mask(
    qrkit@internal@matrix:matrix(),
    integer(),
    qrkit@types:error_correction(),
    integer()
) -> {integer(), qrkit@internal@matrix:matrix()}.
choose_best_mask(Target, Version, Ecc, Size) ->
    do_choose_mask(Target, Version, Ecc, Size, 0, 0, Target, -1).

-file("src/qrkit/internal/micro.gleam", 520).
?DOC(false).
-spec build_matrix(integer(), qrkit@types:error_correction(), list(integer())) -> {ok,
        {integer(), qrkit@internal@matrix:matrix()}} |
    {error, qrkit@error:encode_error()}.
build_matrix(Chosen_version, Ecc, Codewords) ->
    case symbol_size(Chosen_version) of
        {error, Error} ->
            {error, Error};

        {ok, Size} ->
            Base = begin
                _pipe = qrkit@internal@matrix:new(Size, Size),
                _pipe@1 = draw_finder(_pipe, Size),
                _pipe@2 = draw_timing(_pipe@1, Size),
                reserve_format_info(_pipe@2, Size)
            end,
            With_data = place_codewords(Base, Codewords, Chosen_version, Ecc),
            {Best_mask, Masked} = choose_best_mask(
                With_data,
                Chosen_version,
                Ecc,
                Size
            ),
            {ok,
                {Best_mask,
                    place_format_info(Masked, Chosen_version, Ecc, Best_mask)}}
    end.

-file("src/qrkit/internal/micro.gleam", 80).
?DOC(false).
-spec encode(
    binary(),
    qrkit@types:error_correction(),
    gleam@option:option(integer()),
    qrkit@types:mode_preference()
) -> {ok, encoded()} | {error, qrkit@error:encode_error()}.
encode(Text, Ecc, Requested_version, Preference) ->
    result_try(
        validate_requested(Requested_version),
        fun(_) ->
            result_try(
                validate_ecc(Ecc),
                fun(_) ->
                    result_try(
                        select_mode(Text, Preference),
                        fun(Selected_mode) ->
                            result_try(
                                resolve_version(
                                    Text,
                                    Selected_mode,
                                    Ecc,
                                    Requested_version
                                ),
                                fun(Chosen_version) ->
                                    result_try(
                                        create_codewords(
                                            Text,
                                            Selected_mode,
                                            Ecc,
                                            Chosen_version
                                        ),
                                        fun(Codewords) ->
                                            case build_matrix(
                                                Chosen_version,
                                                Ecc,
                                                Codewords
                                            ) of
                                                {ok, {Best_mask, Final_matrix}} ->
                                                    {ok,
                                                        {encoded,
                                                            Chosen_version,
                                                            qrkit@internal@matrix:width(
                                                                Final_matrix
                                                            ),
                                                            qrkit@internal@matrix:height(
                                                                Final_matrix
                                                            ),
                                                            Best_mask,
                                                            qrkit@internal@matrix:rows(
                                                                Final_matrix
                                                            )}};

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