#include <gtk/gtk.h>
#include <gtk_stuff.h>

extern GtkApplication *app;
cairo_surface_t* drawsurface;
cairo_t* painter;
GdkRGBA lastcolor;
int linesize = 2;
GtkWidget* draw_area;

int last_x = -1, last_y = -1;

static void create_fresh_drawsurface()
{
    drawsurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, 1280, 600);
    painter = cairo_create(drawsurface);
    cairo_set_source_rgb(painter, 1,1,1);
    cairo_paint(painter);
    cairo_fill(painter);
    cairo_set_source_rgb(painter, lastcolor.red, lastcolor.green, lastcolor.blue);
}

G_MODULE_EXPORT void brush_tool_clicked(GtkWidget* widget, gpointer data)
{
    cairo_set_source_rgb(painter, lastcolor.red, lastcolor.green, lastcolor.blue);
}

G_MODULE_EXPORT void eraser_tool_clicked(GtkWidget* widget, gpointer data)
{
    cairo_set_source_rgb(painter, 1, 1, 1);
}

extern const char* about_xml;

G_MODULE_EXPORT void about_item_clicked(GtkWidget* widget, gpointer data)
{
    GtkBuilder* builder = gtk_builder_new_from_string(about_xml, strlen(about_xml));
    gtk_builder_set_application(builder, app);
    gtk_builder_connect_signals(builder, NULL);
    GtkWidget* window = GTK_WIDGET(gtk_builder_get_object(builder, "about_window"));
    gtk_widget_show_all(window);
}

G_MODULE_EXPORT void close_window(GtkWidget* widget, gpointer data)
{
    gtk_window_close(GTK_WINDOW(data));
}

G_MODULE_EXPORT void changed_color(GtkWidget* widget, gpointer data)
{
    gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(widget), &lastcolor);
    cairo_set_source_rgb(painter, lastcolor.red, lastcolor.green, lastcolor.blue);
}

G_MODULE_EXPORT void draw_area_pressed(GtkWidget* widget, GdkEventButton* button, gpointer data)
{
    cairo_arc(painter, button->x, button->y, linesize, 0, 2*G_PI);
    cairo_fill(painter);
    
    last_x = button->x;
    last_y = button->y;
    

    gtk_widget_queue_draw(widget);
}

G_MODULE_EXPORT void draw_area_release(GtkWidget* widget, GdkEventButton* button, gpointer data)
{
    last_x = -1;
    last_y = -1;
}

void draw_line(int x_start, int y_start, int x_end, int y_end)
{
    /* this is horrible code, if you are reading this, please look away */
    if (x_start != -1 && y_start != -1)
    {
        if (x_end == x_start)
        {
            for (int i = MIN(y_start, y_end); i < MAX(y_start, y_end); i++)
                cairo_arc(painter, x_start, i, linesize, 0, 2*G_PI);
        }
        else
        {
            if (x_end < x_start)
            {
                int temp = x_end;
                x_end = x_start;
                x_start = temp;
                temp = y_end;
                y_end = y_start;
                y_start = temp;
            }

            /* To lazy to implement bresenham so floats it is */

            float y = y_start;
            float inc = ((float) y_end - (float) y_start) / (((float) x_end - (float) x_start) );
            for (float x = x_start; x <= x_end; x += 0.1)
            {
                cairo_arc(painter, (int) x, (int) y, linesize, 0, 2*G_PI);
                y += 0.1 * inc;
            }
        }

    }
    else
        cairo_arc(painter, x_end, y_end, linesize, 0, 2*G_PI);

    cairo_fill(painter);
}

G_MODULE_EXPORT void draw_area_motion(GtkWidget* widget, GdkEventMotion* event, gpointer data)
{   
    int new_x = event->x;
    int new_y = event->y;

    draw_line(last_x, last_y, new_x, new_y);

    last_x = event->x;
    last_y = event->y;
    
    gtk_widget_queue_draw(widget);
}

