mud++0.35/etc/
mud++0.35/etc/guilds/
mud++0.35/help/propert/
mud++0.35/mudC/
mud++0.35/player/
mud++0.35/src/interface/
mud++0.35/src/os/cygwin32/
mud++0.35/src/os/win32/
mud++0.35/src/os/win32/bcppbuilder/
mud++0.35/src/osaddon/
mud++0.35/src/util/
/*
....[@@@..[@@@..............[@.................. MUD++ is a written from
....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and
....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++.
....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing
....[@......[@..[@@@@@..[@@@@@.................. development project.  All 
................................................ contributions are welcome. 
....Copyright(C).1995.Melvin.Smith.............. Enjoy. 
------------------------------------------------------------------------------
Melvin Smith (aka Fusion)         msmith@hom.net
MUD++ development mailing list    mudpp@van.ml.org
------------------------------------------------------------------------------
properties.cpp
*/

#include "config.h"
#include "properties.h"
#include "erratum.h"
#include "bit.h"

HashTable<Property> properties;
bool properties_initialized = false;


const bitType prop_types[] =
{
	{0,			0},
	{"bool",	PROP_BOOL},
	{"int", 	PROP_INT},
	{"string",	PROP_STRING},
	{"(unknown)", PROP_UNKNOWN},
	{0,			0}
};

Property & Property::operator= (const Property & p)
{
	if ( (type == PROP_STRING) && ( value.s) )
		delete value.s;
	runtime = p.getRuntime();
	type = p.getType();
	nfun = p.getFun();
	value = p.getValue();
	if ( (type == PROP_STRING) && ( value.s ) )
		value.s = new String(*(value.s));
	return *this;
}


int Property::readFrom( StaticInput & si )
{
	char buf[BUF];
	assert( type == PROP_UNKNOWN);
	si.getword(buf);
	if( *buf == 'T' )
		runtime = true;
	else if ( *buf == 'R' )
		runtime = false;
	else if ( *buf == '#' )
		return 1;
	else
	{
		si.errorf( "Property:readFrom - unknown runtime flag '%c'", *buf);
		return -1;
	}

	si.getword(buf);
	type = (property_type) lookupBit( prop_types, buf );
	if ( type == PROP_UNKNOWN )
	{
		si.errorf( "Property:readFrom - unknown type %s", buf);
		return -1;
	}
	si.getword(buf);
	setName( String(buf) );
	switch (type )
	{
		case PROP_BOOL:
			si.getword(buf);
			if ( !strcmp(buf, "true") )
				value.b = true;
			else
				value.b = false;
			break;
		case PROP_INT:
			value.i = si.getnum();
			break;
		case PROP_STRING:
			si.getstring(buf);
			value.s = new String(buf);
			break;
		default:
			Error::dump("Property::readFrom - unknown type despite of check");
	}

	return 0;	
}

const char * Property::asText() const
{
	switch(type)
	{
		case PROP_BOOL:
			return ( value.b ? "true" : "false" );
		case PROP_INT:
			return itoa(value.i);
		case PROP_STRING:
			return value.s->chars();
		default:
			return "(unknown)";
	}
}

const char * Property::getTypeName() const 
{
	return lookupBitName( prop_types, type);
}

int Property::writeTo(Output & out ) const
{
	out << (runtime ? "T " : "R ") << 
		getTypeName() << ' ' << 
		getName() << ' ' << 
		asText();
	if ( type == PROP_STRING )
		out << '~';
	return 0;
}


