# frozen_string_literal: true

# (c) 2017 Ribose Inc.

require 'ffi'

require 'botan/error'
require 'botan/ffi/libbotan'
require 'botan/utils'

module Botan
  # Message Authentication Code
  #
  # == Examples
  # === examples/mac.rb
  # {include:file:examples/mac.rb}
  class MAC
    # @param algo [String] the MAC algorithm name
    def initialize(algo)
      flags = 0
      ptr = FFI::MemoryPointer.new(:pointer)
      Botan.call_ffi(:botan_mac_init, ptr, algo, flags)
      ptr = ptr.read_pointer
      raise Botan::Error, 'botan_mac_init returned NULL' if ptr.null?
      @ptr = FFI::AutoPointer.new(ptr, self.class.method(:destroy))
    end

    # @api private
    def self.destroy(ptr)
      LibBotan.botan_mac_destroy(ptr)
    end

    # Resets the instace back to a clean state, as if no key and
    # input have been supplied.
    #
    # @return [self]
    def reset
      Botan.call_ffi(:botan_mac_clear, @ptr)
      self
    end

    # Retrieve the output length of the MAC.
    #
    # @return [Integer]
    def output_length
      length_ptr = FFI::MemoryPointer.new(:size_t)
      Botan.call_ffi(:botan_mac_output_length, @ptr, length_ptr)
      length_ptr.read(:size_t)
    end

    # Sets the key for the MAC.
    # This must be called before {#update}.
    #
    # @param [String] key
    def key=(key)
      Botan.call_ffi(:botan_mac_set_key, @ptr, key, key.bytesize)
    end

    # Adds input to the MAC computation.
    #
    # @param [String] data
    # @return [self]
    def update(data)
      Botan.call_ffi(:botan_mac_update, @ptr, data, data.bytesize)
      self
    end

    def digest
      out_buf = FFI::MemoryPointer.new(:uint8, output_length)
      Botan.call_ffi(:botan_mac_final, @ptr, out_buf)
      out_buf.read_bytes(out_buf.size)
    end

    def hexdigest
      Botan.hex_encode(digest)
    end

    def inspect
      Botan.inspect_ptr(self)
    end

    alias << update

    # TODO: it's not safe to do this at the moment, since these
    # methods mutate the state.
    # alias inspect hexdigest
    # alias to_s hexdigest
  end # class
end # module