module demos.simple;

import app;

import bindbc.sdl;

import bubel.ecs.attributes;
import bubel.ecs.core;
import bubel.ecs.entity;
import bubel.ecs.manager;
import bubel.ecs.std;

import cimgui.cimgui;

import ecs_utils.gfx.texture;
import ecs_utils.math.vector;
import ecs_utils.utils;

import game_core.basic;

extern(C):

/*#######################################################################################################################
------------------------------------------------ Components ------------------------------------------------------------------
#######################################################################################################################*/

/*struct CLocation
{
    mixin ECS.Component;

    alias location this;

    vec2 location;
}*/

/*#######################################################################################################################
------------------------------------------------ Systems ------------------------------------------------------------------
#######################################################################################################################*/

struct DrawSystem
{
    mixin ECS.System!32;

    struct EntitiesData
    {
        uint length;
        //uint thread_id;
        uint job_id;
        @readonly CLocation[] locations;
    }

    void onUpdate(EntitiesData data)
    {
        if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached
        foreach(i; 0..data.length)
        {
            launcher.renderer.draw(simple.texture, data.locations[i], vec2(16,16), vec4(0,0,1,1), cast(ushort)(data.locations[i].y), 0x80808080, 0, 0, 0, data.job_id);
            // launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), 0, 0x80808080, 0, 0, 0, data.job_id);
            //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1));
        }
        //if(data.thread_id == 0)launcher.renderer.pushData();
    }
}

struct MoveSystem
{
    mixin ECS.System!64;

    struct EntitiesData
    {
        uint length;
        CLocation[] locations;
    }

    void onUpdate(EntitiesData data)
    {
        foreach(i; 0..data.length)
        {
            data.locations[i].y = data.locations[i].y + 1; 
            if(data.locations[i].y > 300)data.locations[i].y = 0;
        }
    }
}

/*#######################################################################################################################
------------------------------------------------ Functions ------------------------------------------------------------------
#######################################################################################################################*/

struct Simple
{
    __gshared const (char)* tips = "Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Simple\" window.";

    EntityTemplate* tmpl;
    Texture texture;
}

__gshared Simple* simple;

void simpleStart()
{
    simple = Mallocator.make!Simple;

    simple.texture.create();
    simple.texture.load("assets/textures/buckler.png");

    launcher.manager.beginRegister();

    launcher.manager.registerComponent!CLocation;

    launcher.manager.registerSystem!MoveSystem(0);
    launcher.manager.registerSystem!DrawSystem(1);

    launcher.manager.endRegister();

    launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System");
    launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System");

    ushort[1] components = [CLocation.component_id];
    simple.tmpl = launcher.manager.allocateTemplate(components);
    //CLocation* loc_comp = simple.tmpl.getComponent!CLocation;

    launcher.gui_manager.addTemplate(simple.tmpl, "Basic");

    foreach(i; 0..10)
        foreach(j; 0..10)
        {
            //loc_comp.value = vec2(i*16+64,j*16+64);
            launcher.manager.addEntity(simple.tmpl,[CLocation(vec2(i*16+64,j*16+64)).ref_].staticArray);
        }
}

void simpleEnd()
{
    launcher.manager.getSystem(MoveSystem.system_id).disable();
    launcher.manager.getSystem(DrawSystem.system_id).disable();

    simple.texture.destroy();

    //launcher.manager.freeTemplate(simple.tmpl);
    Mallocator.dispose(simple);
}

void simpleEvent(SDL_Event* event)
{
}

void spawnEntity()
{
    //CLocation* loc_comp = simple.tmpl.getComponent!CLocation;
    //loc_comp.value = vec2(randomf() * 400,0);
    launcher.manager.addEntity(simple.tmpl,[CLocation(vec2(randomf() * 400,0)).ref_].staticArray);
}

bool simpleLoop()
{
    launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5;

    if(launcher.getKeyState(SDL_SCANCODE_SPACE))
    {
        foreach(i;0..20)spawnEntity();
    }
    
    launcher.manager.begin();
    if(launcher.multithreading)
    {
        launcher.job_updater.begin();
        launcher.manager.updateMT();
        launcher.job_updater.call();
    }
    else
    {
        launcher.manager.update();
    }
    launcher.manager.end();

    return true;
}