/*
Copyright (C) 1997-2001 Id Software, Inc.

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.

*/

#include "ui_local.h"

//=============================================================================
//
// LIST OF PLAYER MODELS
//
//=============================================================================

#define MAX_DISPLAYNAME 16
#define MAX_PLAYERMODELS 1024

m_itemslisthead_t playermodelsItemsList;
byte_vec4_t playerColor;
void UI_ColorRedCallback( menucommon_t *menuitem ) {
	playerColor[0] = menuitem->curvalue;
}
void UI_ColorGreenCallback( menucommon_t *menuitem ) {
	playerColor[1] = menuitem->curvalue;
}
void UI_ColorBlueCallback( menucommon_t *menuitem ) {
	playerColor[2] = menuitem->curvalue;
}

//==============================
// UI_FindIndexForModelAndSkin
// if it fails returns 0 which will be the first indexed one
//==============================
void UI_FindIndexForModelAndSkin( char *model, char *skin, int *modelindex, int *skinindex ) {
	m_listitem_t		*item;
	playermodelinfo_s	*playermodel;
	int					i, j;
	int					currentdirectoryindex = 0;
	int					currentskinindex = 0;

	if( model && model[0] ) {
		// find the skin and model matching our user settings (if any)
		for( i = 0; i < playermodelsItemsList.numItems; i++ ) {
			item = UI_FindItemInScrollListWithId( &playermodelsItemsList, i );
			if( item ) {
				playermodel = (playermodelinfo_s*)item->data;
				if( !Q_stricmp( playermodel->directory, model ) ) {
					currentdirectoryindex = i;
					if( skin && skin[0] ) {
						for( j = 0; j < playermodel->nskins; j++ ) {
							if( !Q_stricmp( playermodel->skinnames[j], skin ) ) {
								currentskinindex = j;
								break;
							}
						}
					}
					break;
				}
			}
		}
	}

	*modelindex = currentdirectoryindex;
	*skinindex = currentdirectoryindex;
}


//==============================
//	ui_PModel_ValidModel - skelmod
//==============================
qboolean ui_PModel_ValidModel( char *model_name )
{
	qboolean found = qfalse;
	char	scratch[MAX_QPATH];

	Q_snprintfz( scratch, sizeof(scratch), "models/players/%s/tris.skm", model_name );
	found = ( trap_FS_FOpenFile(scratch, NULL, FS_READ) != -1 );
	if( !found )
		return qfalse;

	Q_snprintfz( scratch, sizeof(scratch), "models/players/%s/animation.cfg", model_name );
	found = ( trap_FS_FOpenFile(scratch, NULL, FS_READ) != -1 );
	if( !found )
		return qfalse;

	// verify the existence of the "default" skin file
	Q_snprintfz( scratch, sizeof(scratch), "models/players/%s/default.skin", model_name );
	found = ( trap_FS_FOpenFile(scratch, NULL, FS_READ) != -1 );
	if( !found )
		return qfalse;

	return qtrue;
}

//=================
//UI_Playermodels_ScanDirectories
//=================
static void UI_Playermodels_CreateItemList( m_itemslisthead_t *itemlist )
{
	int		ndirs, dirlen;
	char	scratch[MAX_STRING_CHARS];
	char	dirnames[1024];
	char	*dirptr;
	int		i, j;

	UI_FreeScrollItemList( itemlist );

	// get a list of directories (model names)
	ndirs = trap_FS_GetFileList( "models/players", "/", dirnames, sizeof(dirnames) );
	if ( !ndirs )
		return;

	// go through the subdirectories
	//------------------------------
	if ( ndirs > MAX_PLAYERMODELS )
		ndirs = MAX_PLAYERMODELS;
	dirptr = dirnames;

	for( i = 0; i < ndirs; i++, dirptr += dirlen+1 )
	{
		int		k;
		char	skinnamesstring[1024];
		char	**skinnames, *skinptr;
		int		skincount;
		int		nskins = 0, skinlen;

		dirlen = strlen(dirptr);
		if( dirlen && dirptr[dirlen-1]=='/' ) 
			dirptr[dirlen-1]='\0';

		if( !strcmp(dirptr,".") || !strcmp(dirptr,"..") ) // invalid indirections
			continue;

		//check for being already in the list
		for( j = 0; j < itemlist->numItems; j++ ) {
			m_listitem_t *item = UI_FindItemInScrollListWithId( itemlist, j );
			if( item && !Q_stricmp( item->name, dirptr ) )
				continue;
		}

		if( !ui_PModel_ValidModel(dirptr) )
			continue;

		// get the list of skins
		skincount = trap_FS_GetFileList( va("models/players/%s",dirptr), ".skin", skinnamesstring, sizeof(skinnamesstring) );
		if ( !skincount ) // we already checked that the default one was there, so this can never be false, but anyway.
			continue;

		//there are valid skins. So:
		skinnames = UI_Malloc( sizeof( char * ) * ( skincount + 1 ) );
		skinptr = skinnamesstring;
		skinlen = 0;

		//copy the valid skins
		for( nskins = 0, k = 0; k < skincount; k++, skinptr += skinlen+1 )
		{
			qboolean add = qtrue;

			skinlen = strlen( skinptr );
			Q_strncpyz( scratch, skinptr, sizeof(scratch) );
			COM_StripExtension( scratch );

			// see if this skin is already in the list
			for( j = 0; j < nskins; j++ ) {
				if( !Q_stricmp( scratch, skinnames[j] ) ) {
					add = qfalse;
					break;
				}
			}

			if( add ) {
				skinnames[nskins] = UI_CopyString( scratch );
				nskins++;
			}
		}

		//Ignore the model if none of the skin files were valid
		if( !nskins )
			continue;

		{	// put it in the list
			playermodelinfo_s *playermodel = UI_Malloc( sizeof(playermodelinfo_s) );
			Q_strncpyz( playermodel->directory, dirptr, sizeof(playermodel->directory) );
			playermodel->skinnames = skinnames;
			playermodel->nskins = nskins;
			UI_AddItemToScrollList( itemlist, playermodel->directory, (void*)playermodel );
		}
	}
}

