/////////////////////////////////////////////////////////////////////////////
// Name:        imagrgb.cpp
// Purpose:     wxImage RGB handler
// Author:      Paul Bourke & Antonin Misek
// RCS-ID:
// Copyright:   (c)
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// For compilers that support precompilation, includes "wx.h".
//#include <wx/wxprec.h>
#include "flexilog.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

//#if wxUSE_IMAGE && wxUSE_RGB

#include "imagrgb.h"

#ifndef WX_PRECOMP
    #include <wx/intl.h>
    #include <wx/log.h>
#endif


//-----------------------------------------------------------------------------
// wxRGBHandler
//-----------------------------------------------------------------------------


void wxRGBHandler::ConvertShort(unsigned short *array, long length)
{
	unsigned b1, b2;
	unsigned char *ptr = (unsigned char *)array;
	while (length--) {
		b1 = *ptr++;
		b2 = *ptr++;
		*array++ = (b1 << 8) | (b2);
	}
}

void wxRGBHandler::ConvertLong(unsigned *array, long length)
{
	unsigned b1, b2, b3, b4;
	unsigned char *ptr;

	ptr = (unsigned char *)array;
	while (length--) {
		b1 = *ptr++;
		b2 = *ptr++;
		b3 = *ptr++;
		b4 = *ptr++;
		*array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
	}
}

ImageRec *wxRGBHandler::ImageOpen(wxBufferedInputStream &buf_stream)
{
	union {
		int testWord;
		char testByte[4];
	} endianTest;
	ImageRec *img;
	int swapFlag;

	endianTest.testWord = 1;
	if (endianTest.testByte[0] == 1) {
		swapFlag = 1;
	} else {
		swapFlag = 0;
	}

	// Read the RGB header
	img = (ImageRec *)malloc(sizeof(ImageRec));
	if (img == NULL) {
		LOGERROR(_("RGB: Out of memory."));
		return NULL;
	}
	buf_stream.Read(img, 12);
	if (swapFlag) {
		ConvertShort(&img->imagic, 6);
	}
	img->tmp = (unsigned char *)malloc(img->xsize*256);
	img->tmpR = (unsigned char *)malloc(img->xsize*256);
	img->tmpG = (unsigned char *)malloc(img->xsize*256);
	img->tmpB = (unsigned char *)malloc(img->xsize*256);
	if (img->tmp == NULL || img->tmpR == NULL || img->tmpG == NULL || img->tmpB == NULL) {
		LOGERROR(_("RGB: Out of memory."));
		return NULL;
	}

	if ((img->type & 0xFF00) == 0x0100) {
		int x = img->ysize * img->zsize * sizeof(unsigned);
		img->rowStart = (unsigned *)malloc(x);
		img->rowSize = (int *)malloc(x);
		if (img->rowStart == NULL || img->rowSize == NULL) {
			LOGERROR(_("RGB: Out of memory."));
			return NULL;
		}
		img->rleEnd = 512 + (2 * x);
		buf_stream.SeekI(512);
		buf_stream.Read(img->rowStart, x);
		buf_stream.Read(img->rowSize, x);
		if (swapFlag) {
			ConvertLong(img->rowStart, x/(int)sizeof(unsigned));
			ConvertLong((unsigned *)img->rowSize, x/(int)sizeof(int));
		}
	} else {
		img->rowStart = NULL;
		img->rowSize = NULL;
	}
	return img;
}

void wxRGBHandler::ImageClose(ImageRec *img)
{
	free(img->tmp);
	free(img->tmpR);
	free(img->tmpG);
	free(img->tmpB);
	free(img->rowSize);
	free(img->rowStart);
	free(img);
}

void wxRGBHandler::ImageGetRow(wxBufferedInputStream &buf_stream, ImageRec *img, unsigned char *buf, int y, int z)
{
	if ((img->type & 0xFF00) == 0x0100) {
		buf_stream.SeekI((long)img->rowStart[y+z*img->ysize]);
		buf_stream.Read(img->tmp, (unsigned int)img->rowSize[y+z*img->ysize]);

		unsigned char *iPtr = img->tmp;
		unsigned char *oPtr = buf;
		for (;;) {
			unsigned char pixel = *iPtr++;
			int count = (int)(pixel & 0x7F);
			if (!count) {
				return;
			}
			if (pixel & 0x80) {
				while (count--) {
					*oPtr++ = *iPtr++;
				}
			} else {
				pixel = *iPtr++;
				while (count--) {
					*oPtr++ = pixel;
				}
			}
		}
	} else {
		buf_stream.SeekI(512+(y*img->xsize)+(z*img->xsize*img->ysize));
		buf_stream.Read(buf, img->xsize);
	}
}

