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

import "io_Monitor.jnc"
import "io_FileIdMgr.jnc"
import "std_String.jnc"

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

class MailslotMonitor: io.Monitor
{
protected:
	MailslotMonSession* m_session;

public:
	construct(MailslotMonSession* session);

protected:
	override processNotification(io.DeviceMonitorNotifyHdr const* notifyHdr);
	override processError(std.Error const* error);

	setFileId(
		uint64_t timestamp,
		uint64_t fileId
		);
}

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

MailslotMonitor.construct(MailslotMonSession* session)
{
	basetype.construct(session.m_pluginHost);
	m_session = session;
}

MailslotMonitor.setFileId(
	uint64_t timestamp,
	uint64_t fileId
	)
{
	if (fileId == m_lastFileId)
		return;

	m_lastFileId = fileId;
	m_logWriter.write(timestamp, MailslotMonLogRecordCode.FileIdChanged, &m_lastFileId, sizeof(m_lastFileId));
}

MailslotMonitor.processNotification(io.DeviceMonitorNotifyHdr const* notifyHdr)
{
	switch (notifyHdr.m_code)
	{
	case io.win.DeviceMonitorNotifyCode.Create:
		io.win.DeviceMonitorCreateNotifyParams const* params = (io.win.DeviceMonitorCreateNotifyParams const*)(notifyHdr + 1);

		uint64_t recordCode;
		std.Buffer logParams;

		if (notifyHdr.m_ntStatus == 0)
		{
			recordCode = MailslotMonLogRecordCode.ClientFileOpened;
			logParams.append(&params.m_fileId64, sizeof(params.m_fileId64));
			logParams.append(&notifyHdr.m_processId, sizeof(notifyHdr.m_processId));
		}
		else
		{
			recordCode = MailslotMonLogRecordCode.ClientFileOpenError;

			std.Error error;
			error.m_size = sizeof(error);
			error.m_guid = std.g_ntStatusGuid;
			error.m_code = notifyHdr.m_ntStatus;

			logParams.append(&notifyHdr.m_processId, sizeof(notifyHdr.m_processId));
			logParams.append(&error, error.m_size);
		}

		std.StringBuilder name;
		name.copy((utf16_t const*)(params + 1), params.m_fileNameLength);
		logParams.append(name.m_sz, name.m_length + 1);
		logParams.append(try sys.getProcessImageName(notifyHdr.m_processId));

		m_logWriter.write(
			notifyHdr.m_timestamp,
			recordCode,
			logParams.m_p,
			logParams.m_size
			);

		break;

	case io.win.DeviceMonitorNotifyCode.CreateMailslot:
		io.win.DeviceMonitorCreateMailslotNotifyParams const* params = (io.win.DeviceMonitorCreateMailslotNotifyParams const*)(notifyHdr + 1);

		uint64_t recordCode;
		std.Buffer logParams;

		if (notifyHdr.m_ntStatus == 0)
		{
			recordCode = MailslotMonLogRecordCode.ServerFileOpened;
			logParams.append(&params.m_fileId64, sizeof(params.m_fileId64));
			logParams.append(&notifyHdr.m_processId, sizeof(notifyHdr.m_processId));
		}
		else
		{
			recordCode = MailslotMonLogRecordCode.ServerFileOpenError;

			std.Error error;
			error.m_size = sizeof(error);
			error.m_guid = std.g_ntStatusGuid;
			error.m_code = notifyHdr.m_ntStatus;

			logParams.append(&notifyHdr.m_processId, sizeof(notifyHdr.m_processId));
			logParams.append(&error, error.m_size);
		}

		std.StringBuilder name;
		name.copy((utf16_t const*)(params + 1), params.m_fileNameLength);
		logParams.append(name.m_sz, name.m_length + 1);
		logParams.append(try sys.getProcessImageName(notifyHdr.m_processId));

		m_logWriter.write(
			notifyHdr.m_timestamp,
			recordCode,
			logParams.m_p,
			logParams.m_size
			);

		break;

	case io.win.DeviceMonitorNotifyCode.Close:
		io.win.DeviceMonitorCloseNotifyParams const* params = (io.win.DeviceMonitorCloseNotifyParams const*)(notifyHdr + 1);
		setFileId(notifyHdr.m_timestamp, params.m_fileId);
		m_logWriter.write(notifyHdr.m_timestamp, MailslotMonLogRecordCode.FileClosed);
		break;

	case io.win.DeviceMonitorNotifyCode.Read:
	case io.win.DeviceMonitorNotifyCode.FastIoRead:
		io.win.DeviceMonitorReadWriteNotifyParams const* params = (io.win.DeviceMonitorReadWriteNotifyParams const*)(notifyHdr + 1);
		if (!params.m_dataSize)
			break;

		setFileId(notifyHdr.m_timestamp, params.m_fileId);

		m_logWriter.write(
			notifyHdr.m_timestamp,
			log.StdRecordCode.Rx,
			params + 1,
			params.m_dataSize
			);
		break;

	case io.win.DeviceMonitorNotifyCode.Write:
	case io.win.DeviceMonitorNotifyCode.FastIoWrite:
		io.win.DeviceMonitorReadWriteNotifyParams const* params = (io.win.DeviceMonitorReadWriteNotifyParams const*)(notifyHdr + 1);
		if (!params.m_dataSize)
			break;

		setFileId(notifyHdr.m_timestamp, params.m_fileId);

		m_logWriter.write(
			notifyHdr.m_timestamp,
			log.StdRecordCode.Tx,
			params + 1,
			params.m_dataSize
			);
		break;
	}
}

MailslotMonitor.processError(std.Error const* error)
{
	m_logWriter.write(log.StdRecordCode.Error, error, error.m_size);
	m_session.close();
}

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