#include <stdlib.h>
#include <time.h>
#include <fenix/fxdll.h>
#include <string.h>
#include <SDL/SDL.h>

/* PluginVersion is used to identify the plugin structures against which
 * we're linking to prevent potential mismatches and segmentation faults
 */
unsigned int PluginVersion = FXDLL_VERSION;

typedef struct{
	Uint16 FireX, FireY, Pos_X, Pos_Y, StartP, FuelP, SpaceP, FuelY;
	Uint8 *FireField, *FireField2, *FireA, *FireS, Cooling, CoolType, FuelType;
	int FireID, IntPMax, IntPMin, Flag;
	GRAPH *M, *CoolMap, *FuelMap;
}_Fire;


int Info (void * user, REGION * bbox)
{
    bbox->x = 0;
    bbox->y = 0;
    bbox->x2 = scr_width-1;
    bbox->y2 = scr_height-1;
    return 1;
}

void Draw (void * user, REGION * clip)
{
    static int lastmx = -1;
    static int lastmy = -1;
    static int lastmleft = -1;
    static int lastmright = -1;
    static int lastmcenter = -1;
    static int lastmwup = -1;
    static int lastmwdown = -1;
    static int lastkey = -1;

	_Fire *T=(_Fire *)user;
	T->M->data=T->FireA;
	gr_blit(scrbitmap,0, (T->FireX>>1)+T->Pos_X,(T->FireY>>1)+T->Pos_Y,T->Flag,T->M);

}

GRAPH * bn (int w, int h)
{
	GRAPH  * gr ;
	int      bytesPerRow, wb ;

	/* Calculate the row size (dword-aligned) */

	wb = w * 8 / 8;
	if (wb*8/8 < w)
		wb++;

	bytesPerRow = wb;
	if (bytesPerRow & 0x03)
		bytesPerRow = (bytesPerRow & ~3) + 4;

	/* Create and fill the struct */

	gr = (GRAPH *) malloc (sizeof(GRAPH)) ;
	if (!gr)
		return NULL;

	gr->width       = w ;
	gr->widthb      = wb ;
	gr->pitch       = bytesPerRow ;
	gr->height      = h ;
	gr->depth       = 8 ;
	gr->name[0]     = 0 ;
	gr->code        = 0 ;
	gr->data        = NULL ;
	gr->offset      = 0 ;
	gr->modified    = 0 ;
	gr->info_flags  = 0 ;
	gr->cpoints     = NULL ;
	gr->blend_table = NULL ;

	return gr ;
}

static int priv_random(int num1, int num2)
{
	return num1 + (int)(((double)(num2-num1+1) * rand()) / (RAND_MAX+1.0)) ;
}

void Fire(_Fire *T){
	int x,y,i;
	for (y=0;y<T->FireY;y++)
		for (x=0;x<T->FireX;x++){
			Sint16 FF, XP=x+1, XM=x-1, YP=y+1, YM=y-1;
			if (XP>=T->FireX)XP=0;
			if (XM<0)XM=T->FireX-1;
			if (YP>=T->FireY)YP=T->FireY-1;
			if (YM<0)YM=0;
			FF=T->FireS[(y*T->FireX)+XP];
			FF+=T->FireS[(y*T->FireX)+XM];
			FF+=T->FireS[((YP)*T->FireX)+x];
			FF+=T->FireS[((YM)*T->FireX)+x];
			FF>>=2;

			if(!T->CoolType)
				FF-=T->Cooling;
			else
				FF-=gr_get_pixel(T->CoolMap,x,y);

			if(FF<0)FF=0;
			T->FireA[((YM)*T->FireX)+x] = (Uint8)FF;
		}

		y=T->FireY-1;
		if(!T->FuelType){

			x=T->StartP;
			while(x<T->FireX){
				Sint16 F = T->FireS[(y*T->FireX)+x] + priv_random(T->IntPMin,T->IntPMax);
				if (F<0)F=0;
				if (F>255)F=255;
				for(i=x+T->FuelP;x<i && x<T->FireX;x++)
					T->FireA[(y*T->FireX)+x] = (Uint8)F;
				x+=T->SpaceP;
			}
		}else{
			for(x=0;x<T->FireX;x++)
				T->FireA[(y*T->FireX)+x]=gr_get_pixel(T->FuelMap,x,T->FuelY);
			T->FuelY++;
			if(T->FuelY>=T->FireX)T->FuelY=0;
		}
}



static int new_fire(INSTANCE * my, int * params)
{
	_Fire *T=(_Fire *)malloc(sizeof(_Fire));
	memset(T,0,sizeof(_Fire));
	T->M=bitmap_new_syslib(params[0], params[1],8,1);
	T->FireX=params[0];
	T->FireY=params[1];
	T->FireField=T->M->data;
	T->FireField2=(Uint8*)malloc(T->FireX*T->FireY);
	memset(T->FireField,0,T->FireX*T->FireY);
	memset(T->FireField2,0,T->FireX*T->FireY);
	T->FireA = T->FireField;
	T->FireS = T->FireField2;
	T->FuelP=2;
	T->IntPMin=-32;
	T->IntPMax=32;
	T->FireID=-1;
	srand((unsigned int)time(NULL));
	return (int)T;
}


