/************************************************************************/
/*	Copyright (C) 2004  Michael C. Shultz				*/
/*									*/
/* 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.							*/
/* 									*/
/* Michael C. Shultz							*/
/* ringworm@inbox.lv							*/
/* Box 3238 Landers, CA 92285						*/
/************************************************************************/

/*
	(c/w)s2.1.1.1 build a cache database containing the name of each
	portname looked up, and the date, time and size of the Makefile.  Get
	the available name of the installed port from the cache if the
	Makefile's time,date, size still match those in the cache. If they
	don't match update the cache record. The initial cache db should be
	created by an "ifFileExists command that returns false, then the cache
	db is touched.  


	( C/W) 2.1.1.2 When having to run make describe currently the output
	is sent to a temp file, then read from the temp file into a Buffer. 
	Change this so that the Buffer is filled directly from popen'ing "make
	describe" instead of system( "make describe > tempfile" ). This will
	probably be just a minor speed up, but is a much better way to
	program.
*/

/* available = PMGRrMakeDescribe( portI.array[recIdxPortI][PORTNAME_F1] ); */

#include	"PMGRrMakeDescribe.h"

#define PORTDIR_F0	0
#define PORTNAME_F1	1
#define MAKEFILESIZE_F2 2
#define MAKEFILETIME_F4 4
#define	CACHE_TMP_2_DB	"mv"" "DATADIR"portCache.tmp "DATADIR PORTS_CACHE_DB



/*globals */
MGsDb	portCache;

/* protos */
char*	rGetFromMakeDescribe( char* );
int	rPurgeCacheRecord( char*, char*, char*, char* );

MGsDb	config_db;
char	config_db_file[]	= DATADIR"configure.db";

