//.............................................................................
//
// Sniffer log packet declarations and representer
//

import "io_Packet.jnc"

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

enum SnifferLogRecordCode
{
	Packet          = 1 | log.RecordCodeFlags.Foldable,
	InjectedPacket  = 2 | log.RecordCodeFlags.Foldable,
	DefragmentedIp  = 3 | log.RecordCodeFlags.Foldable,
	StartingCapture = 4, // non foldable
	CaptureStarted,
	CaptureError,
	CaptureStopped,
	ChangingFilter,
	FilterChanged,
	FilterError,
}

enum SnifferLogPartCode
{
	StartingCapture  = 1 | log.PartCodeFlags.MergeableForward,
	CaptureCompleted = 1 | log.PartCodeFlags.MergeableBackward,
	ChangingFilter   = 2 | log.PartCodeFlags.MergeableForward,
	FilterCompleted  = 2 | log.PartCodeFlags.MergeableBackward,
}

enum SnifferLogHdrColor
{
	Ethernet   = gui.StdColor.Green,
	Ip         = gui.StdColor.Cyan,
	IpOptions  = gui.StdColor.Purple,
	Ip6        = gui.StdColor.Cyan,
	Tcp        = gui.StdColor.Blue,
	TcpOptions = gui.StdColor.Purple,
	Udp        = gui.StdColor.Blue,
	Icmp       = gui.StdColor.Blue,
}

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

bool representSnifferLog (
	log.RepresenterTarget* target,
	uint_t recordCode,
	void const* p,
	size_t size,
	uint_t foldFlags
	)
{
	switch (recordCode)
	{
	case SnifferLogRecordCode.Packet:
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Packet;
		representPacket (target, p, size, foldFlags);
		break;

	case SnifferLogRecordCode.InjectedPacket:
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.TxPacket;
		representPacket (target, p, size, foldFlags);
		break;
		
	case SnifferLogRecordCode.DefragmentedIp:
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Packet;
		representDefragmentedIp (target, p, size, foldFlags);
		break;

	case SnifferLogRecordCode.StartingCapture:
		char const* filter = (char const*) p;
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		target.m_lineAttr.m_backColor = log.StdLogColor.Info;
		target.addHyperText (SnifferLogPartCode.StartingCapture, $"Starting capture with filter \e[34m$filter\e[m...");
		break;

	case SnifferLogRecordCode.CaptureStarted:
		target.m_lineAttr.m_flags = log.LineAttrFlags.Override;
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Listen;
		target.m_lineAttr.m_backColor = log.StdLogColor.Connect;
		target.addPlainText (SnifferLogPartCode.CaptureCompleted, "ok");
		break;

	case SnifferLogRecordCode.CaptureError:
		std.Error const* error = (std.Error const*) p;
		target.m_lineAttr.m_flags = log.LineAttrFlags.Override;
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Error;
		target.m_lineAttr.m_backColor = log.StdLogColor.Error;
		target.addPlainText (SnifferLogPartCode.CaptureCompleted, $"error: $(error.m_description)");
		break;

	case SnifferLogRecordCode.CaptureStopped:
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.StopListen;
		target.m_lineAttr.m_backColor = log.StdLogColor.Disconnect;
		target.addPlainText ("Capture stopped");
		break;

	case SnifferLogRecordCode.ChangingFilter:
		char const* filter = (char const*) p;
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		target.m_lineAttr.m_backColor = log.StdLogColor.Info;
		target.addHyperText (SnifferLogPartCode.ChangingFilter, $"Changing capture filter to \e[34m$filter\e[m...");
		break;

	case SnifferLogRecordCode.FilterChanged:
		target.addPlainText (SnifferLogPartCode.FilterCompleted, "ok");
		break;

	case SnifferLogRecordCode.FilterError:
		std.Error const* error = (std.Error const*) p;
		target.m_lineAttr.m_flags = log.LineAttrFlags.Override;
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Error;
		target.m_lineAttr.m_backColor = log.StdLogColor.Error;
		target.addPlainText (SnifferLogPartCode.FilterCompleted, $"error: $(error.m_description)");
		break;

	default:
		return false;
	}

	return true;
}

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

representPacket (
	log.RepresenterTarget* target,
	void const* p,
	size_t size,
	uint_t foldFlags
	)
{
	// TODO: add data link switch, currently we support ethernet only

	representEthernet (target, p, size, foldFlags);
}

representColorizedBin (
	log.RepresenterTarget* target,
	void const* p,
	size_t size,
	size_t const* hdrSizeTable,
	uint_t const* hdrColorTable,
	size_t hdrCount
	)
{
	target.m_lineAttr.m_textColor = gui.StdColor.Gray;		
	target.m_lineAttr.m_backColor = gui.ColorFlags.Transparent;		
	target.addBin (p, size);

	gui.TextAttr attr;
	attr.m_backColor = gui.ColorFlags.Transparent;
	
	intptr retroOffset = -size;	
	for (size_t i = 0; i < hdrCount; i++)
	{
		size_t size = hdrSizeTable [i];
		attr.m_textColor = hdrColorTable [i];
		target.retroColorize (retroOffset, size, attr);
		retroOffset += size;
	}	
}

representDefragmentedIp (
	log.RepresenterTarget* target,
	void const* p,
	size_t size,
	uint_t foldFlags
	)
{
	target.m_lineAttr.m_backColor = gui.StdColor.PastelCyan;
	target.addPlainText ("Defragmented IP packet");
	
	if (foldFlags)
	{
		target.addHyperText ("[\e^-1\e[34m-\e[m]");
		
		size_t hdrSizeTable [8];
		uint_t hdrColorTable [8];
		
		size_t hdrCount = representIpHdr (target, p, size, 0, hdrSizeTable, hdrColorTable, 0);
		representColorizedBin (target, p, size, hdrSizeTable, hdrColorTable, hdrCount);
	}
	else
	{
		representIp (target, p, size, 0);
	}
}

representPacketData (
	log.RepresenterTarget* target,
	void const* p,
	size_t size,
	size_t baseOffset,
	size_t length
	)
{
	if (baseOffset >= size)
		return;

	if (length == -1 || baseOffset + length >= size)
		length = size - baseOffset;

	target.m_lineAttr.m_textColor = gui.StdColor.Gray;
	target.m_lineAttr.m_backColor = gui.ColorFlags.Transparent;
	target.addBin (p + baseOffset, length);
}

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