#include <stdio.h>
#include <string.h>
#include "wx-utils.h"
#include "wx-display.h"
#include "wx-glslp-parser.h"
#include "wx-shaderconfig.h"
#include "config.h"

#define MAX_USER_SHADERS 20

extern char *get_filename(char *s);

extern char gl3_shader_file[MAX_USER_SHADERS][512];
static char shaders[MAX_USER_SHADERS][512];

void read_shader_config(glslp_t* shader)
{
        char s[512];
        int i;
        char* name = shader->name;
        sprintf(s, "GL3 Shaders - %s", name);
        for (i = 0; i < shader->num_parameters; ++i)
        {
                struct parameter* param = &shader->parameters[i];
                param->value = config_get_float(CFG_MACHINE, s, param->id, param->default_value);
        }
}

void write_shader_config(glslp_t* shader)
{
        char s[512];
        int i;
        char* name = shader->name;
        sprintf(s, "GL3 Shaders - %s", name);
        for (i = 0; i < shader->num_parameters; ++i)
        {
                struct parameter* param = &shader->parameters[i];
                config_set_float(CFG_MACHINE, s, param->id, param->value);
        }
}

static void add_shader(int p, const char* s)
{
        memmove(&shaders[p+1], &shaders[p], (MAX_USER_SHADERS-p-2)*512);
        strcpy(shaders[p], s);
}

static int shader_list_update(void* hdlg)
{
        int c;
        void* h;
        int num = 0;

        h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST"));
        wx_sendmessage(h, WX_LB_RESETCONTENT, 0, 0);

        for (c = 0; c < MAX_USER_SHADERS; c++)
        {
                if (strlen(shaders[c]))
                {
                        char* p = get_filename(shaders[c]);
                        wx_sendmessage(h, WX_LB_INSERTSTRING, c, (LONG_PARAM)p);
                        ++num;
                }
        }
        return num;
}

static void set_shaders()
{
        int i, j, available;
        char s[128];
        char name[64];
        for (i = 0; i < MAX_USER_SHADERS; ++i)
        {
                if (strlen(gl3_shader_file[i]))
                {
                        available = 0;
                        for (j = 0; j < MAX_USER_SHADERS; ++j)
                        {
                                if (!strcmp(gl3_shader_file[i], shaders[j]))
                                {
                                        available = 1;
                                        continue;
                                }
                        }
                        if (!available)
                        {
                                get_glslp_name(gl3_shader_file[i], name, sizeof(name));
                                sprintf(s, "GL3 Shaders - %s", name);
                                config_free_section(CFG_MACHINE, s);
                        }
                }
        }
        memcpy(&gl3_shader_file, &shaders, sizeof(gl3_shader_file));

}

static int shader_manager_dlgproc(void* hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam)
{
        char s[512];
        switch (message)
        {
                case WX_INITDIALOG:
                {
                        void* h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST"));
                        memcpy(&shaders, &gl3_shader_file, sizeof(gl3_shader_file));
                        int len = shader_list_update(hdlg);
                        if (len)
                                wx_sendmessage(h, WX_LB_SETCURSEL, len-1, 0);
                        return TRUE;
                }
                case WX_COMMAND:
                {
                        if (wParam == wxID_OK)
                        {
                                set_shaders();
                                wx_enddialog(hdlg, 1);
                                return TRUE;
                        }
                        else if (wParam == wxID_CANCEL)
                        {
                                wx_enddialog(hdlg, 0);
                                return TRUE;
                        }
                        else if (wParam == WX_ID("IDC_APPLY"))
                        {
                                set_shaders();
                                renderer_doreset = 1;
                                return TRUE;
                        }
                        else if (wParam == WX_ID("IDC_ADD"))
                        {
                                void* h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST"));
                                int c = wx_sendmessage(h, WX_LB_GETCURSEL, 0, 0);
                                int count = wx_sendmessage(h, WX_LB_GETCOUNT, 0, 0);
                                if (count >= MAX_USER_SHADERS)
                                {
                                        wx_simple_messagebox("Error", "Can't add more shaders.");
                                        return FALSE;
                                }

                                int ret = !wx_filedialog(hdlg, "Open", shaders[c], "GLSL Shaders (*.glslp;*.glsl)|*.glslp;*.glsl|All files (*.*)|*.*", 0, 1, s);

                                if (ret)
                                {
                                        add_shader(c+1, s);
                                        shader_list_update(hdlg);
                                        wx_sendmessage(h, WX_LB_SETCURSEL, c+1, 0);
                                }

                                return TRUE;
                        }
                        else if (wParam == WX_ID("IDC_CONFIG"))
                        {
                                void* h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST"));
                                int c = wx_sendmessage(h, WX_LB_GETCURSEL, 0, 0);
                                if (c >= 0)
                                {
                                        glslp_t* glsl = glslp_parse(shaders[c]);
                                        if (glsl)
                                        {
                                                read_shader_config(glsl);
                                                shaderconfig_open(hdlg, glsl);
                                                write_shader_config(glsl);
                                                glslp_free(glsl);
                                                return TRUE;
                                        }
                                }
                                return FALSE;
                        }
                        else if (wParam == WX_ID("IDC_REMOVE"))
                        {
                                void* h;
                                int c;
                                h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST"));
                                c = wx_sendmessage(h, WX_LB_GETCURSEL, 0, 0);
                                if (c >= 0)
                                {
                                        memmove(&shaders[c], &shaders[c+1], (MAX_USER_SHADERS-c-1)*512);
                                        int len = shader_list_update(hdlg);
                                        if (len > 0)
                                        {
                                                if (c > 0)
                                                        c--;
                                                wx_sendmessage(h, WX_LB_SETCURSEL, c, 0);
                                        }
                                }
                        }
                        else if (wParam == WX_ID("IDC_MOVE_UP"))
                        {
                                void* h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST"));
                                int c = wx_sendmessage(h, WX_LB_GETCURSEL, 0, 0);
                                if (c > 0)
                                {
                                        strcpy(s, shaders[c-1]);
                                        strcpy(shaders[c-1], shaders[c]);
                                        strcpy(shaders[c], s);
                                        shader_list_update(hdlg);
                                        wx_sendmessage(h, WX_LB_SETCURSEL, c-1, 0);
                                }
                        }
                        else if (wParam == WX_ID("IDC_MOVE_DOWN"))
                        {
                                void* h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST"));
                                int c = wx_sendmessage(h, WX_LB_GETCURSEL, 0, 0);
                                if (c < MAX_USER_SHADERS-1)
                                {
                                        if (strlen(shaders[c+1]))
                                        {
                                                strcpy(s, shaders[c+1]);
                                                strcpy(shaders[c+1], shaders[c]);
                                                strcpy(shaders[c], s);
                                                shader_list_update(hdlg);
                                                wx_sendmessage(h, WX_LB_SETCURSEL, c+1, 0);
                                        }
                                }
                        }
                }
                break;
        }
        return FALSE;
}

int shader_manager_open(void* hwnd)
{
        return wx_dialogbox(hwnd, "ShaderManagerDlg", shader_manager_dlgproc);
}
