// Сжатие данных: энтропия и RLE
// Компиляция: zig build-exe compress_demo.zig && ./compress_demo

const std = @import("std");

pub fn main() !void {
    const stdout = std.fs.File.stdout().deprecatedWriter();

    try stdout.print("=== Zig: сжатие данных ===\n\n", .{});

    // 1. Энтропия Шеннона
    try stdout.print("--- 1. Энтропия Шеннона ---\n", .{});
    const texts = [_]struct { data: []const u8, label: []const u8 }{
        .{ .data = "aaaaaaaaaa", .label = "aaa...a" },
        .{ .data = "abcdefghij", .label = "abcdefghij" },
        .{ .data = "hello world", .label = "hello world" },
        .{ .data = "aababcabcd", .label = "aababcabcd" },
    };
    for (texts) |t| {
        const h = shannonEntropy(t.data);
        try stdout.print("  {s:<14} H = {d:.3} бит/символ\n", .{ t.label, h });
    }
    try stdout.print("\n", .{});

    // 2. RLE
    try stdout.print("--- 2. RLE (Run-Length Encoding) ---\n", .{});
    const data = "AAABBBCCDDDDDDEEEF";
    try stdout.print("  Вход: \"{s}\" ({d} байт)\n", .{ data, data.len });

    // Подсчитаем размер RLE
    var rle_len: usize = 0;
    var i: usize = 0;
    while (i < data.len) {
        var count: usize = 1;
        while (i + count < data.len and data[i + count] == data[i]) {
            count += 1;
        }
        rle_len += 2;
        i += count;
    }
    const ratio = @as(f64, @floatFromInt(rle_len)) / @as(f64, @floatFromInt(data.len)) * 100.0;
    try stdout.print("  RLE: {d} байт ({d:.1}%)\n", .{ rle_len, ratio });
    try stdout.print("  RLE эффективен только при длинных повторах.\n\n", .{});

    // 3. Частотный анализ
    try stdout.print("--- 3. Частотный анализ ---\n", .{});
    const text = "abracadabra";
    var freq: [256]u32 = .{0} ** 256;
    for (text) |c| {
        freq[c] += 1;
    }
    try stdout.print("  \"{s}\":\n", .{text});
    for (freq, 0..) |f, ch| {
        if (f > 0) {
            const pct = @as(f64, @floatFromInt(f)) / @as(f64, @floatFromInt(text.len)) * 100.0;
            try stdout.print("    '{c}': {d} ({d:.0}%)\n", .{
                @as(u8, @intCast(ch)),
                f,
                pct,
            });
        }
    }
    try stdout.print("  Хаффман: частым — короткие коды, редким — длинные.\n\n", .{});

    // 4. Алгоритмы
    try stdout.print("--- 4. Алгоритмы сжатия ---\n", .{});
    try stdout.print("  Huffman (1952): оптимальное префиксное кодирование\n", .{});
    try stdout.print("  LZ77 (1977):    скользящее окно, ссылки на повторы\n", .{});
    try stdout.print("  DEFLATE:        LZ77 + Huffman (gzip, ZIP, PNG)\n", .{});
    try stdout.print("  zstd (2016):    3-5x быстрее gzip при лучшем сжатии\n", .{});
    try stdout.print("  LZ4 (2011):     декомпрессия ~4 ГБ/с\n\n", .{});

    // 5. Zig и сжатие
    try stdout.print("--- 5. Zig stdlib ---\n", .{});
    try stdout.print("  std.compress: deflate, gzip, zlib, xz, zstd (декодирование)\n", .{});
    try stdout.print("  Для кодирования: C-биндинги через @cImport.\n", .{});
    try stdout.print("  Минимализм: std покрывает чтение, не запись.\n\n", .{});

    try stdout.print("--- Итог ---\n", .{});
    try stdout.print("Энтропия — нижняя граница сжатия (Шеннон, 1948)\n", .{});
    try stdout.print("DEFLATE = LZ77 + Huffman (основа gzip и ZIP)\n", .{});
    try stdout.print("zstd: замена gzip — быстрее и лучше\n", .{});
    try stdout.print("Универсального компрессора не существует (Колмогоров)\n", .{});
}

fn shannonEntropy(data: []const u8) f64 {
    var freq: [256]u32 = .{0} ** 256;
    for (data) |b| {
        freq[b] += 1;
    }
    const n: f64 = @floatFromInt(data.len);
    var h: f64 = 0.0;
    for (freq) |f| {
        if (f > 0) {
            const p: f64 = @as(f64, @floatFromInt(f)) / n;
            h -= p * std.math.log2(p);
        }
    }
    return h;
}
