/*
Copyright (C) 2003-2006 Andrey Nazarov

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

//
// cl_locs.c
//

#include "client.h"

typedef struct {
	listElem_t elem;
	vec3_t origin;
	char name[1];
} location_t;

static list_t		cl_locations;

static cvar_t	*loc_draw;
static cvar_t	*loc_trace;
static cvar_t	*loc_dist;

/*
==============
LOC_Alloc
==============
*/
static location_t *LOC_Alloc( const char *name ) {
	location_t *loc;
	char buffer[MAX_QPATH];
	int length;

	Q_CleanStr( name, buffer, sizeof( buffer ) );

	length = strlen( buffer );
	loc = Z_Malloc( sizeof( *loc ) + length );
	strcpy( loc->name, buffer );
	List_Append( &cl_locations, loc );

	return loc;
}

/*
==============
LOC_LoadLocations
==============
*/
void LOC_LoadLocations( void ) {
	char path[MAX_QPATH];
	char *buffer, *s, *p;
	int line, count;
	location_t *loc;
	int argc;

	// load from main directory
	Com_sprintf( path, sizeof( path ), "locs/%s.loc", cl.mapname );

	FS_LoadFile( path, (void **)&buffer );
	if( !buffer ) {
		Com_DPrintf( "Couldn't load %s\n", path );
		return;
	}

	s = buffer;
	line = count = 0;
	while( *s ) {
		p = strchr( s, '\n' );
		if( p ) {
			*p = 0;
		}

		Cmd_TokenizeString( s, qfalse );
		line++;

		argc = Cmd_Argc();
		if( argc != 0 && argc < 4 ) {
			Com_WPrintf( "Line %i is incomplete in %s\n", line, path );
		} else {
			loc = LOC_Alloc( Cmd_RawArgsFrom( 3 ) );
			loc->origin[0] = atof( Cmd_Argv( 0 ) ) * 0.125f;
			loc->origin[1] = atof( Cmd_Argv( 1 ) ) * 0.125f;
			loc->origin[2] = atof( Cmd_Argv( 2 ) ) * 0.125f;
			count++;
		}

		if( !p ) {
			break;
		}

		s = p + 1;
	}

	Com_Printf( "Loaded %i locations from %s\n", count, path );

	FS_FreeFile( buffer );

}

/*
==============
LOC_FreeLocations
==============
*/
void LOC_FreeLocations( void ) {
	List_Free( &cl_locations );
}

/*
==============
LOC_FindClosest
==============
*/
static location_t *LOC_FindClosest( vec3_t pos ) {
	listElem_t *elem;
	location_t *loc, *nearest;
	vec3_t dir;
	float dist, minDist;
	trace_t trace;

	minDist = 99999;
	nearest = NULL;
	for( elem = cl_locations.first; elem; elem = elem->next ) {
		loc = ( location_t * )elem;
		VectorSubtract( pos, loc->origin, dir );
		dist = VectorLength( dir );

		if( dist > loc_dist->value ) {
			continue;
		}

		if( loc_trace->integer ) {
			CM_BoxTrace( &trace, pos, loc->origin, vec3_origin, vec3_origin,
                cl.cm.cache->nodes, MASK_SOLID );
			if( trace.fraction != 1.0f ) {
				continue;
			}
		}
		
		if( dist < minDist ) {
			minDist = dist;
			nearest = loc;
		}
	}

	return nearest;
}

/*
==============
LOC_AddLocationsToScene
==============
*/
void LOC_AddLocationsToScene( void ) {
	listElem_t *elem;
	location_t *loc, *nearest;
	vec3_t dir;
	float dist;
	entity_t ent;

	if( !loc_draw->integer ) {
		return;
	}

	memset( &ent, 0, sizeof( ent ) );
	ent.model = ref.RegisterModel( "models/items/c_head/tris.md2" );
	ent.skin = ref.RegisterSkin( "models/items/c_head/skin.pcx" );

	nearest = LOC_FindClosest( cl.playerEntityOrigin );
	if( !nearest ) {
		return;
	}

	for( elem = cl_locations.first; elem; elem = elem->next ) {
		loc = ( location_t * )elem;
		VectorSubtract( cl.playerEntityOrigin, loc->origin, dir );
		dist = VectorLength( dir );

		if( dist > loc_dist->integer ) {
			continue;
		}

		VectorCopy( loc->origin, ent.origin );

		if( loc == nearest ) {
			ent.origin[2] += 10.0f * sin( cl.time * 0.01f );
			V_AddLight( loc->origin, 200, 1, 1, 1 );
		}

		V_AddEntity( &ent );

	}

}

/*
==============
LOC_Here_m
==============
*/
static void LOC_Here_m( char *buffer, int bufferSize ) {
	location_t *loc;

	Q_strncpyz( buffer, "unknown", bufferSize );

	if( cls.state != ca_active ) {
		return;
	}

	loc = LOC_FindClosest( cl.playerEntityOrigin );
	if( loc ) {
		Q_strncpyz( buffer, loc->name, bufferSize );
	}

}

/*
==============
LOC_There_m
==============
*/
static void LOC_There_m( char *buffer, int bufferSize ) {
	location_t *loc;
	vec3_t pos;
	trace_t trace;

	Q_strncpyz( buffer, "unknown", bufferSize );

	if( cls.state != ca_active ) {
		return;
	}

	VectorMA( cl.playerEntityOrigin, 8192, cl.v_forward, pos );
	CM_BoxTrace( &trace, cl.playerEntityOrigin, pos, vec3_origin, vec3_origin,
        cl.cm.cache->nodes, MASK_SOLID );

	loc = LOC_FindClosest( trace.endpos );
	if( loc ) {
		Q_strncpyz( buffer, loc->name, bufferSize );
	}

}

/*
==============
LOC_Init
==============
*/
void LOC_Init( void ) {
//	loc_enable = Cvar_Get( "loc_enable", "0", 0 );
	loc_trace = Cvar_Get( "loc_trace", "0", 0 );
	loc_draw = Cvar_Get( "loc_draw", "0", 0 );
	loc_dist = Cvar_Get( "loc_dist", "500", 0 );

	Cmd_AddMacro( "loc_here", LOC_Here_m );
	Cmd_AddMacro( "loc_there", LOC_There_m );

}
	


