// SPDX-License-Identifier: LGPL-2.1

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

/**
 *  @file    EventFieldDialog.cpp
 *  @brief   Dialog class used by the LatencyPlot plugin.
 */

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

// KernelShark
#include "KsMainWindow.hpp"
#include "LatencyPlotDialog.hpp"

/** The name of the menu item used to start the dialog of the plugin. */
#define DIALOG_NAME "Plot Latency"

/** Create plugin dialog widget. */
LatencyPlotDialog::LatencyPlotDialog(QWidget *parent)
: QDialog(parent),
  _evtALabel("\tEvent A", this),
  _evtBLabel("\tEvent B", this),
  _applyButton("Apply", this),
  _resetButton("Reset", this),
  _cancelButton("Cancel", this)
{
	setWindowTitle(DIALOG_NAME);

	_fieldSelectLayout.addWidget(&_evtALabel, 0, 0);
	_fieldSelectLayout.addWidget(&_evtBLabel, 0, 1);

	_fieldSelectLayout.addWidget(&_efsWidgetA, 1, 0);
	_fieldSelectLayout.addWidget(&_efsWidgetB, 1, 1);
	_topLayout.addLayout(&_fieldSelectLayout);

	_buttonLayout.addWidget(&_applyButton);
	_applyButton.setAutoDefault(false);

	_buttonLayout.addWidget(&_resetButton);
	_resetButton.setAutoDefault(false);

	_buttonLayout.addWidget(&_cancelButton);
	_cancelButton.setAutoDefault(false);

	_buttonLayout.setAlignment(Qt::AlignLeft);
	_topLayout.addLayout(&_buttonLayout);

	connect(&_applyButton,	&QPushButton::pressed,
		this,		&LatencyPlotDialog::_apply);

	connect(&_applyButton,	&QPushButton::pressed,
		this,		&QWidget::close);

	connect(&_resetButton,	&QPushButton::pressed,
		this,		&LatencyPlotDialog::_reset);

	connect(&_resetButton,	&QPushButton::pressed,
		this,		&QWidget::close);

	connect(&_cancelButton,	&QPushButton::pressed,
		this,		&QWidget::close);

	setLayout(&_topLayout);
}

/** Update the dialog, using the current settings of the plugin. */
void LatencyPlotDialog::update()
{
	_efsWidgetA.setStreamCombo();
	_efsWidgetB.setStreamCombo();
}

static LatencyPlotDialog *lp_dialog(nullptr);

/**
 * Use the Events and Field names selected by the user to update the plugin's
 * context.
 */
__hidden void plugin_set_event_fields(struct plugin_latency_context *plugin_ctx)
{
	std::string buff;
	char *name;
	int ret;

	plugin_ctx->event_name[0] = plugin_ctx->event_name[1] = NULL;

	buff = lp_dialog->_efsWidgetA.eventName().toStdString();
	ret = asprintf(&name, "%s", buff.c_str());
	if (ret > 0)
		plugin_ctx->event_name[0] = name;

	buff = lp_dialog->_efsWidgetB.eventName().toStdString();
	ret = asprintf(&name, "%s", buff.c_str());
	if (ret > 0)
		plugin_ctx->event_name[1] = name;

	plugin_ctx->field_name[0] = plugin_ctx->field_name[1] = NULL;

	buff = lp_dialog->_efsWidgetA.fieldName().toStdString();
	ret = asprintf(&name, "%s", buff.c_str());
	if (ret > 0)
		plugin_ctx->field_name[0] = name;

	buff = lp_dialog->_efsWidgetB.fieldName().toStdString();
	ret = asprintf(&name, "%s", buff.c_str());
	if (ret > 0)
		plugin_ctx->field_name[1] = name;
}

/**
 * @brief Mark an entry in the KernelShark GUI.
 *
 * @param e: The entry to be selected ith the marker.
 * @param mark: The marker to be used (A or B).
 */
__hidden void plugin_mark_entry(const struct kshark_entry *e, char mark)
{
	DualMarkerState st = DualMarkerState::A;
	if (mark == 'B')
		st = DualMarkerState::B;

	lp_dialog->_gui_ptr->markEntry(e, st);
}

void LatencyPlotDialog::_apply()
{
	auto work = KsWidgetsLib::KsDataWork::UpdatePlugins;
	int sdA = lp_dialog->_efsWidgetA.streamId();
	int sdB = lp_dialog->_efsWidgetB.streamId();

	/*
	 * The plugin needs to process the data and this may take time
	 * on large datasets. Show a "Work In Process" warning.
	 */
	_gui_ptr->wipPtr()->show(work);
	_gui_ptr->registerPluginToStream("latency_plot", {sdA, sdB});
	_gui_ptr->wipPtr()->hide(work);
}

void LatencyPlotDialog::_reset()
{
	auto work = KsWidgetsLib::KsDataWork::UpdatePlugins;
	kshark_context *kshark_ctx(nullptr);
	QVector<int> streamIds;

	if (!kshark_instance(&kshark_ctx))
		return;

	streamIds = KsUtils::getStreamIdList(kshark_ctx);

	/*
	 * The plugin needs to process the data and this may take time
	 * on large datasets. Show a "Work In Process" warning.
	 */
	_gui_ptr->wipPtr()->show(work);
	_gui_ptr->unregisterPluginFromStream("latency_plot", streamIds);
	_gui_ptr->wipPtr()->hide(work);
}

static void showDialog(KsMainWindow *ks)
{
	lp_dialog->update();
	lp_dialog->show();
}

/** Add the dialog of the plugin to the KernelShark menus. */
__hidden void *plugin_latency_add_menu(void *ks_ptr)
{
	if (!lp_dialog) {
		lp_dialog = new LatencyPlotDialog();
		lp_dialog->_gui_ptr = static_cast<KsMainWindow *>(ks_ptr);
	}

	QString menu("Tools/");
	menu += DIALOG_NAME;
	lp_dialog->_gui_ptr->addPluginMenu(menu, showDialog);

	return lp_dialog;
}
