#include "world.h"
#include "light.h"

////////////////////////////////////////////////////////////////////////////////////
//	exports
////////////////////////////////////////////////////////////////////////////////////

DllExport	void	light(userEntity_t *self);
DllExport	void	light_walltorch (userEntity_t *self);
DllExport	void	light_spot (userEntity_t *self);
DllExport	void	light_strobe (userEntity_t *self);
DllExport	void	light_flare (userEntity_t *self);
DllExport	void	light_flame (userEntity_t *self);

////////////////////////////////////////////////////////////////////////////////////
//	defines
////////////////////////////////////////////////////////////////////////////////////

#define	NO_SOUND	1
#define	START_OFF	1
#define	LIGHT_FLARE	2

////////////////////////////////////////////////////////////////////////////////////
//	globals
////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////
//	typedefs
////////////////////////////////////////////////////////////////////////////////////

typedef struct
{
	char	*ambient_sound;
	char	*stylestr;

	int		style;
} lightHook_t;

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

void	light_use (userEntity_t *self, userEntity_t *other, userEntity_t *activator)
{
	lightHook_t		*hook = (lightHook_t *) self->userHook;

	if (self->spawnflags & START_OFF)
	{
		gstate->ConfigString (CS_LIGHTS + hook->style, "m");
		self->spawnflags = self->spawnflags - START_OFF;
	}
	else
	{
		gstate->ConfigString (CS_LIGHTS + hook->style, "a");
		self->spawnflags = self->spawnflags | START_OFF;
	}
}

///////////////////////////////////////////////////////////////////////////////
// light_flare
///////////////////////////////////////////////////////////////////////////////

void light_flare (userEntity_t *self)
{
	int		i;
	char	*model;

	model = "models/l_flare2/l_flare2.sp2";

	for (i = 0; self->epair [i].key != NULL; i++)
	{
		if (!stricmp (self->epair [i].key, "model"))
			model = self->epair [i].value;
	}

	self->solid = SOLID_NOT;
	self->movetype = MOVETYPE_NONE;
	self->s.modelindex = gstate->ModelIndex (model);
	self->s.renderfx = SPR_ALPHACHANNEL | RF_TRANSLUCENT | RF_LIGHTFLARE;

	VectorCopy (zero_vector, self->s.mins);
	VectorCopy (zero_vector, self->s.maxs);
	gstate->LinkEntity (self);
}

///////////////////////////////////////////////////////////////////////////////
// light
///////////////////////////////////////////////////////////////////////////////

void light (userEntity_t *self)
{
	int				i, alloc_hook;
	lightHook_t		*hook;
	int				style_defined = FALSE;

	self->userHook = com->malloc_hook (sizeof (lightHook_t), MEM_MALLOC);
	hook = (lightHook_t *) self->userHook;

	hook->style = 32;

	i = 0;
	while (self->epair [i].key != NULL)
	{
		if (!stricmp (self->epair [i].key, "delay"))
			self->delay = atof (self->epair [i].value);
		else if (!stricmp (self->epair [i].key, "sound"))
			hook->ambient_sound = self->epair [i].value;
		else if (!stricmp (self->epair [i].key, "targetname"))
			self->targetname = self->epair [i].value;
		else if (!stricmp (self->epair [i].key, "flag"))
		{
			if (!stricmp (self->epair [i].value, "NO_SOUND"))
				self->spawnflags = (int)self->spawnflags | NO_SOUND;
		}
		else if (!stricmp (self->epair [i].key, "style"))
			hook->style = atof (self->epair [i].value);
		else if (!stricmp (self->epair [i].key, "nelnosmama"))
		{
			style_defined = TRUE;
			hook->stylestr = self->epair [i].value;
		}

		i++;
	}
		
	if (style_defined)
		gstate->ConfigString (CS_LIGHTS + hook->style, hook->stylestr);

	if (hook->ambient_sound)
		gstate->Precache_Sound (hook->ambient_sound);

	if (hook->style >= 32)
	{
		self->use = light_use;
		if (self->spawnflags & START_OFF)
			gstate->ConfigString (CS_LIGHTS + hook->style, "a");
		else
			gstate->ConfigString (CS_LIGHTS + hook->style, "m");
	}

//	self->spawnflags |= LIGHT_FLARE;

	if (self->spawnflags & LIGHT_FLARE)
	{
		self->solid = SOLID_NOT;
		self->movetype = MOVETYPE_NONE;
		self->s.modelindex = gstate->ModelIndex ("models/l_flare2/l_flare2.sp2");
		self->s.renderfx = SPR_ALPHACHANNEL | RF_TRANSLUCENT;

		VectorCopy (zero_vector, self->s.mins);
		VectorCopy (zero_vector, self->s.maxs);
		gstate->LinkEntity (self);
	}

	// if this light is inert we want to remove it to save edicts
	if (!self->targetname && !(self->spawnflags & LIGHT_FLARE))
	{	
		com->free (self->userHook);
		gstate->RemoveEntity (self);
		return;
	}
}

