// This file has been completely rewritten

#include "jinclude.h"

#ifndef RENDER
#ifndef TSMORPH_H
#include "/TSMorph.h"
#endif
#else
/* recognized file formats */
extern UWORD FileFormat;
#define FORMAT_IFF	1
#define FORMAT_JPEG	2
#define FORMAT_GIF	3
#define FORMAT_PPM	4
#define FORMAT_TARGA	5
#include <intuition/intuition.h>
#include <proto/gadtools.h>
#include "/progress.h"
void AddMessage(UBYTE *message);
#endif

#include <proto/exec.h>

#include <setjmp.h>

static jmp_buf setjmp_buffer;	/* for return to caller */

static struct External_methods_struct e_methods;
static struct Decompress_info_struct cinfo;
static struct Decompress_methods_struct dc_methods;

extern UBYTE *r1=NULL,*g1=NULL,*b1=NULL;

METHODDEF void
progress_monitor (decompress_info_ptr cinfo, long loopcounter, long looplimit)
{
#ifndef RENDER
	if (ProgressWnd) {
      GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass2],ProgressWnd,NULL,
  	  							GTSL_Level,(ULONG)loopcounter,
  	  							GTSL_Max,(ULONG)looplimit-1,
  	  							TAG_END);
      GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass1],ProgressWnd,NULL,
  	  							GTSL_Level,(ULONG)cinfo->completed_passes+1,
  	  							GTSL_Max,(ULONG)cinfo->total_passes +
  	  										 (cinfo->quantize_colors?0:1),
  	  							TAG_END);
		HandleProgressIDCMP();
	}
#endif
}

METHODDEF void
trace_message(const char *msgtext)
{
	char text[512];
	sprintf(text,msgtext,e_methods.message_parm[0],e_methods.message_parm[1],e_methods.message_parm[2],
				e_methods.message_parm[3],e_methods.message_parm[4],e_methods.message_parm[5],
				e_methods.message_parm[6],e_methods.message_parm[7]);
#ifndef RENDER
	if (ProgressWnd) {
  	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
	 						 GTTX_Text,(ULONG)text,
							 TAG_END);
		HandleProgressIDCMP();
	}
#else
	AddMessage(text);
#endif
}

METHODDEF void
error_exit (const char *msgtext)
{
  (*e_methods.free_all) ();	/* clean up memory allocation & temp files */
  longjmp(setjmp_buffer, 1);	/* return control to outer routine */
}

/*
 * This routine gets control after the input file header has been read.
 * It must determine what output file format is to be written,
 * and make any other decompression parameter changes that are desirable.
 */

METHODDEF void
d_ui_method_selection (decompress_info_ptr cinfo)
{
}

static BOOL
LoadOther(UBYTE **p) {
	UBYTE *pixel_row[3];
	UWORD i;
	if (FileFormat == FORMAT_GIF) {
		jselrgif(&cinfo);
	}
	else {
		if (FileFormat == FORMAT_PPM) {
			jselrppm(&cinfo);
		}
		else {
			jselrtarga(&cinfo);
		}
	}
#ifndef RENDER
	if (ProgressWnd) {
      GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass1],ProgressWnd,NULL,
  	  							GTSL_Level,1,
  	  							GTSL_Max,2,
  	  							TAG_END);
		HandleProgressIDCMP();
	}
#endif
	(*cinfo.methods->input_init)(&cinfo);
#ifndef RENDER
	if (ProgressWnd) {
      GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass2],ProgressWnd,NULL,
  	  							GTSL_Level,0,
  	  							GTSL_Max,cinfo.image_height-1,
  	  							TAG_END);
		HandleProgressIDCMP();
	}
#endif
  if (!cinfo.quantize_colors) {
    if (cinfo.output_file = (BPTR)AllocVec((((cinfo.image_width+15)>>4)<<4) * cinfo.image_height * 3,NULL)) {
      pixel_row[0] = (UBYTE *)cinfo.output_file;
      pixel_row[1] = pixel_row[0] + (((cinfo.image_width+15)>>4)<<4) * cinfo.image_height;
      pixel_row[2] = pixel_row[1] + (((cinfo.image_width+15)>>4)<<4) * cinfo.image_height;
    }
    else {
    	return FALSE;
    }
  }
  else {
	if (p[0] = AllocVec((((cinfo.image_width+15)>>4)<<4)*cinfo.image_height*3,0)) {
      p[1] = p[0] + (((cinfo.image_width+15)>>4)<<4)*cinfo.image_height;
      p[2] = p[1] + (((cinfo.image_width+15)>>4)<<4)*cinfo.image_height;
      pixel_row[0] = p[0];
      pixel_row[1] = p[1];
      pixel_row[2] = p[2];
    }
    else {
      return FALSE;
    }
  }
 	for (i = 0;
 		  i < cinfo.image_height;
 		  i++) {
#ifndef RENDER
			if (ProgressWnd) {
		      GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass2],ProgressWnd,NULL,
		  	  							GTSL_Level,i,
  	  									TAG_END);
				HandleProgressIDCMP();
			}
