//! mach/ecs is an Entity component system implementation.
//!
//! ## Design principles:
//!
//! * Clean-room implementation (author has not read any other ECS implementation code.)
//! * Solve the problems ECS solves, in a way that is natural to Zig and leverages Zig comptime.
//! * Avoid patent infringement upon Unity ECS patent claims.
//! * Fast. Optimal for CPU caches, multi-threaded, leverage comptime as much as is reasonable.
//! * Simple. Small API footprint, should be natural and fun - not like you're writing boilerplate.
//! * Enable other libraries to provide tracing, editors, visualizers, profilers, etc.
//!
//! ## Copyright & patent mitigation
//!
//! The initial implementation was a clean-room implementation by Stephen Gutekanst without having
//! read other ECS implementations' code, but with speaking to people familiar with other ECS
//! implementations. Contributions past the initial implementation may be made by individuals in
//! non-clean-room settings.
//!
//! Critically, this entity component system stores components for a classified archetype using
//! independent arrays allocated per component as well as hashmaps for sparse component data as an
//! optimization. This is a novel and fundamentally different process than what is described in
//! Unity Software Inc's patent US 10,599,560. This is not legal advice.
//!

const std = @import("std");
const testing = std.testing;

const EntityID = @import("entities.zig").EntityID;
const Entities = @import("entities.zig").Entities;

const Adapter = @import("systems.zig").Adapter;
const System = @import("systems.zig").System;
const World = @import("systems.zig").World;

// TODO:
// * Iteration
// * Querying
// * Multi threading
// * Multiple entities having one value
// * Sparse storage?

test "inclusion" {
    _ = Entities;
}

test "example" {
    const allocator = testing.allocator;

    //-------------------------------------------------------------------------
    // Create a world.
    var world = try World.init(allocator);
    defer world.deinit();

    const player1 = try world.entities.new();
    const player2 = try world.entities.new();
    const player3 = try world.entities.new();
    try world.entities.setComponent(player1, "physics", @as(u16, 1234));
    try world.entities.setComponent(player1, "geometry", @as(u16, 1234));

    try world.entities.setComponent(player2, "physics", @as(u16, 1234));
    try world.entities.setComponent(player3, "physics", @as(u16, 1234));

    const physics = (struct {
        pub fn physics(adapter: *Adapter) void {
            var iter = adapter.query(&.{"physics"});
            std.debug.print("\nphysics ran\n", .{});
            while (iter.next()) |row| {
                std.debug.print("found entity: {}\n", .{row.entity});
                defer row.unlock();
            }
        }
    }).physics;
    try world.register("physics", physics);

    const rendering = (struct {
        pub fn rendering(adapter: *Adapter) void {
            var iter = adapter.query(&.{"geometry"});
            std.debug.print("\nrendering ran\n", .{});
            while (iter.next()) |row| {
                std.debug.print("found entity: {}\n", .{row.entity});
                defer row.unlock();
            }
        }
    }).rendering;
    try world.register("rendering", rendering);

    world.tick();
}
