//..............................................................................
//
// Mailslot Monitor session
//

import "io_BufferUi.jnc"
import "doc_Session.jnc"
import "gui_History.jnc"
import "gui_StdSessionInfo.jnc"
import "log_ThroughputCalc.jnc"
import "log_ChecksumCalc.jnc"

using extension gui.ComboBoxHistory;

//..............................................................................

class MailslotMonSession: doc.Session
{
protected:
	enum Defaults
	{
		PendingNotifySizeLimit = 1 * 1024 * 1024, // 1MB
		UseLanmanMonitor       = true,
	}

	enum State
	{
		Closed,
		Opened,
	}

	enum ActionId
	{
		Capture,
		_Count,
	}

	enum IconId
	{
		Capture,
		StopCapture,
		_Count,
	}

	enum StatusPaneId
	{
		State,
		_Count,
	}

protected:
	// named pipe monitor

	State bindable m_state;
	MailslotMonitor m_msfsMonitor;
	MailslotMonitor m_lanmanMonitor;

	// toolbar, status bar & menu

	gui.Action* m_actionTable[ActionId._Count];
	gui.Icon* m_iconTable[IconId._Count];
	gui.StatusPane* m_statusPaneTable[StatusPaneId._Count];
	gui.ComboBox* m_nameCombo;

	// pipe mon property grid

	gui.StringProperty* m_nameProp;
	gui.BoolProperty* m_useLanmanMonitorProp;
	io.BufferPropertySet m_bufferPropertySet;
	gui.IntProperty* m_pendingNotifySizeLimitProp;

	// information grid

	gui.StdSessionInfoSet m_stdSessionInfoSet;
	log.ThroughputInfoSet m_throughputInfoSet;
	log.ChecksumInfoSet m_checksumInfoSet;

	// ui reactor

	reactor m_uiReactor;

public:
	construct(doc.PluginHost* pluginHost);

	bool errorcode capture();
	close();

	override void load(doc.Storage* storage);
	override void save(doc.Storage* storage);
	override void updateProperties();
	override bool errorcode applyProperties();
	override void restoreDefaultProperties();

protected:
	onCapture()
	{
		m_state ? close() : try capture();
	}

	onNameComboEnter()
	{
		try capture();
	}

	createUi();
}

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

MailslotMonSession.construct(doc.PluginHost* pluginHost)
{
	basetype.construct(pluginHost);
	m_msfsMonitor.construct(this);
	m_lanmanMonitor.construct(this);

	createUi();

	pluginHost.m_log.addSelectionProcessor(log.ThroughputCalcRangeProcessor.factory ~(m_throughputInfoSet));
	pluginHost.m_log.addSelectionProcessor(log.ChecksumCalcRangeProcessor.factory ~(m_checksumInfoSet));
	m_stdSessionInfoSet.addLogListener(pluginHost.m_log);
}

MailslotMonSession.createUi()
{
	// toolbar

	m_pluginHost.m_toolBar.addLabel("Name filter:");
	m_nameCombo = m_pluginHost.m_toolBar.addComboBox(-1);
	m_nameCombo.m_isEditable = true;
	m_nameCombo.m_onEnter += onNameComboEnter;

	m_iconTable[IconId.Capture] = new gui.Icon("images/capture.png");
	m_iconTable[IconId.StopCapture] = new gui.Icon("images/pause.png");

	m_actionTable[ActionId.Capture] = createAction("Capture", m_iconTable[IconId.Capture]);
	m_actionTable[ActionId.Capture].m_onTriggered += onCapture;

	// status bar

	m_statusPaneTable[StatusPaneId.State] = m_pluginHost.m_statusBar.addPane(, 80);

	// property grid

	gui.GroupProperty* group = m_pluginHost.m_propertyGrid.createGroupProperty(
		"Connection",
		"Named pipe monitor connection settings"
		);

	m_nameProp = m_pluginHost.m_propertyGrid.createStringProperty(
		group,,
		"Name filter",
		"Specify name wildcard filter"
		);

	m_useLanmanMonitorProp = m_pluginHost.m_propertyGrid.createBoolProperty(
		group,,
		"Monitor remote connection",
		"Attach and monitor pipe connections redirected over Windows LANMAN"
		);

	group = m_pluginHost.m_propertyGrid.createGroupProperty(
		"Buffering & compatibility",
		"Advanced options controlling performance, throughtput and compatibility"
		);

	m_bufferPropertySet.createProperties(
		m_pluginHost.m_propertyGrid,
		group,,
		io.BufferPropertySet.PropertyId.ReadParallelism |
		io.BufferPropertySet.PropertyId.ReadBufferSize |
		io.BufferPropertySet.PropertyId.ReadBlockSize |
		io.BufferPropertySet.PropertyId.NotifyReadBufferFull
		);

	m_pendingNotifySizeLimitProp = m_pluginHost.m_propertyGrid.createIntProperty(
		group,,
		"Pending notification limit",
		"Set the maximum size of kernel notification queue (exceeding notification will be dropped)"
		);

	m_bufferPropertySet.m_readBlockSizeProp.m_minValue = 1024;
	m_bufferPropertySet.m_readBufferSizeProp.m_minValue = 1024;
	m_pendingNotifySizeLimitProp.m_minValue = 1024;
	m_pendingNotifySizeLimitProp.m_spinBoxStep = 1024; // 1KB

	// information grid

	gui.InformationGroup* infoGroup = m_pluginHost.m_informationGrid.createGroup("Mailslot monitor");

	m_stdSessionInfoSet.createInformationValues(
		m_pluginHost.m_informationGrid,
		infoGroup,,
		gui.StdSessionInfoSet.InfoId.SessionTime |
		gui.StdSessionInfoSet.InfoId.RxTotalSize
		);

	m_throughputInfoSet.createInformationValuesGrouped(m_pluginHost.m_informationGrid);
	m_checksumInfoSet.createInformationValuesGrouped(m_pluginHost.m_informationGrid);

	m_pluginHost.m_informationGrid.resizeNameColumnToContents();

	m_uiReactor.start();
}