//===============
// UI_Playermodel_Init
//===============
void UI_Playermodel_Init( void ) {
	UI_Playermodels_CreateItemList( &playermodelsItemsList );
}

//------------------------------------------------------------------------

//===============
// UI_SkelposeBounds
//===============
static void UI_SkelposeBounds( cgs_skeleton_t *skel, bonepose_t *boneposes, vec3_t mins, vec3_t maxs )
{
	int	j, i;
	
	VectorClear( mins );
	VectorClear( maxs );
	
	for( j = 0; j < skel->numBones; j++ ) {
		for( i = 0; i < 3; i++ ) {
			if( boneposes[j].origin[i] > maxs[i] )
				maxs[i] = boneposes[j].origin[i];
			if(  boneposes[j].origin[i] < mins[i] )
				mins[i] = boneposes[j].origin[i];
		}	
	}

	// HACK: since the model is always some bigger than the skeleton, expand it a 40%
	for( i = 0; i < 3; i++ ) {
		maxs[i] *= 1.45f;
		mins[i] *= 1.45f;
	}
}

//===============
// UI_DrawPlayerModel
//===============
void UI_DrawPlayerModel( char *model, char *skin, byte_vec4_t color, int xpos, int ypos, int width, int height ) {
	refdef_t	refdef;
	static vec3_t angles;
	entity_t	entity;
	vec3_t		mins, maxs;
	cgs_skeleton_t	*skel = NULL;
	char		scratch[MAX_QPATH];

	
	if( !skin || !model )
		return;

	// refdef
	memset( &refdef, 0, sizeof( refdef ) );

	refdef.x = xpos;
	refdef.y = ypos;
	refdef.width = width;
	refdef.height = height;

	refdef.fov_x = 30;
	refdef.fov_y = 30;
	refdef.areabits = 0;
	refdef.time = uis.time * 0.001;
	refdef.rdflags = RDF_NOWORLDMODEL;

	// draw player model

	memset( &entity, 0, sizeof( entity ) );

	Q_snprintfz( scratch, sizeof( scratch ), "models/players/%s/%s.skin", model, skin );
	entity.customShader = NULL;
	entity.customSkin = trap_R_RegisterSkinFile( scratch );
	if( !entity.customSkin )
		return;

	Q_snprintfz( scratch, sizeof( scratch ), "models/players/%s/tris.skm", model );
	entity.model = trap_R_RegisterModel( scratch );
	if( trap_R_SkeletalGetNumBones( entity.model, NULL ) ) {
		skel = UI_SkeletonForModel( entity.model );
		if( !skel ) return;
	}

	entity.frame = entity.oldframe = 234;
	UI_SetBoneposesForTemporaryEntity( &entity );
	UI_SkelposeBounds( skel, entity.boneposes, mins, maxs );
	//trap_R_ModelBounds( entity.model, mins, maxs );
	entity.origin[0] = 0.5 * (maxs[2] - mins[2]) * (1.0 / 0.268);
	entity.origin[1] = 0.5 * (mins[1] + maxs[1]);
	entity.origin[2] = -0.5 * (mins[2] + maxs[2]);
	entity.flags = RF_FULLBRIGHT | RF_NOSHADOW | RF_FORCENOLOD;
	entity.scale = 0.9f;
	Vector4Set( entity.color, color[0], color[1], color[2], 255 );
	VectorCopy( entity.origin, entity.oldorigin );
	VectorCopy( entity.origin, entity.lightingOrigin );
	angles[1] += 1.0f;

	if( angles[1] > 360 )
		angles[1] -= 360;

	AnglesToAxis( angles, entity.axis );

	trap_R_ClearScene();
	trap_R_AddEntityToScene( &entity );
	entity.customSkin = NULL;
	entity.customShader = trap_R_RegisterPic( PATH_NOLODOUTLINE_SHADER );
	Vector4Set( entity.color, color[0] * 0.25f, color[1] * 0.25f, color[2] * 0.25f, 255 );
	trap_R_AddEntityToScene( &entity );
	trap_R_RenderScene( &refdef );

	UI_ResetTemporaryBoneposesCache();
}



