//..............................................................................
//
// $(pluginName) layer
//

import "doc_Plugin.jnc"

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

class $(layerClass):
	doc.Layer,
	log.Converter
{
protected:
	jnc.RegexState m_txScannerState;
	jnc.RegexState m_rxScannerState;

	log.Writer* m_writer;
	uint64_t m_timestamp;
	uint_t m_recordCode;
	void const* m_p;
	size_t m_offset;

public:
	construct (doc.PluginHost* pluginHost);

	override bool convert (
		log.Writer* writer,
		uint64_t timestamp,
		uint_t recordCode,
		void const* p,
		size_t size
		);

protected:
	scanStream (
		jnc.RegexState* state,
		char const* p,
		size_t length
		);

	writeOriginalData (jnc.RegexState* state);
}

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

$(layerClass).construct (doc.PluginHost* pluginHost)
{
	basetype1.construct (pluginHost);
	pluginHost.m_log.attachConverter (
		this,
		&pluginHost.m_pluginGuid,
		$(logRepresenterFunc)
		);

	m_txScannerState.m_isIncremental = true;
	m_rxScannerState.m_isIncremental = true;
}

bool $(layerClass).convert (
	log.Writer* writer,
	uint64_t timestamp,
	uint_t recordCode,
	void const* p,
	size_t size
	)
{
	jnc.RegexState* state;

	switch (recordCode)
	{
	case log.StdRecordCode.Tx:
		state = &m_txScannerState;
		break;

	case log.StdRecordCode.Rx:
		state = &m_rxScannerState;
		break;

	default:
		return false; // don't convert other records
	}

	// prepare context for the scanner

	m_writer = writer;
	m_timestamp = timestamp;
	m_recordCode = recordCode;
	m_p = p;
	m_offset = state.m_currentOffset;

	// scan

	scanStream (state, p, size);

	// write the rest of original data

	writeOriginalData (state);
	return true;
}

$(layerClass).writeOriginalData (jnc.RegexState* state)
{
	size_t chunkLength = state.m_currentOffset - m_offset;
	if (!chunkLength)
		return;

	m_writer.write (m_timestamp, m_recordCode, m_p, chunkLength);

	m_p += chunkLength;
	m_offset += chunkLength;
}

$(layerClass).scanStream (
	jnc.RegexState* state,
	char const* p,
	size_t length
	)
{
	char const* end = p + length;
	while (p < end)
	{
		reswitch (state, p, length)
		{
		case r"<[^>]*>":
			// write original data first...

			writeOriginalData (state);

			// ...and then the decoded in-band command

			m_writer.write (
				m_timestamp,
				$(logRecordCodeEnum).InBandCommand,
				state.m_match.m_text + 1,
				state.m_match.m_length - 2
				);

			break;

		case ".":
			// ignore the rest
			break;
		}

		p += state.m_consumedLength;
	}
}

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