////////////////////////////////////
// light
////////////////////////////////////

void	light_spot (userEntity_t *self)
{
	int				i;
	lightHook_t		*hook;

	self->userHook =com->malloc_hook (sizeof (lightHook_t), MEM_HUNK); 
	hook = (lightHook_t *) self->userHook;

	hook->style = 0;

	i = 0;
	while (self->epair [i].key != NULL)
	{
		if (stricmp (self->epair [i].key, "delay") == 0)
			self->delay = atof (self->epair [i].value);
		else if (stricmp (self->epair [i].key, "sound") == 0)
			hook->ambient_sound = self->epair [i].value;
		else if (stricmp (self->epair [i].key, "targetname") == 0)
			self->targetname = self->epair [i].value;
		else if (stricmp (self->epair [i].key, "flag") == 0)
		{
			if (stricmp (self->epair [i].value, "NO_SOUND") == 0)
				self->spawnflags = (int)self->spawnflags | NO_SOUND;
		}
		else if (!stricmp (self->epair [i].key, "style"))
			hook->style = atof (self->epair [i].value);
		else if (!stricmp (self->epair [i].key, "nelnosmama"))
		{
			hook->stylestr = self->epair [i].value;
			gstate->LightStyle (hook->style, hook->stylestr);
		}

		i++;
	}

	if (hook->ambient_sound)
		gstate->Precache_Sound (hook->ambient_sound);

	self->use = light_use;
}

////////////////////////////////////
// light_strobe_think
////////////////////////////////////
/*
void	light_strobe_think (userEntity_t *self)
{
	lightHook_t		*hook = (lightHook_t *) self->userHook;

	if (hook->state == FALSE)
	{
		//FIXME: change LightStyle
		hook->state = TRUE;
	}
	else
	{
		//FIXME: change LightStyle
		hook->state = FALSE;
	}

	if (hook->ambient_sound)
		gstate->sound (self, CHAN_AUTO, hook->ambient_sound, 255, ATTN_NORM);

	self->nextthink = gstate->time + self->delay;
	self->think = light_strobe_think;
}
*/
////////////////////////////////////
// light_strobe
////////////////////////////////////

void	light_strobe (userEntity_t *self)
{
	int				i;
	lightHook_t		*hook;

	self->userHook = com->malloc_hook (sizeof (lightHook_t), MEM_HUNK); 
	hook = (lightHook_t *) self->userHook;

	hook->style = 0;

	i = 0;
	while (self->epair [i].key != NULL)
	{
		if (stricmp (self->epair [i].key, "delay") == 0)
			self->delay = atof (self->epair [i].value);
		else if (stricmp (self->epair [i].key, "sound") == 0)
			hook->ambient_sound = self->epair [i].value;
		else if (stricmp (self->epair [i].key, "targetname") == 0)
			self->targetname = self->epair [i].value;
		else if (stricmp (self->epair [i].key, "flag") == 0)
		{
			if (stricmp (self->epair [i].value, "NO_SOUND") == 0)
				self->spawnflags = (int)self->spawnflags | NO_SOUND;
		}
		else if (!stricmp (self->epair [i].key, "style"))
			hook->style = atof (self->epair [i].value);
		else if (!stricmp (self->epair [i].key, "nelnosmama"))
		{
			hook->stylestr = self->epair [i].value;
			gstate->LightStyle (hook->style, hook->stylestr);
		}

		i++;
	}

	if (hook->ambient_sound)
		gstate->Precache_Sound (hook->ambient_sound);
	
	self->use = light_use;
}

