#include <stdio.h>
#include <cstring>
#include <cstdlib>
#include "safestring.h"


#pragma implementation "vars.h"
#include "vars.h"

//#include <stl_hashtable.h>
//#include <stl_tree.h>


//template _Rb_tree< string const, pair<string const, varstring>, _Select1st<pair<string const, varstring> >, less<string const>, allocator<varstring> >;
//template _Rb_tree<long, pair<long const, long>, _Select1st<pair<long const, long> >, less<long>, allocator<long> >;


using namespace std;

//template class std::_Rb_tree<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, varstring>, std::_Select1st<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, varstring> >, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const>, std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, varstring> > >;


// template class _Rb_tree<string const, pair<string const, varstring>, _Select1st<pair<basic_string<char, char_traits<char>, allocator<char> > const, varstring> >, less<basic_string<char, char_traits<char>, allocator<char> > const>, allocator<pair<basic_string<char, char_traits<char>, allocator<char> > const, varstring> > >;

template class _Rb_tree< string const, pair<string const, varstring>, _Select1st<pair<string const, varstring> >, less<string const>, allocator<pair<string const,varstring> > >;



 //::operator=(std::_Rb_tree<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, varstring>, std::_Select1st<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, varstring> >, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const>, std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, varstring> > > const&);




// default constructor

varstring::varstring() : string()
{
	validated = false;
	db_var = false;
	binary_var = false;
}

varstring::varstring( const char *c ) : string( c )
{
	this->validated = false;
	db_var = false;
	binary_var = false;
}

varstring::varstring(const char* c, int len) : string( c, len )
{
//	logfmt( FLOG_MAX, "varstring constructor( c='%s', len=%d )", c, len );
	validated = false;
	db_var = false;
	binary_var = false;
}

// copy constructor

varstring::varstring( const varstring &c ) : string( c )
{
//	logfmt( FLOG_MAX, "varstring copy constructor, c.validated=%d, value=%s", c.validated, c.c_str() );
	this->validated = c.validated;
	this->db_var = c.db_var;
	this->binary_var = c.binary_var;
}

varstring::varstring( const string &c ) : string( c )
{
//	logfmt( FLOG_MAX, "string->varstring copy constructor, value=%s", c.c_str() );
	validated = false;
	db_var = false;
	binary_var = false;
}




long varstring::Long() const
{
	return atol( c_str() );
}

double varstring::Double()
{
	return atof( c_str() );
}

varstring& varstring::operator=( const char* c )
{
	set_valid( false );
	string::operator=( c );
	return *this;
};


void varstring::operator=( long l )
{
	set_valid( false );
	char s[20];
	snprintf( s, sizeof(s), "%ld", l );
	string::operator=( s );
};


varstring& varstring::operator=( const varstring &c )
{
	//set_valid( false );
	this->validated = c.validated;
	this->binary_var = c.binary_var;
	string::operator=( c );

	return *this;
};


void varstring::operator=( const string c )
{
	set_valid( false );
	binary_var = false;
	string::operator=( c );
}

varstring::operator long()
{
	return this->Long();
}

varstring::operator const char*()	// type conversion
{
	return this->c_str();
}


bool varstring::valid() const
{
	return validated;
}

void varstring::set_valid( bool validated /*= true*/ )
{
	this->validated = validated;
}



bool varstring::db() const
{
	return db_var;
}

void varstring::set_db( bool db /*= true*/ )
{
	this->db_var = db;
}




bool varstring::binary() const
{
	return this->binary_var;
}

void varstring::set_binary( bool binary_var /*= true*/ )
{
	this->binary_var = binary_var;
}




// ---------------- string_key --------
/*
string_key& string_key::operator=( const char* c )
{
//	set_valid( false );
	string::operator=( c );

	return *this;
};


void string_key::operator=( long l )
{
//	set_valid( false );
	char s[20];
	snprintf( s, sizeof(s), "%ld", l );
	string::operator=( s );
};


void string_key::operator=( const string c )
{
//	set_valid( false );
	string::operator=( c );
};
*/



// ---------------- CVars -------------


CVars& CVars::operator<<( char const *name )
{
	//logfmt( FLOG_MAX, "CVars << %s", name );

	CVars::iterator i = find( name );
	if ( i != end() )
	{
		i->second.set_db();

	}

	return *this;
}


CVars& CVars::operator>>( char const *name )
{
	//logfmt( FLOG_MAX, "CVars >> %s", name );

	CVars::iterator i = find( name );
	if ( i != end() )
	{
		i->second.set_db( false );
	}

	return *this;
}


void CVars::ClearDB()
{
	CVars::iterator i;

	for ( i=begin(); i!=end(); i++ )
		i->second.set_db( false );

}


/*
FORMAT:
	int count;


	{
	name,value,
	bitmap{
		bool validated;
		bool db_var;		// is this variable to be used in DB updates
		bool binary_var;
	}

*/


//implement << operator??

long CVars::serialize( unsigned char *&buf )	// this will serialize the data into buf and return the resulting size
															// it is the responsibility of the caller to free the buffer with free()
{
	long len;
	CVars::iterator i;
	int count = 0;		// do NOT change this datatype as this will affect data structure below!!!
	unsigned char *c = buf + sizeof(count);


	// Calculate the length

	for ( i=begin(); i!=end(); i++ )
	{
		count++;

		int size = i->first.size();
		c += sizeof(unsigned char);		// name should be no longer than 255
		c += size;

		size = i->second.size();
		c += sizeof(int);
		c += size;

		// record bits
		c++;
	}

	len = c-buf;

	buf = (unsigned char*)malloc( len );

	if ( !buf ) return 0;


	// Populate buf

	// first store the number of elements

	*(int*)buf = count;
	c = buf + sizeof(count);

	for ( i=begin(); i!=end(); i++ )
	{
		int size = *(int*)c = i->first.size();
		c += sizeof(unsigned char);
		memcpy( c, i->first.data(), size );
		c += size;

		size = *(int*)c = i->second.size();
		c += sizeof(int);
		memcpy( c, i->second.data(), size );
		c += size;

		// record bits
		*c = i->second.validated | i->second.db_var << 1 | i->second.binary_var << 2;

		c++;
	}

	return len;
}


int CVars::deserialize( unsigned char *buf, long buf_sz )	// this will initialize the current instance by de-serializing the data from buf
{
	// clear out the underlying map / erase any previous data

	erase( begin(), end() );

	if ( buf_sz < (long)sizeof(int) ) return 0;

	unsigned char *c = buf;
	int count = *(int*)buf;
	c += sizeof( count );
	int i = 0;

	for ( i=0; i<count; i++ )
	{
		if ( c-buf >= buf_sz ) return 0;

		char name[256];

		int size = *(unsigned char*)c;
		c += sizeof(unsigned char);

		if ( c-buf+size >= buf_sz ) break;	// boundary check

		strnsafecpy( name, (char*)c, size, sizeof(name) );
		c += size;

		if ( c-buf+(long)sizeof(int) >= buf_sz ) break;	// boundary check

		size = *(int*)c;
		c += sizeof(int);

		if ( c-buf+size+1 > buf_sz ) break;	// boundary check

		(*this)[name].assign( (char*)c, size );
		c += size;

		(*this)[name].validated = *c & 1;
		(*this)[name].db_var = (*c >> 1) & 1;
		(*this)[name].binary_var = (*c >> 2) & 1;

		c++;

		//printf( "i=%d\n", i );
	}

	return i;	//>0 ? i-1 : 0;
}
