const std    = @import("std");
const entity = @import("entity.zig");
const misc   = @import("misc.zig");

// pub fn Storage(comptime T: type) type {
//     return struct {
//         items: std.ArrayList(T),

//         pub fn init(allocator: std.mem.Allocator) !@This() {
//             return .{
//                 .items = try std.ArrayList(T).initCapacity(allocator, 32),
//             };
//         }

//         pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void {
//             self.items.deinit(allocator);
//         }

//         pub fn update(self: *@This()) void {
//             for (self.items.items, 0..) |*item, i| {
//                 _ = i;
//                 if (@hasDecl(T, "update"))
//                     item.update();
//             }
//         }
//     };
// }

// pub const Chunk = _Chunk();

// fn _Chunk() type {
//     const FieldCount = entity.EntityKinds.len;

//     var fields: [FieldCount]std.builtin.Type.StructField = undefined;

//     inline for (entity.EntityKinds, 0..) |T, i| {
//         fields[i] = .{
//             .name = misc.short_type_name(T),
//             .type = std.ArrayList(T),
//             .default_value_ptr = null,
//             .is_comptime = false,
//             .alignment = @alignOf(std.ArrayList(T)),
//         };
//     }

//     return @Type(.{
//         .@"struct" = .{
//             .layout = .auto,
//             .fields = &fields,
//             .decls = &.{},
//             .is_tuple = false,
//         },
//     });
// }

// pub fn initChunk(allocator: std.mem.Allocator) !Chunk {
//     var chunk: Chunk = undefined;

//     inline for (@typeInfo(Chunk).@"struct".fields) |field| {
//         const ListT = field.type;
//         @field(chunk, field.name) = try ListT.initCapacity(allocator, 32);
//     }

//     return chunk;
// }

// pub fn deinitChunk(chunk: *Chunk, allocator: std.mem.Allocator) void {
//     switch (@typeInfo(Chunk)) {
//         .@"struct" => |s| {
//             inline for (s.fields) |field| {
//                 @field(chunk, field.name).deinit(allocator);
//             }
//         },
//         else => unreachable,
//     }
// }

// pub fn updateChunk(chunk: *Chunk) void {
//     inline for (@typeInfo(Chunk).@"struct".fields) |field| {
//         const list = &@field(chunk, field.name);

//         for (list.items, 0..) |*item, i| {
//             _ = i;
//             if (@hasDecl(@TypeOf(item.*), "update"))
//                 item.update();
//         }
//     }
// }

pub const Chunk = struct {
    entities : std.ArrayList(entity.Ref),

    pub fn init(allocator: std.mem.Allocator) !Chunk {
        return .{
            .entities = try std.ArrayList(entity.Ref).initCapacity(allocator, 128),
        };
    }

    pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void {
        for (self.entities.items) |ref| {
            switch (ref) {
                inline else => |ptr| allocator.destroy(ptr),
            }
        }

        self.entities.deinit(allocator);
    }

    pub fn update(self: *@This(), dt: f32) void {
        for (self.entities.items) |e| {
            switch (e) {
                .Soldier => |s| {
                    s.update(dt);
                },
                .Alien => |a|  {
                    a.update(dt);
                },
            }
        }
    }
};
