/*
Copyright (C) 2021 The Falco Authors.

Falco is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.

Falco is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Falco.  If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <set>
#include <list>
#include <map>
#include <memory>
#include <string>
#include <vector>

/*
 * Operators to compare events
 */
enum cmpop {
	CO_NONE = 0,
	CO_EQ = 1,
	CO_NE = 2,
	CO_LT = 3,
	CO_LE = 4,
	CO_GT = 5,
	CO_GE = 6,
	CO_CONTAINS = 7,
	CO_IN = 8,
	CO_EXISTS = 9,
	CO_ICONTAINS = 10,
	CO_STARTSWITH = 11,
	CO_GLOB = 12,
	CO_PMATCH = 13,
	CO_ENDSWITH = 14,
	CO_INTERSECTS = 15,
};

enum boolop
{
	BO_NONE = 0,
	BO_NOT = 1,
	BO_OR = 2,
	BO_AND = 4,

	// obtained by bitwise OR'ing with one of above ops
	BO_ORNOT = 3,
	BO_ANDNOT = 5,
};

enum evt_src
{
	ESRC_NONE = 0,
	ESRC_SINSP = 1,
	ESRC_K8S_AUDIT = 2,
	ESRC_MAX = 3,
};

class gen_event
{
public:
	gen_event();
	virtual ~gen_event();

	/*!
	  \brief Set an opaque "check id", corresponding to the id of the last filtercheck that matched this event.
	*/
	void set_check_id(int32_t id);

	/*!
	  \brief Get the opaque "check id" (-1 if not set).
	*/
	int32_t get_check_id() const;

	// Every event must expose a timestamp
	virtual uint64_t get_ts() const = 0;

	/*!
	  \brief Get the source of the event.
	*/
	virtual uint16_t get_source() const = 0;

	/*!
	  \brief Get the type of the event.
	*/
	virtual uint16_t get_type() const = 0;

private:
	int32_t m_check_id = 0;

};


class gen_event_filter_check
{
public:
	gen_event_filter_check();
	virtual ~gen_event_filter_check();

	boolop m_boolop;
	cmpop m_cmpop;

	virtual int32_t parse_field_name(const char* str, bool alloc_state, bool needed_for_filtering) = 0;
	virtual void add_filter_value(const char* str, uint32_t len, uint32_t i = 0 ) = 0;
	virtual bool compare(gen_event *evt) = 0;
	virtual uint8_t* extract(gen_event *evt, uint32_t* len, bool sanitize_strings = true) = 0;

	//
	// Configure numeric id to be set on events that match this filter
	//
	void set_check_id(int32_t id);
	virtual int32_t get_check_id();

	// Return all event types used by this filtercheck. It's used in
	// programs like falco to speed up rule evaluation.
	virtual const std::set<uint16_t> &evttypes();

	// Return all possible event types. Used for "not" operators
	// where a set of events must be inverted.
	virtual const std::set<uint16_t> &possible_evttypes();

	static std::set<uint16_t> s_default_evttypes;

private:
	int32_t m_check_id = 0;

};

///////////////////////////////////////////////////////////////////////////////
// Filter expression class
// A filter expression contains multiple filters connected by boolean expressions,
// e.g. "check or check", "check and check and check", "not check"
///////////////////////////////////////////////////////////////////////////////

class gen_event_filter_expression : public gen_event_filter_check
{
public:
	gen_event_filter_expression();
	virtual ~gen_event_filter_expression();

	//
	// The following methods are part of the filter check interface but are irrelevant
	// for this class, because they are used only for the leaves of the filtering tree.
	//
	int32_t parse_field_name(const char* str, bool alloc_state, bool needed_for_filtering)
	{
		return 0;
	}

	void add_filter_value(const char* str, uint32_t len, uint32_t i = 0 )
	{
		return;
	}

	void add_check(gen_event_filter_check* chk);

	bool compare(gen_event *evt);

	uint8_t* extract(gen_event *evt, uint32_t* len, bool sanitize_strings = true);

