/*
 * 2007+ Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <sys/types.h>
#include <sys/stat.h>

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>

#include <gtk/gtk.h>

#include "sky.h"

static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
	return FALSE;
}

static void destroy(GtkWidget *widget, gpointer data)
{
	gtk_main_quit();
}

static struct list_head *sky_object_current;
static struct sky_found_object *sky_found_object;
static struct sky_graph *sky_current_graph;

static gboolean sky_draw_map(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
	struct sky_graph *g = sky_current_graph;
	struct sky_map *map = data;
	GdkGC *gc_point = gdk_gc_new(widget->window);
	GdkGC *gc_arc = gdk_gc_new(widget->window);
	GdkColor cpoint = {0, 0, 0, 0};
	GdkColor carc = {0xff0f0f, 0, 0, 0};
	unsigned int i;
	double scalex, scaley;
	int width, height;
	struct sky_xy *c, *e;
	double vector_len, scale, cos_a, sin_a, x, y, len;

	gdk_drawable_get_size(widget->window, &width, &height);

	scalex = (double)width/(double)map->maxx;
	scaley = (double)height/(double)map->maxy;

	gdk_gc_set_foreground(gc_point, &cpoint);
	gdk_gc_set_foreground(gc_arc, &carc);

	for (i=0; i<map->num; ++i) {
		struct sky_xy *c = &map->coords[i];

		gdk_draw_point(widget->window, gc_point, c->x*scalex, c->y*scaley);
	}

	if (!sky_found_object)
		goto out;

	c = &map->coords[sky_found_object->c];
	e = &map->coords[sky_found_object->e];

	vector_len = sqrt((c->x - e->x)*(c->x - e->x) + (c->y - e->y)*(c->y - e->y));
	scale = vector_len / g->vector_len;

	cos_a = (e->x - c->x) / vector_len;
	sin_a = (e->y - c->y) / vector_len;
	
	for (i=0; i<g->map->num; ++i) {
		struct sky_param *p = &g->pc[i];

		len = p->len * scale;

		x = c->x + len * (cos_a*p->cos_b + sin_a*p->sin_b);
		y = c->y + len * (sin_a*p->cos_b + cos_a*p->sin_b);

		gdk_draw_arc(widget->window, gc_arc, TRUE, x*scalex-2, y*scaley-2, 3, 3, 0, 360*64);
		gdk_draw_line(widget->window, gc_point, c->x*scalex, c->y*scaley, x*scalex, y*scaley);
	}

out:
	gdk_gc_destroy(gc_arc);
	gdk_gc_destroy(gc_point);

	return TRUE;
}

static gboolean sky_draw_object(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
	struct sky_graph *g = data;
	GdkGC *gc_point = gdk_gc_new(widget->window);
	GdkGC *gc_arc = gdk_gc_new(widget->window);
	GdkColor carc = {0xff0f0f, 0, 0, 0};
	GdkColor cpoint = {0, 0, 0, 0};
	unsigned int i;
	double scalex, scaley;
	int width, height;
	struct sky_xy *c, *a;

	gdk_drawable_get_size(widget->window, &width, &height);

	scalex = (double)width/(double)g->map->maxx;
	scaley = (double)height/(double)g->map->maxy;

	scalex = width/g->map->maxx;
	scaley = height/g->map->maxy;

	gdk_gc_set_foreground(gc_point, &cpoint);
	gdk_gc_set_foreground(gc_arc, &carc);
	
	c = &g->map->coords[g->start];

	for (i=0; i<g->map->num; ++i) {
		a = &g->map->coords[i];

		gdk_draw_arc(widget->window, gc_arc, TRUE, a->x*scalex-3, a->y*scaley-3, 5, 5, 0, 360*64);

		if (c != a)
			gdk_draw_line(widget->window, gc_point, c->x*scalex, c->y*scaley, a->x*scalex, a->y*scaley);
	}

	gdk_gc_destroy(gc_arc);
	gdk_gc_destroy(gc_point);

	return TRUE;
}

static gboolean sky_set_object(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
	struct sky_graph *g = sky_current_graph;
	struct sky_found_object *o;

	if (!sky_object_current)
		sky_object_current = &g->found_list;

	o = list_entry(sky_object_current->next, struct sky_found_object, found_entry);
	if (&o->found_entry == &g->found_list) {
		sky_object_current = &g->found_list;
		return TRUE;
	}

	sky_object_current = sky_object_current->next;
	sky_found_object = o;

	gdk_window_clear(widget->window);
	sky_draw_map(widget, event, data);

	return FALSE;
}

static void usage(char *p)
{
	g_print("Usage: %s -l letter_image -h\n", p);
}

int main(int argc, char *argv[])
{
	GtkWidget *window, *box, *sky_area, *object_area;
	struct sky_map *m, *pat;
	struct sky_graph *g;

	m = sky_gen_map(400, 0, 100, 100);
	if (!m)
		return -1;
	
	pat = sky_gen_map(3, 0, 10, 10);
	if (!pat)
		return -1;

	g = sky_current_graph = sky_gen_graph(pat, 2, 0);
	if (!g)
		return -1;

	sky_search_map(m, g, 0, m->num);

	gtk_init(&argc, &argv);

	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

	gtk_window_set_title(GTK_WINDOW(window), "Sky walker");

	g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), NULL);
	g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL);

	gtk_container_set_border_width(GTK_CONTAINER(window), 10);

	sky_area = gtk_drawing_area_new();
	gtk_widget_set_size_request(sky_area, m->maxx, m->maxy);
	
	object_area = gtk_drawing_area_new();

	g_signal_connect(G_OBJECT(sky_area), "expose_event", G_CALLBACK(sky_draw_map), m);
	g_signal_connect(G_OBJECT(object_area), "expose_event", G_CALLBACK(sky_draw_object), g);

	gtk_widget_add_events(sky_area, GDK_BUTTON_PRESS_MASK);
	g_signal_connect(G_OBJECT(sky_area), "button_press_event", G_CALLBACK(sky_set_object), m);

	box = gtk_hbox_new(1, 1);

	gtk_box_pack_start(GTK_BOX(box), sky_area, 1, 1, 1);
	gtk_box_pack_start(GTK_BOX(box), object_area, 1, 1, 1);

	gtk_container_add(GTK_CONTAINER(window), box);

	/* The final step is to display this newly created widget. */
	gtk_widget_show(sky_area);
	gtk_widget_show(object_area);
	gtk_widget_show(box);
	gtk_widget_show(window);

	gtk_main ();

	return 0;
}