G_MODULE_EXPORT void change_line_size(GtkWidget* widget, gpointer data)
{
    linesize = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
}

G_MODULE_EXPORT void file_save_clicked(GtkWidget* widget, gpointer data)
{
    GtkWindow* window = GTK_WINDOW(gtk_widget_get_toplevel(widget));
    GtkWidget* dialog = gtk_file_chooser_dialog_new("Save your creation", window, GTK_FILE_CHOOSER_ACTION_SAVE, "Cancel", GTK_RESPONSE_CANCEL, "Save", GTK_RESPONSE_ACCEPT, NULL);

    gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
    gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document.png");
    int res = gtk_dialog_run(GTK_DIALOG(dialog));
    if (res == GTK_RESPONSE_ACCEPT)
    {
        char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
        cairo_surface_write_to_png(drawsurface, filename);
        g_free(filename);
    }

    gtk_widget_destroy(dialog);
}

G_MODULE_EXPORT void file_open_clicked(GtkWidget* widget, gpointer data)
{
    GtkWindow* window = GTK_WINDOW(gtk_widget_get_toplevel(widget));
    GtkWidget* dialog = gtk_file_chooser_dialog_new("Open a creation", window, GTK_FILE_CHOOSER_ACTION_OPEN, "Cancel", GTK_RESPONSE_CANCEL, "Save", GTK_RESPONSE_ACCEPT, NULL);
    
    int res = gtk_dialog_run(GTK_DIALOG(dialog));
    if (res == GTK_RESPONSE_ACCEPT)
    {
        char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
        
        cairo_surface_destroy(drawsurface);
        cairo_destroy(painter);
        drawsurface = cairo_image_surface_create_from_png(filename);
        painter = cairo_create(drawsurface);
        cairo_set_source_rgb(painter, lastcolor.red, lastcolor.green, lastcolor.blue);

        g_free(filename);
    }

    gtk_widget_destroy(dialog);
}

G_MODULE_EXPORT void file_new_clicked(GtkWidget* widget, gpointer data)
{
    cairo_surface_destroy(drawsurface);
    create_fresh_drawsurface();
    gtk_widget_queue_draw(draw_area);
}


G_MODULE_EXPORT int draw_area_draw(GtkWidget* widget, cairo_t* cr, gpointer data)
{
    GtkStyleContext* context = gtk_widget_get_style_context(widget);
    int width  = gtk_widget_get_allocated_width(widget);
    int height = gtk_widget_get_allocated_height(widget);
    gtk_render_background(context, cr, 0, 0, width, height);
    
    cairo_set_source_surface(cr, drawsurface, 0, 0);
    cairo_paint(cr);
    return FALSE;
}

static void close_application(GtkWidget* widget, gpointer data)
{
    g_application_quit(G_APPLICATION(app));
}

void gtk_buffer_poll(int x_start, int y_start, int x_end, int y_end)
{
    draw_line(x_start, y_start, x_end, y_end);
    gtk_widget_queue_draw(draw_area);
}

extern const char* paint_xml;

void build_paint()
{
    GtkBuilder* builder = gtk_builder_new_from_string(paint_xml, strlen(paint_xml));
    gtk_builder_set_application(builder, app);
    gtk_builder_connect_signals(builder, NULL);
    GtkWidget* window = GTK_WIDGET(gtk_builder_get_object(builder, "main_window"));
    g_signal_connect(window, "destroy", G_CALLBACK(close_application), NULL);
    
    lastcolor.alpha = 1;
    GtkWidget* chooser = GTK_WIDGET(gtk_builder_get_object(builder, "color_selector"));
    gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(chooser), &lastcolor);

    draw_area = GTK_WIDGET(gtk_builder_get_object(builder, "draw_area"));
    gtk_widget_add_events(draw_area, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK);
    gtk_widget_show_all(window);
    create_fresh_drawsurface();

    gtk_buffer_ready_for_refresh(gtk_buffer_poll);
}
