/* SPDX-License-Identifier: LGPL-2.1 */

/*
 * Copyright (C) 2018 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
 */

/**
  *  @file    KsPlugins.hpp
  *  @brief   KernelShark C++ plugin declarations.
  */

#ifndef _KS_PLUGINS_H
#define _KS_PLUGINS_H

// C++
#include <vector>
#include <functional>

// KernelShark
#include "libkshark-plugin.h"
#include "libkshark-model.h"
#include "KsPlotTools.hpp"

class KsMainWindow;
/** Function type used for launching of plugin control menus. */
typedef void (pluginActionFunc) (KsMainWindow *);

/**
 * Structure representing the vector of C++ arguments of the drawing function
 * of a plugin.
 */
struct KsCppArgV {
	/** Pointer to the model descriptor object. */
	kshark_trace_histo	*_histo;

	/** Pointer to the graph object. */
	KsPlot::Graph		*_graph;

	/**
	 * Pointer to the list of shapes. All shapes created by the plugin
	 * will be added to this list.
	 */
	KsPlot::PlotObjList	*_shapes;

	/**
	 * Convert the "this" pointer of the C++ argument vector into a
	 * C pointer.
	 */
	kshark_cpp_argv *toC()
	{
		return reinterpret_cast<kshark_cpp_argv *>(this);
	}
};

/**
 * Macro used to convert a C pointer into a pointer to KsCppArgV (C++ struct).
 */
#define KS_ARGV_TO_CPP(a) (reinterpret_cast<KsCppArgV *>(a))

/**
 * Function of this type has to be implemented by the user in order to use
 * some of the Generic plotting method. The returned shape will be plotted
 * by KernelShark on top of the existing Graph generated by the model.
 */
typedef std::function<KsPlot::PlotObject *(std::vector<const KsPlot::Graph *> graph,
					   std::vector<int> bin,
					   std::vector<kshark_data_field_int64 *> data,
					   KsPlot::Color col,
					   float size)> pluginShapeFunc;

/**
 * Function of this type has to be implemented by the user in order to use
 * some of the Generic plotting method. The user must implement a logic
 * deciding if the record, having a given index inside the data container has
 * to be visualized.
 */
typedef std::function<bool(kshark_data_container *, ssize_t)> IsApplicableFunc;

void eventPlot(KsCppArgV *argvCpp, IsApplicableFunc isApplicable,
	       pluginShapeFunc makeShape, KsPlot::Color col, float size);

void eventFieldPlotMax(KsCppArgV *argvCpp,
		       kshark_data_container *dataEvt,
		       IsApplicableFunc checkField,
		       pluginShapeFunc makeShape,
		       KsPlot::Color col,
		       float size);

void eventFieldPlotMin(KsCppArgV *argvCpp,
		       kshark_data_container *dataEvt,
		       IsApplicableFunc checkField,
		       pluginShapeFunc makeShape,
		       KsPlot::Color col,
		       float size);

void eventFieldIntervalPlot(KsCppArgV *argvCpp,
			    kshark_data_container *dataEvtA,
			    IsApplicableFunc checkFieldA,
			    kshark_data_container *dataEvtB,
			    IsApplicableFunc checkFieldB,
			    pluginShapeFunc makeShape,
			    KsPlot::Color col,
			    float size);

/**
 * This class represents the graphical element visualizing the latency between
 * two events.
 */
class LatencyBox : public KsPlot::Rectangle
{
	/** On double click do. */
	void _doubleClick() const override {}

public:
	/** The trace record data that corresponds to this LatencyBox. */
	std::vector<kshark_data_field_int64 *>	_data;

	double distance(int x, int y) const override;
};

/**
 * This template function make shape of hollow box for two events and
 * return the shape to be plotted by KernelShark on top of the existing
 * Graph generated by the model.
 */
template<class T> KsPlot::PlotObject *
makeLatencyBox(std::vector<const KsPlot::Graph *> graph,
	       std::vector<int> bins,
	       std::vector<kshark_data_field_int64 *> data,
	       KsPlot::Color col, float size)
{
	LatencyBox *rec = new T;
	rec->_data = data;

	KsPlot::Point p0 = graph[0]->bin(bins[0])._base;
	KsPlot::Point p1 = graph[0]->bin(bins[1])._base;
	int height = graph[0]->height() * .3;

	rec->setFill(false);
	rec->setPoint(0, p0.x() - 1, p0.y() - height);
	rec->setPoint(1, p0.x() - 1, p0.y() - 1);

	rec->setPoint(3, p1.x() - 1, p1.y() - height);
	rec->setPoint(2, p1.x() - 1, p1.y() - 1);

	rec->_size = size;
	rec->_color = col;

	return rec;
}

#endif
