// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//

BALL_INLINE 
PropertyManager::PropertyManager()
{
}

BALL_INLINE 
PropertyManager::PropertyManager(const PropertyManager& property_manager)
	:	bitvector_(property_manager.bitvector_),
		named_properties_(property_manager.named_properties_)
{
}

BALL_INLINE 
PropertyManager::~PropertyManager()
{
}


BALL_INLINE 
void NamedProperty::clear()
{
	// free allocated space for strings
	if ((type_ == STRING) && (boost::any_cast<std::string*>(data_) != 0))
	{
		delete boost::any_cast<std::string*>(data_);
	}
	type_ = NONE;
	name_ = "";
}

BALL_INLINE 
NamedProperty::NamedProperty(const std::string& name)
	: PersistentObject(),
		type_(NONE),
		name_(name)
{
}

BALL_INLINE 
NamedProperty::NamedProperty(const std::string& name, bool value)
	:	PersistentObject(),
		type_(BOOL),
		name_(name)
{
	data_ = value;
}

BALL_INLINE 
NamedProperty::NamedProperty(const std::string& name, int value)
	:	PersistentObject(),
		type_(INT),
		name_(name)
{
	data_ = value;
}

BALL_INLINE 
NamedProperty::NamedProperty(const std::string& name, unsigned int value)
	:	PersistentObject(),
		type_(UNSIGNED_INT),
		name_(name)
{
	data_ = value;
}

BALL_INLINE 
NamedProperty::NamedProperty(const std::string& name, float value)
	:	PersistentObject(),
		type_(FLOAT),
		name_(name)
{
	data_ = value;
}

BALL_INLINE 
NamedProperty::NamedProperty(const std::string& name, double value)
	:	PersistentObject(),
		type_(DOUBLE),
		name_(name)
{
	data_ = value;
}

BALL_INLINE 
NamedProperty::NamedProperty(const std::string& name, const string& str)
	:	PersistentObject(),
		type_(STRING),
		name_(name)
{
	data_ = new string(str);
}

BALL_INLINE 
NamedProperty::NamedProperty(const std::string& name, PersistentObject& po)
	:	PersistentObject(),
		type_(OBJECT),
		name_(name)
{
	data_ = &po;
}

BALL_INLINE 
NamedProperty::NamedProperty(const std::string& name, boost::shared_ptr<PersistentObject>& po)
	:	PersistentObject(),
		type_(SMART_OBJECT),
		name_(name)
{
	data_ = po;
}

BALL_INLINE 
NamedProperty::~NamedProperty()
{
	clear();
}

BALL_INLINE 
bool NamedProperty::operator == (const NamedProperty& np) const
{
	if (type_	!= np.type_)
	{
		return false;
	}

	switch (type_)
	{
		case	BOOL:         return(boost::any_cast<bool>(data_) == boost::any_cast<bool>(np.data_));
		case	INT:          return(boost::any_cast<int> (data_) == boost::any_cast<int> (np.data_));
		case	UNSIGNED_INT: return(boost::any_cast<unsigned int> (data_) == boost::any_cast<unsigned int> (np.data_));
		case	FLOAT:        return(boost::any_cast<float> (data_) == boost::any_cast<float> (np.data_));
		case	DOUBLE:       return(boost::any_cast<double> (data_) == boost::any_cast<double> (np.data_));
		case	NONE:         return(true);
		case	STRING:       return(*boost::any_cast<std::string*>(data_) == *boost::any_cast<std::string*>(np.data_));
		case	OBJECT:       return(boost::any_cast<PersistentObject*>(data_) == boost::any_cast<PersistentObject*>(np.data_));
		case	SMART_OBJECT: return(boost::any_cast<boost::shared_ptr<PersistentObject> >(data_) == boost::any_cast<boost::shared_ptr<PersistentObject> >(np.data_));
		default:
			Log.error() << "property.C: can not cast type!" << std::endl;
	}

	return true;
}

BALL_INLINE 
bool NamedProperty::operator != (const NamedProperty& np) const
{
	return !(*this == np);
}
	

BALL_INLINE 
int NamedProperty::getInt() const
{
	return (type_ == INT ? boost::any_cast<int>(data_) : 0);
}

BALL_INLINE 
float NamedProperty::getFloat() const
{
	return (type_ == FLOAT ? boost::any_cast<float>(data_) : 
						(type_ == DOUBLE ? (float)boost::any_cast<double>(data_) : 
							(type_ == INT    ? (float)boost::any_cast<int>(data_) : (float)0.0)));
}

BALL_INLINE 
double NamedProperty::getDouble() const
{
	return (type_ == FLOAT ? (double)boost::any_cast<float>(data_) : 
						(type_ == DOUBLE ?       boost::any_cast<double>(data_) : 
							(type_ == INT    ? (double)boost::any_cast<int>(data_) : 0.0)));
}

BALL_INLINE 
String NamedProperty::getString() const
{
	return (((type_ == STRING) && (boost::any_cast<std::string*>(data_) != 0)) ? (*boost::any_cast<std::string*>(data_)) : std::string(""));
}

BALL_INLINE 
String NamedProperty::toString() const
{
	String res;
	if(type_ == INT)
	{
		int value = getInt();
		res = String(value);
		return res;
	}
	if(type_ == FLOAT)
	{
		float value = getFloat();
		res = String(value);
		return res;
	}
	if(type_ == DOUBLE)
	{
		double value = getDouble();
		res = String(value);
		return res;
	}
	if(type_ == UNSIGNED_INT)
	{
		unsigned int value = getUnsignedInt();
		res = String(value);
		return res;		
	}
	if(type_ == BOOL)
	{
		bool value = getBool();
		res = String(value);
		return res;
	}
	if(type_ == STRING)
	{
		return getString();
	}
	return "";	
}