////////////////////////////////////
// light_walltorch
////////////////////////////////////

void	light_walltorch (userEntity_t *self)
{
	int				i;
	lightHook_t		*hook;
	float			fade = 1.0;

	return;

	self->userHook = com->malloc_hook (sizeof (lightHook_t), MEM_HUNK); 
	hook = (lightHook_t *) self->userHook;

	i = 0;
	while (self->epair [i].key != NULL)
	{
//		gstate->Con_Printf ("key = %s, value = %s\n", self->epair [i].key, self->epair [i].value);
		
		if (strcmp (self->epair [i].key, "ambient_sound") == 0)
			hook->ambient_sound = self->epair [i].value;
		else if (stricmp (self->epair [i].key, "targetname") == 0)
			self->targetname = self->epair [i].value;
		else if (strcmp (self->epair [i].key, "flag") == 0)
		{
			if (strcmp (self->epair [i].value, "NO_SOUND") == 0)
				self->spawnflags = (int)self->spawnflags | NO_SOUND;
		}
		else if (!stricmp (self->epair [i].key, "style"))
			hook->style = atof (self->epair [i].value);
		else if (!stricmp (self->epair [i].key, "nelnosmama"))
		{
			hook->stylestr = self->epair [i].value;
			gstate->LightStyle (hook->style, hook->stylestr);
		}
		else if (!stricmp (self->epair [i].key, "fade"))
			fade = atof (self->epair [i].value);

		i++;
	}

	gstate->Precache_Model ("models/deco/e3/torch.mdl");
	gstate->SetModel (self, "models/deco/e3/torch.mdl");

	if (!((int)self->spawnflags & NO_SOUND))
	{
		if (hook->ambient_sound)
		{
			// FIXME: add ambientsound to 
			gstate->Precache_Sound (hook->ambient_sound);
			gstate->AmbientSound (self->s.origin, hook->ambient_sound, 255, ATTN_STATIC, fade);
		}
		else
		{
			gstate->Precache_Sound ("ambience/fire1.wav");
			gstate->AmbientSound (self->s.origin, "ambience/fire1.wav", 255, ATTN_STATIC, fade);
		}
	}

	// FIXME: add makestatic to 
	//	gstate->makestatic (self);
	self->use = light_use;
};

///////////////////////////////////////////////////////////////////////////////
// light_flame_burn
//
///////////////////////////////////////////////////////////////////////////////

void	light_flame_burn (userEntity_t *self, userEntity_t *other, cplane_t *plane, csurface_t *surf)
{
	if (other->takedamage = DAMAGE_YES)
		com->Damage (other, self, self, other->s.origin, zero_vector, 2.0, DAMAGE_NONE | DAMAGE_NO_BLOOD);
}


///////////////////////////////////////////////////////////////////////////////
// light_flame_animate
//
///////////////////////////////////////////////////////////////////////////////

void	light_flame_animate (userEntity_t *self)
{
	//	animate self
	self->s.frame++;

	if (self->s.frame > 9)
		self->s.frame = 0;

	self->s.render_scale [0] = (rnd () * 0.05 - 0.025) + self->delay;
	self->s.render_scale [1] = (rnd () * 0.05 - 0.025) + self->delay;

	//	animate owner (other sprite rotated 90 degrees)
	self->owner->s.frame++;

	if (self->owner->s.frame > 9)
		self->owner->s.frame = 0;

	self->owner->s.render_scale [0] = (rnd () * 0.05 - 0.025) + self->delay;
	self->owner->s.render_scale [1] = (rnd () * 0.05 - 0.025) + self->delay;

	self->nextthink = gstate->time + 0.1;
}

