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;
import game_core.rendering;

extern(C):

enum float px = 1.0/512.0;

/*#######################################################################################################################
------------------------------------------------ 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
        import ecs_utils.gfx.renderer;
        Renderer.DrawData draw_data;
        draw_data.size = vec2(16,16);
        draw_data.coords = vec4(0,0,1,1);
        draw_data.color = 0x80808080;
        draw_data.material_id = 0;
        draw_data.thread_id = data.job_id;
        draw_data.texture = simple.texture;

        foreach(i; 0..data.length)
        {
            draw_data.position = data.locations[i];
            draw_data.depth = cast(ushort)(data.locations[i].y);
            launcher.renderer.draw(draw_data);
        }
    }
}*/

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 simpleRegister()
{
    simple = Mallocator.make!Simple;

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

    launcher.manager.beginRegister();

    registerRenderingModule(launcher.manager);

    launcher.manager.registerComponent!CLocation;

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

    launcher.manager.endRegister();
}

void simpleStart()
{
    DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem;
    draw_system.default_data.color = 0x80808080;
    draw_system.default_data.texture = simple.texture;
    draw_system.default_data.size = vec2(16,16);
    draw_system.default_data.coords = vec4(0,48,16,16)*px;//vec4(0,0,1,1);

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

    simple.tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CDrawDefault.component_id].staticArray);
    //*simple.tmpl.getComponent!CTexCoordsIndex = TexCoordsManager.instance.getCoordIndex(vec4(0,48,16,16)*px);
    //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;
}

DemoCallbacks getSimpleDemo()
{
    DemoCallbacks demo;
    demo.register = &simpleRegister;
    demo.initialize = &simpleStart;
    demo.deinitialize = &simpleEnd;
    demo.loop = &simpleLoop;
    demo.tips = simple.tips;
    return demo;
}