#include <alloc.h>
#include <mem.h>
#include <i_chpdrv.h>
#include <i_frmdrv.h>

#define FC	((FrameContext *)fc)

typedef struct
{
	ZafFrameDriver *frameDriver;
	ZafChipDriver *chipDriver;
	ZafChipContext cc;
	int rasterMode;
} FrameContext;

typedef struct
{
	int mono;
	int transparent;
	int width;
	int height;
	unsigned char *colorArray;
} Bitmap;

static ZafFrameContext Initialize(void *thisDriver, int displayWidth,
	int displayHeight, int colorBitsPerPixel)
{
	FrameContext *fc = (FrameContext *)malloc(sizeof(FrameContext));

	if (fc)
	{
		extern ZafChipDriver zafChipDriver;

		memset(fc, 0, sizeof(FrameContext));
		fc->frameDriver = thisDriver;
		fc->chipDriver = &zafChipDriver;

		fc->cc = (*fc->chipDriver->Initialize)(fc->chipDriver, displayWidth, displayHeight, colorBitsPerPixel);

		return (fc);
	}

	return (0);
}

static int Deinitialize(ZafFrameContext fc)
{
	if (fc)
	{
		(*FC->chipDriver->Deinitialize)(FC->cc);
		free(fc);
		return (0);
	}

	return (-1);
}

static int SetRasterMode(ZafFrameContext fc, int rasterMode)
{
	FC->rasterMode = rasterMode;
	return (0);
}

static void HLine(ZafFrameContext fc, int y, int x1, int x2, long colorRef)
{
	unsigned char *lineBuffer = (unsigned char *)(*FC->chipDriver->GetLineBuffer)(FC->cc, y);
	unsigned char color = (unsigned char)colorRef;
	int size = x2 - x1 + 1;

	if (FC->rasterMode == 1)
	{
		lineBuffer += x1;
		while (size--)
			*(lineBuffer++) ^= color;
	}
	else
		memset(lineBuffer + x1, color, size);
}

static void VLine(ZafFrameContext fc, int x, int y1, int y2, long colorRef)
{
	int i;
	unsigned char color = (unsigned char)colorRef;
	ZafChipContext cc = FC->cc;
	void *(*GetLineBuffer)(ZafChipContext, int) = FC->chipDriver->GetLineBuffer;

	if (FC->rasterMode == 1)
	{
		for (i = y1; i < y2; i++)
			*((unsigned char *)(*GetLineBuffer)(cc, i) + x) ^= color;
	}
	else
	{
		for (i = y1; i < y2; i++)
			*((unsigned char *)(*GetLineBuffer)(cc, i) + x) = color;
	}
}

static void Pixel(ZafFrameContext fc, int x, int y, long colorRef)
{
	*((unsigned char *)(*FC->chipDriver->GetLineBuffer)(FC->cc, y) + x) = (unsigned char)colorRef;
}

static void *CreateBitmap(ZafFrameContext fc, int width, int height,
	ZafColorRef *colorTable, unsigned char *indexArray)
{
	Bitmap *bitmap = (Bitmap *)malloc(sizeof(Bitmap));
	int count = width * height;

	if (colorTable)
		bitmap->mono = 0;
	else
		bitmap->mono = 1;

	bitmap->transparent = 0;

	while (--count >= 0)
		if (indexArray[count] == 0xFF)
		{
			bitmap->transparent = 1;
			break;
		}

	bitmap->width = width;
	bitmap->height = height;

	bitmap->colorArray = (unsigned char *)malloc(width * height);
	memcpy(bitmap->colorArray, indexArray, width * height);

	return (bitmap);
}

static int BitBlt(ZafFrameContext fc, ZafBitmapHandle sourceBitmap,
	int sourceLeft, int sourceTop, int sourceRight, int sourceBottom,
	ZafBitmapHandle destBitmap, int destLeft, int destTop,
	int destRight, int destBottom)
{
	ZafChipContext cc = FC->cc;
	void *(*GetLineBuffer)(ZafChipContext, int) = FC->chipDriver->GetLineBuffer;

	// Test for stretching.
	if (destRight - destLeft == sourceRight - sourceLeft &&
		destBottom - destTop == sourceBottom - sourceTop)
	{
		if (!destBitmap)
		{
			int y;
			int copyWidth = destRight - destLeft + 1;
			int bitmapWidth = ((Bitmap *)sourceBitmap)->width;
			unsigned char *sourceBuffer = ((Bitmap *)sourceBitmap)->colorArray + sourceLeft;

			if (((Bitmap *)sourceBitmap)->transparent)
			{
				for (y = destTop; y <= destBottom; y++)
				{
			 		unsigned char *screenBuffer = (unsigned char *)(*GetLineBuffer)(cc, y) + destLeft;
					unsigned char *bitmapBuffer = sourceBuffer;
					int count = copyWidth;

					while (count--)
					{
						if (*bitmapBuffer != 0xFF)
							*screenBuffer = *bitmapBuffer;
						screenBuffer++;
						bitmapBuffer++;
					}

					sourceBuffer += bitmapWidth;
				}
			}
			else
			{
				for (y = destTop; y <= destBottom; y++)
				{
			 		unsigned char *screenBuffer = (unsigned char *)(*GetLineBuffer)(cc, y) + destLeft;
					memcpy(screenBuffer, sourceBuffer, copyWidth);
					sourceBuffer += bitmapWidth;
				}
			}
		}
		else if (!sourceBitmap)
		{
			int y;
			int copyWidth = destRight - destLeft + 1;
			int bitmapWidth = ((Bitmap *)destBitmap)->width;
			unsigned char *destBuffer = ((Bitmap *)destBitmap)->colorArray + destLeft;

			for (y = sourceTop; y <= sourceBottom; y++)
			{
			 	unsigned char *screenBuffer = (unsigned char *)(*GetLineBuffer)(cc, y) + sourceLeft;
				memcpy(destBuffer, screenBuffer, copyWidth);
				destBuffer += bitmapWidth;
			}
		}
	}

	return (0);
}

ZafFrameDriver zafFrameDriver =
{
 	Initialize,
	Deinitialize,
	SetRasterMode,
	HLine,
	VLine,
	Pixel,
	CreateBitmap,
	BitBlt
};
