/*
 * Copyright (C)2011 D. R. Commander.  All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * - Neither the name of the libjpeg-turbo Project nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <string.h>
#include <setjmp.h>
#include <errno.h>
#include "cdjpeg.h"
#include <jpeglib.h>
#include <jpegint.h>
#include "tjutil.h"
#include "bmp.h"


/* This duplicates the functionality of the VirtualGL bitmap library using
   the components from cjpeg and djpeg */


/* Error handling (based on example in example.c) */

static char errStr[JMSG_LENGTH_MAX]="No error";

struct my_error_mgr
{
	struct jpeg_error_mgr pub;
	jmp_buf setjmp_buffer;
};
typedef struct my_error_mgr *my_error_ptr;

static void my_error_exit(j_common_ptr cinfo)
{
	my_error_ptr myerr=(my_error_ptr)cinfo->err;
	(*cinfo->err->output_message)(cinfo);
	longjmp(myerr->setjmp_buffer, 1);
}

/* Based on output_message() in jerror.c */

static void my_output_message(j_common_ptr cinfo)
{
	(*cinfo->err->format_message)(cinfo, errStr);
}

#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m);  \
	retval=-1;  goto bailout;}
#define _throwunix(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s\n%s", m,  \
	strerror(errno));  retval=-1;  goto bailout;}


static void pixelconvert(unsigned char *srcbuf, int srcpf, int srcbottomup,
	unsigned char *dstbuf, int dstpf, int dstbottomup, int w, int h)
{
	unsigned char *srcptr=srcbuf, *srcptr2;
	int srcps=tjPixelSize[srcpf];
	int srcstride=srcbottomup? -w*srcps:w*srcps;
	unsigned char *dstptr=dstbuf, *dstptr2;
	int dstps=tjPixelSize[dstpf];
	int dststride=dstbottomup? -w*dstps:w*dstps;
	int row, col;

	if(srcbottomup) srcptr=&srcbuf[w*srcps*(h-1)];
	if(dstbottomup) dstptr=&dstbuf[w*dstps*(h-1)];
	for(row=0; row<h; row++, srcptr+=srcstride, dstptr+=dststride)
	{
		for(col=0, srcptr2=srcptr, dstptr2=dstptr; col<w; col++, srcptr2+=srcps,
			dstptr2+=dstps)
		{
			dstptr2[tjRedOffset[dstpf]]=srcptr2[tjRedOffset[srcpf]];
			dstptr2[tjGreenOffset[dstpf]]=srcptr2[tjGreenOffset[srcpf]];
			dstptr2[tjBlueOffset[dstpf]]=srcptr2[tjBlueOffset[srcpf]];
		}
	}
}


int loadbmp(char *filename, unsigned char **buf, int *w, int *h, 
	int dstpf, int bottomup)
{
	int retval=0, dstps, srcpf, tempc;
	struct jpeg_compress_struct cinfo;
	struct my_error_mgr jerr;
	cjpeg_source_ptr src;
	FILE *file=NULL;

	if(!filename || !buf || !w || !h || dstpf<0 || dstpf>=TJ_NUMPF)
		_throw("loadbmp(): Invalid argument");

	if((file=fopen(filename, "rb"))==NULL)
		_throwunix("loadbmp(): Cannot open input file");

	cinfo.err=jpeg_std_error(&jerr.pub);
	jerr.pub.error_exit=my_error_exit;
	jerr.pub.output_message=my_output_message;

	if(setjmp(jerr.setjmp_buffer))
	{
		/* If we get here, the JPEG code has signaled an error. */
		retval=-1;  goto bailout;
	}

	jpeg_create_compress(&cinfo);
	if((tempc=getc(file))<0 || ungetc(tempc, file)==EOF)
		_throwunix("loadbmp(): Could not read input file")
	else if(tempc==EOF) _throw("loadbmp(): Input file contains no data");

	if(tempc=='B')
	{
		if((src=jinit_read_bmp(&cinfo))==NULL)
			_throw("loadbmp(): Could not initialize bitmap loader");
	}
	else if(tempc=='P')
	{
		if((src=jinit_read_ppm(&cinfo))==NULL)
			_throw("loadbmp(): Could not initialize bitmap loader");
	}
	else _throw("loadbmp(): Unsupported file type");

	src->input_file=file;
	(*src->start_input)(&cinfo, src);
	(*cinfo.mem->realize_virt_arrays)((j_common_ptr)&cinfo);

	*w=cinfo.image_width;  *h=cinfo.image_height;

	if(cinfo.input_components==1 && cinfo.in_color_space==JCS_RGB)
		srcpf=TJPF_GRAY;
	else srcpf=TJPF_RGB;

	dstps=tjPixelSize[dstpf];
	if((*buf=(unsigned char *)malloc((*w)*(*h)*dstps))==NULL)
		_throw("loadbmp(): Memory allocation failure");

	while(cinfo.next_scanline<cinfo.image_height)
	{
		int i, nlines=(*src->get_pixel_rows)(&cinfo, src);
		for(i=0; i<nlines; i++)
		{
			unsigned char *outbuf;  int row;
			row=cinfo.next_scanline+i;
			if(bottomup) outbuf=&(*buf)[((*h)-row-1)*(*w)*dstps];
			else outbuf=&(*buf)[row*(*w)*dstps];
			pixelconvert(src->buffer[i], srcpf, 0, outbuf, dstpf, bottomup, *w,
				nlines);
		}
		cinfo.next_scanline+=nlines;
  }

	(*src->finish_input)(&cinfo, src);

	bailout:
	jpeg_destroy_compress(&cinfo);
	if(file) fclose(file);
	if(retval<0 && buf && *buf) {free(*buf);  *buf=NULL;}
	return retval;
}


