/*
 * 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 <sys/mman.h>

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

#include <gtk/gtk.h>

static char *input;
static int width, height, scale;

static int draw_image(GtkWidget *widget)
{
	unsigned char *data;
	GdkColor fg = {0, 0, 0, 0};
	GdkColor bg = {0xffffff, 0, 0, 0};
	int data_size, fd, i, j, pos, off, idx, bit;
	GdkGC *gc_point = gdk_gc_new(widget->window);

	gdk_gc_set_foreground(gc_point, &fg);

	fd = open(input, O_RDONLY);
	if (fd == -1)
		return -1;

	data_size = lseek(fd, 0, SEEK_END);
	if (data_size == -1) {
		fprintf(stderr, "Failed to determine file size.\n");
		return -1;
	}

	if (data_size < width * height / 8) {
		fprintf(stderr, "Wrong parameters: data size: %d, width*height: %d.\n",
				data_size, width*height);
		return -1;
	}
	data_size = (data_size + 4096)&~0xfffULL;

	data = mmap(NULL, data_size, PROT_READ, MAP_SHARED, fd, 0);
	if (data == MAP_FAILED) {
		fprintf(stderr, "Failed to map %d bytes of file '%s'.\n", data_size, input);
		return -1;
	}

	for (i=0; i<height; ++i) {
		for (j=0; j<width; ++j) {
			pos = i*width + j;

			idx = pos / 8;
			off = pos % 8;

			bit = (data[idx] >> off) & 1;

			if (bit)
				gdk_draw_rectangle(widget->window, gc_point, TRUE, j*scale, i*scale, 1*scale, 1*scale);
		}
	}

	munmap(data, data_size);
	close(fd);

	return 0;
}

static gboolean expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
	draw_image(widget);
	return TRUE;
}

static void usage(char *p)
{
	g_print("Usage: %s -s scale -i input -w width -h height -h\n", p);
}

int main(int argc, char *argv[])
{
	/* GtkWidget is the storage type for widgets */
	GtkWidget *img, *window, *daw;
	int ch;

	input = NULL;
	width = height = 0;
	scale = 1;

	while ((ch = getopt(argc, argv, "s:w:h:o:i:h")) != -1) {
		switch (ch) {
			case 's':
				scale = atoi(optarg);
				break;
			case 'w':
				width = atoi(optarg);
				break;
			case 'h':
				height = atoi(optarg);
				break;
			case 'i':
				input = optarg;
				break;
			default:
				usage(argv[0]);
				return -1;
		}
	}

	if (!input || !width || !height) {
		g_print("Wrong parameters, upi must specify all of them.\n");
		usage(argv[0]);
		return -1;
	}

	printf("file: %s, width: %d, height: %d, scale: %d.\n", 
			input, width, height, scale);

	gtk_init(&argc, &argv);

	daw = gtk_drawing_area_new();
	gtk_widget_set_size_request(daw, scale*width, scale*height);
	g_signal_connect(G_OBJECT(daw), "expose_event", G_CALLBACK(expose_event_callback), NULL);

	/* create a new window */
	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

	gtk_window_set_title(GTK_WINDOW(window), "Generate image");

	gtk_container_set_border_width(GTK_CONTAINER(window), 10);
	gtk_container_add(GTK_CONTAINER(window), daw);
	
	gtk_widget_show(daw);
	gtk_widget_show(window);
	
	gtk_main();

	return 0;
}

