const std = @import("std");
const Self = @This();

fh: std.fs.File,
dat: []u8,
buf: []u8,
perc: u8 = 0,

pub fn init(self: *Self, alloc: std.mem.Allocator) !void {
    self.fh = try std.fs.openFileAbsolute("/proc/meminfo", .{ .mode = .read_only });
    errdefer self.fh.close();

    self.dat = try alloc.alloc(u8, 256);
    errdefer alloc.free(self.dat);

    self.buf = try alloc.alloc(u8, 256);
    errdefer alloc.free(self.buf);
}

pub fn update(self: *Self) ![]const u8 {
    try self.fh.seekTo(0);
    var br = std.io.bufferedReader(self.fh.reader());
    const reader = br.reader();

    var total: u32 = undefined;
    var free: u32 = undefined;
    var avail: u32 = undefined;

    for (0..3) |_| {
        const line = try reader.readUntilDelimiterOrEof(self.dat, '\n');
        var tokens = std.mem.tokenizeAny(u8, line.?, ": ");

        const label = tokens.next().?;
        const value = try std.fmt.parseInt(u32, tokens.next().?, 10);

        if (std.mem.eql(u8, label, "MemTotal")) {
            total = value;
        } else if (std.mem.eql(u8, label, "MemFree")) {
            free = value;
        } else if (std.mem.eql(u8, label, "MemAvailable")) {
            avail = value;
        }
    }

    const perc_used: u8 = @intCast(@divFloor(1 + 2 * 100 * (total - avail), 2 * total));

    return try std.fmt.bufPrint(
        self.buf,
        "mem: {d: >2}%",
        .{perc_used},
    );
}

pub fn deinit(self: Self, alloc: std.mem.Allocator) void {
    self.fh.close();
    alloc.free(self.dat);
    alloc.free(self.buf);
}
