#include <ctype.h>
#include "tdhkit.h"
#include "shsql.h"

int TDH_setfmdelim();


/* ============================== */
/* LOADFIELDMAP - get field name header of a file and load the TDH fieldmap.
 */

static char curtable[MAXPATH] = ""; 	/* remember current table */

int
SHSQL_loadfieldmap( tablename )
char *tablename;
{
char filename[MAXPATH];
char buf[ MAXRECORDLEN+1 ];
FILE *fp;
int found, stat;

if( strcmp( tablename, curtable )==0 ) return( 0 );

if( GL_member( tablename[0], "./" )) fp = fopen( tablename, "r" );
else 	{
	sprintf( filename, "%s/data/%s", SHSQL_projdir, tablename );
	fp = fopen( filename, "r" );
	}
if( fp == NULL ) return( SHSQL_err( 200, "cannot open data file to get field names", tablename ) );
found = 0;
while( fgets( buf, MAXRECORDLEN, fp ) != NULL ) {
	if( strncmp( buf, "//", 2 )==0 || isdelim( buf[0] )) continue;
	else { found = 1; break; }
	}
fclose( fp );  /* too many files open bug on repeated ops .. added scg 8/1/05 */
if( !found ) return( 201 ); /* (SHSQL_err) */
TDH_setfmdelim( SHSQL_delim );
stat = TDH_loadfieldmap( "shsql_header", buf );		/* tagvalue */
TDH_setfmdelim( BLANK );
if( stat == 0 ) strcpy( curtable, tablename );
return( stat );
}

/* ============================= */
/* LFMCURTABLE - set curtable for situations where we don't access TDH_fieldmap thru here.. */
int
SHSQL_lfmcurtable( s )
char *s;
{
strcpy( curtable, s );
return( 0 );
}

/* =============================== */
/* ERR - display error message, log error, and return error number */
int
SHSQL_err( errno, msg, parm )
int errno;
char *msg;
char *parm;
{

/* if a data file is locked, unlock it.. */
SHSQL_unlock( );

err( errno, msg, parm );
SHSQL_logdberr( errno, msg, parm );
return( errno );
}

/* =============================== */
/* LOGDBERR - log an error to db Errorfile */
int
SHSQL_logdberr( errno, parm, parm2 )
int errno;
char *parm, *parm2;
{
FILE *errfp;
int m, d, y, h, min, s;
char *identity;
char filename[MAXPATH];

GL_sysdate( &m, &d, &y );
GL_systime( &h, &min, &s );

sprintf( filename, "%s/logs/dberrorlog", SHSQL_projdir );
errfp = fopen( filename, "a" );
if( errfp == NULL ) return( 1 );
identity = TDH_getvarp( "_IDENTITY" );
if( identity == NULL ) identity = "=";
fprintf( errfp, "%02d/%02d/%02d %02d:%02d:%02d %d %s %s %s\n", 
	y, m, d, h, min, s, errno, identity, parm, parm2 );

fclose( errfp ); 
return( 0 );
}


/* ============================== */
/* LOG - make a log entry for a transaction.   */

static FILE *Logfp = NULL;

int
SHSQL_log( action, parm, data, nitems, buf )
char *action, *parm;
char data[MAXITEMS][DATAMAXLEN+1];
int nitems;	/* if data[] is used, # items in array.  Otherwise not used */
char *buf;	/* may be passed if record has already been built; otherwise it will be built into here using data[] */
{
int i;
int hr, min, sec, mon, day, yr;
char filename[ MAXPATH ];
char *identity;


if( SHSQL_translog == 0 ) return( 0 ); /* do nothing */

GL_sysdate( &mon, &day, &yr );
GL_systime( &hr, &min, &sec );
identity = TDH_getvarp( "_IDENTITY" );
if( identity == NULL ) identity = "=";

if( SHSQL_splitlog && strcmp( identity, "=" )!=0 ) sprintf( filename, "%s/logs/dbtranslog.%s", SHSQL_projdir, identity );
else sprintf( filename, "%s/logs/dbtranslog", SHSQL_projdir );
if( Logfp == NULL ) Logfp = fopen( filename, "a" ); 
if( Logfp == NULL ) return( 1 );

fprintf( Logfp, "%s %s %s %02d/%02d/%02d %02d:%02d:%02d ", parm, action, identity, yr, mon, day, hr, min, sec );
if( data != NULL ) {
	for( i = 0; i < nitems; i++ ) fprintf( Logfp, "%s%c", data[i], SHSQL_delim );
	fprintf( Logfp, "\n" );
	}
else 	{
	fputs( buf, Logfp );
	if( strcmp( action, "add" )==0 || strcmp( action, "update-new" )==0 ) fprintf( Logfp, "\n" );
	}

/* the transaction log file pointer will be left open */
return( 0 );
}