static int update_fire(INSTANCE * my, int * params)
{
	_Fire *T=(_Fire *)params[0];
	Uint8 *temp = T->FireA;
	Fire(T);
	T->FireA = T->FireS;
	T->FireS = temp;
	return 1;
}


static int start_fire(INSTANCE * my, int * params)
{
	_Fire *T=(_Fire *)params[0];
	T->FireID=gr_new_object (params[1], Info, Draw, (void *)params[0]);
	return 0;
}

static int stop_fire(INSTANCE *my, int *params)
{
	_Fire *T=(_Fire *)params[0];
	if(T->FireID!=-1){
		gr_destroy_object(T->FireID);
		T->FireID=-1;
	}
	return 0;
}

static int delete_fire(INSTANCE *my, int *params)
{
	_Fire *T=(_Fire *)params[0];
	free(T->FireField2);
	bitmap_destroy(T->M);
	free(T);
	return 0;
}

static int pos_fire(INSTANCE *my, int *params)
{
	_Fire *T=(_Fire *)params[0];
	T->Pos_X=params[1];
	T->Pos_Y=params[2];
	return 0;
}

static int cooling_fire(INSTANCE *my, int *params)
{
	_Fire *T=(_Fire *)params[0];
	T->Cooling=params[1];
	return 0;
}


static int coolmap_fire(INSTANCE *my, int *params)
{
	_Fire *T=(_Fire *)params[0];
	T->CoolMap=bitmap_get(params[1], params[2]);
	return 0;
}


static int fuelmap_fire(INSTANCE *my, int *params)
{
	_Fire *T=(_Fire *)params[0];
	T->FuelMap=bitmap_get(params[1], params[2]);
	return 0;
}

static int cooltype_fire(INSTANCE *my, int *params)
{
	_Fire *T=(_Fire *)params[0];
	T->CoolType=params[1];
	return 0;
}


static int fueltype_fire(INSTANCE *my, int *params)
{
	_Fire *T=(_Fire *)params[0];
	T->FuelType=params[1];
	return 0;
}

static int fueling_fire(INSTANCE *my, int *params)
{
	_Fire *T=(_Fire *)params[0];
	T->StartP=params[1];
	T->FuelP=params[2];
	T->SpaceP=params[3];
	T->IntPMin=params[4];
	T->IntPMax=params[5];
	return 0;
}

static int flag_fire(INSTANCE *my, int *params)
{
	_Fire *T=(_Fire *)params[0];
	T->Flag=params[1];
	return 0;
}

static int graph_fire(INSTANCE *my, int *params)
{
	_Fire *T=(_Fire *)params[0];
	return T->M->code;
}

FENIX_MainDLL RegisterFunctions (COMMON_PARAMS)
{
    FENIX_DLLImport
	FENIX_export ("NEW_FIRE" , "II", TYPE_DWORD, new_fire); // x, y
	FENIX_export ("STOP_FIRE" , "I", TYPE_DWORD, stop_fire); // fireid
	FENIX_export ("DELETE_FIRE" , "I", TYPE_DWORD, delete_fire); // fireid
	FENIX_export ("UPDATE_FIRE", "I", TYPE_DWORD, update_fire); // fireid
	FENIX_export ("START_FIRE", "II", TYPE_DWORD, start_fire); // fireid, z
	FENIX_export ("POS_FIRE", "III", TYPE_DWORD, pos_fire); // fireid, x, y
	FENIX_export ("COOLING_FIRE", "II", TYPE_DWORD, cooling_fire); // fireid, cooling
	FENIX_export ("COOLMAP_FIRE", "III", TYPE_DWORD, coolmap_fire); // fireid, fpg, map
	FENIX_export ("COOLTYPE_FIRE", "II", TYPE_DWORD, cooltype_fire); //fireid, cooltype
	FENIX_export ("FUELMAP_FIRE", "III", TYPE_DWORD, fuelmap_fire); // fireid, fpg, map
	FENIX_export ("FUELING_FIRE", "IIIIII", TYPE_DWORD, fueling_fire); //fireid, pixelsprincipio, pixelsseguidosafuelear, pixelsespaciado, intensidadfuelmax, intensidadfuelmin
	FENIX_export ("FUELTYPE_FIRE", "II", TYPE_DWORD, fueltype_fire); //fireid, fueltype
	FENIX_export ("FLAG_FIRE", "II", TYPE_DWORD, flag_fire); //fireid, blitflag
	FENIX_export ("GRAPH_FIRE", "I", TYPE_DWORD, graph_fire);
}
