const std = @import("std");

const Str = []const u8;

const PATH = "input/day08.txt";

pub fn first(allocator: std.mem.Allocator) !usize {
    _ = allocator;

    var chars: usize = 0;
    var real_chars: usize = 0;

    var lines = std.mem.tokenize(u8, @embedFile(PATH), "\n");
    while (lines.next()) |line| {
        chars += line.len;
        real_chars += try realChars(line);
    }

    return chars - real_chars;
}

pub fn second(allocator: std.mem.Allocator) !usize {
    var chars: usize = 0;
    var encode_chars: usize = 0;

    var encoded = std.ArrayList(u8).init(allocator);
    defer encoded.deinit();

    var lines = std.mem.tokenize(u8, @embedFile(PATH), "\n");
    while (lines.next()) |line| {
        chars += line.len;
        try encoded.resize(0);
        try encodeString(&encoded, line);
        encode_chars += encoded.items.len + 2; // leading and trailing double-quotes
    }

    return encode_chars - chars;
}

fn realChars(line: Str) !usize {
    var ret: usize = 0;

    var idx: usize = 0;
    while (idx < line.len) : (idx += 1) {
        switch (line[idx]) {
            '"' => {},
            '\\' => {
                if (line[idx + 1] == '"' or line[idx + 1] == '\\') {
                    ret += 1;
                    idx += 1;
                } else if (line[idx + 1] == 'x') {
                    ret += 1;
                    idx += 3;
                }
            },
            else => ret += 1,
        }
    }

    return ret;
}

fn encodeString(encoded: *std.ArrayList(u8), raw: Str) !void {
    var idx: usize = 0;

    while (idx < raw.len) : (idx += 1) {
        switch (raw[idx]) {
            '"' => {
                try encoded.appendSlice("\\\"");
            },
            '\\' => {
                try encoded.appendSlice("\\\\");
            },
            else => try encoded.append(raw[idx]),
        }
    }
}

const test_input =
    \\""
    \\"abc"
    \\"aaa\"aaa"
    \\"\x27"
;

test "day08a" {
    try std.testing.expectEqual(@as(usize, 1333), try first(std.testing.allocator));
}

test "day08b" {
    try std.testing.expectEqual(@as(usize, 2046), try second(std.testing.allocator));
}