const std = @import("std");
const print = std.debug.print;

pub fn main() !void
{
    const allocator = std.heap.page_allocator;
    var rules = std.ArrayList([]u8).init(allocator);
    var data = std.ArrayList([]u8).init(allocator);
    var sum : usize = 0;

    print("typeof arraylist: {}",.{@TypeOf(rules)});
    try readFile(allocator,"day5.txt",&rules,&data);    

    print("rules:\n",.{});
    for(rules.items) | rule |
    {
        print("{s}\n",.{rule});
    }
    print("data:\n",.{});
    for(data.items) | dat |
    {
        print("{s}\n",.{dat});
    }



    for(data.items) | dat |
    {
    const values = try parseIntsToSlice(allocator,dat);
    print("ints: {d}\n",.{values});
        if(try checkOrder(allocator,dat,&rules)) | failed_rule |
        {
            print("dataset failed at rule {d}\n",.{failed_rule});
            //try to rearange those
        }
        else
        {
            print("dataset {d} clean\n",.{values});
            const middle = getMiddleFromSlice(values);
            print("middle value {d}\n",.{values[middle]});
            sum = sum + values[middle];
        }
    }

print("Final result: {d}",.{sum});

}

fn readFile(allocator : std.mem.Allocator, filename : [] const u8, rules : *std.ArrayList([]u8), data : *std.ArrayList([]u8)) !void
{
    const file = try std.fs.cwd().openFile(filename,.{});
    var buf_reader = std.io.bufferedReader(file.reader());
    var reader = buf_reader.reader();

    var buf: [1024]u8 = undefined;

    while(try reader.readUntilDelimiterOrEof(&buf,'\n') )| line |
    {

            if(std.mem.indexOf(u8,line,"|")) | _ |
            {
                print("this is a rule: ",.{});
                try rules.append(try std.fmt.allocPrint(allocator,"{s}",.{line}));
            }
            else if(std.mem.indexOf(u8,line,",")) | _ |
            {
                try data.append( try std.fmt.allocPrint(allocator,"{s}",.{line}));
                print("this is a data set: ",.{});
            }

        print("{s}\n",.{line});
    }
}

fn parseIntsToSlice(allocator : std.mem.Allocator, data : []u8) ![]u64
{
    var values : []u64 = try allocator.alloc(u64,0);
    var start_pos : usize = 0;

    //first must be different as dataset does not beginn with a ,
    
    if(std.mem.indexOfAnyPos(u8,data,0,",")) | index |
    {
        values = try allocator.realloc(values,values.len + 1);
        const cur_index = values.len - 1;
        
        //parses the string from beginning to , to an integer
        values[cur_index] = try std.fmt.parseInt(u64,data[0..index],10);
    }

    while(std.mem.indexOfAnyPos(u8,data,start_pos,",")) | index |  
    {
    if(start_pos >= data.len - 1) break;

        if(std.mem.indexOfAnyPos(u8,data,index+1,",")) | sub_index |
        {
            values = try allocator.realloc(values,values.len + 1);
            const cur_index = values.len - 1;
            
            //parses the string from , to , to an integer
            values[cur_index] = try std.fmt.parseInt(u64,data[index+1..sub_index],10);
            start_pos = sub_index;
        }
        else
        {
            values = try allocator.realloc(values,values.len + 1);
            const cur_index = values.len - 1;
            values[cur_index] = try std.fmt.parseInt(u64,data[index+1..data.len],10);
            break;
        }
    }
    //print("address of heap allocated memory: {}\nvalues itself: {d}\n",.{&values,values});
    return values;
}
fn parseRule(allocator : std.mem.Allocator,rule : []u8) ![2]u64
{
    _ = allocator;

    if(std.mem.indexOf(u8,rule,"|")) | index |
    {
        const int1 = try std.fmt.parseInt(u64,rule[0..index],10);
        const int2 = try std.fmt.parseInt(u64,rule[index+1..],10);
        return .{int1,int2};
    }
    return.{0,0};
}

//returns the rule number which first caused a rule mismatch
fn checkOrder(allocator : std.mem.Allocator,data : []u8,rules : *std.ArrayList([]u8)) !? usize
{
    const nbrs = try parseIntsToSlice(allocator,data);
    //const nbrs2 = try parseIntsToSlice(allocator,data);
    var pass_test : bool = false;
    var fail_index : usize = 0;

    for(nbrs,0..) | nbr, index_nbr |
    {
        for (rules.items,0..) | rule, index_rule |
        {

            const rule_i = try parseRule(allocator,rule);
            if(nbr == rule_i[0])
            {
                print("check rule: {s}",.{rule});
                for(nbrs,0..) | nbr2, index_nbr2 |
                {
                    if(nbr2 == rule_i[1])
                    {
                        if(index_nbr2 > index_nbr)
                        {   
                            print("... OK\n",.{});
                            pass_test = true;
                            break;
                        }
                        else
                        {
                            print("... failed at rule {d}\n",.{index_rule});
                            pass_test = false;
                            fail_index = index_rule;
                            return fail_index;
                        }
                    }
                }
                else
                {
                    print("... skip rule\n",.{});
                }
            }
        }
    }
    return null;
}

fn getMiddleFromSlice(data : []u64) usize
{
    const middle = (data.len - 1) / 2;
    print("middle: {}\n",.{middle});

    return middle;
}

fn orderNums(allocator : std.mem.Allocator, data : *[]u64, rules : *std.ArrayList([]u8)) ! void
{

        const rules_i = try parseRule(allocator,rule);
        
        for(data) | dat |
        {

            const failed_rule_index = try checkOrder(allocator,dat,rules);
            const failed_rule = rules[failed_rule_index];

            failed_rule_i = parseRule(allocator,failed_rule);

            const tmp = failed_rule_i[1];

            //find the number in dat
            if(std.mem.indexOf(u64,dat,tmp)) | index |
            {
               for( 
            }

        }