	//
	// An expression is consistent if all its checks are of the same type (or/and).
	//
	// This method returns the expression operator (BO_AND/BO_OR/BO_NONE) if the
	// expression is consistent. It returns -1 if the expression is not consistent.
	//
	int32_t get_expr_boolop();

	// Return all event types used by this expression. It's used in
	// programs like falco to speed up rule evaluation.
	const std::set<uint16_t> &evttypes() override;

	// An expression does not directly have a set of possible
	// event types, but it can determine them from the m_checks
	// vector.
	const std::set<uint16_t> &possible_evttypes() override;

	gen_event_filter_expression* m_parent;
	std::vector<gen_event_filter_check*> m_checks;

private:

	std::set<uint16_t> m_expr_event_types;
	std::set<uint16_t> m_expr_possible_evttypes;

	// Return the "inverse" of the provided set of event types, using the
	// provided full possible set of event types as a hint.
	std::set<uint16_t> inverse(const std::set<uint16_t> &evttypes);

	// Given a boolean op and a set of event types from a
	// filtercheck in the expression, update m_expr_event_types appropriately.
	void combine_evttypes(boolop op, const std::set<uint16_t> &evttypes);
};



class gen_event_filter
{
public:
	gen_event_filter();

	virtual ~gen_event_filter();

	/*!
	  \brief Applies the filter to the given event.

	  \param evt Pointer that needs to be filtered.
	  \return true if the event is accepted by the filter, false if it's rejected.
	*/
	bool run(gen_event *evt);
	void push_expression(boolop op);
	void pop_expression();
	void add_check(gen_event_filter_check* chk);

	// Return all event types used by this filter. It's used in
	// programs like falco to speed up rule evaluation.
	std::set<uint16_t> evttypes();

	gen_event_filter_expression* m_filter;

protected:
	gen_event_filter_expression* m_curexpr;

	friend class sinsp_filter_compiler;
	friend class sinsp_filter_optimizer;
};

class gen_event_filter_factory
{
public:

	// A struct describing a single filtercheck field ("ka.user")
	struct filter_field_info
	{
		// The name of the field
		std::string name;

		// A description of the field
		std::string desc;
	};

	// A struct describing a group of filtercheck fields ("ka")
	struct filter_fieldclass_info
	{
		// The name of the group of fields
		std::string name;

		// A short description for the fields
		std::string desc;

		// Additional information about proper use of the fields
		std::string class_info;

		std::list<filter_field_info> fields;
	};

	gen_event_filter_factory() {};
	virtual ~gen_event_filter_factory() {};

	// Create a new filter
	virtual gen_event_filter *new_filter() = 0;

	// Create a new filtercheck
	virtual gen_event_filter_check *new_filtercheck(const char *fldname) = 0;

	// Return the set of fields supported by this factory
	virtual std::list<filter_fieldclass_info> get_fields() = 0;
};

class gen_event_formatter
{
public:
	enum output_format {
		OF_NORMAL = 0,
		OF_JSON   = 1
	};

	gen_event_formatter();
	virtual ~gen_event_formatter();

	virtual void set_format(output_format of, const std::string &format) = 0;

	// Format the output string with the configured format
	virtual bool tostring(gen_event *evt, std::string &output) = 0;

	// In some cases, it may be useful to format an output string
	// with a custom format.
	virtual bool tostring_withformat(gen_event *evt, std::string &output, output_format of) = 0;

	// The map should map from field name, without the '%'
	// (e.g. "proc.name"), to field value (e.g. "nginx")
	virtual bool get_field_values(gen_event *evt, std::map<std::string, std::string> &fields) = 0;

	virtual output_format get_output_format() = 0;
};


class gen_event_formatter_factory
{
public:
	gen_event_formatter_factory();
	virtual ~gen_event_formatter_factory();

	// This should be called before any calls to
	// create_formatter(), and changes the output format of new
	// formatters.
	virtual void set_output_format(gen_event_formatter::output_format of) = 0;

	virtual std::shared_ptr<gen_event_formatter> create_formatter(const std::string &format) = 0;
};
