/* $Id$ */

/* syntax: ./simplehist < sourcefile.ppm > histogram.ppm */

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "ppm.h"

typedef struct
{
	ppm_size_t luminance[256];
	ppm_size_t max_luminance;
} data_t;

static void calculate(data_t *data, const ppm_t *ppm)
{
	ppm_size_t pixel;

	memset(data, 0, sizeof(*data));

	for (pixel = 0; pixel < ppm->width * ppm->height; ++pixel)
		++data->luminance[(ppm->data[pixel].rgb[0] * 30 + ppm->data[pixel].rgb[1] * 59 + ppm->data[pixel].rgb[2] * 11) / 100];

	for (pixel = 0; pixel < 256; ++pixel)
		if (data->luminance[pixel] > data->max_luminance)
			data->max_luminance = data->luminance[pixel];
}

static inline void draw_pixel(ppm_t *ppm, int x, int y, const ppm_pixel_t *rgb)
{
	memcpy(&PPM_PIXEL(ppm, x, y), rgb, sizeof(*rgb));
}

static void draw_vline(ppm_t *ppm, int x, int y0, int y1, const ppm_pixel_t *rgb)
{
	assert(y0 <= y1);
	while (y0 <= y1)
		draw_pixel(ppm, x, y0++, rgb);
}

static void draw_hline(ppm_t *ppm, int x0, int x1, int y, const ppm_pixel_t *rgb)
{
	assert(x0 <= x1);
	while (x0 <= x1)
		draw_pixel(ppm, x0++, y, rgb);
}

static void draw_box(ppm_t *ppm, int x0, int y0, int x1, int y1, const ppm_pixel_t *rgb)
{
	assert(y0 <= y1);
	while (y0 <= y1)
		draw_hline(ppm, x0, x1, y0++, rgb);
}

static void histogram(data_t *data, ppm_t *ppm)
{
	static const ppm_pixel_t black = {{0, 0, 0}};
	static const ppm_pixel_t darkgrey = {{63, 63, 63}};
	static const ppm_pixel_t lightgrey = {{192, 192, 192}};
	static const ppm_pixel_t white = {{255, 255, 255}};
	ppm_size_t x, y;

	assert(!(ppm->width & 16));
	assert(!(ppm->height & 16));

	draw_box(ppm, 0, 0, ppm->width - 1, ppm->height - 1, &black);

	for (x = 0; x < ppm->width; x += 16)
		draw_vline(ppm, x, 0, ppm->height - 1, &darkgrey);

	for (y = 0; y < ppm->height; y += 16)
		draw_hline(ppm, 0, ppm->width - 1, y, &darkgrey);

	for (x = 0; x < 256; ++x) {
		ppm_size_t ly = ppm->height - (data->luminance[x] * ppm->height) / data->max_luminance;

		if (ly == ppm->height)
			continue;

		while (ly <= ppm->height - 1) {
			PPM_PIXEL(ppm, x, ly) = memcmp(&PPM_PIXEL(ppm, x, ly), &black, sizeof(black)) ? lightgrey : white;
			++ly;
		}
	}
}

int main(int ac, char * const av[])
{
	ppm_t *ppm;
	data_t data;

	// args ignored
	ac = 0;
	av = NULL;

	ppm = ppm_load(NULL);
	if (!ppm) {
		fprintf(stderr, "Error reading input stream\n");
		return EXIT_FAILURE;
	}

	calculate(&data, ppm);
	ppm_free(ppm);

	ppm = ppm_alloc(256, 192);
	if (!ppm) {
		fprintf(stderr, "Error creating intermediate buffer\n");
		return EXIT_FAILURE;
	}

	histogram(&data, ppm);

	if (ppm_save(ppm, NULL) == -1) {
		fprintf(stderr, "Error writing output stream\n");
		return EXIT_FAILURE;
	}

	ppm_free(ppm);

	return EXIT_SUCCESS;
}
