---
-- Decode a Varicode encoded bit stream into bytes.
--
-- @category Protocol
-- @block VaricodeDecoderBlock
--
-- @signature in:Bit > out:Byte
--
-- @usage
-- local decoder = radio.VaricodeDecoderBlock()

local block = require('radio.core.block')
local types = require('radio.types')

local VaricodeDecoderBlock = block.factory("VaricodeDecoderBlock")

function VaricodeDecoderBlock:instantiate()
    self:add_type_signature({block.Input("in", types.Bit)}, {block.Output("out", types.Byte)})
end

function VaricodeDecoderBlock:initialize()
    self.state = types.Bit.vector()
    self.out = types.Byte.vector()
end

local varicode_table = {
    [0x2ab] = 0x00, [0x2db] = 0x01, [0x2ed] = 0x02, [0x377] = 0x03,
    [0x2eb] = 0x04, [0x35f] = 0x05, [0x2ef] = 0x06, [0x2fd] = 0x07,
    [0x2ff] = 0x08, [0x0ef] = 0x09, [0x01d] = 0x0A, [0x36f] = 0x0B,
    [0x2dd] = 0x0C, [0x01f] = 0x0D, [0x375] = 0x0E, [0x3ab] = 0x0F,
    [0x2f7] = 0x10, [0x2f5] = 0x11, [0x3ad] = 0x12, [0x3af] = 0x13,
    [0x35b] = 0x14, [0x36b] = 0x15, [0x36d] = 0x16, [0x357] = 0x17,
    [0x37b] = 0x18, [0x37d] = 0x19, [0x3b7] = 0x1A, [0x355] = 0x1B,
    [0x35d] = 0x1C, [0x3bb] = 0x1D, [0x2fb] = 0x1E, [0x37f] = 0x1F,
    [0x3b5] = 0x7F, [0x001] = 0x20, [0x1ff] = 0x21, [0x15f] = 0x22,
    [0x1f5] = 0x23, [0x1db] = 0x24, [0x2d5] = 0x25, [0x2bb] = 0x26,
    [0x17f] = 0x27, [0x0fb] = 0x28, [0x0f7] = 0x29, [0x16f] = 0x2A,
    [0x1df] = 0x2B, [0x075] = 0x2C, [0x035] = 0x2D, [0x057] = 0x2E,
    [0x1af] = 0x2F, [0x0b7] = 0x30, [0x0bd] = 0x31, [0x0ed] = 0x32,
    [0x0ff] = 0x33, [0x177] = 0x34, [0x15b] = 0x35, [0x16b] = 0x36,
    [0x1ad] = 0x37, [0x1ab] = 0x38, [0x1b7] = 0x39, [0x0f5] = 0x3A,
    [0x1bd] = 0x3B, [0x1ed] = 0x3C, [0x055] = 0x3D, [0x1d7] = 0x3E,
    [0x2af] = 0x3F, [0x2bd] = 0x40, [0x07d] = 0x41, [0x0eb] = 0x42,
    [0x0ad] = 0x43, [0x0b5] = 0x44, [0x077] = 0x45, [0x0db] = 0x46,
    [0x0fd] = 0x47, [0x155] = 0x48, [0x07f] = 0x49, [0x1fd] = 0x4A,
    [0x17d] = 0x4B, [0x0d7] = 0x4C, [0x0bb] = 0x4D, [0x0dd] = 0x4E,
    [0x0ab] = 0x4F, [0x0d5] = 0x50, [0x1dd] = 0x51, [0x0af] = 0x52,
    [0x06f] = 0x53, [0x06d] = 0x54, [0x157] = 0x55, [0x1b5] = 0x56,
    [0x15d] = 0x57, [0x175] = 0x58, [0x17b] = 0x59, [0x2ad] = 0x5A,
    [0x1f7] = 0x5B, [0x1ef] = 0x5C, [0x1fb] = 0x5D, [0x2bf] = 0x5E,
    [0x16d] = 0x5F, [0x2df] = 0x60, [0x00b] = 0x61, [0x05f] = 0x62,
    [0x02f] = 0x63, [0x02d] = 0x64, [0x003] = 0x65, [0x03d] = 0x66,
    [0x05b] = 0x67, [0x02b] = 0x68, [0x00d] = 0x69, [0x1eb] = 0x6A,
    [0x0bf] = 0x6B, [0x01b] = 0x6C, [0x03b] = 0x6D, [0x00f] = 0x6E,
    [0x007] = 0x6F, [0x03f] = 0x70, [0x1bf] = 0x71, [0x015] = 0x72,
    [0x017] = 0x73, [0x005] = 0x74, [0x037] = 0x75, [0x07b] = 0x76,
    [0x06b] = 0x77, [0x0df] = 0x78, [0x05d] = 0x79, [0x1d5] = 0x7A,
    [0x2b7] = 0x7B, [0x1bb] = 0x7C, [0x2b5] = 0x7D, [0x2d7] = 0x7E,
}

function VaricodeDecoderBlock:process(x)
    local out = self.out:resize(0)

    for i = 0, x.length-1 do
        self.state:append(x.data[i])

        if self.state.length >= 2 then
            -- If we hit the 00 delimeter
            if self.state.data[self.state.length-2].value == 0 and self.state.data[self.state.length-1].value == 0 then
                -- Decode the character
                local offset = (self.state.data[0].value == 1) and 0 or 1
                local char = varicode_table[types.Bit.tonumber(self.state, offset, self.state.length-offset-2)]
                if char then
                    self.out:append(types.Byte(char))
                end

                -- Reset the state
                self.state:resize(0)
            elseif self.state.length > 10 then
                -- If state got too long, reset it
                self.state:resize(0)
            end
        end
    end

    return out
end

return VaricodeDecoderBlock