#if wxUSE_STREAMS
bool wxRGBHandler::LoadFile( wxImage *image, wxInputStream& stream, bool WXUNUSED(verbose), int WXUNUSED(index) )
{
	image->Destroy();
	wxBufferedInputStream buf_stream(stream);

	unsigned char *rbuf=NULL, *gbuf=NULL, *bbuf=NULL, *abuf=NULL;
	ImageRec *img;
	int y;

	img = ImageOpen(buf_stream);

	if(!img)
		return false;
	image->Create( img->xsize, img->ysize );
	if (((img->zsize>=4)||(img->zsize==2)) && (!image->HasAlpha()))
		image->InitAlpha();
	rbuf = (unsigned char *)malloc(img->xsize*sizeof(unsigned char));
	gbuf = (unsigned char *)malloc(img->xsize*sizeof(unsigned char));
	bbuf = (unsigned char *)malloc(img->xsize*sizeof(unsigned char));
	abuf = (unsigned char *)malloc(img->xsize*sizeof(unsigned char));
	if(!rbuf || !gbuf || !bbuf || !abuf)
	{
		if (rbuf)
			free(rbuf);
		if (gbuf)
			free(gbuf);
		if (bbuf)
			free(bbuf);
		if (abuf)
			free(abuf);
		return false;
	}
	for (y=0; y<img->ysize; y++) {
		if (img->zsize>=4) {
			ImageGetRow(buf_stream, img,rbuf,y,0);
			ImageGetRow(buf_stream, img,gbuf,y,1);
			ImageGetRow(buf_stream, img,bbuf,y,2);
			ImageGetRow(buf_stream, img,abuf,y,3);
			for (int x=0; x<img->xsize; x++)
			{
				image->SetRGB(x, img->ysize-y-1, rbuf[x], gbuf[x], bbuf[x]);
				image->SetAlpha(x, img->ysize-y-1, abuf[x]);
			}
		} else if(img->zsize==3) {
			ImageGetRow(buf_stream, img,rbuf,y,0);
			ImageGetRow(buf_stream, img,gbuf,y,1);
			ImageGetRow(buf_stream, img,bbuf,y,2);
			for (int x=0; x<img->xsize; x++)
			{
				image->SetRGB(x, img->ysize-y-1, rbuf[x], gbuf[x], bbuf[x]);
			}
		} else if(img->zsize==2) {
			ImageGetRow(buf_stream, img,rbuf,y,0);
			ImageGetRow(buf_stream, img,abuf,y,1);
			for (int x=0; x<img->xsize; x++)
			{
				image->SetRGB(x, img->ysize-y-1, rbuf[x], rbuf[x], rbuf[x]);
				image->SetAlpha(x, img->ysize-y-1, abuf[x]);
			}
		} else {
			ImageGetRow(buf_stream, img,rbuf,y,0);
			for (int x=0; x<img->xsize; x++)
			{
				image->SetRGB(x, img->ysize-y-1, rbuf[x], rbuf[x], rbuf[x]);
			}
		}
	}
	ImageClose(img);
	free(rbuf);
	free(gbuf);
	free(bbuf);
	free(abuf);
	
//	*image = image->Mirror(true);
	return true;
}

bool wxRGBHandler::SaveFile( wxImage * WXUNUSED(image), wxOutputStream & WXUNUSED(stream), bool WXUNUSED(verbose) )
{
	return false;
}

bool wxRGBHandler::DoCanRead( wxInputStream& stream )
{
    if ( (stream.GetC() == 1) && (stream.GetC() == 218))
		return true;
    return false;
}

#endif // wxUSE_STREAMS

//#endif // wxUSE_IMAGE && wxUSE_RGB
