// gzip compression helpers built on moonbitlang/core/compress/gzip.
//
// Payloads are compressed individually so that a package can mix compressed
// and stored entries (text compresses well, already-compressed binaries do
// not).

///|
/// The compression level that the entries use.
///
/// Level 1 is the fastest setting of the deflate encoder, and it is also the
/// one that produces the smallest packages here: measured on an application
/// of 392 files it compresses faster, decompresses faster and yields a
/// package that is about a quarter smaller than the stream implementation
/// did.
pub const GZIP_LEVEL : Int32 = 1

///|
/// Compress `data` with gzip.
pub fn gzip_compress(data : Bytes) -> Bytes {
  @gzip.compress(data, strategy=@flate.Strategy::Standard(level=GZIP_LEVEL))
}

///|
/// Decompress gzip-compressed `data`.
///
/// A stream that cannot be decompressed is returned as it is, so that the
/// checksum of the entry reports the damage instead of the program stopping
/// with an error.
pub fn gzip_decompress(data : Bytes) -> Bytes {
  @gzip.decompress(data) catch {
    _ => data
  }
}

///|
/// Compress `data` with the method that `method` names.
///
/// The codec is one of "none", "gzip", "lz4" or "auto". "auto" keeps the
/// raw bytes when the compression would make the entry bigger, which is what
/// happens with the small files that do not compress at all.
///
/// Returns the payload to store plus the codec name to record in the
/// manifest.
pub fn compress_with(data : Bytes, codec_name : String) -> (Bytes, String) {
  if codec_name == "lz4" {
    (lz4_compress_frame(data), "lz4")
  } else if codec_name == "gzip" {
    (gzip_compress(data), "gzip")
  } else if codec_name == "none" {
    (data, "raw")
  } else {
    let gz = gzip_compress(data)
    if gz.length() < data.length() {
      (gz, "gzip")
    } else {
      (data, "raw")
    }
  }
}