#include <cassert>
#include <cstdarg>
#include <string>
#include <stdlib.h>
#include <string.h>
#include "cvariables.h"
#include "safestring.h"

CVariables::CVariables(  )
{
		var_top = NULL;
};


void CVariables::Cleanup()
{
	L_Variables * v, *_v;

	v = var_top;

	while (v)
	{
		_v = v->next;

		free( v->value );
		delete v;

		v = _v;
	}

	var_top = NULL;	// Used when the desctructor is called explicitly to cleanup
}

CVariables::~CVariables()
{
//	LOG( "~CVariables()", LOG_MAX );
	Cleanup();
//	LOG( "/~CVariables()", LOG_MAX );
}

L_Variables * CVariables::FindVariable( const char * var, bool create/*=false*/ )
{
	L_Variables * v;

	char _var[MAX_CGI_VAR_LEN+1];

	tolower( var, _var, sizeof(_var) );

	if (!var_top && !create)
		return NULL;

	if (!var_top)
	{
		v = var_top = new L_Variables;
	}
	else
	{	// Search to see if such variable already exists
		v = var_top;
		do {
			if ( strcmp( v->name, _var )==0 )
			{
				return v;
			}
			if ( v->next)
				v = v->next;
			else
				break;
		} while ( 1 );

		// no variable found

		if ( create )
		{
			v->next = new L_Variables;
			v = v->next;
		}
		else
			return NULL;
	}

	v->next = NULL;
	strncpy( v->name, _var, MAX_CGI_VAR_LEN );

	v->value = NULL; // So we know the space has not been allocated

	return v;

}


char * CVariables::GetVariable( const char * var  )
{
	L_Variables * v;

	v = FindVariable( var );

	if ( !v )
		return NULL;
	else
		return v->value;
}


bool CVariables::GetBool( char * var, bool test /*= false*/, char * section /*= ""*/ )
{
	L_Variables * v;

	v = FindVariable( var );

	if ( !v )
		return false;
	else
	{
			char * s = v->value;
			return
				strcasecmp( s, "yes" )==0 ||
				strcasecmp( s, "on" )==0 ||
				strcasecmp( s, "1" )==0 ||
				strcasecmp( s, "enable" )==0 ||
				strcasecmp( s, "enabled" )==0 ||
				strcasecmp( s, "true" )==0 ;
	}
}

char * CVariables::GetVariable( const char * var, bool test, char * section /*= ""*/ )
{
	L_Variables * v;

	char name_[MAX_CGI_VAR_LEN+1];
	strsafecpy( name_, test?".":"", sizeof( name_ ) );
	strsafecat( name_, section, sizeof(name_) );
 	if (section[0])
		strsafecat( name_, "_", sizeof(name_) );
	strsafecat( name_, var, sizeof(name_) );

	v = FindVariable( name_ );

	if ( !v )
		return NULL;
	else
		return v->value;
}

char * CVariables::GetVariable( const char * var, char * result, int size )
{
	L_Variables * v;

	v = FindVariable( var );

	if ( !v )
		result[0] = 0;
	else
	{
		strncpy( result, v->value, size );
		result[size-1] = 0;
	}

	return result;
}

long CVariables::GetVariableLong( char * name, bool *valid /*= NULL*/ )
{
	char var[20];
	GetVariable( name, var, sizeof(var) );

//	if (!valid)
//	 	return atol( var );

	char * ep;
	long res = strtol( var, &ep, 10 );
	if (valid)
		*valid = var[0] && !*ep;
	return res;
}


long CVariables::GetVariableLong( char * name, bool test, char * section /*= ""*/ )
{
	char name_[MAX_CGI_VAR_LEN+1];
	strsafecpy( name_, test?".":"", sizeof( name_ ) );
	strsafecat( name_, section, sizeof(name_) );
 	if (section[0])
		strsafecat( name_, "_", sizeof(name_) );
	strsafecat( name_, name, sizeof(name_) );


	char var[20];
	GetVariable( name_, var, sizeof(var) );
	return atol( var );
}


void CVariables::LetInt16( char * var, int value )
{
	L_Variables * v;
	v = FindVariable( var, true );

	if (v->value)
		free( v->value );

	char st[10];
	snprintf( st, sizeof(st), "%d", value);

	v->value = strdup( st );
}

void CVariables::LetStr( const char * var, const char * value ) // NULL-terminated
{
	L_Variables * v;
	v = FindVariable( var, true );

	if (v->value)
		free( v->value );

	if ( value )
    	    v->value = strdup( value );
	else
	    v->value = strdup( "" );
}


