#include <stdio.h>
#include "colorthread.h"
#include "huethread.h"
#include "intensitythread.h"
#include "tpool.h"
#include "image.h"
#include "systime.h"
#include "workunit.h"
#include "global.h"
#include <errno.h>

color_t * color_thread_init(CvSize size)
{
	color_t *color;

	color = malloc(sizeof(color_t));
	if (errno == ENOMEM)
	{
		fprintf(stderr, "ENOMEM failure allocating a color_t structure " \
				"in the function color_thread_init.\n");
		return NULL;
	}

	if ((color->intensity = cvCreateImage(size, IPL_DEPTH_32F, 1)) == NULL)
	{
		fprintf(stderr, "cvCreateImage failure allocating memory for " \
				"intensity in the function color_thread_init.\n");
		return NULL;
	}

	if ((color->r_temp_8u = cvCreateImage(size, IPL_DEPTH_8U, 1)) == NULL)
	{
		fprintf(stderr, "cvCreateImage failure allocating memory for " \
				"r_temp_8u in the function color_thread_init.\n");
		return NULL;
	}

	if ((color->g_temp_8u = cvCreateImage(size, IPL_DEPTH_8U, 1)) == NULL)
	{
		fprintf(stderr, "cvCreateImage failure allocating memory for " \
				"g_temp_8u in the function color_thread_init.\n");
		return NULL;
	}

	if ((color->b_temp_8u = cvCreateImage(size, IPL_DEPTH_8U, 1)) == NULL)
	{
		fprintf(stderr, "cvCreateImage failure allocating memory for " \
				"b_temp_8u in the function color_thread_init.\n");
		return NULL;
	}

	// Temporary rgb buffers for computation.
	if ((color->r_temp = cvCreateImage(size, IPL_DEPTH_32F, 1)) == NULL)
	{
		fprintf(stderr, "cvCreateImage failure allocating memory for " \
				"r_temp in the function color_thread_init.\n");
		return NULL;
	}

	if ((color->g_temp = cvCreateImage(size, IPL_DEPTH_32F, 1)) == NULL)
	{
		fprintf(stderr, "cvCreateImage failure allocating memory for " \
				"g_temp in the function color_thread_init.\n");
		return NULL;
	}

	if ((color->b_temp = cvCreateImage(size, IPL_DEPTH_32F, 1)) == NULL)
	{
		fprintf(stderr, "cvCreateImage failure allocating memory for " \
				"b_temp in the function color_thread_init.\n");
		return NULL;
	}

	if ((color->y_temp = cvCreateImage(size, IPL_DEPTH_32F, 1)) == NULL)
	{
		fprintf(stderr, "cvCreateImage failure allocating memory for " \
				"y_temp in the function color_thread_init.\n");
		return NULL;
	}

	if ((color->temp1 = cvCreateImage(size, IPL_DEPTH_32F, 1)) == NULL)
	{
		fprintf(stderr, "cvCreateImage failure allocating memory for " \
				"temp1 in the function color_thread_init.\n");
		return NULL;
	}

	if ((color->temp2 = cvCreateImage(size, IPL_DEPTH_32F, 1)) == NULL)
	{
		fprintf(stderr, "cvCreateImage failure allocating memory for " \
				"temp2 in the function color_thread_init.\n");
		return NULL;
	}

	if ((color->three = cvCreateImage(size, IPL_DEPTH_32F, 1)) == NULL)
	{
		fprintf(stderr, "cvCreateImage failure allocating memory for " \
				"three in the function color_thread_init.\n");
		return NULL;
	}

	cvSet(color->three, cvRealScalar(3), 0);

	return color;
}

void color_thread_destroy(color_t *color)
{
	// All good girls and boys clean up their mess.
	cvReleaseImage(&color->intensity);
	cvReleaseImage(&color->r_temp_8u);
	cvReleaseImage(&color->g_temp_8u);
	cvReleaseImage(&color->b_temp_8u);
	cvReleaseImage(&color->r_temp);
	cvReleaseImage(&color->g_temp);
	cvReleaseImage(&color->b_temp);
	cvReleaseImage(&color->y_temp);
	cvReleaseImage(&color->temp1);
	cvReleaseImage(&color->temp2);
	cvReleaseImage(&color->three);

	free(color);
	color = NULL;
}

void * color_thread_routine(void *args)
{
	work_t *work = (work_t *)args;
	color_t *obj = work->color;

	// Extract red, green, and blue channels from the image
	// into the temporary image buffers.  The image is saved
	// in BGR and not RGB.  This is very important!
	cvCvtPixToPlane(work->image, obj->b_temp_8u, obj->g_temp_8u,
					obj->r_temp_8u, NULL);

//	cvSaveImage("red_channel.jpg", obj->r_temp_8u);
//	cvSaveImage("green_channel.jpg", obj->g_temp_8u);
//	cvSaveImage("blue_channel.jpg", obj->b_temp_8u);

	// Extract red, green, and blue channels from the image
	// Convert 8-bit integer colors to 32-bit float values.
	// Using 8-bit integer values results in errors due to
	// rounding and overflow.
	cvConvertScale(obj->r_temp_8u, obj->r_temp, 1, 0);
	cvConvertScale(obj->g_temp_8u, obj->g_temp, 1, 0);
	cvConvertScale(obj->b_temp_8u, obj->b_temp, 1, 0);

	// Compute the image luminance (intensity)
	// at each point in the image matrix.

	cvAdd(obj->r_temp, obj->g_temp, obj->temp1, 0);		// r + g
	cvAdd(obj->b_temp, obj->temp1, obj->temp2, 0);		// r + g + b
	cvDiv(obj->temp2, obj->three, obj->intensity, 1);	// (r + g + b)/3

	work->hue->intensity_plane = obj->intensity;
	work->hue->red_channel = obj->r_temp;
	work->hue->green_channel = obj->g_temp;
	work->hue->blue_channel = obj->b_temp;
	work->hue->yellow_channel = obj->y_temp;

	hue_thread_routine(work);

	work->intensity->intensity_plane = obj->intensity;

	save_scaled("intensity.jpg", obj->intensity);

	intensity_thread_routine(work);

	return NULL;
}