#endif
			(*cinfo.methods->get_input_row)(&cinfo,pixel_row);
			pixel_row[0] += (((cinfo.image_width+15)>>4)<<4);
			pixel_row[1] += (((cinfo.image_width+15)>>4)<<4);
			pixel_row[2] += (((cinfo.image_width+15)>>4)<<4);
	}
	(*cinfo.methods->input_term)(&cinfo);
#ifndef RENDER
	if (ProgressWnd) {
      GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass1],ProgressWnd,NULL,
  	  							GTSL_Level,2,
  	  							TAG_END);
		HandleProgressIDCMP();
	}
#endif
	return TRUE;
}

extern decompress_info_ptr
LoadJPEG(char *filename,UWORD colors,UBYTE *r,UBYTE *g,UBYTE *b,UBYTE **p) {

  r1=r;
  g1=g;
  b1=b;

  if (!(cinfo.input_file = Open(filename,MODE_OLDFILE))) {
    return NULL;
  }

  cinfo.out_color_space = CS_RGB;

  cinfo.output_file = NULL;

  cinfo.methods = &dc_methods;
  cinfo.emethods = &e_methods;

  jselwmem(&cinfo);

  e_methods.error_exit = error_exit; /* supply error-exit routine */
  e_methods.trace_message = trace_message; /* supply trace-message routine */
  e_methods.trace_level = 1;	/* default = no tracing */
  e_methods.num_warnings = 0;	/* no warnings emitted yet */
  e_methods.first_warning_level = 0; /* display first corrupt-data warning */
  e_methods.more_warning_level = 3; /* but suppress additional ones */

  if (setjmp(setjmp_buffer)) {
    Close(cinfo.input_file);
    if (cinfo.output_file) {
      FreeVec((void *)cinfo.output_file);
      cinfo.output_file = NULL;
    }
    if (p) {
	  if (p[0]) {
		FreeVec(p[0]);
		p[0] = NULL;
	  }
     p[1] = NULL;
	  p[2] = NULL;
	 }
    return NULL;
  }

  jselmemmgr(cinfo.emethods);	/* memory allocation routines */

  cinfo.methods->d_ui_method_selection = d_ui_method_selection;

  j_d_defaults(&cinfo, TRUE);

  jselrjfif(&cinfo);

  if (colors) {
    cinfo.desired_number_of_colors = colors;
    cinfo.quantize_colors = TRUE;
  }
  else {
    cinfo.quantize_colors = FALSE;
  }
  cinfo.use_dithering = FALSE;
  cinfo.two_pass_quantize = FALSE;
  cinfo.methods->progress_monitor = progress_monitor;

  /* Here we go! */
  if (FileFormat == FORMAT_JPEG) {
	  jpeg_decompress(&cinfo);
#ifndef RENDER
	  if (!colors) {
	      GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass1],ProgressWnd,NULL,
  	  							GTSL_Level,(ULONG)cinfo.total_passes + 1,
  	  							TAG_END);
  	  	}
#endif
  }
  else {
     if (!LoadOther(p)) {
		  (*e_methods.free_all) ();	/* clean up memory allocation & temp files */
		  Close(cinfo.input_file);
		  if (cinfo.output_file) {
		    FreeVec((void *)cinfo.output_file);
		    cinfo.output_file = NULL;
		  }
		  if (p) {
  		    if (p[0]) {
  			  	FreeVec(p[0]);
				p[0] = NULL;
		    }
			 p[1] = NULL;
			 p[2] = NULL;
		  }
		  return NULL;
     }
  }

  (*e_methods.free_all) ();	/* clean up memory allocation & temp files */
  Close(cinfo.input_file);

  return &cinfo;
}