BALL_INLINE 
unsigned int NamedProperty::getUnsignedInt() const
{
	return (type_ == UNSIGNED_INT ? boost::any_cast<unsigned int>(data_) : 0);
}

BALL_INLINE 
const std::string& NamedProperty::getName() const
{
	return name_;
}

BALL_INLINE 
NamedProperty::Type NamedProperty::getType() const
{
	return type_;
}

BALL_INLINE 
PersistentObject* NamedProperty::getObject() const
{
	return (type_ == OBJECT ? boost::any_cast<PersistentObject*>(data_) : 0);
}

BALL_INLINE 
boost::shared_ptr<PersistentObject> NamedProperty::getSmartObject() const
{
	return (type_ == SMART_OBJECT ? boost::any_cast<boost::shared_ptr<PersistentObject> >(data_) : boost::shared_ptr<PersistentObject>());
}

BALL_INLINE 
bool NamedProperty::getBool() const
{
	return (type_ == BOOL ? boost::any_cast<bool>(data_) : false);
}

BALL_INLINE 
void PropertyManager::clear()
{
	bitvector_.clear();
	named_properties_.clear();
}

BALL_INLINE 
void PropertyManager::destroy()
{
  clear();	// same as clear
}

BALL_INLINE 
const PropertyManager& PropertyManager::operator = (const PropertyManager& property_manager)
{
  set(property_manager);
  return *this;
}

BALL_INLINE 
void PropertyManager::get(PropertyManager& property_manager) const
{
  property_manager.set(*this);
}

BALL_INLINE 
BitVector& PropertyManager::getBitVector()
{
  return bitvector_;
}

BALL_INLINE 
const BitVector& PropertyManager::getBitVector() const
{
  return bitvector_;
}

BALL_INLINE
PropertyManager::operator BitVector & ()
{
  return bitvector_;
}

BALL_INLINE 
void PropertyManager::setProperty(Property property)
{
  bitvector_.setBit(property);
}

BALL_INLINE 
void PropertyManager::setProperty(const std::string& name, bool value)
{
	setProperty(NamedProperty(name, value));
}

BALL_INLINE 
void PropertyManager::setProperty(const std::string& name, float value)
{
	setProperty(NamedProperty(name, value));
}

BALL_INLINE 
void PropertyManager::setProperty(const std::string& name, double value)
{
	setProperty(NamedProperty(name, value));
}

BALL_INLINE 
void PropertyManager::setProperty(const std::string& name, unsigned int value)
{
	setProperty(NamedProperty(name, value));
}

BALL_INLINE 
void PropertyManager::setProperty(const std::string& name, int value)
{
	setProperty(NamedProperty(name, value));
}

BALL_INLINE 
void PropertyManager::setProperty(const std::string& name, const std::string& value)
{
	setProperty(NamedProperty(name, const_cast<std::string&>(value)));
}

BALL_INLINE 
void PropertyManager::setProperty(const std::string& name, const PersistentObject& value)
{
	setProperty(NamedProperty(name, const_cast<PersistentObject&>(value)));
}

BALL_INLINE 
void PropertyManager::clearProperty(Property property)
{
  bitvector_.setBit(property, false);
}

BALL_INLINE 
void PropertyManager::toggleProperty(Property property)
{
  bitvector_.toggleBit(property);
}

BALL_INLINE 
void PropertyManager::swap(PropertyManager& property_manager)
{
	BitVector tmp = bitvector_;
	bitvector_ = property_manager.bitvector_;
	property_manager.bitvector_ = tmp;
	named_properties_.swap(property_manager.named_properties_);
}

BALL_INLINE 
bool PropertyManager::hasProperty(Property property) const
{
	if (bitvector_.getSize() <= (Size)property)
	{
		return false;
	}
  return bitvector_.getBit(property);
}

BALL_INLINE 
bool PropertyManager::isValid() const
{
  return (bitvector_.isValid());
}

BALL_INLINE 
Size PropertyManager::countProperties() const
{
  return ((Size)bitvector_.getSize() + (Size)named_properties_.size());
}

BALL_INLINE
const NamedProperty& PropertyManager::getNamedProperty(Position index) const
{
	if (index >= named_properties_.size())
	{
		throw Exception::IndexOverflow(__FILE__, __LINE__, index, (Size)named_properties_.size());
	}
	return named_properties_[index];
}

BALL_INLINE
NamedProperty& PropertyManager::getNamedProperty(Position index)
{
	if (index >= named_properties_.size())
	{
		throw Exception::IndexOverflow(__FILE__, __LINE__, index, (Size)named_properties_.size());
	}
	return named_properties_[index];
}

BALL_INLINE 
Size PropertyManager::countNamedProperties() const
{
  return (Size)named_properties_.size();
}

BALL_INLINE 
bool PropertyManager::operator == (const PropertyManager& pm) const
{
	return (bitvector_				== pm.bitvector_ &&
					named_properties_	== pm.named_properties_);
}

BALL_INLINE 
bool PropertyManager::operator != (const PropertyManager& pm) const
{
	return (bitvector_				!= pm.bitvector_ ||
					named_properties_	!= pm.named_properties_);
}
