//..............................................................................
//
//  Device Monitor machine interface transport for SerialMonProcessor
//

import "io_devmon.jncx"
import "io_DeviceMonitorMi.jnc"
import "SerialMonProcessor_win.jnc"
import "SerialMonProcessor_lnx.jnc"
import "std_Buffer.jnc"

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

class SerialMonitor_mi
{
protected:
	log.Writer* m_logWriter;
	SerialMonProcessor* m_processor;
	std.Buffer m_buffer;
	size_t m_expectedMsgSize;

public:
	construct (log.Writer* logWriter)
	{
		m_logWriter = logWriter;
		reset ();
	}

	reset ();

	bool errorcode write (
		void const* p,
		size_t size
		);

protected:
	bool errorcode processMsg (io.DeviceMonitorMiMsgHdr const* hdr);
}

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

SerialMonitor_mi.reset ()
{
	m_expectedMsgSize = sizeof (io.DeviceMonitorMiMsgHdr);
	m_buffer.clear ();
	m_processor = null;
}

bool errorcode SerialMonitor_mi.write (
	void const* p,
	size_t size
	)
{
	while (size)
	{
		if (m_buffer.m_size < m_expectedMsgSize)
		{
			size_t leftover = m_expectedMsgSize - m_buffer.m_size;
			if (size < leftover)
			{
				m_buffer.append (p, size);
				break;
			}

			m_buffer.append (p, leftover);
			p += leftover;
			size -= leftover;
		}

		io.DeviceMonitorMiMsgHdr const* hdr = (io.DeviceMonitorMiMsgHdr const*) m_buffer.m_p;
		size_t msgSize = sizeof (io.DeviceMonitorMiMsgHdr) + hdr.m_paramSize;
		if (m_expectedMsgSize < msgSize)
		{
			m_expectedMsgSize = msgSize;
			continue;
		}

		processMsg (hdr);
		m_expectedMsgSize = sizeof (io.DeviceMonitorMiMsgHdr);
		m_buffer.clear ();
	}

	return true;
}

bool errorcode SerialMonitor_mi.processMsg (io.DeviceMonitorMiMsgHdr const* hdr)
{
	switch (hdr.m_code)
	{
	case io.DeviceMonitorMiMsgCode.Error:
		std.Error const* error = (std.Error const*) (hdr + 1);
		if (hdr.m_paramSize < sizeof (std.Error) ||
			hdr.m_paramSize < error.m_size)
		{
			std.setError ("machine interface error: ERROR message too small");
			return false;
		}

		std.setError (error);
		return false;

	case io.DeviceMonitorMiMsgCode.Start:
		if (hdr.m_paramSize < sizeof (io.DeviceMonitorMiStartParams))
		{
			std.setError ("machine interface error: START message too small");
			return false;
		}

		io.DeviceMonitorMiStartParams const* params = (io.DeviceMonitorMiStartParams const*) (hdr + 1);
		if (params.m_flags & io.DeviceMonitorMiStartFlags.Windows)
			m_processor = new SerialMonProcessor_win (m_logWriter);
		else if (params.m_flags & io.DeviceMonitorMiStartFlags.Linux)
			m_processor = new SerialMonProcessor_lnx (m_logWriter);
		else
		{
			std.setError ("unsupported target OS");
			return false;
		}

		break;

	case io.DeviceMonitorMiMsgCode.Notification:
		if (!m_processor)
		{
			std.setError ("machine interface error: NOTIFY before START");
			return false;
		}

		io.DeviceMonitorNotifyHdr const* notifyHdr = (io.DeviceMonitorNotifyHdr const*) (hdr + 1);
		if (hdr.m_paramSize < sizeof (io.DeviceMonitorNotifyHdr) ||
			hdr.m_paramSize < sizeof (io.DeviceMonitorNotifyHdr) + notifyHdr.m_paramSize)
		{
			std.setError ("machine interface error: NOTIFY message too small");
			return false;
		}

		m_processor.processNotification (notifyHdr);
		break;

	default:
		std.setError ("machine interface error: undefined message code");
		return false;
	}

	return true;
}

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