char*	PMGRrMakeDescribe( char* installedPortDir )
{
	FILE*			cacheStream		= NULL;
	FILE*			cacheTempStream 	= NULL;
	char			cachFileName[]		= DATADIR PORTS_CACHE_DB;
	char			id[]			= "PMGRrMakeDescribe";
	char*			Buffer			= NULL;
	char*			Makefile		= NULL;
	char*			MakefileSize		= NULL;
	char*			MakefileSizeTemp	= NULL;
	char*			MakefileTime		= NULL;
	char*			MakefileTimeTemp	= NULL;
	int			cacheIdx		= 0;
	int			errorCode		= 0;
	unsigned	int	MakefileSizeInt		= 0;

	MGmDbArray( config_db, config_db_file, "r" );

	if( !( MGrIfFileExist( cachFileName ) ) )
	{
		fprintf( stdout, "%s message:  Creating %s%s\n", id, DATADIR, PORTS_CACHE_DB );
		fflush( stdout );
		cacheStream	= fopen( cachFileName, "w" );
		/*
			0 = dir
			1 = available name
			2 = makefile size
			3 = makefile date
			4 = makefile time
		*/
		fprintf( cacheStream, "%s%c%s%c%s%c%s%c%s%c\n",
			"dir",			0,
			"available name",	0,
			"makefile size",	0,
			"makefile date",	0,
			"makefile time",	0 );
		fclose( cacheStream );
	}

	/************************/
	/* check cach db	*/
	/************************/
	MakefileSizeInt = strlen( PORTSDIR ) + strlen( installedPortDir ) + strlen( "/Makefile" ) + 1;
	Makefile = ( char* )malloc( MakefileSizeInt );
	strncpy( Makefile, PORTSDIR, strlen(PORTSDIR)+1 );
	strncat( Makefile, installedPortDir, strlen(installedPortDir)+1 );
	strncat( Makefile, "/Makefile", strlen("/Makefile")+1 );

	MakefileSizeTemp	= MGrIntToString( MGrFileSize( Makefile ) );
	MakefileSize		= ( char* )malloc( strlen( MakefileSizeTemp ) + 1 );

	MakefileTimeTemp	= MGrIntToString( (int)MGrFileTime( Makefile ) );
	MakefileTime		= ( char* )malloc( strlen( MakefileTimeTemp ) + 1 );

	strncpy( MakefileSize, MakefileSizeTemp, strlen(MakefileSizeTemp)+1 );
	strncpy( MakefileTime, MakefileTimeTemp, strlen(MakefileTimeTemp)+1 );

	MGmDbArray( portCache, cachFileName, "r+" );
	if( errno )
	{
		fprintf( stderr, "%s error:  MGmDbArray returned with an error\n", id );
		return( NULL );
	}
	cacheIdx		= 0;
	while( cacheIdx < portCache.recordQty )
	{
		if( strcmp( installedPortDir, portCache.array[cacheIdx][PORTDIR_F0] ) == 0 ) 
		{
			if( strcmp( MakefileSize, portCache.array[cacheIdx][MAKEFILESIZE_F2] ) == 0 ) 
			{
				if( strcmp( MakefileTime, portCache.array[cacheIdx][MAKEFILETIME_F4] ) == 0 ) 
				{
					Buffer	= (char* )malloc( strlen( portCache.array[cacheIdx][PORTNAME_F1] ) + 1 );
					strncpy( Buffer, portCache.array[cacheIdx][PORTNAME_F1],
						strlen(portCache.array[cacheIdx][PORTNAME_F1])+1 );
					MGmDbArrayFree( portCache );
					free( MakefileSize );
					free( MakefileTime );
					free( Makefile );
					return( Buffer );
				}
				else
				{
					/* if here then Makefile time is wrong */
					errorCode	= rPurgeCacheRecord( 
							portCache.array[0][0],		/* start of buffer */
							portCache.array[cacheIdx][0],	 /* point in buffer
											  just before current
											  record */
							portCache.array[cacheIdx+1][0], /* point just past current record */
							portCache.buffer + portCache.eof ); /* end of buffer */
					if( errorCode )
					{
						return( NULL );
					}
					cacheIdx	= portCache.recordQty;
				}
			}
			else
			{
				/* if here, then there is a record, but the
				makefile size is wrong, for now this record
				will always be a cache miss, someday when I
				can do record updates, this should be fixed to
				insert the new port name int
				portCache.array[cacheIdx][PORTNAME_F1].
				Probably I can to this easily with
				MGrInStringSwap */

				/*  I think merely removing the record from
				portCache.db will be sufficient, then let the
				cache miss section rewite a corrected record.
				*/
					errorCode	= rPurgeCacheRecord( 
							portCache.array[0][0],		/* start of buffer */
							portCache.array[cacheIdx][0], 	/* point in buffer
											  just before current
											  record */
							portCache.array[cacheIdx+1][0], /* point just past current record */
							portCache.buffer + portCache.eof ); /* end of buffer */

				cacheIdx	= portCache.recordQty;
			}
		}
		cacheIdx++;
	}
	fprintf( stdout, "(Cache miss)" );
	fflush( stdout );

	if( !( Buffer = rGetFromMakeDescribe( installedPortDir ) ) )
	{
		fprintf( stderr, "%s error: rGetFromMakeDescribe returned NULL\n", 
			id );
		fflush( stderr );
		free( Makefile );
		free( MakefileSize );
		free( MakefileTime );
		MGmDbArrayFree(config_db);
		return( NULL ); 
	}

	/************************/
	/* cache miss		*/
	/************************/
	cacheTempStream = fopen( DATADIR"portCache.tmp", "w" );
	fwrite( portCache.buffer, portCache.eof, 1, cacheTempStream );
	fprintf( cacheTempStream, "%s%c%s%c%s%c%s%c%s%c\n",	
			installedPortDir,	0,
			Buffer,			0,
			MakefileSize,		0,
			"makefile date",	0,
			MakefileTime,		0 );
	fflush( cacheTempStream );
	fclose( cacheTempStream );
	MGmDbArrayFree( portCache );
	system( CACHE_TMP_2_DB );
	/************************/
	free( MakefileSize );
	free( Makefile );
	MGmDbArrayFree(config_db);
	return( Buffer );
}

