#pragma once

#include "jpeglib\jpeglib.h"

struct FileHeader
{
	int w,h,numframes;	
};


/////////////////////////////////

struct BSMFile : public FileHeader
{
	int fps;
	int curframe;
	int loaded;
	int *frameofs;
	unsigned char *framebuf;
	
	
#ifdef USEDJPEG
	Pjpeg_decoder_file_stream f;
	Pjpeg_decoder Pd;
	int firsttime;
#else
	int *Pd;
	FILE *f;
	int greyscale;
	
	struct jpeg_error_mgr ijerr;
	struct jpeg_decompress_struct icinfo;
	JSAMPARRAY buffer;		/* Output row buffer */
	int row_stride;		/* physical row width in output buffer */
#endif
	
	BSMFile(int gs)
	{
		greyscale=gs;
		f=NULL;
		Pd=NULL;
		loaded=0;
		framebuf=NULL;
		frameofs=NULL;
		Close();
	}
	
	void Close()
	{
#ifdef USEDJPEG
		delete f;
#else
		if(f)fclose(f);
#endif
		f=NULL;
		delete Pd;
		Pd=NULL;
		delete [] frameofs;
		delete [] framebuf;
		framebuf=NULL;
		frameofs=NULL;
		numframes=0;
		w=h=0;
		fps=25;
		curframe=-1;
		if (loaded)
		{
			/* This is an important step since it will release a good deal of memory. */
#ifndef USEDJPEG
			
			jpeg_destroy_decompress(&icinfo);
#endif
			loaded=0;
			
		}
	}
	
	~BSMFile()
	{
		Close();
	}
	
	int Open(char *fname)
	{
		Close();
		FILE *fo;
		fo=fopen(fname,"rb");
		if (!fo) return -1;
		fread(&w,1,sizeof(FileHeader),fo);
		frameofs=new int[numframes];
		framebuf=new unsigned char[w*h*3];
		
		fread(frameofs,4,numframes,fo);
		int filestart=ftell(fo);
		
		loaded=1;
#ifdef USEDJPEG
		f= new jpeg_decoder_file_stream();
		if (f->open(fname,filestart))
		{
			delete f;
			f=NULL;
			Report3D("failed to open jpeg file\n");
		}
		if (f)
		{
			Pd = new jpeg_decoder(f, false);
			if (Pd->get_error_code() != 0)
			{
				delete Pd;
				delete f;
				Report3D("failed to open decoder\n");
			}
			if (Pd)
			{
				
				Report3D("Width: %i\n", Pd->get_width());
				Report3D("Height: %i\n", Pd->get_height());
				Report3D("Components: %i\n", Pd->get_num_components());
				//empty_mmx();
				firsttime=1;
				ReadFrame(0); // just to get the tables going!!
				
				
			}
		}
#else
		f=fo;
		icinfo.err = jpeg_std_error(&ijerr);
		jpeg_create_decompress(&icinfo);
		jpeg_stdio_src(&icinfo, f);
		(void) jpeg_read_header(&icinfo, FALSE);

		
#endif
		return 0;
	}
	
	void ReadFrame(int frame)
	{
		if (loaded && framebuf && numframes)
		{
			if (frame==curframe) return;
			frame%=numframes;if (frame<0) frame+=numframes;
			
#ifdef USEDJPEG
			
			if (f && Pd)
			{
				if (!firsttime)
				{
					Pd->ready_flag=0;
					Pd->locate_sof_marker();
				}
				else firsttime=0;
				if (Pd->begin())
				{
					delete Pd;
					delete f;
					Report3D("failed to begin decoder\n");
				}
				else
				{
					
					//if (firsttime)
					{
					
						int lines_decoded = 0;
						
						for ( ;lines_decoded<height ; )
						{
							void *Pscan_line_ofs;
							uint scan_line_len;
							
							if (Pd->decode(&Pscan_line_ofs, &scan_line_len))
								break;
							memcpy(framebuf+lines_decoded*width*3,Pscan_line_ofs,width*3);
							lines_decoded++;
						}
					}						
					
					
				}
			}
			
			
#else
			if (frame!=curframe+1)
			{
				fseek(f,frameofs[frame],SEEK_SET);
				//((my_src_ptr)cinfo.src)->pub.next_input_byte = NULL;
				((my_src_ptr)icinfo.src)->pub.bytes_in_buffer = 0;
				//((my_src_ptr)acinfo.src)->pub.bytes_in_buffer = 0;
			}	
			
			int ml = greyscale ? 1 : 3;

			(void) jpeg_read_header(&icinfo, TRUE);
			(void) jpeg_start_decompress(&icinfo);
			/* Make a one-row-high sample array that will go away when done with image */
			row_stride=w*ml;
			buffer = (*icinfo.mem->alloc_sarray)
				((j_common_ptr) &icinfo, JPOOL_IMAGE, row_stride, 1);
			
			int y=0;
			while (icinfo.output_scanline < icinfo.output_height) {
				(void) jpeg_read_scanlines(&icinfo, buffer, 1);
				memcpy(framebuf+y*row_stride,buffer[0], row_stride);
				y++;
			}
			(void) jpeg_finish_decompress(&icinfo);

			
#endif
			curframe=frame;
		}
	}
	
};
