@VisibleForTesting
	void colorChatMessage()
	{
		final int[] intStack = client.getIntStack();
		final String[] stringStack = client.getStringStack();
		final int size = client.getStringStackSize();
		final int isize = client.getIntStackSize();
		final int uid = intStack[isize - 1];
		final boolean splitpmbox = intStack[isize - 2] == 1;

		final MessageNode messageNode = client.getMessages().get(uid);
		assert messageNode != null : "chat message build for unknown message";

		String message = stringStack[size - 2];
		final String username = stringStack[size - 3];
		final String channel = stringStack[size - 4];
		final ChatMessageType chatMessageType = messageNode.getType();

		final boolean isChatboxTransparent = client.isResized() && client.getVarbitValue(Varbits.TRANSPARENT_CHATBOX) == 1;
		Color usernameColor = null;
		Color channelColor = null;

		switch (chatMessageType)
		{
			// username recoloring for MODPRIVATECHAT, PRIVATECHAT and PRIVATECHATOUT
			// ChatMessageTypes is handled in the script callback event
			case TRADEREQ:
			case AUTOTYPER:
			case PUBLICCHAT:
			case MODCHAT:
			{
				String sanitizedUsername = Text.removeTags(username).replace('\u00A0', ' ');

				if (client.getLocalPlayer().getName().equals(sanitizedUsername))
				{
					usernameColor = isChatboxTransparent ? chatColorConfig.transparentPlayerUsername() : chatColorConfig.opaquePlayerUsername();
				}
				else if (client.isFriended(sanitizedUsername, true))
				{
					usernameColor = isChatboxTransparent ? chatColorConfig.transparentPublicFriendUsernames() : chatColorConfig.opaquePublicFriendUsernames();
				}
				else
				{
					usernameColor = isChatboxTransparent ? chatColorConfig.transparentUsername() : chatColorConfig.opaqueUsername();
				}
				break;
			}
			case FRIENDSCHAT:
			case FRIENDSCHATNOTIFICATION:
				usernameColor = isChatboxTransparent ? chatColorConfig.transparentFriendsChatUsernames() : chatColorConfig.opaqueFriendsChatUsernames();
				channelColor = isChatboxTransparent ? chatColorConfig.transparentFriendsChatChannelName() : chatColorConfig.opaqueFriendsChatChannelName();
				break;
			case CLAN_CHAT:
			case CLAN_MESSAGE:
			case CLAN_GIM_CHAT:
			case CLAN_GIM_MESSAGE:
				usernameColor = isChatboxTransparent ? chatColorConfig.transparentClanChatUsernames() : chatColorConfig.opaqueClanChatUsernames();
				channelColor = isChatboxTransparent ? chatColorConfig.transparentClanChannelName() : chatColorConfig.opaqueClanChannelName();
				break;
			case CLAN_GUEST_CHAT:
			case CLAN_GUEST_MESSAGE:
				usernameColor = isChatboxTransparent ? chatColorConfig.transparentClanChatGuestUsernames() : chatColorConfig.opaqueClanChatGuestUsernames();
				channelColor = isChatboxTransparent ? chatColorConfig.transparentClanChannelGuestName() : chatColorConfig.opaqueClanGuestChatChannelName();
				break;
		}

		if (usernameColor != null)
		{
			stringStack[size - 3] = ColorUtil.wrapWithColorTag(username, usernameColor);
		}

		if (channelColor != null && !Strings.isNullOrEmpty(channel))
		{
			stringStack[size - 4] = ColorUtil.wrapWithColorTag(channel, channelColor);
		}

		String prefix = "";
		if (chatMessageType == ChatMessageType.CLAN_GIM_CHAT || chatMessageType == ChatMessageType.CLAN_GIM_MESSAGE)
		{
			message = message.substring(1); // remove |
			prefix = "|";
		}

		if (messageNode.getRuneLiteFormatMessage() != null)
		{
			message = formatRuneLiteMessage(messageNode.getRuneLiteFormatMessage(),
				chatMessageType, splitpmbox);
		}

		final Collection<ChatColor> chatColors = colorCache.get(chatMessageType);
		for (ChatColor chatColor : chatColors)
		{
			if (chatColor.isTransparent() != isChatboxTransparent || chatColor.getType() != ChatColorType.NORMAL || chatColor.isDefault())
			{
				continue;
			}

			// Replace </col> tags in the message with the new color so embedded </col> won't reset the color
			final Color color = chatColor.getColor();
			message = ColorUtil.wrapWithColorTag(
				message.replace(ColorUtil.CLOSING_COLOR_TAG, ColorUtil.colorTag(color)),
				color);
			break;
		}

		stringStack[size - 2] = prefix + message;
	}
@Test
	public void testPublicFriendUsernameRecolouring()
	{
		final String localPlayerName = "RuneLite";
		final String friendName = "Zezima";

		when(chatColorConfig.opaquePublicFriendUsernames()).thenReturn(Color.decode("#b20000"));

		setupVm(ChatMessageType.PUBLICCHAT, friendName, "");

		// Setup friend checking
		Player localPlayer = mock(Player.class);

		when(client.isFriended(friendName, true)).thenReturn(true);
		when(client.getLocalPlayer()).thenReturn(localPlayer);
		when(localPlayer.getName()).thenReturn(localPlayerName);

		chatMessageManager.colorChatMessage();

		assertEquals("<col=b20000>" + friendName + "</col>", sstack[1]);
	}