// makevmt.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
#include <io.h>
#include "windows.h"
#include "cmdlib.h"

#define VERSION_STRING "1.0"

const char *default_shader			= "BaseTimesLightmap";
const char *default_model_shader	= "basetimesVertexColor";
const char *filter_file				= "vmtfilters.txt";

//-----------------------------------------------------------------------------
// Purpose: Does a strstr for substring in the raw texture name, if it's found, then no .vmt is generated
//-----------------------------------------------------------------------------
typedef struct filter_s
{
	struct filter_s *next;
	char	substring[ 128 ];
} filter_t;

static filter_t *filters = NULL;

// Number of .vmt files to be created
static int materials_created = 0;
// Flag whether to actually create the .vmt files
static bool docreate = true;

// Selected shaders (either from command line or defaults)
static const char *shader		= NULL;
static const char *model_shader	= NULL;

//-----------------------------------------------------------------------------
// Purpose: Loads the filter data from the filter file
// Input  : *exedir - 
//-----------------------------------------------------------------------------
void LoadFilters( const char *exedir, const char *filename )
{
	char *filter_data = NULL;
	char *data;
	char fullpath[ _MAX_PATH ];

	sprintf( fullpath, "%s%s", exedir, filename );
	
	printf( "Loading filters from:  %s\n", fullpath );

	if ( !LoadFile ( fullpath, (void **)&filter_data )  )
	{
		return;
	}
	
	data = filter_data;

	while( 1 )
	{
		data = COM_Parse( data );
		if ( strlen( com_token ) <= 0 )
			break;

		// Add a filter
		printf( " Adding filter %s\n", com_token );
		filter_t *pf = new filter_t;
		pf->next = filters;
		filters = pf;

		strcpy( pf->substring, com_token );
	}

	free( filter_data );
}

//-----------------------------------------------------------------------------
// Purpose: Cleanup dynamically alloc'd objects
//-----------------------------------------------------------------------------
void Cleanup( void )
{
	filter_t *p, *n;

	p = filters;
	while ( p )
	{
		n = p->next;
		delete p;
		p = n;
	}
	filters = NULL;
}

//-----------------------------------------------------------------------------
// Purpose: Check for filter substrings in rawfilename
// Input  : *rawfilename - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CheckFilters( char *rawfilename )
{
	filter_t *p = filters;
	while ( p )
	{
		// Found one?
		if ( strstr( rawfilename, p->substring ) )
		{
			return true;
		}

		p = p->next;
	}

	return false;
}

