//..............................................................................
//
// Socket log representer
//

import "io_base.jncx"
import "io_SocketAddress.jnc"
import "log_Representation.jnc"

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

string_t getDisconnectReasonString(uint_t flags) {
	if (flags & SocketLogDisconnectFlags.Aborted)
		return "aborted by local node";

	string_t closeKind = (flags & SocketLogDisconnectFlags.ResetMask) ? "reset" : "closed";
	string_t initiator = (flags & SocketLogDisconnectFlags.Remote) ? "remote" : "local";
	return $"$closeKind by $initiator";
}

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

bool representSocketLog(
	log.Representation* representation,
	uint64_t recordCode,
	void const* p,
	size_t size,
	uint_t foldFlags
) {
	switch (recordCode) {
	case SocketLogRecordCode.Open:
		string_t addressString = ((io.SocketAddress const*)p).getString();
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Connect;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Connect;
		representation.addHyperText($"Opened socket at \e[34m$addressString");
		break;

	case SocketLogRecordCode.OpenError:
		io.SocketAddress const* address = (io.SocketAddress const*)p;
		string_t addressString = address.getString();
		std.Error const* error = (std.Error const*)(address + 1);
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Error;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Error;
		representation.addHyperText($"Cannot open socket at \e[34m$addressString\e[m: $(error.m_description)");
		break;

	case SocketLogRecordCode.Close:
		string_t addressString = ((io.SocketAddress const*)p).getString();
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Disconnect;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Disconnect;
		representation.addHyperText($"Socket at \e[34m$addressString\e[m closed");
		break;

	case SocketLogRecordCode.Resolving:
		string_t addressString = (char const*)p;
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText(SocketLogPartCode.Connecting, $"Resolving \e[34m$addressString\e[m...");
		break;

	case SocketLogRecordCode.Connecting:
		string_t addressString = ((io.SocketAddress const*)p).getString();
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText(SocketLogPartCode.Connecting, $"Connecting to \e[34m$addressString\e[m...");
		break;

	case SocketLogRecordCode.ConnectingFrom:
		string_t remoteAddressString = ((io.SocketAddress const*)p).getString();
		string_t localAddressString = ((io.SocketAddress const*)p + 1).getString();
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText(SocketLogPartCode.Connecting, $"Connecting to \e[34m$remoteAddressString\e[m from \e[34m$localAddressString\e[m...");
		break;

	case SocketLogRecordCode.ResolveCompleted:
		string_t addressString = ((io.SocketAddress const*)p).getString();
		representation.addHyperText(SocketLogPartCode.ConnectCompleted, $"ok (\e[34m$addressString\e[m)");
		break;

	case SocketLogRecordCode.ResolveCompletedPrefix:
		string_t addressString = (char const*)p;
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText(SocketLogPartCode.Connecting, $"Resolve of \e[34m$addressString\e[m completed: ");
		break;

	case SocketLogRecordCode.ConnectCompletedPrefix:
		string_t addressString = ((io.SocketAddress const*)p).getString();
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText(SocketLogPartCode.Connecting, $"Connect to \e[34m$addressString\e[m completed: ");
		break;

	case SocketLogRecordCode.ConnectCompleted:
		representation.m_lineAttr.m_flags = log.LineAttrFlags.Override;
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Connect;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Connect;
		representation.addHyperText(SocketLogPartCode.ConnectCompleted, "ok");
		break;

	case SocketLogRecordCode.ConnectCancelled:
		representation.addHyperText(SocketLogPartCode.ConnectCompleted, "cancelled");
		break;

	case SocketLogRecordCode.ConnectError:
		std.Error const* error = (std.Error const*)p;
		representation.m_lineAttr.m_flags = log.LineAttrFlags.Override;
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Error;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Error;
		representation.addHyperText(SocketLogPartCode.ConnectCompleted, $"error: $(error.m_description)");
		break;

	case SocketLogRecordCode.Disconnected:
		SocketLogDisconnectParams const* params = (SocketLogDisconnectParams const*)p;
		string_t addressString = params.m_address.getString();
		string_t reasonString = getDisconnectReasonString(params.m_flags);

		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Disconnect;
		representation.m_lineAttr.m_backColor = (params.m_flags & SocketLogDisconnectFlags.Aborted) ?
			log.StdLogColor.Warning :
			log.StdLogColor.Disconnect;

		representation.addHyperText($"Disconnected from \e[34m$addressString\e[m ($reasonString)");
		break;

	case SocketLogRecordCode.Disconnected_old:
		string_t addressString = ((io.SocketAddress const*)p).getString();
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Disconnect;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Disconnect;
		representation.addHyperText($"Disconnected from \e[34m$addressString\e[m");
		break;

	case SocketLogRecordCode.ReconnectDelay:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText($"About to reconnect...");
		break;

	case SocketLogRecordCode.Listening:
		string_t addressString = ((io.SocketAddress const*)p).getString();
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Listen;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText($"Listening on \e[34m$addressString");
		break;

	case SocketLogRecordCode.ListenError:
		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 listen: $(error.m_description)");
		break;

	case SocketLogRecordCode.ListenStopped:
		string_t addressString = ((io.SocketAddress const*)p).getString();
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.StopListen;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText($"Stopped listening on \e[34m$addressString");
		break;

	case SocketLogRecordCode.ClientConnected:
		string_t addressString = ((io.SocketAddress const*)p).getString();
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Connect;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Connect;
		representation.addHyperText($"Client connected from \e[34m$addressString");
		break;

	case SocketLogRecordCode.ClientDisconnected:
		SocketLogDisconnectParams const* params = (SocketLogDisconnectParams const*)p;
		string_t addressString = params.m_address.getString();
		string_t reasonString = getDisconnectReasonString(params.m_flags);

		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Disconnect;
		representation.m_lineAttr.m_backColor = (params.m_flags & SocketLogDisconnectFlags.Aborted) ?
			log.StdLogColor.Warning :
			log.StdLogColor.Disconnect;

		representation.addHyperText($"Client \e[34m$addressString\e[m disconnected ($reasonString)");
		break;

	case SocketLogRecordCode.ClientRejected:
		string_t addressString = ((io.SocketAddress const*)p).getString();
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Warning;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Warning;
		representation.addHyperText($"Client \e[34m$addressString\e[m is rejected ");
		break;

	case SocketLogRecordCode.ClientChanged:
		string_t addressString = ((io.SocketAddress const*)p).getString();
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText($"Client \e[34m$addressString\e[m:");
		break;

	case SocketLogRecordCode.DisconnectDataPending:
		uint32_t pendingSize = *(uint32_t const*)p;
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = ui.StdColor.PastelGray;
		representation.addHyperText($"Data pending after disconnect (\e[34m$pendingSize\e[m bytes)");
		break;

	case SocketLogRecordCode.ClientRemoved: // for filters only
		break;

	default:
		return false;
	}

	return true;
}

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