/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   minirt.c                                           :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: bszilas <bszilas@student.42vienna.com>     +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2024/09/08 16:33:29 by victor            #+#    #+#             */
/*   Updated: 2025/05/31 18:22:50 by victor           ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#include "../minirt.h"

void create_display() {
    InitWindow(WI, HI, "miniRT in Raylib!!");
    SetTargetFPS(60);
}

void    data_destroy_func(void *data_ptr)
{
    t_data    *data;

    data = data_ptr;
    data->go = false;
    pthread_rwlock_unlock(&data->rwlock);
    while (data->thread_count--)
        pthread_join(data->threads[data->thread_count].thread, NULL);
    pthread_barrier_destroy(&data->barrier);
    pthread_rwlock_destroy(&data->rwlock);
    UnloadTexture(data->texture);
    CloseWindow();
}

t_container    *menu_init(t_data *data)
{
    t_container    *menu;
    t_item        item;

    menu = ft_calloc(16, sizeof(*menu));
    lst_memory(menu, free, ADD);
    menu[ID_GROUP_MENU_MAIN - 1] = container_create("Main menu", \
            NULL, CONTAINER_GRID);
    item = container_item_button_create("add sphere", \
            NULL, scene_add_sphere_func);
    container_item_add(&menu[ID_GROUP_MENU_MAIN - 1], &item);
    item = container_item_button_create("add plane", NULL, \
            scene_add_plane_func);
    container_item_add(&menu[ID_GROUP_MENU_MAIN - 1], &item);
    item = container_item_button_create("add cylinder", NULL, \
            scene_add_cylinder);
    container_item_add(&menu[ID_GROUP_MENU_MAIN - 1], &item);
    item = container_item_button_create("add disk", NULL, \
            scene_add_disk);
    container_item_add(&menu[ID_GROUP_MENU_MAIN - 1], &item);
    item = container_item_button_create("show_help", NULL, help_menu_draw);
    container_item_add(&menu[ID_GROUP_MENU_MAIN - 1], &item);
    item = container_item_button_create("Load Scene", NULL, explorer_read_dir);
    item.param = (t_param){&data->scene, NULL, PARAM_SCENE};
    container_item_add(&menu[ID_GROUP_MENU_MAIN - 1], &item);
    return (menu);
}

t_container    *menus_create(t_data *data)
{
    t_container    *menu;
    uint        i;

    menu = menu_init(data);
    sphere_menu_create(&menu[ID_GROUP_SPHERE]);
    plane_menu_create(&menu[ID_GROUP_PLANE]);
    cone_menu_create(&menu[ID_GROUP_CONE]);
    disc_menu_create(&menu[ID_GROUP_DISC]);
    cylinder_menu_create(&menu[ID_GROUP_CYLINDER]);
    i = 0;
    while (i < 16)
        menu[i++].data = data;
    return (menu);
}

void    initialize_data(t_data *data, char *path)
{
    ft_bzero(data, sizeof(*data));
    scene_create(path, &data->scene);
    create_display();
    data->pixel = pixel_plane_create();
    data->func_ptr = help_menu_draw;
    data->mouse.data = data;
    data->scene.pixel = data->pixel;
    data->menu = menus_create(data);
    Image img = GenImageColor(WI, HI, BLACK);
    data->pixel_colors = img.data;
    data->texture = LoadTextureFromImage(img);
    pixels_image_syncronize(data->pixel_colors, data->pixel);
}

char*     validate_file_extension(int argc, char **argv)
{
    if (argc == 2 && ft_strlen(argv[1]) > 3 && ft_memcmp(&argv[1][ft_strlen(argv[1]) - 3], ".rt\0", 4) == 0)
        return argv[1];
    ft_fprintf(STDERR_FILENO, "Invalid Argument to Program!\nExiting...\n");
    exit(EXIT_FAILURE);
}

void    get_key_code(int keys[]) {
    uint c = 0;

    if (IsKeyPressed(KEY_ESCAPE)) {
        keys[c++] = KEY_ESCAPE;
        if (c == 3) return;
    }
    if ((IsKeyPressed(KEY_W) || IsKeyDown(KEY_W))) {
        keys[c++] = KEY_W;
        if (c == 3) return;
    }
    if ((IsKeyPressed(KEY_E) || IsKeyDown(KEY_E))) {
        keys[c++] = KEY_E;
        if (c == 3) return ;
    }
    if ((IsKeyPressed(KEY_Q) || IsKeyDown(KEY_Q))) {
        keys[c++] = KEY_Q;
        if (c == 3) return ;
    }
    if ((IsKeyPressed(KEY_A) || IsKeyDown(KEY_A))) {
        keys[c++] = KEY_A;
        if (c == 3) return ;
    }
    if ((IsKeyPressed(KEY_S) || IsKeyDown(KEY_S))) {
        keys[c++] = KEY_S;
        if (c == 3) return ;
    }
    if ((IsKeyPressed(KEY_D) || IsKeyDown(KEY_D))) {
        keys[c++] = KEY_D;
        if (c == 3) return ;
    }
    if (IsKeyPressed(KEY_ENTER)) {
        keys[c++] = KEY_ENTER;
        if (c == 3) return ;
    }
    if (IsKeyPressed(KEY_BACKSPACE)) {
        keys[c++] = KEY_BACKSPACE;
        if (c == 3) return ;
    }
    if (IsKeyPressed(KEY_SLASH)) {
        keys[c++] = KEY_SLASH;
        if (c == 3) return ;
    }
    if (IsKeyPressed(KEY_PERIOD)) {
        keys[c++] = KEY_PERIOD;
        if (c == 3) return ;
    }
    if (IsKeyPressed(KEY_M)) {
        keys[c++] = KEY_M;
        if (c == 3) return ;
    }
    if (IsKeyPressed(KEY_P)) {
        keys[c++] = KEY_P;
        if (c == 3) return ;
    }
    if (IsKeyPressed(KEY_EQUAL)) {
        keys[c++] = KEY_EQUAL;
        if (c == 3) return ;
    }
    if (IsKeyPressed(KEY_MINUS)) {
        keys[c++] = KEY_MINUS;
        if (c == 3) return ;
    }
    if (IsKeyDown(KEY_ONE)) {
        keys[c++] = KEY_ONE;
        if (c == 3) return ;
    }
    if (IsKeyDown(KEY_TWO)) {
        keys[c++] = KEY_TWO;
        if (c == 3) return ;
    }
    if (IsKeyDown(KEY_THREE)) {
        keys[c++] = KEY_THREE;
        if (c == 3) return ;
    }
    if (IsKeyDown(KEY_FOUR)) {
        keys[c++] = KEY_FOUR;
        if (c == 3) return ;
    }
    if ((IsKeyPressed(KEY_UP) || IsKeyDown(KEY_UP))) {
        keys[c++] = KEY_UP;
        if (c == 3) return ;
    }
    if ((IsKeyPressed(KEY_DOWN) || IsKeyDown(KEY_DOWN))) {
        keys[c++] = KEY_DOWN;
        if (c == 3) return ;
    }
    if ((IsKeyPressed(KEY_LEFT) || IsKeyDown(KEY_LEFT))) {
        keys[c++] = KEY_LEFT;
        if (c == 3) return ;
    }
    if ((IsKeyPressed(KEY_RIGHT) || IsKeyDown(KEY_RIGHT))) {
        keys[c++] = KEY_RIGHT;
        if (c == 3) return ;
    }
}

int     main(int argc, char **argv)
{
    t_data      data;
    char        *path;
    t_thread    thread[THREAD_COUNT];
    int         keys[3] = { 0 };

    if (argc == 1)
        path = "scenes/multilight.rt";
    else
        path = validate_file_extension(argc, argv);
    initialize_data(&data, path);
    lst_memory(&data, data_destroy_func, ADD);
    threads_init(thread, &data);
    rendering_loop(&data);
    data.threads = thread;
    while(!WindowShouldClose()) {
        Vector2 mouse_pos = GetMousePosition();
        if (data.mouse.left_is_pressed || data.mouse.right_is_pressed)
        {
            mouse_move(mouse_pos.x, mouse_pos.y, &data);
            mouse_release(mouse_pos.x, mouse_pos.y, &data);
        }
        else
            mouse_press(mouse_pos.x, mouse_pos.y, &data);
        bzero(keys, sizeof(keys));
        get_key_code(keys);
        for (int i = 0; i < 3; i++)
        {
            if (keys[i])
            {
                data.scene.resolution_x = RESOLUTION_SCALE_X;
                data.scene.resolution_y = RESOLUTION_SCALE_Y;
                key_press(keys[i], &data);
            }
        }
        rendering_loop(&data);
        data.scene.resolution_x = 1;
        data.scene.resolution_y = 1;
    }
    return (0);
}