///////////////////////////////////////////////////////////////////////////////
// light_flame
//
///////////////////////////////////////////////////////////////////////////////

void	light_flame (userEntity_t *self)
{
	userEntity_t	*flame;
	Vector			temp;
	int				i;
	char			*model = "models/fire/fire.sp2";

	for (i = 0; self->epair [i].key != NULL; i++)
	{
		if (!stricmp (self->epair [i].key, "scale"))
			self->s.render_scale [0] = self->s.render_scale [1] = self->s.render_scale [2] = atof (self->epair [i].value);
		else if (!stricmp (self->epair [i].key, "model"))
			model = self->epair [i].value;
	}

	self->solid = SOLID_TRIGGER;
	self->movetype = MOVETYPE_NONE;
	self->s.renderfx = SPR_ALPHACHANNEL | SPR_ORIENTED | RF_TRANSLUCENT;

	//	spawn the other flame facing 90 degrees
	self->owner = flame = gstate->SpawnEntity ();
	flame->solid = SOLID_NOT;
	flame->movetype = MOVETYPE_NONE;
	flame->s.renderfx = SPR_ALPHACHANNEL + SPR_ORIENTED;

	flame->s.angles [0] = self->s.angles [0];
	flame->s.angles [1] = self->s.angles [1] + 90;
	flame->s.angles [2] = self->s.angles [2];
	
	VectorCopy (self->s.render_scale, flame->s.render_scale);
	self->delay = self->s.render_scale [0];

	VectorCopy (self->s.origin, flame->s.origin);

	temp = Vector (-8, -8, -8);
	temp.set (flame->s.mins);
	temp = Vector (8, 8, 8);
	temp.set (flame->s.maxs);

	self->s.modelindex = flame->s.modelindex = gstate->ModelIndex (model);

	gstate->LinkEntity (self);
	gstate->LinkEntity (flame);

	self->touch = light_flame_burn;

	self->think = light_flame_animate;
	self->nextthink = gstate->time + 0.1;
}

///////////////////////////////////////////////////////////////////////////////
//	light_setstyles
//
///////////////////////////////////////////////////////////////////////////////

void	light_setstyles (void)
{
	// 0 normal
	gstate->ConfigString (CS_LIGHTS + 0, "m");
	
	// 1 FLICKER (first variety)
	gstate->ConfigString (CS_LIGHTS + 1, "mmnmmommommnonmmonqnmmo");
	
	// 2 SLOW STRONG PULSE
	gstate->ConfigString (CS_LIGHTS + 2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba");
	
	// 3 CANDLE (first variety)
	gstate->ConfigString (CS_LIGHTS + 3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg");
	
	// 4 FAST STROBE
	gstate->ConfigString (CS_LIGHTS + 4, "mamamamamama");
	
	// 5 GENTLE PULSE 1
	gstate->ConfigString (CS_LIGHTS + 5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj");
	
	// 6 FLICKER (second variety)
	gstate->ConfigString (CS_LIGHTS + 6, "nmonqnmomnmomomno");
	
	// 7 CANDLE (second variety)
	gstate->ConfigString (CS_LIGHTS + 7, "mmmaaaabcdefgmmmmaaaammmaamm");
	
	// 8 CANDLE (third variety)
	gstate->ConfigString (CS_LIGHTS + 8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa");
	
	// 9 SLOW STROBE (fourth variety)
	gstate->ConfigString (CS_LIGHTS + 9, "aaaaaaaazzzzzzzz");
	
	// 10 FLUORESCENT FLICKER
	gstate->ConfigString (CS_LIGHTS + 10, "mmamammmmammamamaaamammma");

	// 11 SLOW PULSE NOT FADE TO BLACK
	gstate->ConfigString (CS_LIGHTS + 11, "abcdefghijklmnopqrrqponmlkjihgfedcba");

	//	styles 12 - 16 are definable by individual lights

	// 63 testing
	gstate->ConfigString (CS_LIGHTS + 63, "a");
}
