//..............................................................................
//
// $(pluginName) plugin for performing transmit-receive tests
//

import "doc_Plugin.jnc"
import "sys_Timer.jnc"

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

class $(layerClass): doc.Layer
{
protected:
	jnc.Recognizer m_rxScanner;

	gui.BoolProperty* m_enableRetransmitProp;
	gui.IntProperty* m_retransmitCountProp;
	gui.IntProperty* m_retransmitDelayProp;
	gui.BoolProperty* m_analyzeRxProp;

	sys.Timer m_retransmitTimer;

	void const* m_packet;
	size_t m_packetSize;
	size_t m_retransmitNumber;

public:
	construct (doc.PluginHost* pluginHost);

	override void load (doc.Storage* storage);
	override void save (doc.Storage* storage);
	override void restoreDefaultProperties ();

	override size_t errorcode transmit (
		void const* p,
		size_t size
		);

protected:
	onLogRecord (
		uint64_t timestamp,
		uint_t recordCode,
		void const* p,
		size_t size
		)
	{
		if (recordCode == log.StdRecordCode.Rx)
			try m_rxScanner.write (p, size);
	}

	onRetransmitTimer ();

	jnc.AutomatonResult automaton scanRx (jnc.Recognizer* recognizer);

	createUi ();
	reactor m_uiReactor ();
}

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

$(layerClass).construct (doc.PluginHost* pluginHost)
{
	basetype.construct (pluginHost);
	m_rxScanner.construct (scanRx);

	createUi ();

	pluginHost.m_log.m_representerFunc = $(logRepresenterFunc);
	pluginHost.m_log.attachListener (onLogRecord @ pluginHost.m_mainThreadScheduler);
}

$(layerClass).createUi ()
{
	m_enableRetransmitProp = m_pluginHost.m_propertyGrid.createBoolProperty (
		"Analyze incoming data",
		"When checked, incoming packets will be analyzed"
		);

	m_retransmitCountProp = m_pluginHost.m_propertyGrid.createIntProperty (
		"Transmit count",
		"How many times total to send the packet"
		);

	m_retransmitDelayProp = m_pluginHost.m_propertyGrid.createIntProperty (
		"Retransmit delay (ms)",
		"Specify the delay between retransmissions (in milliseconds)"
		);

	m_analyzeRxProp = m_pluginHost.m_propertyGrid.createBoolProperty (
		"Analyze incoming data",
		"When checked, incoming packets will be analyzed"
		);

	m_uiReactor.start ();
}

void $(layerClass).load (doc.Storage* storage)
{
	m_enableRetransmitProp.m_value = storage.readBool ("enableRetransmit");
	m_retransmitCountProp.m_value = storage.readInt ("retransmitCount");
	m_retransmitDelayProp.m_value = storage.readInt ("retransmitDelay");
	m_analyzeRxProp.m_value = storage.readBool ("analyzeRx");
}

void $(layerClass).save (doc.Storage* storage)
{
	storage.writeBool ("enableRetransmit", m_enableRetransmitProp.m_value);
	storage.writeInt ("retransmitCount", m_retransmitCountProp.m_value);
	storage.writeInt ("retransmitDelay", m_retransmitDelayProp.m_value);
	storage.writeBool ("analyzeRx", m_analyzeRxProp.m_value);
}

void $(layerClass).restoreDefaultProperties ()
{
	m_enableRetransmitProp.m_value = true;
	m_retransmitCountProp.m_value = 3;
	m_retransmitDelayProp.m_value = 1000;
	m_analyzeRxProp.m_value = true;
}

size_t errorcode $(layerClass).transmit (
	void const* p,
	size_t size
	)
{
	size_t result = transmitNext (p, size);

	m_retransmitTimer.stop ();

	if (m_enableRetransmitProp.m_value && m_retransmitCountProp.m_value)
	{
		m_retransmitNumber = 0;
		m_packet = memdup (p, size);
		m_packetSize = size;

		m_retransmitTimer.startPeriodicTimer (onRetransmitTimer, m_retransmitDelayProp.m_value);
	}

	return result;
}

$(layerClass).onRetransmitTimer ()
{
	transmitNext (m_packet, m_packetSize);

	m_retransmitNumber++;

	if (m_retransmitNumber >= m_retransmitCountProp.m_value)
		m_retransmitTimer.stop ();
}

jnc.AutomatonResult automaton $(layerClass).scanRx (jnc.Recognizer* recognizer)
{
	%% "info" [\r\n]
		writeLog ($(logRecordCodeEnum).InfoMessage);

	%% "warning" [\r\n]
		writeLog ($(logRecordCodeEnum).WarningMessage);

	%% "error" [\r\n]
		writeLog ($(logRecordCodeEnum).ErrorMessage);

	%% .
		// ignore everything else
}

reactor $(layerClass).m_uiReactor ()
{
	m_retransmitCountProp.m_isEnabled = m_enableRetransmitProp.m_value;
	m_retransmitDelayProp.m_isEnabled = m_enableRetransmitProp.m_value;
}

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