//-----------------------------------------------------------------------------
// Purpose: Convert \\ to /
// Input  : *in - 
//-----------------------------------------------------------------------------
void ForwardSlashes( char *in )
{
	while( *in )
	{
		if ( *in == '\\' )
			*in = '/';
		in++;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Create .vmt file for texture
// Input  : *filename - 
//			*texturename - 
//-----------------------------------------------------------------------------
void Create_VMT( const char *filename, char *texturename )
{
	FILE *fp;
	fp = fopen( filename, "w" );
	if ( !fp )
	{
		return;
	}

	// Increment creation count
	materials_created++;

	// Fix texture name
	ForwardSlashes( texturename );

	// Construct file
	fprintf( fp, "// Generated by makevmt.exe\n" );
	fprintf( fp, "$baseTexture = \"%s\"\n", texturename );

	bool ismodel = strstr( filename, "materials\\models" ) ||
		strstr( filename, "materials/models" ) ? true : false;

	fprintf( fp, "$shader = \"%s\"\n", ismodel ? model_shader : shader );
	fclose( fp );
}

//-----------------------------------------------------------------------------
// Purpose: Recursive search basedir for missing .vmt files
// Input  : *original - base materials directory
//			*basedir - current subdir
//-----------------------------------------------------------------------------
void Traverse_Materials( const char *original, const char *basedir )
{
	char	filename[MAX_PATH];
	char	search[ 128 ];

	sprintf( search, "%s\\*.*", basedir );

	WIN32_FIND_DATA wfd;
	HANDLE hResult;
	memset(&wfd, 0, sizeof(WIN32_FIND_DATA));
	
	hResult = FindFirstFile( search, &wfd );
	if (hResult != INVALID_HANDLE_VALUE)
	{
		BOOL bMoreFiles = TRUE;
		for ( ; bMoreFiles; bMoreFiles = FindNextFile(hResult, &wfd) )
		{
			// Skip . and ..
			if ( wfd.cFileName[0] == '.' )
			{
				continue;
			}

			// If it's a subdirectory, just recurse down it
			if ( (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
			{
				char	subdir[MAX_PATH];
				sprintf( subdir, "%s\\%s", basedir, wfd.cFileName );

				// Recurse
				Traverse_Materials( original, subdir );
				continue;
			}

			
			// Check that it's a tga
			//
			
			char fname[_MAX_FNAME];
			char ext[_MAX_EXT];
			
			_splitpath( wfd.cFileName, NULL, NULL, fname, ext );

			// Not a .tga
			if ( stricmp( ext, ".tga" ) )
				continue;

			// One of the filters applied?
			if ( CheckFilters( fname ) )
				continue;

			// Check for .vmt
			sprintf( filename, "%s\\%s.vmt", basedir, fname );
			// Exists, so don't overwrite it
			if ( access( filename, 0 ) != -1 )
				continue;

			char texturename[ _MAX_PATH ];
			char *p = ( char * )basedir;

			// Skip over the base path to get a material system relative path
			p += strlen( original ) + 1;

			// Construct texture name
			sprintf( texturename, "%s\\%s", p, fname );
			
			// Convert all to lower case
			strlwr( texturename );
			strlwr( filename );
			
			// Create or report
			if ( docreate )
			{
				printf( "creating %s\n", filename );
				Create_VMT( filename, texturename );
			}
			else
			{
				printf( "missing %s\n", filename );
			}
		}
		
		FindClose(hResult);
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : argc - 
//			argv[] - 
// Output : int
//-----------------------------------------------------------------------------
int main(int argc, char* argv[])
{
	char *basedir;
	int	i = 1;
	char modulefile[ _MAX_PATH ];
	char exedir[ _MAX_PATH ];
	char filterdir[ _MAX_PATH ];
	char drive[_MAX_DRIVE];
   

	GetModuleFileName( GetModuleHandle( NULL ), modulefile, _MAX_PATH );

	_splitpath(modulefile, drive, exedir, NULL, NULL );

	printf( "%s (c) 2000 Valve, v. %s, build:  %s\n\n",
		argv[0], VERSION_STRING, __DATE__ );

	for ( i = 1 ; i < argc ; i++ )
	{
		if ( !strcmp( argv[ i ], "-shader" ) )
		{
			if ( ++i < argc )
			{
				shader = argv[ i ];
			}
			else
			{
				fprintf( stderr, "Error: expected a value after '-shader'\n" );
				return 1;
			}
		}
		else if ( !strcmp( argv[ i ], "-modelshader" ) )
		{
			if ( ++i < argc )
			{
				model_shader = argv[ i ];
			}
			else
			{
				fprintf( stderr, "Error: expected a value after '-modelshader'\n" );
				return 1;
			}
		}
		else if ( !strcmp( argv[ i ], "-nocreate" ) )
		{
			docreate = false;
		}
		else
		{
			break;
		}
	}

	if (i != ( argc - 1) )
	{
		fprintf( stderr, "Usage: %s [-nocreate] [-shader <shader>] [-modelshader <shader>] <materials dir>\n", argv[ 0 ] );
		return 1;
	}

	if ( shader == NULL )
		shader = default_shader;

	if ( model_shader == NULL )
		model_shader = default_model_shader;

	// Traverse the materials directory for the project
	basedir = argv[ i ];

	if ( !strstr( basedir, "materials" ) )
	{
		fprintf( stderr, "Couldn't find 'materials' in directory specification\n" );
		return 1;
	}

	// Strip trailing extension
	if ( basedir[ strlen( basedir ) - 1 ] == '\\' ||
		 basedir[ strlen( basedir ) - 1 ] == '/' )
	{
		basedir[ strlen( basedir ) - 1 ] = '\0';
	}

	sprintf( filterdir, "%s%s", drive, exedir );

	// Load filters
	LoadFilters( filterdir, filter_file );

	// Traverse
	printf( "Traversing %s\n", basedir );
	Traverse_Materials( basedir, basedir );

	// Report
	if ( materials_created )
	{
		printf( "Created %i .vmt files\n", materials_created );
	}

	// Clean up memory
	Cleanup();

	return 0;
}
