#ifndef __IPTSTATS_C__
#define __IPTSTATS_C__

#include "iptstats.h"

  AnyType initializeServerPlugin( PluginID pluginID, int argc, char *argv[ ] )
{
	FormattedLogMessage( NULL, PLGNAME, "v%d.%d Build %d (2005-2006) by Paul Taylor (Janus) <janus@thepalacehost.com>", vMajor, vMinor, vBuild );

	while ( --argc )
		newvar( argv[ argc ] );

	uint32 j;
	uint8 bfr[ 32 ], *isPtr, *fPtr, *ptr;

	if ( fPtr = ( uint8 * ) fopen( "psdata/iptstats.ini", "rt" ) )
	{
		while ( 1 )
		{
			fgets( bfr, sizeof( bfr ), ( FILE * ) fPtr );
			if ( feof( ( FILE * ) fPtr ) )
				break;
			if ( ( ptr = strchr( bfr, '[' ) ) && strchr( ++ptr, ']' ) )
				isPtr = ( uint8 * ) newrec( cvtH2S( ptr ), ( ( isPtr = strchr( ptr, ':' ) ) ? atoi( ++isPtr ) : 0 ) );
			else if ( isPtr )
				if ( ptr = strchr( bfr, '=' ) )
				{
					*( ptr++ ) = '\0';
					if ( j = fndvar( bfr ) )
						( ( iptStatPtr ) isPtr )->list[ --j ] = ( sint16 ) atoi( ptr );
				}
		}

		fclose( ( FILE * ) fPtr );

		scheduleTimerEvent( pluginID, 0, 0 );
	}

	return ( AnyType ) pluginID;
}

  void handleTimerEvent(ServerState *state, AnyType pluginDat, AnyType timerDat)
{
	uint32 i, j;
	uint8 bfr[ 9 ], *fPtr;

	for ( j = 0; j < nbrRec; )
		if ( ( time( NULL ) - isRec[ j ].last ) > minTime )
		{
			memmove( &isRec[ --j ], &isRec[ ++j ], ( nbrRec - j ) * sizeof( iptStatRec ) );
			isRec = realloc( isRec, --nbrRec * sizeof( iptStatRec ) );
		} else
			j++;

	if ( fPtr = ( uint8 * ) fopen( "psdata/iptstats.ini", "wt" ) )
	{
		for ( j = 0; j < nbrRec; j++ )
		{
			cvtS2H( isRec[ j ].seed, bfr );
			fprintf( ( FILE * ) fPtr, "[%0.9s:%0.10u]\n", bfr, isRec[ j ].last );
			for ( i = 0; i < nbrVar; i++ )
				fprintf( ( FILE * ) fPtr, "%0.15s=%hd\n", isVar[ i ], ( sint16 ) isRec[ j ].list[ i ] );
		}
		fclose( ( FILE * ) fPtr );
	}

	scheduleTimerEvent( ( PluginID ) pluginDat, 0, intTime );
}

  void shutdownServerPlugin( ServerState *state, AnyType pluginDat )
{
	handleTimerEvent( NULL, 0, 0 );

	uint32 j;
	for ( j = 0; j < nbrRec; j++ )
		DisposePtr( isRec[ j ].list );

	DisposePtr( isRec );
	DisposePtr( isVar );
}

  ClientMsg * handleMessage( ServerState *state, AnyType pluginDat, ClientMsg *msg )
{
	uint32 j, seed;
	uint8 *room, *spot, *ptr, *rec;
	if ( msg->eventType == MSG_ROOMGOTO || msg->eventType == MSG_SPOTSTATE )
		seed = state->currentUser->crc ^ state->currentUser->counter ^ MAGICLNG;
	switch ( msg->eventType )
	{
		case MSG_LOGON:
			if ( ComputeLicenseCRC( seed = ( ( ( AuxRegistrationRec * ) &msg->msg )->crc ^ ( ( AuxRegistrationRec * ) &msg->msg )->counter ^ MAGICLNG ) ) != ( ( AuxRegistrationRec * ) &msg->msg )->crc )
				break;
		case MSG_ROOMGOTO:
			if ( room = ( uint8 * ) ( msg->eventType == MSG_LOGON ? state->entrance : GetRoom( ( ( ClientMsg_roomGoto * ) &msg->msg )->dest ) ) )
				if ( spot = ( uint8 * ) &( ( ServerRoomRec * ) room )->varBuf[ ( ( ServerRoomRec * ) room )->room.hotspotOfst ] )
					for ( j = 0; j < ( ( ServerRoomRec * ) room )->room.nbrHotspots; j++ )
						if ( ptr = ( uint8 * ) CvtToCString( &( ( ServerRoomRec * ) room )->varBuf[ ( ( Hotspot * ) spot )[ j ].nameOfst ] ) )
							if ( ! strncmp( GETSTATS, ptr, sizeof( GETSTATS ) - 1 ) )
								( ( Hotspot * ) spot )[ j ].state = ( sint16 ) ( ( rec = ( uint8 * ) fndrec( seed ) ) && ( ptr = ( uint8 * ) fndvar( ( uint8 * ) &ptr[ sizeof( GETSTATS ) - 1 ] ) ) ? ( ( iptStatPtr ) rec )->list[ ( uint32 ) --ptr ] : 0 );
							else if ( ! strncmp( SETSTATS, ptr, sizeof( SETSTATS ) - 1 ) )
								( ( Hotspot * ) spot )[ j ].state = ( sint16 ) 0;
			break;
		case MSG_SPOTSTATE:
			if ( state->currentUser->user.roomID != ( ( ClientMsg_spotState * ) &msg->msg )->roomID )
				return NULL;
			else if ( room = ( uint8 * ) GetRoom( state->currentUser->user.roomID ) )
				if ( spot = ( uint8 * ) GetHotspot( ( ServerRoomRec * ) room, ( ( ClientMsg_spotState * ) &msg->msg )->spotID ) )
					if ( ptr = ( uint8 * ) CvtToCString( &( ( ServerRoomRec * ) room )->varBuf[ ( ( Hotspot * ) spot )->nameOfst ] ) )
						if ( ! strncmp( GETSTATS, ptr, sizeof( GETSTATS ) - 1 ) )
							return NULL;
						else if ( ! strncmp( SETSTATS, ptr, sizeof( SETSTATS ) - 1 ) )
							if ( rec = ( uint8 * ) newrec( seed, 0 ) )
								if ( j = fndvar( ( uint8 * ) &ptr[ sizeof( SETSTATS ) - 1 ] ) )
									( ( iptStatPtr ) rec )->list[ --j ] = ( sint16 ) ( ( ClientMsg_spotState * ) &msg->msg )->state;
			break;
	}
	return msg;
}

  static iptStatPtr newrec( uint32 seed, uint32 date )
{
	if ( seed < 1001 )
		return NULL;
	iptStatPtr ptr;
	if ( ! ( ptr = fndrec( seed ) ) )
		if ( isRec = realloc( isRec, ++nbrRec * sizeof( iptStatRec ) ) )
		{
			( ptr = &isRec[ nbrRec - 1 ] )->seed = seed;
			ptr->list = ( sint16 * ) NewPtrClear( nbrVar * sizeof( sint16 ) );
		} else
			return NULL;
	ptr->last = ( date ? date : time( NULL ) );
	return ptr;
}

  static void newvar( uint8 *ptr )
{
	if ( ptr )
		if ( ! fndvar( ptr ) )
			if ( isVar = realloc( isVar, ++nbrVar * sizeof( Str15 ) ) )
				snprintf( isVar[ nbrVar - 1 ], sizeof( Str15 ), ptr );
}

  static iptStatPtr fndrec( uint32 seed )
{
	uint32 j;
	if ( nbrRec && isRec && seed > 1000 )
		for ( j = 0; j < nbrRec; j++ )
			if ( seed == isRec[ j ].seed )
				return &isRec[ j ];
	return NULL;
}

  static uint32 fndvar( uint8 *ptr )
{
	uint32 j;
	if ( nbrVar && isVar && ptr )
		for ( j = 0; j < nbrVar; j++ )
			if ( ! strcmp( ptr, isVar[ j ] ) )
				return ++j;
	return 0;
}

  static uint32 cvtH2S( uint8 *hash )
{
	uint8 i, j = 0;
	uint32 seed = 0;
	while ( *hash && j < 9 )
		if ( ( i = ( uint8 ) ( ( uint8 * ) strchr( hMsk, toupper( *( hash++ ) ) ) - ( uint8 * ) hMsk ) ) < hMskLen )
			seed += ( i * pow( hMskLen, j++ ) );
	return seed;
}

  static void cvtS2H( uint32 seed, uint8 *hash )
{
	if ( hash )
		while ( seed )
		{
			*( hash++ ) = hMsk[ seed % hMskLen ];
			seed /= hMskLen;
		}
}

#endif /* __IPTSTATS_C__ */