int savebmp(char *filename, unsigned char *buf, int w, int h, int srcpf,
	int bottomup)
{
	int retval=0, srcps, dstpf;
	struct jpeg_decompress_struct dinfo;
	struct my_error_mgr jerr;
	djpeg_dest_ptr dst;
	FILE *file=NULL;
	char *ptr=NULL;

	if(!filename || !buf || w<1 || h<1 || srcpf<0 || srcpf>=TJ_NUMPF)
		_throw("savebmp(): Invalid argument");

	if((file=fopen(filename, "wb"))==NULL)
		_throwunix("savebmp(): Cannot open output file");

	dinfo.err=jpeg_std_error(&jerr.pub);
	jerr.pub.error_exit=my_error_exit;
	jerr.pub.output_message=my_output_message;

	if(setjmp(jerr.setjmp_buffer))
	{
		/* If we get here, the JPEG code has signaled an error. */
		retval=-1;  goto bailout;
	}

	jpeg_create_decompress(&dinfo);
	if(srcpf==TJPF_GRAY)
	{
		dinfo.out_color_components=dinfo.output_components=1;
		dinfo.out_color_space=JCS_GRAYSCALE;
	}
	else
	{
		dinfo.out_color_components=dinfo.output_components=3;
		dinfo.out_color_space=JCS_RGB;
	}
	dinfo.image_width=w;  dinfo.image_height=h;
	dinfo.global_state=DSTATE_READY;
	dinfo.scale_num=dinfo.scale_denom=1;

	ptr=strrchr(filename, '.');
	if(ptr && !strcasecmp(ptr, ".bmp"))
	{
		if((dst=jinit_write_bmp(&dinfo, 0))==NULL)
			_throw("savebmp(): Could not initialize bitmap writer");
	}
	else
	{
		if((dst=jinit_write_ppm(&dinfo))==NULL)
			_throw("savebmp(): Could not initialize PPM writer");
	}

  dst->output_file=file;
	(*dst->start_output)(&dinfo, dst);
	(*dinfo.mem->realize_virt_arrays)((j_common_ptr)&dinfo);

	if(srcpf==TJPF_GRAY) dstpf=srcpf;
	else dstpf=TJPF_RGB;
	srcps=tjPixelSize[srcpf];

	while(dinfo.output_scanline<dinfo.output_height)
	{
		int i, nlines=dst->buffer_height;
		for(i=0; i<nlines; i++)
		{
			unsigned char *inbuf;  int row;
			row=dinfo.output_scanline+i;
			if(bottomup) inbuf=&buf[(h-row-1)*w*srcps];
			else inbuf=&buf[row*w*srcps];
			pixelconvert(inbuf, srcpf, bottomup, dst->buffer[i], dstpf, 0, w,
				nlines);
		}
		(*dst->put_pixel_rows)(&dinfo, dst, nlines);
		dinfo.output_scanline+=nlines;
  }

	(*dst->finish_output)(&dinfo, dst);

	bailout:
	jpeg_destroy_decompress(&dinfo);
	if(file) fclose(file);
	return retval;
}

const char *bmpgeterr(void)
{
	return errStr;
}