char*	rGetFromMakeDescribe( char* installedPortDir )
{
	FILE*			tempStream		= NULL;
	char			id[]			= "rGetFromMakeDescribe";
	char*			Buffer			= NULL;
	char*			currentPortMakefile	= NULL;
	int			idx			= 0;
	int			skip			= 0;
	unsigned	int	BufferSize		= 65000;
	unsigned	int	miscPtr 		= 0;

	Buffer	= (char* )malloc( BufferSize );
	Buffer[BufferSize]	= 0;

	while( idx < config_db.recordQty )
	{
		/* see if this port has anything special in config.db */
		if( strnstr( installedPortDir, config_db.array[idx][0], strlen( installedPortDir ) ) != 0 )
		{
			currentPortMakefile	= ( char* )malloc( 
							strlen( "( cd /usr/ports/" )
							+ strlen( installedPortDir ) 
							+ strlen( "; make " )
							+ strlen( config_db.array[idx][1] )
							+ strlen( " describe" )
							+ 1 );
			strncpy( currentPortMakefile, "( cd /usr/ports/", strlen("( cd /usr/ports/")+1 );
			strncat( currentPortMakefile, installedPortDir, strlen(installedPortDir)+1 );
			strncat( currentPortMakefile, "; make ", strlen("; make ")+1 );
			strncat( currentPortMakefile, config_db.array[idx][1], strlen(config_db.array[idx][1])+1 );
			strncat( currentPortMakefile, " describe", strlen(" describe")+1 );
			strncat( currentPortMakefile, " ) ", strlen(" ) ")+1 );
			skip	= 1;
			break;
		}
		idx++;
	}
	if( skip == 0 )
	{
		/*	set get portname for Makefile lookup from portI.db	*/
		currentPortMakefile	= ( char* )malloc( 
						strlen( "( cd /usr/ports/" )
						+ strlen( installedPortDir ) 
						+ strlen( "; make describe )" )
						+ 1 );


		strncpy( currentPortMakefile, "( cd /usr/ports/", strlen("( cd /usr/ports/")+1 );
		strncat( currentPortMakefile, installedPortDir, strlen(installedPortDir)+1 );
		strncat( currentPortMakefile, "; make describe )", strlen("; make describe )")+1 );
	}
	tempStream	= popen( currentPortMakefile, "r" );

	if( ferror( tempStream ) )
	{
		fprintf( stderr, "%s error: reading make describe into buffer\n", id );
		perror( "system message" );
		pclose( tempStream );
		free( Buffer );
		free( currentPortMakefile );
		return( NULL ); 
	}
	fread( Buffer, BufferSize, 1, tempStream );
	pclose( tempStream );
	free( currentPortMakefile );
	miscPtr = 0;
	while( miscPtr < ( int )strlen( Buffer ) )
	{
		if( Buffer[miscPtr] == '|' )
		{
			Buffer[miscPtr] = 0;
			Buffer = realloc( Buffer, miscPtr + 1 );
			miscPtr = ( int )strlen( Buffer );
		}
		miscPtr++;
	}
	Buffer	= ( char* )realloc( Buffer, strlen( Buffer ) + 1 );
	return( Buffer );
}
int	rPurgeCacheRecord( char* ptrStart, char* ptrMid, char* ptrMidSkip, char* ptrEof )
{
	FILE*	cacheTempStream 	= NULL;
	char	cachFileName[]		= DATADIR PORTS_CACHE_DB;
	char	id[]			= "PMGRrMakeDescribe.rPurgeCacheRecord";

	/************************/
	/* cache purge		*/
	/************************/
	cacheTempStream = fopen( DATADIR"portCache.tmp", "w" );
	fwrite( ptrStart, (unsigned int)ptrMid - (unsigned int)ptrStart, 1, cacheTempStream );
	fclose( cacheTempStream );

	cacheTempStream = fopen( DATADIR"portCache.tmp", "a" );
	fwrite( ptrMidSkip, (unsigned int)ptrEof - (unsigned int)ptrMidSkip, 1, cacheTempStream );
	fclose( cacheTempStream );
	fflush( cacheTempStream );

	MGmDbArrayFree( portCache );
	system( CACHE_TMP_2_DB );

	MGmDbArray( portCache, cachFileName, "r+" );
	if( errno )
	{
		fprintf( stderr, "%s error:  MGmDbArray returned with an error\n", id );
		return( 1 );
	}
	/************************/
	return( 0 );
}