#### Benben
#### Copyright (C) 2023-2024 Remilia Scarlet <remilia@posteo.jp>
####
#### This program is free software: you can redistribute it and/or
#### modify it under the terms of the GNU Affero General Public
#### License as published by the Free Software Foundation, either
#### version 3 of the License, or (at your option) any later version.
####
#### This program 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
#### Affero General Public License for more details.
####
#### You should have received a copy of the GNU Affero General Public License
#### along with this program.  If not, see <https://www.gnu.org/licenses/>.

####
#### Simple wrapper for module files.
####

module Benben
  # A simple wrapper for module files.  This stores raw module data in RAM by
  # reading it from a file.  The file can optionally be compressed with Gzip,
  # Bzip2, or ZStandard.
  class ModuleFile
    @data : Bytes = Bytes.new(0)
    @filename : Path|String

    def initialize(@filename : Path|String)
    end

    def data : Bytes
      return @data if @data.size > 0
      Benben.dlog!("Loading data for module file: #{@filename}")

      io = IO::Memory.new
      magic = Bytes.new(4)

      File.open(@filename, "rb") do |file|
        file.read(magic)
        file.rewind

        case
        when magic[0] == 0x1F && magic[1] == 0x8B
          Compress::Gzip::Reader.open(file) do |comp|
            Benben.dlog!("Loading gzip-compressed raw module file data into RAM: #{@filename}")
            IO.copy(comp, io)
          end

        when magic[0] == 'B'.ord &&
             magic[1] == 'Z'.ord &&
             magic[2] == 'h'.ord &&
             (magic[3] >= '1'.ord && magic[3] <= '9'.ord)
          RemiLib::Compression::BZip2::Reader.open(file) do |bz|
            Benben.dlog!("Loading bzip2-compressed raw module file data into RAM: #{@filename}")
            IO.copy(bz, io)
          end

        when magic[0] == 0x28 &&
             magic[1] == 0xB5 &&
             magic[2] == 0x2f &&
             magic[3] == 0xFD
          Zstd::Decompress::IO.open(file) do |zstd|
            Benben.dlog!("Loading zstandard-compressed raw module file data into RAM: #{@filename}")
            IO.copy(zstd, io)
          end

        else
          Benben.dlog!("Loading raw module file data into RAM: #{@filename}")
          IO.copy(file, io)
        end
      end
      @data = io.to_slice
    end

    def unload : Nil
      @data = Bytes.new(0) unless @data.empty?
    end
  end
end