const char * Property::parseValue( const char * arg )
{
	prop_val nval;
	prop_val old;
	const char * txt;


	switch ( type )
	{
		case PROP_BOOL:
			if ( !strcmp(arg, "true") )
				nval.b = true;
			else if ( !strcmp(arg ,"false") )
				nval.b = false;
			else
				return "This is boolean property - specify 'true' or 'false'";

			if ( value.b == nval.b )
				return "Same value was already set";
			break;
		case PROP_INT:
			nval.i = atoi(arg);
			if ( value.i == nval.i )
				return "Same value was already set";
			break;
		case PROP_STRING:
			if ( nfun )
			{
				old = value;
				value.s = new String( arg );
				if ( (txt = (*nfun) (this)) )
				{
					delete value.s;
					value = old;
					return txt;
				}
				if ( old.s )
					delete old.s;
				return 0;
			}
			else
			{
				if ( value.s )
					delete value.s;
				value.s = new String ( arg );
				return 0;
			}
		default:
			Error::dump("Property:parseValue - unknown type");
	}

	if ( !nfun )
	{
		value = nval;
		return 0;
	}
	else
	{
		old = value;
		value = nval;
		if ( (txt = (*nfun) (this)) )
		{
			value = old;
			return txt;
		}
		return 0;
	}
}

void lookup_property( Property ** holder, const char * name, property_type type,
			const char * defl, notifyFun fun, bool runtime )
{
	Property * prop;
	const char * init_err;

	prop = properties.lookup( name );
	if ( prop )
	{
		assert( prop->getType() == type );
		if ( !prop->getFun() && fun )
		{
			prop->setFun( fun );
			init_err = (*fun) (prop);
			if ( init_err )
			{
				Cout.sendf( "Property %s set to illegal value before initialization.\n\r"
					"Changing to default.\n\r", prop->getName().chars() );
				init_err = prop->parseValue(defl);
				if ( init_err )
					Error::dumpf("Default value %s for property %s is unacceptable",
						defl, name);
			}

		}
		else
		{
			assert( prop->getFun() == fun );
		}
	}
	else
	{
		prop = new Property();
		prop->setName(String(name));
		prop->setType(type);
		prop->setFun(fun);
		prop->setRuntime(runtime);
		init_err = prop->parseValue(defl);
		if ( init_err )
			Error::dumpf("Default value %s for property %s is unacceptable",
				defl, name);
		properties.add( prop->getName(), prop);
	}

	*holder = prop;
}


void initProperties()
{
	Property * prop;
	int answer;
	assert( !properties_initialized );
	InputFile inf(DEFAULT_PROPERTIES_FILE);
	if ( !inf )
	{
		Cout << "no properties file." << endl;
		return;
	}

	while ( true )
	{
		prop = new Property();
		if ( (answer = prop->readFrom(inf)) )
		{
			delete prop;
			if ( answer == 1 )
				Cout << "sucessfull" << endl;
			else
				Cout << "with error" << endl;
			return;
		}
		properties.add( prop->getName(), prop );
	}

}

void loadProperties( StaticInput & si, String & log )
{
	Property * prop;
	Property * oldprop;
	int state;
	int iprop =-1;
	const char * txt;

	while ( true )
	{
		iprop++;
		prop = new Property();
		state = prop->readFrom(si);
		if ( state == 1 )
		{
			log << "Completed sucessfully\n\r";
			delete prop;
			return;
		}
		else if (state == -1 )
		{
			log << "Error ocurred during load of " << iprop << " property.\n\r";
			delete prop;
			return;
		}

		oldprop = properties.lookup(prop->getName());
		if (oldprop)
		{
			prop->setFun(oldprop->getFun());
			if ( prop->getFun() )
			{
				txt = prop->notify();
				if ( txt )
				{
					log << txt << endl;
					delete prop;
					continue;
				}
			}
			*oldprop = *prop;
			delete prop;
			continue;
		}
		properties.add(prop->getName(),prop);
	}

}

void saveProperties( Output & outp )
{
	Property * prop;
	for_each( properties, prop )
	{
		prop->writeTo(outp);
		outp << endl;
	}
	outp << '#' << endl;
}


const char * nf_gtz( const Property * prop )
{
	assert(prop->getType() == PROP_INT );
	if ( prop->getInt() <= 0 )
		return "Value has to be greater than zero";
	return 0;
}

const char * nf_gez( const Property * prop )
{
	assert(prop->getType() == PROP_INT );
	if ( prop->getInt() < 0 )
		return "Value has to be greater or equal to zero";
	return 0;
}