bool errorcode MailslotMonSession.capture()
{
	close();
	startSession();

	m_nameCombo.addEditTextToHistory();

	char const* name = m_nameCombo.m_currentText;
	if (!name || !*name)
		name = "*"; // null wildcard means we will be also notified by already-opened "nameless" files

	m_msfsMonitor.applyProperties(m_bufferPropertySet, m_pendingNotifySizeLimitProp.m_value);
	m_msfsMonitor.capture(r"\device\mailslot", name);

	if (m_useLanmanMonitorProp.m_value)
	{
		m_lanmanMonitor.applyProperties(m_bufferPropertySet, m_pendingNotifySizeLimitProp.m_value);
		m_lanmanMonitor.capture(r"\device\lanmanredirector", name);
	}

	writeLogString(DeviceMonLogRecordCode.CaptureStarted_filter, name);

	m_state = State.Opened;
	m_stdSessionInfoSet.startSession(m_pluginHost.m_mainThreadScheduler);
	return true;

catch:
	m_msfsMonitor.close();
	m_lanmanMonitor.close();

	std.Error const* error = std.getLastError();
	writeLog(
		DeviceMonLogRecordCode.CaptureError,
		error,
		error.m_size
		);
	return false;
}

MailslotMonSession.close()
{
	if (m_state != State.Opened)
		return;

	writeLog(DeviceMonLogRecordCode.CaptureStopped);

	m_msfsMonitor.close();
	m_lanmanMonitor.close();
	m_state = State.Closed;
	m_stdSessionInfoSet.endSession();
}

void MailslotMonSession.load(doc.Storage* storage)
{
	m_nameCombo.loadHistory(storage, "nameHistory");
	m_nameCombo.m_editText = storage.readString("name");
	m_useLanmanMonitorProp.m_value = storage.readString("useLanmanMonitor");
	m_pendingNotifySizeLimitProp.m_value = storage.readInt("pendingNotifySizeLimit", Defaults.PendingNotifySizeLimit);

	m_bufferPropertySet.load(storage);
	m_msfsMonitor.setReadBufferSize(m_bufferPropertySet.m_readBufferSizeProp.m_value);
	m_lanmanMonitor.setReadBufferSize(m_bufferPropertySet.m_readBufferSizeProp.m_value);
}

void MailslotMonSession.save(doc.Storage* storage)
{
	m_nameCombo.saveHistory(storage, "nameHistory");
	storage.writeString("name", m_nameCombo.m_currentText);
	storage.writeBool("useLanmanMonitor", m_useLanmanMonitorProp.m_value);
	storage.writeInt("pendingNotifySizeLimit", m_pendingNotifySizeLimitProp.m_value);

	m_bufferPropertySet.save(storage);
}

void MailslotMonSession.updateProperties()
{
	m_nameProp.m_value = m_nameCombo.m_editText;
}

bool errorcode MailslotMonSession.applyProperties()
{
	m_nameCombo.m_editText  = m_nameProp.m_value;

	if (m_state != State.Opened)
		return true;

	m_msfsMonitor.applyProperties(m_bufferPropertySet, m_pendingNotifySizeLimitProp.m_value);
	m_lanmanMonitor.applyProperties(m_bufferPropertySet, m_pendingNotifySizeLimitProp.m_value);
	return true;
}

void MailslotMonSession.restoreDefaultProperties()
{
	m_pendingNotifySizeLimitProp.m_value = Defaults.PendingNotifySizeLimit;
	m_useLanmanMonitorProp.m_value = Defaults.UseLanmanMonitor;
	m_bufferPropertySet.restoreDefaults();
}

reactor MailslotMonSession.m_uiReactor
{
	m_title = $"MSFS mon $(m_nameCombo.m_currentText)";
	m_actionTable[ActionId.Capture].m_text = m_state ? "Stop Capture" : "Capture";
	m_actionTable[ActionId.Capture].m_icon = m_iconTable[m_state ? IconId.StopCapture : IconId.Capture];
	m_statusPaneTable[StatusPaneId.State].m_text = m_state ? "Capturing" : "Closed";
}

//..............................................................................
