/**
 * \file ppm.c
 * \brief A reimplemented reader for PPM files
 *
 *  \date Apr 21, 2009
 *  \author Alexander Pimenov
 *
 *  Based on
 *      Author : Anthoniraj.A
 *      Date   : 24/03/2009
 */
#include "global.h"

#include <stdio.h>
#include <stdlib.h>

#include "ppm.h"
#include "g12buffer.h"



G12Buffer* g12BufferCreateFromPPM (char *PPMname)
{
	FILE* fp;

	//PGM Headers Variable Declaration
	int i, j;
	long int h, w;
	unsigned short int maxval;

	char header[100];

	//Open file for Reading in Binary Mode
	fp = fopen(PPMname, "rb");


	if (fp == NULL) {
		printf("Image %s does not exist \n", PPMname);
		return NULL;
	}

	//Check the PGM file Type P2 or P5
	fgets(header, 100, fp);
	if ((header[0] != 'P') || (header[1] != '5')) {
		printf("Image is not a supported PGM\n");
		return NULL;
	}

	int isComment = 1;
	//Check the Comments and empty lines
	do {
		fgets(header, 100, fp);
		if (header[0] == '#')
			continue;
		char *runner = header;
		while (*runner != 0)
		{
			if (!(*runner == ' ' || *runner == '\n' || *runner == '\r' || *runner == '\t'))
			{
				isComment = 0;
				break;
			}
			runner++;
		}
	} while (isComment);

	if (sscanf(header, "%lu %lu", &w, &h) != 2)
	{
		printf("Image dimensions could not be read form line %s\n", header);
		return NULL;
	}
	fgets(header, 100, fp);
	if (sscanf(header, "%hu", &maxval) != 1)
	{
		printf("Image metric could not be read form line %s\n", header);
		return NULL;
	}

#ifdef TRACE
	printf("Image %s is P5 PPM [%lu %lu] max=%u\n", PPMname, h, w, maxval);
#endif



	G12Buffer *toReturn = g12BufferCreate(h, w);

	if (maxval < 255)
	{
		uint8_t *charImage = (uint8_t *) malloc(w * h * sizeof(uint8_t));
		fread(charImage, 1, (w * h) * sizeof(uint8_t), fp);

		for (i = 0; i < h; i++)
			for (j = 0; j < w; j++)
				toReturn->data[i * w + j] = (charImage[i * w + j]) << 4;
		free(charImage);
	}
	else
	{
		int shiftCount;
		for (shiftCount = 0; (maxval >> shiftCount) > G12BUFFER_MAX_VALUE; shiftCount++);

		uint8_t *charImage = (uint8_t *) dv_malloc(w * h * sizeof(uint8_t) * 2);
		fread(charImage, 1, (w * h) * sizeof(uint8_t) * 2, fp);

		for (i = 0; i < h; i++)
			for (j = 0; j < w; j++)
			{
				int offset = i * w + j;
				toReturn->data[offset] = ((charImage[offset * 2]    ) << 8 |
				                         (charImage[offset * 2 + 1])) >> shiftCount;

#ifdef ASSERTS
				if (toReturn->data[offset] >= (1 << 16))
					DOASSERT("INTERNAL ERROR IN IMAGE LOADER\n");
#endif

				/*toReturn->data[offset] = (charImage[offset * 2]    )  |
				                         (charImage[offset * 2 + 1]) << 8;*/

			}
		dv_free(charImage);
	}


	fclose(fp);

	return toReturn;
}

G12Buffer* g12BufferCreateFromPPM6 (char *PPMname)
{
	FILE* fp;

	//PGM Headers Variable Declaration
	int i, j;
	long int h, w;
	unsigned short int maxval;

	char header[100];

	//Open file for Reading in Binary Mode
	fp = fopen(PPMname, "rb");


	if (fp == NULL) {
		printf("Image %s does not exist \n", PPMname);
		return NULL;
	}

	//Check the PGM file Type P2 or P5
	fgets(header, 100, fp);
	if ((header[0] != 'P') || (header[1] != '6')) {
		printf("Image is not a supported PGM\n");
		return NULL;
	}

	//Check the Commnets
	fgets(header, 100, fp);
	while (header[0] == '#') {
		//printf("%c\n", header[0]);
		fgets(header, 100, fp);
	}

	if (sscanf(header, "%lu %lu", &w, &h) != 2)
	{
		printf("Image dimensions could not be read form line %s\n", header);
		return NULL;
	}
	fgets(header, 100, fp);
	if (sscanf(header, "%hu", &maxval) != 1)
	{
		printf("Image metric could not be read form line %s\n", header);
		return NULL;
	}

#ifdef TRACE
	printf("Image %s is P6 PPM [%lu %lu] max=%u\n", PPMname, h, w, maxval);
#endif



	G12Buffer *toReturn = g12BufferCreate(h, w);

	if (maxval < 255)
	{
		uint8_t *charImage = (uint8_t *) dv_malloc(w * h * sizeof(uint8_t));
		fread(charImage, 1, (w * h) * sizeof(uint8_t), fp);

		for (i = 0; i < h; i++)
			for (j = 0; j < w; j++)
			{
				toReturn->data[i * w + j] = (charImage[i * w + j]) << 4;
			}
		dv_free(charImage);
	}
	else
	{
		uint8_t *charImage = (uint8_t *) dv_malloc(w * h * sizeof(uint8_t) * 2);
		fread(charImage, 1, (w * h) * sizeof(uint8_t) * 2, fp);

		for (i = 0; i < h; i++)
			for (j = 0; j < w; j++)
			{
				int offset = i * w + j;
				toReturn->data[offset] = (charImage[offset * 2]    ) << 8 |
				                         (charImage[offset * 2 + 1]);
			}
		dv_free(charImage);
	}


	fclose(fp);

	return toReturn;
}

int g12BufferSaveAsPPM(G12Buffer *buffer, char *PPMname)
{
	int h = buffer->h;
	int w = buffer->w;

	if (buffer == NULL)
		return -1;

	FILE *fp;
	fp = fopen(PPMname, "wb");

	if (fp == NULL) {
		printf("Image %s could not be written \n", PPMname);
		return -1;
	}

	fprintf(fp, "P5\n");
	fprintf(fp, "############################################\n");
    fprintf(fp, "# This file is written by DeepView library.\n");
    fprintf(fp, "# \n");
    fprintf(fp, "# The original souce buffer had 12 bit.\n");

    ///\todo TODO: Add some metadata saving

    fprintf(fp, "############################################\n");
    fprintf(fp, "%d %d\n", w, h);
    fprintf(fp, "%d\n", G12BUFFER_MAX_VALUE);

	uint8_t *charImage = (uint8_t *) dv_malloc(w * h * sizeof(uint8_t) * 2);
	int i,j;
	for (i = 0; i < h; i++)
		for (j = 0; j < w; j++)
		{
			int offset = i * w + j;
			charImage[offset * 2] = (buffer->data[offset] >> 8) & 0xFF;
			charImage[offset * 2 + 1] = (buffer->data[offset] & 0xFF);
		}
	fwrite(charImage, 2, h * w, fp);
	dv_free(charImage);
	fclose(fp);
	return 0;
}


