/**
 * \file integral.c
 * \brief This file contains the implementation of the Integral Buffer creation, deletion and manipulation
 *
 *
 *  Created on: Apr 14, 2009
 *      Author: Alexander Pimenov
 *
 *
 *
 */

#include <stdlib.h>
#include "g12buffer.h"
#include "integral.h"
#include "global.h"

#ifdef ASSERTS
#include <stdio.h>
#endif

#ifdef ASSERTS
static int integralBufferCounter = 0;
#endif

/**
 * \brief This function creates an integral buffer
 *
 * This function creates a 32 bit depth buffer. This should be enough for the planned
 * 1024*512 * 12bit grayscale image. On exit this method returns a buffer filled with 0es
 *
 *  You should not forget to destroy the created buffer with the call to integralBufferDelete(toDelete)
 *
 *
 * \param h The height of the buffer to be created.
 * \param w The width of the buffer to be created.
 *
 * \return a newly created buffer
 *
 *
 *
 */
integralBuffer *integralBufferCreate(int h, int w)
{
	integralBuffer *toReturn = (integralBuffer *) dv_malloc (sizeof (integralBuffer));
	toReturn->h = h;
	toReturn->w = w;
	toReturn->data = (uint32_t *) dv_calloc(h * w , sizeof(uint32_t));

#ifdef ASSERTS
	integralBufferCounter++;
#endif

	return toReturn;
}

/**
 * \brief This function deletes an integral buffer.
 *
 * \attention It is not allowed to delete the same buffer twice.
 *
 * \param toDelete the buffer to be deleted
 */
void integralBufferDelete(integralBuffer *toDelete)
{
	if (toDelete->data != NULL)
		dv_free(toDelete->data);
	dv_free(toDelete);


#ifdef ASSERTS
	integralBufferCounter--;
#endif

}

/**
 *  \brief This function creates an integral buffer from a 12bit greyscale buffer
 *
 *  This function returns a new integral buffer
 *
 *  \param src  a buffer to create an integral image for.
 *  \return a new integral buffer
 */
integralBuffer *integralBufferCreateFromG12(G12Buffer *src)
{
	integralBuffer *toReturn = integralBufferCreate(src->h, src->w);
	uint32_t sum = 0;
	int h = toReturn->h;
	int w = toReturn->w;

	int i,j;
	// Scan the first line
	for (j = 0; j < w; j++)
	{
		sum += src->data[j];
		toReturn->data[j] = sum;
	}

	// Scan all the picture
	for (i = 1; i < h; i++)
	{
		sum = 0;
		for (j = 0; j < w; j ++)
		{
#ifdef ASSERTS
			uint32_t test_sum = sum + src->data[i * w + j];
			if (test_sum < sum || test_sum < src->data[i * w + j])
			{
				DOASSERT("Overflow while creating the integral buffer");
			}
#endif
			sum += src->data[i * w + j];
			toReturn->data[i * w + j] = sum + toReturn->data[((i-1) * w) + j];
		}
	}
	return toReturn;
}

/**
 *
 * This function returns a sum of the values of the greyscale buffer over the rectangle.
 * This is done by only 4 accesses using integral buffer
 *
 */
uint32_t getRectangleValue(integralBuffer *buf, int y1, int x1, int y2, int x2)
{
	return  buf->data[y1 * buf->w + x1] + buf->data[y2 * buf->w + x2]
	      - buf->data[y1 * buf->w + x2] - buf->data[y2 * buf->w + x1];
}