/* ======================== */
/* ATVAR - prefix variables with an at-sign.  used in where clauses. */
int
SHSQL_atvar( out, in )
char *out;
char *in;
{

int j, ix, ntoks;
char tok[DATAMAXLEN+1];

ix = 0;
j = 0;
ntoks = 0;
while( 1 ) {
	strcpy( tok, GL_getok( in, &ix ) );
	if( tok[0] == '\0' ) break;

	if( stricmp( tok, TDH_dbnull )==0 ) {  /* avoid upper/lower case problems with null */
		sprintf( &out[j], "%s ", TDH_dbnull );
		j+= strlen( TDH_dbnull ) + 1; 
		}

	/* - and . added to below condition, scg 6/14/01 */
	else if( ntoks % 2 == 0 && tok[0] != '@' && !isdigit( (int) tok[0] ) && tok[0] != '-' && tok[0] != '.' ) {
		sprintf( &out[j], "@%s ", tok );
		j+= strlen( tok ) + 2; 
		}

	else 	{
		sprintf( &out[j], "%s ", tok );
		j+= strlen( tok ) + 1; 
		}
	ntoks++;
	}
return( 0 );
}


/* ======================================== */
/* L_TO_B64 - convert a long to a base64 representation */
static char *syms = "0123456789?@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static long raise[8] = { 1, 64, 4096, 262144, 16777216, 1073741824, -1 };

int
SHSQL_l_to_b64( in, out )
long in;
char *out;
{
int i, j, len;
char temp[80];

/* convert integer to ascii number in new base */
i=0;
while ( in > 0) {
	temp[i++] = syms[ (int)(in % 64) ];
	in /= 64;
	}
temp[i] = '\0';
len = i;

/* reverse.. */
for( i = 0, j = len-1; j >= 0; j--, i++ ) out[i] = temp[j];
out[i] = '\0';
return( 0 );
}

/* =========================================== */
/* B64_TO_L - convert our base64 representation to long */

int
SHSQL_b64_to_l( in, out )
char *in;
long *out;
{
int i, j, len;
long val;	
char c;

len = strlen( in );

/* now convert back.. */
(*out) = 0;
for( i = len-1, j = 0; i >= 0; i--, j++ ) {
	c = in[i];
	if( c >= '?' && c <= 'Z' ) val = (c - '?' ) + 10;
	else if( c >= 'a' && c <= 'z' ) val = (c - 'a') + 38;
	else val = c - '0';
	if( raise[i] == -1 ) { out[0] = '\0'; return( 101 ); }
	(*out) += (val * raise[j] );
	}
return( 0 );
}

#ifdef TEST
main()
{
char buf[80];
long num;
while( 1 ) {
	scanf( "%ld", &num );
	SHSQL_l_to_b64( num, buf );
	printf( "%s\n", buf );
	SHSQL_b64_to_l( buf, &num );
	printf( "%ld\n", num );
	}
}
#endif


/* ========================================== */
/* ISDELIM - return 1 if given character is a field delimitation character, 0 if not */
int
SHSQL_isdelim( c )
char c;
{
if( isspace( (int) SHSQL_delim ) ) return( isspace( (int) c ));
else if( c == SHSQL_delim ) return( 1 );
else return( 0 );
}

/* =========================================== */
/* GETFLD - get the next field in buf */
int
SHSQL_getfld( out, buf, ix )
char *out, *buf;
int *ix;
{
if( isspace( (int) SHSQL_delim )) strcpy( out, GL_getok( buf, ix ));
else 	{
	GL_getseg( out, buf, ix, SHSQL_delims );
	if( out[(*ix)-1] == '\n' ) out[(*ix)-1] = '\0'; 	/* added 10/16/02 */
	}
if( out[0] == '\n' ) out[0] = '\0'; /* handle eor correctly for non-ws delim */
return( 0 );
}

/* =========================== */
/* READFDF (stub) */
int
TDH_readfdf( a, b, c, d )
char *a, *b, *c, *d;
{
SHSQL_err( 199, "attempt to get field definitions for a table but none loaded yet", a );
return( -1 );
}

