//..............................................................................
//
// Ethernet Tap log representer
//

import "log_Representation.jnc"
import "crc32.jnc"

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

char const* getValidityString(bool isValid)
{
	return isValid ? "\e[32mOK\e[m" : "\e[31mINVALID\e[m";
}

bool representEthernetSnifferLog(
	log.Representation* representation,
	uint64_t recordCode,
	void const* p,
	size_t size,
	uint_t foldFlags
	)
{
	switch (recordCode)
	{
	case EthernetSnifferLogRecordCode.DeviceOpened:
		char const* name = (char const*)p;
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText($"Sniffer device \e[34m$name\e[m opened");
		break;

	case EthernetSnifferLogRecordCode.InterfaceClaimed:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText($"Interface \e[34m#0\e[m claimed");
		break;

	case EthernetSnifferLogRecordCode.InEndpointOpened:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText($"In endpoint \e[34m#86\e[m opened");
		break;

	case EthernetSnifferLogRecordCode.OutEndpointOpened:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText($"Out endpoint \e[34m#2\e[m opened");
		break;

	case EthernetSnifferLogRecordCode.CaptureStarted:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Connect;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Connect;
		representation.addHyperText($"Capture started");
		break;

	case EthernetSnifferLogRecordCode.CaptureStopped:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Disconnect;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Disconnect;
		representation.addHyperText("Capture stopped");
		break;

	case EthernetSnifferLogRecordCode.CaptureError:
		std.Error const* error = (std.Error const*)p;
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Error;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Error;
		representation.addHyperText($"Cannot open sniffer: $(error.m_description)");
		break;

	case EthernetSnifferLogRecordCode.Packet_ch1:
	case EthernetSnifferLogRecordCode.Packet_ch2:
		PacketHdr const* hdr = (PacketHdr const*)(p + sizeof(uint32_t));
		uint_t channel = (hdr.m_flags & PacketFlags.ChannelId) != 0;

		if (hdr.m_flags & PacketFlags.BufferOverflow)
		{
			representation.m_lineAttr.m_backColor = ui.StdColor.PastelOrange;
			representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Warning;
			representation.addHyperText($"Hardware buffer overflow on channel \e[34m$(channel + 1)");
			break;
		}

		if (hdr.m_size < sizeof(uint32_t))
		{
			representation.m_lineAttr.m_backColor = ui.StdColor.PastelRed;
			representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Error;
			representation.addHyperText($"Invalid packet size: \e[34m$(hdr.m_size)");
			break;
		}

		representation.m_lineAttr.m_backColor = ui.StdColor.PastelGray;

		if (channel)
		{
			representation.m_lineAttr.m_iconIdx = log.StdLogIcon.TxPacket;
			representation.m_lineAttr.m_backColor = ui.StdColor.PastelGray + 0x00000f;
		}
		else
		{
			representation.m_lineAttr.m_iconIdx = log.StdLogIcon.RxPacket;
			representation.m_lineAttr.m_backColor = ui.StdColor.PastelGray + 0x000f00;
		}

		size_t dataSize = hdr.m_size - sizeof(uint32_t);
		uint32_t actualCrc = *(uint32_t const*)(p + sizeof(uint32_t) + hdr.m_size);
		uint32_t expectedCrc = crc32(hdr + 1, dataSize);

		representation.addHyperText(
			$"%1 \e[34m#%(2; 03d)\e[m "
			$"channel: \e[34m%3\e[m "
			$"size: \e[34m%4 + 4\e[m "
			$"CRC-hw: %5 CRC-sw: %6"(
			foldFlags ? "[\e^-1\e[34m-\e[m]" : "[\e^+1\e[34m+\e[m]",
			*(uint32_t const*)p,
			channel + 1,
			dataSize,
			getValidityString(hdr.m_flags & PacketFlags.CrcValid),
			getValidityString(actualCrc == expectedCrc)
			));

		if (!foldFlags)
			break;

		if (channel)
		{
			representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Tx;
			representation.m_lineAttr.m_textColor = log.StdLogColor.Tx;
		}
		else
		{
			representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Rx;
			representation.m_lineAttr.m_textColor = log.StdLogColor.Rx;
		}

		representation.m_lineAttr.m_flags = log.LineAttrFlags.TileIcon;
		representation.m_lineAttr.m_backColor = ui.ColorFlags.Transparent;
		representation.addBin(hdr + 1, hdr.m_size);
		break;

	case EthernetSnifferLogRecordCode.CypressBufferCleared:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText($"Hardware buffer cleared");
		break;

	default:
		return false;
	}

	return true;
}

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