/** @file filter.h
 *
 *	Interface declaration of module performing some filtration tasks.
 *
 *	(C) Ceslav Przywara 2008, MFF UK Prague
 *
 */

#ifndef _FILTER_H
#define _FILTER_H

#include <string>
#include <vector>

namespace ace {

/** Rule is just a single string.
 */
typedef std::string unirule_t;

/** Rule is a bunch of strings.
 */
typedef std::vector<std::string> multirule_t;

/** For each rule there's a counter of values matched.
 */
typedef std::vector<size_t> filter_matches_stats_t;

/** Abstract class declares some basic interface for counting filter rules matches.
 */
class Filter {
public:
	/** Struct for filtration statistics.
	 */
	struct Stats {
		/** Counter of matched calls to filter.
		 */
		filter_matches_stats_t matched;
		/** Counter of unmatched calls to filter.
		 */
		size_t unmatched;
		/** Default constructor does nothing interesting.
		 */
		Stats(void): matched(), unmatched(0) {}
		/** Reset stats (everything set to 0).
		 */
		void reset(void);
	};
protected:
	/** Overall stats.
	 */
	Stats _stats_so_far;
	/** Recent stats (resetable).
	 */
	Stats _recent_stats;
public:
	/** Class is abstract, so declaring virtual destructor is in good taste.
	 */
	virtual ~Filter(void) {}
	/** @return True, if there are any rules to use.
	 */
	virtual bool is_on(void) const = 0;
	/** @return Recent stats counter.
	 */
	inline Stats recent_stats(void) const { return _recent_stats; }
	/** Resets recent stats counter.
	 */
	inline void reset_recent_stats(void) { _recent_stats.reset(); }
	/** @return Overall stats counter.
	 */
	inline Stats stats_so_far(void) const { return _stats_so_far; }
};


/** Class declares interface of unirules filter. Unirule is rule with just
 *	simple (single-parted) rules.
 */
class UniRulesFilter: public Filter {
public:
	/** The rules are stored within container.
	 */
	typedef std::vector<unirule_t> rules_t;
private:
	/** Rules container.
	 */
	rules_t _rules;
public:
	/** Adds given rule to filter.
	 *	@param rule Rule to add.
	 */
	void add_rule(unirule_t& rule);
	/** @return Reference to const instance of rules container.
	 */
	inline const rules_t& get_rules(void) const { return _rules; }
	/** Essencial filter method - checks, if given value matches the filter.
	 *	@param value Value to check.
	 *	@param include_in_stats Include this one in statistics?
	 *	@return True, if given value pass the filter.
	 */
	bool match(const unirule_t& value, bool include_in_stats = true);
	/** @return True, if there are any rules to match.
	 */
	virtual bool is_on(void) const { return !_rules.empty(); }
	/** Reads rules from given file.
	 *	@param rules_filename Pointer to C-string with filename.
	 *	@return True, if file was processed (it doesn't mean there are any rules to check!).
	 */
	bool read_rules(const char *rules_filename);
};


/** Class declares interface of multirules filter. Multirule is rule which
 *	may contain any number of parts (strings).
 */
class MultiRulesFilter: public Filter {
public:
	/** The rules are stored within container.
	 */
	typedef std::vector<multirule_t> rules_t;
private:
	/** Rules container.
	 */
	rules_t _rules;
public:
	/** Adds given rule to filter.
	 *	@param rule Rule to add.
	 */
	void add_rule(multirule_t& rule);
	/** @return Reference to const instance of rules container.
	 */
	inline const rules_t& get_rules(void) const { return _rules; }
	/** Essencial filter method - checks, if given value matches the filter.
	 *	@param value Value to check.
	 *	@param include_in_stats Include this one in statistics?
	 *	@return True, if given value pass the filter.
	 */
	bool match(const multirule_t& value, bool include_in_stats = true);
	/** @return True, if there are any rules to match.
	 */
	virtual bool is_on(void) const { return !_rules.empty(); }
	/** Reads rules from given file.
	 *	@param rules_filename Pointer to C-string with filename.
	 *	@param only_of_size Store only rules of given size (0 stands for all sizes).
	 *	@return True, if file was processed (it doesn't mean there are any rules to check!).
	 */
	bool read_rules(const char *rules_filename, size_t only_of_size = 0);
};

} // namespace ace

#endif
