void CLogic::quantize_to_allowed_states( CValue &value, const value_set &allowed_states ) const
	{
		const CValue *nearest_allowed_state = NULL;
		float distance_to_current = 0;
		float distance_to_nearest_allowed_state = 0;
		bool first = true;

		for( value_set::const_iterator i = allowed_states.begin(); i != allowed_states.end(); i++ )
		{
			const CValue *allowed_state = *i;
			if( value.get_type() != allowed_state->get_type() )
			{
				INTEGRA_TRACE_ERROR << "Value type mismatch whilst quantizing to allowed states";
				continue;
			}

			distance_to_current = value.get_distance( *allowed_state );

			if( first || distance_to_current < distance_to_nearest_allowed_state )
			{
				distance_to_nearest_allowed_state = distance_to_current;
				nearest_allowed_state = allowed_state;
				first = false;
			}
		}

		if( !nearest_allowed_state )
		{
			INTEGRA_TRACE_ERROR << "failed to quantize to allowed states - allowed states is empty";
			return;
		}

		assert( nearest_allowed_state->get_type() == value.get_type() );

		value = *nearest_allowed_state;
	}
	bool CStateInfo::test_constraint( const CValue &value ) const
	{
		CValue::type endpoint_type = get_type();

		if( value.get_type() != endpoint_type )
		{
			CValue *fixed_type = value.transmogrify( endpoint_type );

			bool test_result = test_constraint( *fixed_type );
			delete fixed_type;
			return test_result;
		}

		const IConstraint &constraint = get_constraint();

		const IValueRange *range = constraint.get_value_range();
		if( range )
		{
			switch( value.get_type() )
			{
				case CValue::STRING:
					{
						/* for strings, range constraint defines min/max length */
						const string &string_value = value;
						int string_length = string_value.length();
			
						if( string_length < ( int ) range->get_minimum() ) return false;
						if( string_length > ( int ) range->get_maximum() ) return false;

						return true;
					}

				case CValue::INTEGER:
					{
						/* for integers, range constraint defines min/max value */
						int int_value = value;

						if( int_value < ( int ) range->get_minimum() ) return false;
						if( int_value > ( int ) range->get_maximum() ) return false;

						return true;
					}

				case CValue::FLOAT:
					{
						/* for floats, range constraint defines min/max value */
						float float_value = value;

						if( float_value < ( float ) range->get_minimum() ) return false;
						if( float_value > ( float ) range->get_maximum() ) return false;

						return true;
					}

				default:
					INTEGRA_TRACE_ERROR << "unhandled value type";
					return false;
			}
		}
		else	/* allowed value constraint */
		{
			const value_set *allowed_states = constraint.get_allowed_states();
			assert( allowed_states );
			for( value_set::const_iterator i = allowed_states->begin(); i != allowed_states->end(); i++ )
			{
				if( value.is_equal( **i ) ) 
				{
					return true;
				}
			}

			return false;	//not found
		}
	}