--
-- This file is part of TALER
-- Copyright (C) 2026 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
-- Foundation; either version 3, or (at your option) any later version.
--
-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with
-- TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
--

DROP FUNCTION IF EXISTS base32_crockford;
CREATE FUNCTION base32_crockford(data BYTEA)
RETURNS TEXT
LANGUAGE plpgsql
IMMUTABLE
STRICT
PARALLEL SAFE
AS $$
DECLARE
    alphabet TEXT := '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
    chars     TEXT[]  := '{}';
    bit_buf   BIGINT  := 0;   -- sliding window of accumulated bits
    bit_count INT     := 0;   -- how many valid bits are in bit_buf
    b         INT;
    i         INT;
BEGIN
    IF length(data) = 0 THEN
        RETURN '';
    END IF;

    -- Process each byte, emitting 5-bit groups as we go
    FOR i IN 0 .. length(data) - 1
    LOOP
        b := get_byte(data, i);
        bit_buf   := (bit_buf << 8) | b;
        bit_count := bit_count + 8;

        WHILE bit_count >= 5
        LOOP
            bit_count := bit_count - 5;
            chars := array_append(
                chars,
                substr(alphabet, ((bit_buf >> bit_count) & 31)::INT + 1, 1)
            );
        END LOOP;
    END LOOP;

    -- Flush any remaining bits (zero-padded to 5)
    IF bit_count > 0
    THEN
        chars := array_append(
            chars,
            substr(alphabet, ((bit_buf << (5 - bit_count)) & 31)::INT + 1, 1)
        );
    END IF;
    RETURN array_to_string(chars, '');
END;
$$;
COMMENT ON FUNCTION base32_crockford(BYTEA)
  IS 'Encodes binary data using Crockford Base32';