void CVariables::RenameVariable( const char * name, const char * newname )
{
	L_Variables * v;
	v = FindVariable( name, true );

	//logfmt( FLOG_MAX, "RenameVariable(): '%s'->'%s'", name, newname );

	if ( !v )
	{
		//logfmt( FLOG_MAX, "RenameVariable(): Variable '%s' not found", name );
		return;
	}

	strsafecpy( v->name, newname, sizeof( v->name ) );
}



void CVariables::vLetStrf( char * var, const char * format, va_list ap )
{
  size_t  buf_size = 512;
  char   *buffer   = new char[buf_size];

  size_t length;

  while (true) {
    if (!buffer) {
      assert(buffer); // to stop when debugging
      snprintf(buffer, buf_size, "<alloc problem>");
      break;
    }
    length = vsnprintf(buffer, buf_size, format, ap);

    if (length >= 0 && length < buf_size - 1) {
      // string fits into current buffer
      break;
    }
    // otherwise resize buffer :
    buf_size *= 2;
    //        fprintf(stderr, "Reallocating vstrf-buffer to size=%u\n", buf_size);
    delete [] buffer;
    buffer = new char[buf_size];
  }

	L_Variables * v;
	v = FindVariable( var, true );

	if (v->value)
		free( v->value );

	if (buffer) {
		v->value = strdup( buffer );
		delete [] buffer;
	} else {
		v->value = strdup( "" );
	}
}


void CVariables::LetStrf( char * var, const char * format, ... )
{
	va_list	ap;
	va_start( ap, format );

	vLetStrf( var, format, ap );

	va_end( ap );
}


/*
void CVariables::LetStrf( char * var, const char * format, ... )
{
	char tmp[1000];

	va_list	ap;
	va_start( ap, format );
	vsnprintf( tmp, sizeof(tmp), format, ap );
	va_end( ap );


	L_Variables * v;
	v = FindVariable( var, true );

	if (v->value)
		free( v->value );

    	v->value = strdup( tmp );
}
*/




void CVariables::StrCat( char * var, const char * format, ... )
{
	char tmp[1000];
	L_Variables * v;

	v = FindVariable( var, true );

	va_list	ap;
	va_start( ap, format );

	if ( !v->value )
		vsnprintf( tmp, sizeof(tmp), format, ap );
	else
	{
//		logfmt( FLOG_MAX, "v->value='%s'", v->value );
		strsafecpy( tmp, v->value, sizeof(tmp) );
		strsafecat( tmp, "<br>", sizeof(tmp) );
		int len = strlen(tmp);
		vsnprintf( &tmp[len], sizeof(tmp)-len, format, ap );

	}
	va_end( ap );

	if (v->value)
		free( v->value );

    	v->value = strdup( tmp );

//        logfmt( FLOG_MAX, "tmp='%s'", tmp );
}


void CVariables::StrCatf( char * var, const char * format, ... )
{
	char tmp[5000];
	L_Variables * v;

	v = FindVariable( var, true );

	va_list	ap;
	va_start( ap, format );

	if ( !v->value )
		vsnprintf( tmp, sizeof(tmp), format, ap );
	else
	{
//		logfmt( FLOG_MAX, "v->value='%s'", v->value );
		strsafecpy( tmp, v->value, sizeof(tmp) );
		//strsafecat( tmp, "<br>", sizeof(tmp) );
		int len = strlen(tmp);
		vsnprintf( &tmp[len], sizeof(tmp)-len, format, ap );

	}
	va_end( ap );

	if (v->value)
		free( v->value );

    	v->value = strdup( tmp );

//        logfmt( FLOG_MAX, "tmp='%s'", tmp );
}


void CVariables::LetStr( char * var, const char * value, int len ) // non-NULL terminated
{
	L_Variables * v;
	v = FindVariable( var, true );

	if (v->value)
		free( v->value );

	if ( value )
	{
    	    v->value = (char*)malloc(len+1);
	    memcpy( v->value, value, len );
	    v->value[len] = 0;
	}
	else
	    v->value = strdup( "" );
}


void CVariables::PrintVars( FILE * f /*= stdout*/ )
{
	L_Variables * v;
	v = var_top;

	fprintf( f, "\nVariable listing (NEW):\n\n" );
	while ( v )
	{
		fprintf( f, "%s[%d] = %s\n", v->name, strlen(v->value), v->value );
		v = v->next;
	}
}

/*
vi:ts=2
*/

