//
// Copyright (c) 2009-2010 Ronald Kluth
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

/**
 * @file InfoTypeFilter.h
 * @author Ronald Kluth
 * @date created at 2009/06/07
 * @brief Declaration and implementation of class InfoTypeFilter and template InfoTypeFilterImpl
 * @since 0.1
 */

#ifndef LOG_DETAIL_INFOTYPEFILTER_INCLUDED
#define LOG_DETAIL_INFOTYPEFILTER_INCLUDED

#include "../Record.h"

#include <set>

namespace Log {
namespace Detail {

/**
 * @class InfoTypeFilter
 * @brief Interface class to emulate hetrogeneous containers
 *
 * A record filter holds a map of info type filters. In order to check records
 * for filtering, the record filter iterates over all InfoTypeFilter objects
 * and checks whether one of the stored values matches that stored in the record.
 */
class InfoTypeFilter
{
public:
	/// Destruction
	virtual ~InfoTypeFilter() {}
	/// Called on derived objects that store sets of InfoType values
	virtual bool matches( const Record& record ) = 0;
};

/**
 * @class InfoTypeFilterImpl
 * @brief Implementation of record filtering functionality based on info types
 * @tparam InfoT Type of record info to be filtered
 *
 * The implementation of InfoTypeFilter holds a set of @c InfoT values to be
 * matched against those transported by records. This class defines the method
 * @c matches, which determines whether a given record contains an info
 * type value that is stored in the filter set.
 */
template < typename InfoT >
class InfoTypeFilterImpl
:	public InfoTypeFilter
{
public:
	/// The record info type that can be filtered by this class
	typedef InfoT InfoType;
	/// Set type to hold filter values
	typedef std::set< typename InfoType::ValueType > FilterSet;

	/// Destruction
	virtual ~InfoTypeFilterImpl() {}

	/// Check if the @c InfoT value of @c record is found in the filter set
	virtual bool matches( const Record& record )
	{
		// try to retrieve the InfoType value from the record, may be 0
		typename InfoType::ValueType const* value = record.get< InfoType >();
		if( ! value )
		{
			return false;
		}
		// a record matches if the value is found in the filter set
		return filterSet_.find( *value ) != filterSet_.end();
	}

	/// Stores @c InfoT values to determine which records get filtered out
	FilterSet filterSet_;
};

} } // namespace Log::Detail

#endif /* LOG_DETAIL_INFOTYPEFILTER_INCLUDED */
