#include <pspkernel.h>
#include <pspdebug.h>
#include <pspsdk.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pspdisplay.h>
#include <oslib/oslib.h>
#include "share.h"
extern unsigned int tocolor(lua_State *L,int a);

static void imagetoimage(int sx, int sy, int width, int height, OSL_IMAGE* source, int dx, int dy, OSL_IMAGE* destination)
{
	if(dx == 0){
		dx = 0;
	}else{
		dx = (dx*4)+4;//+12
	}
	if(dy == 0){
		dy = 0;
	}else{
		dy = (dy*4)+4;
	}
	Color* destinationData = &destination->data[destination->sysSizeX * dy + dx];
	int destinationSkipX = destination->sysSizeX - width;
	Color* sourceData = &source->data[source->sysSizeX * sy + sx];
	int sourceSkipX = source->sysSizeX - width;
	int x, y;
	for (y = 0; y < height; y++, destinationData += destinationSkipX, sourceData += sourceSkipX) {
		for (x = 0; x < width; x++, destinationData++, sourceData++) {
			*destinationData = *sourceData;
		}
	}
}
UserdataStubs(Image, OSL_IMAGE*)
static int Image_load(lua_State *L)
{ 
	OSL_IMAGE *image = oslLoadImageFile(luaL_checkstring(L,1), OSL_IN_RAM | OSL_SWIZZLED, OSL_PF_8888);
	OSL_IMAGE** luaImage = pushImage(L);
	*luaImage = image;
 return 1;
}
static int Image_blit (lua_State *L) 
{
	if (lua_type(L, 1) == LUA_TUSERDATA){
			OSL_IMAGE *source = *toImage(L, 4);
			OSL_IMAGE *dest = *toImage(L, 1);
			//oslUnswizzleImage(source);
			//oslUnswizzleImage(dest);
			oslLockImage(source);
			oslLockImage(dest);
			imagetoimage(0, 0, source->sizeX, source->sizeY, source, luaL_checkinteger(L, 2), luaL_checkinteger(L, 3), dest);
			oslUnlockImage(source);
			oslUnlockImage(dest);
			//oslSwizzleImage(dest);
			//oslSwizzleImage(source);
		return 0;
	}
	oslDrawImageXY(*toImage(L, 3), luaL_checkinteger(L, 1), luaL_checkinteger(L, 2));
	return 0;
}
static int Image_createEmpty(lua_State *L)
{	
	OSL_IMAGE *image = oslCreateImage(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2), OSL_IN_RAM, OSL_PF_8888);
	OSL_IMAGE** luaImage = pushImage(L);
	*luaImage = image;
	return 1;
}
static int Image_loadfrommemory (lua_State *L) 
{
	OSL_IMAGE* image;
	size_t size;
	unsigned char *string = (unsigned char *) luaL_checklstring(L, 1, &size);
	oslSetTempFileData(string, size, &VF_MEMORY);
	if (luaL_checknumber(L, 2)==1){
		image = oslLoadImageFilePNG(oslGetTempFileName(), OSL_IN_RAM, OSL_PF_8888);
	}else{
		image = oslLoadImageFileJPG(oslGetTempFileName(), OSL_IN_RAM, OSL_PF_8888);
	}
	OSL_IMAGE** luaImage = pushImage(L);
	*luaImage = image;
	return 1;
}
static void fillImageRect(Color color, int x0, int y0, int width, int height, OSL_IMAGE* image)
{
	int skipX = image->sysSizeX - width;
	int x, y;
	Color* data = image->data + x0 + y0 * image->sysSizeX;
	for (y = 0; y < height; y++, data += skipX) {
		for (x = 0; x < width; x++, data++) *data = color;
	}
}
static int Image_fillRect (lua_State *L) {
	if (lua_type(L, 1)== LUA_TUSERDATA){
		OSL_IMAGE *dest = *toImage(L, 1);
		/*OSL_IMAGE *source = oslCreateImage((luaL_checkinteger(L, 4)-luaL_checkinteger(L, 2)), (luaL_checkinteger(L,5)-luaL_checkinteger(L, 3)), OSL_IN_RAM, OSL_PF_8888);
		oslStartDrawing();
		oslClearImage(source, tocolor(L,6));
		oslEndDrawing();*/
		//oslUnswizzleImage(dest);
		oslLockImage(dest);
		//oslLockImage(source);
		fillImageRect(tocolor(L,6), luaL_checkinteger(L, 2), luaL_checkinteger(L, 3), (luaL_checkinteger(L, 4)-luaL_checkinteger(L, 2)), (luaL_checkinteger(L,5)-luaL_checkinteger(L, 3)), dest);
		//imagetoimage(0, 0, source->sizeX, source->sizeY, source, luaL_checkinteger(L, 2), luaL_checkinteger(L,3), dest);
		//oslUnlockImage(source);
		oslUnlockImage(dest);
		//oslSwizzleImage(dest);
		//oslDeleteImage(source);
		return 0;
	}
	oslDrawFillRect(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2), luaL_checkinteger(L, 3), luaL_checkinteger(L, 4), tocolor(L,5));
	return 0;
	
}
static int Image_unswizzle (lua_State *L)
{
	oslUnswizzleImage(*toImage(L, 1));
	return 0;
}
static int Image_swizzle (lua_State *L)
{
	oslSwizzleImage(*toImage(L, 1));
	return 0;
}
static int Image_drawLine (lua_State *L) {
	if (lua_type(L, 1)== LUA_TUSERDATA){
		OSL_IMAGE *dest = *toImage(L, 1);
		//oslUnswizzleImage(dest);
		//oslLockImage(dest);
		float x0 = luaL_checkinteger(L, 2);
		float y0 = luaL_checkinteger(L, 3);
		float x1 = luaL_checkinteger(L, 4);
		float y1 = luaL_checkinteger(L, 5);
		float grad = ((y1-y0)/(x1-x0));
		float i;
		oslStartDrawing();
		for (i = 0; i < x1; i=i+1){
			oslSetImagePixel(dest, i+x0,y0+(i*grad), tocolor(L,6));
		}
		oslEndDrawing();
		//drawLine(luaL_checkinteger(L, 2), luaL_checkinteger(L, 3), luaL_checkinteger(L, 4),luaL_checkinteger(L, 5), tocolor(L,6), dest->data, dest->sysSizeX);
		//oslUnlockImage(dest);
		//oslSwizzleImage(dest);
		return 0;
	}
	oslDrawLine(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2), luaL_checkinteger(L, 3), luaL_checkinteger(L, 4), tocolor(L,5));
	return 0;
}
static int Image_pixel (lua_State *L) 
{
	if (lua_type(L, 1) == LUA_TUSERDATA){
		oslSetImagePixel(*toImage(L,1), luaL_checkinteger(L, 2), luaL_checkinteger(L, 3), tocolor(L,4));
	}else{
		oslSetImagePixel(oslGetDrawBuffer(), luaL_checkinteger(L, 1), luaL_checkinteger(L, 2), tocolor(L,3));
	}
	return 0;
}
static int Image_resize (lua_State *L) {
	OSL_IMAGE* temp = *toImage(L, 3);
	oslLockImage(temp);
	temp->stretchX = luaL_checkinteger(L, 1);
	temp->stretchY = luaL_checkinteger(L, 2);
	oslUnlockImage(temp);
	return 0;
}
static int Image_rotate (lua_State *L) 
{
	OSL_IMAGE* temp = *toImage(L, 4); 
	oslLockImage(temp);
		temp->centerX = luaL_checkinteger(L, 1);
		temp->centerY = luaL_checkinteger(L, 2);
		temp->angle = luaL_checkinteger(L, 3);
	oslUnlockImage(temp);
	return 0;
}
static int Image_reset (lua_State *L) 
{
	OSL_IMAGE* temp = *toImage(L, 1);
	oslLockImage(temp);
	oslResetImageProperties(temp);
	oslUnlockImage(temp);
	return 0;
}
static int Image_center (lua_State *L) 
{
	OSL_IMAGE* temp = *toImage(L, 3);
	oslLockImage(temp);
		temp->centerX = luaL_checkinteger(L, 1);
		temp->centerY = luaL_checkinteger(L, 2);
	oslUnlockImage(temp);
	return 0;
}
static int Image_width (lua_State *L) 
{	
	OSL_IMAGE *dest = *toImage(L, 1);
	lua_pushnumber(L, dest->realSizeX);
	return 1;
}
static int Image_height (lua_State *L) 
{
	OSL_IMAGE *dest = *toImage(L, 1);
	lua_pushnumber(L, dest->realSizeY);
	return 1;
}
static int Image_clear (lua_State *L) 
{
	oslClearImage(*toImage(L, 1), tocolor(L,2));
	return 0;
}
static int Image_getpixel (lua_State *L) 
{
	unsigned int a = oslGetImagePixel(*toImage(L, 3), luaL_checkinteger(L, 1), luaL_checkinteger(L, 2));
	char buffer[50];
  	sprintf (buffer, "0x%x", a);
	lua_pushstring(L, buffer);
	return 1;
}
static int Image_creatsprite (lua_State *L) 
{
	OSL_IMAGE* image = oslCreateImageTile(*toImage(L, 5),luaL_checkinteger(L, 1), luaL_checkinteger(L, 2), luaL_checkinteger(L, 3), luaL_checkinteger(L, 4));
	OSL_IMAGE** luaImage = pushImage(L);
	*luaImage = image;
	return 1;
}
static int Image_free(lua_State *L) {
	oslDeleteImage(*toImage(L, 1));
	return 0;
}
static int Image_tovram (lua_State *L) {
	oslMoveImageTo(*toImage(L, 1), OSL_IN_VRAM);
	return 0;
}
static int Image_toram (lua_State *L) {
	oslMoveImageTo(*toImage(L, 1), OSL_IN_RAM);
	return 0;
}
static int Image_save (lua_State *L) {
	oslWriteImageFilePNG(*toImage(L, 2), luaL_checkstring(L,1), 0);
	return 0;
}
static const luaL_reg Image_methods[] = {
	{"load", Image_load},
	{"createEmpty", Image_createEmpty},
	{"blit", Image_blit},
	{"fillRect", Image_fillRect},
	{"drawLine", Image_drawLine},
	{"setPixel", Image_pixel},
	{"getPixel", Image_getpixel},
	{"width", Image_width},
	{"height", Image_height},
	{"resize", Image_resize},
	{"rotate", Image_rotate},
	{"center", Image_center},
	{"reset", Image_reset},
	{"clear", Image_clear},
	{"loadFromMemory", Image_loadfrommemory},
	{"free", Image_free},
	{"creatsprite", Image_creatsprite},
	{"unswizzle", Image_unswizzle},
	{"swizzle", Image_swizzle},
	{"toVRam", Image_tovram},
	{"toRam", Image_toram},
	{"save", Image_save},
	{0,0}
};
static const luaL_reg Image_meta[] = {
	{"__gc", Image_free},
	{0,0}
};
UserdataRegister(Image, Image_methods, Image_meta)
void image_init(lua_State *L) {
	Image_register(L);
}
