#if !defined _CHATPRINT_INCLUDED
#define _CHATPRINT_INCLUDED

#include <amxmodx>
#include <fakemeta>

// Hack hack hack
#if !defined SetGlobalTransTarget
	#define SetGlobalTransTarget ChatPrint_SetGlobalTransTarget
	
	stock ChatPrint_SetGlobalTransTarget(nClientIndex) {
		new oldFlags = pev(nClientIndex, pev_flags);
		set_pev(nClientIndex, pev_flags, FL_FAKECLIENT); // Emulate bot
		console_cmd(nClientIndex, ""); // When player is bot this function call only SetDefLang function
		set_pev(nClientIndex, pev_flags, oldFlags); // Restore flags
	}
#endif

#if !defined MAX_PLAYERS
	const MAX_PLAYERS = 32;
#endif

#define CHATPRINT_NEWLINE_CODE          0x0A // '\n'
#define CHATPRINT_COLOR_CTRLCHAR_CODE   0x5C // '\'
#define CHATPRINT_DEFAULT_COLOR_CODE    1
#define CHATPRINT_TEAM_COLOR_CODE       3
#define CHATPRINT_GREEN_COLOR_CODE      4
#define CHATPRINT_RED_COLOR_CODE        5
#define CHATPRINT_BLUE_COLOR_CODE       6
#define CHATPRINT_GREY_COLOR_CODE       7
#define CHATPRINT_DEFAULT_COLOR_LETTER  'd' // default
#define CHATPRINT_DEFAULT_COLOR_LETTER2 'y' // yellow
#define CHATPRINT_DEFAULT_COLOR_LETTER3 'n' // none
#define CHATPRINT_DEFAULT_COLOR_NUMBER  '1'
#define CHATPRINT_TEAM_COLOR_LETTER     't' // team
#define CHATPRINT_TEAM_COLOR_NUMBER     '3'
#define CHATPRINT_GREEN_COLOR_LETTER    'g' // green
#define CHATPRINT_GREEN_COLOR_NUMBER    '4'
#define CHATPRINT_RED_COLOR_LETTER      'r' // red
#define CHATPRINT_RED_COLOR_NUMBER      '5'
#define CHATPRINT_BLUE_COLOR_LETTER     'b' // blue
#define CHATPRINT_BLUE_COLOR_NUMBER     '6'
#define CHATPRINT_GREY_COLOR_LETTER     'w' // white
#define CHATPRINT_GREY_COLOR_NUMBER     '7'

#define CHATPRINT_USERMSG_MAXBYTES      192
#define CHATPRINT_CHATMSG_MAXBYTES      (CHATPRINT_USERMSG_MAXBYTES - 1 - 3) // CHATPRINT_USERMSG_MAXBYTES - sizeof(byte) - sizeof("%s")
#define CHATPRINT_RAWCHATMSG_MAXBYTES   ((CHATPRINT_CHATMSG_MAXBYTES - 1 - 1) * 2 + 1) // (CHATPRINT_CHATMSG_MAXBYTES - sizeof(char(CHATPRINT_NEWLINE_CODE)) - sizeof(char(EOS))) * 2 + sizeof(char(EOS))

#define CHATPRINT_PLAYERINFO_MAXINDEX   63
#define CHATPRINT_RED_COLOR_PLINDEX     (CHATPRINT_PLAYERINFO_MAXINDEX - 2)
#define CHATPRINT_BLUE_COLOR_PLINDEX    (CHATPRINT_PLAYERINFO_MAXINDEX - 1)
#define CHATPRINT_GREY_COLOR_PLINDEX    CHATPRINT_PLAYERINFO_MAXINDEX

static stock const CHATPRINT_LIBRARY_NAME[] = "ChatPrint";

static stock g_msgidSayText;

stock ChatPrint(nClientIndex, const szFormat[], any:...) {
	ChatPrint_Initialize();
	
	static szRaw[CHATPRINT_RAWCHATMSG_MAXBYTES];
	if (nClientIndex > 0) {
		SetGlobalTransTarget(nClientIndex);
		vformat(szRaw, charsmax(szRaw), szFormat, 3);
		
		ChatPrint_PrepareAndSendMessage(nClientIndex, szRaw);
	} else {
		static players[MAX_PLAYERS];
		new playersCount;
		get_players(players, playersCount, "c"); // Don't include bots
		
		for (new n = 0; n < playersCount; n++) {
			if (nClientIndex < 0 && players[n] == -nClientIndex) { // Send all exclude this player
				continue;
			}
			
			SetGlobalTransTarget(players[n]);
			vformat(szRaw, charsmax(szRaw), szFormat, 3);
			
			ChatPrint_PrepareAndSendMessage(players[n], szRaw);
		}
	}
}

static stock ChatPrint_PrepareAndSendMessage(nClientIndex, const szRaw[]) {
	static szMsg[CHATPRINT_CHATMSG_MAXBYTES];
	new bool:fUseColors = false;
	new nMsgLen = 0;
	new nColorPlayerIndex = nClientIndex;
	for (new nRawPos = 0; szRaw[nRawPos] != EOS && nMsgLen < (charsmax(szMsg) - 1); nRawPos++, nMsgLen++) { // charsmax(szMsg) - sizeof(char(CHATPRINT_NEWLINE_CODE))
		switch (szRaw[nRawPos]) {
			case CHATPRINT_DEFAULT_COLOR_CODE, CHATPRINT_GREEN_COLOR_CODE: {
				fUseColors = true;
				szMsg[nMsgLen] = szRaw[nRawPos];
			}
			case CHATPRINT_TEAM_COLOR_CODE: {
				fUseColors = true;
				nColorPlayerIndex = nClientIndex;
				szMsg[nMsgLen] = CHATPRINT_TEAM_COLOR_CODE;
			}
			case CHATPRINT_RED_COLOR_CODE: {
				fUseColors = true;
				nColorPlayerIndex = CHATPRINT_RED_COLOR_PLINDEX;
				szMsg[nMsgLen] = CHATPRINT_TEAM_COLOR_CODE;
			}
			case CHATPRINT_BLUE_COLOR_CODE: {
				fUseColors = true;
				nColorPlayerIndex = CHATPRINT_BLUE_COLOR_PLINDEX;
				szMsg[nMsgLen] = CHATPRINT_TEAM_COLOR_CODE;
			}
			case CHATPRINT_GREY_COLOR_CODE: {
				fUseColors = true;
				nColorPlayerIndex = CHATPRINT_GREY_COLOR_PLINDEX;
				szMsg[nMsgLen] = CHATPRINT_TEAM_COLOR_CODE;
			}
			case CHATPRINT_COLOR_CTRLCHAR_CODE: {
				switch (szRaw[++nRawPos]) {
					case CHATPRINT_DEFAULT_COLOR_LETTER, CHATPRINT_DEFAULT_COLOR_LETTER2, CHATPRINT_DEFAULT_COLOR_LETTER3, CHATPRINT_DEFAULT_COLOR_NUMBER: {
						fUseColors = true;
						szMsg[nMsgLen] = CHATPRINT_DEFAULT_COLOR_CODE;
					}
					case CHATPRINT_TEAM_COLOR_LETTER, CHATPRINT_TEAM_COLOR_NUMBER: {
						fUseColors = true;
						nColorPlayerIndex = nClientIndex;
						szMsg[nMsgLen] = CHATPRINT_TEAM_COLOR_CODE;
					}
					case CHATPRINT_GREEN_COLOR_LETTER, CHATPRINT_GREEN_COLOR_NUMBER: {
						fUseColors = true;
						szMsg[nMsgLen] = CHATPRINT_GREEN_COLOR_CODE;
					}
					case CHATPRINT_RED_COLOR_LETTER, CHATPRINT_RED_COLOR_NUMBER: {
						fUseColors = true;
						nColorPlayerIndex = CHATPRINT_RED_COLOR_PLINDEX;
						szMsg[nMsgLen] = CHATPRINT_TEAM_COLOR_CODE;
					}
					case CHATPRINT_BLUE_COLOR_LETTER, CHATPRINT_BLUE_COLOR_NUMBER: {
						fUseColors = true;
						nColorPlayerIndex = CHATPRINT_BLUE_COLOR_PLINDEX;
						szMsg[nMsgLen] = CHATPRINT_TEAM_COLOR_CODE;
					}
					case CHATPRINT_GREY_COLOR_LETTER, CHATPRINT_GREY_COLOR_NUMBER: {
						fUseColors = true;
						nColorPlayerIndex = CHATPRINT_GREY_COLOR_PLINDEX;
						szMsg[nMsgLen] = CHATPRINT_TEAM_COLOR_CODE;
					}
					default: {
						szMsg[nMsgLen] = szRaw[nRawPos];
					}
				}
			}
			default: {
				szMsg[nMsgLen] = szRaw[nRawPos];
			}
		}
	}
	
	message_begin(MSG_ONE, g_msgidSayText, _, nClientIndex);
	write_byte(nColorPlayerIndex);
	write_string("%s");
	
	if (fUseColors && szMsg[0] > CHATPRINT_GREEN_COLOR_CODE) {
		write_char(CHATPRINT_DEFAULT_COLOR_CODE);
		if (nMsgLen > (charsmax(szMsg) - 1 - 1)) { // charsmax(szMsg) - sizeof(char(CHATPRINT_DEFAULT_COLOR_CODE)) - sizeof(char(CHATPRINT_NEWLINE_CODE))
			nMsgLen = (charsmax(szMsg) - 1 - 1);
		}
	}
	szMsg[nMsgLen++] = CHATPRINT_NEWLINE_CODE;
	szMsg[nMsgLen] = EOS;
	
	write_string(szMsg);
	message_end();
}

static stock ChatPrint_Initialize() {
	static bool:fInitialized = false;
	
	if (!fInitialized) { // Is locally initialized? (this plugin)
		if (!LibraryExists(CHATPRINT_LIBRARY_NAME, LibType_Library)) { // Is globally initialized? (all plugins)
			new msgidTeamInfo = get_user_msgid("TeamInfo");
			
			// Precaching teaminfo's
			engfunc(EngFunc_MessageBegin, MSG_INIT, msgidTeamInfo, 0, 0);
			write_byte(CHATPRINT_RED_COLOR_PLINDEX);
			write_string("TERRORIST");
			message_end();
			engfunc(EngFunc_MessageBegin, MSG_INIT, msgidTeamInfo, 0, 0);
			write_byte(CHATPRINT_BLUE_COLOR_PLINDEX);
			write_string("CT");
			message_end();
			engfunc(EngFunc_MessageBegin, MSG_INIT, msgidTeamInfo, 0, 0);
			write_byte(CHATPRINT_GREY_COLOR_PLINDEX);
			write_string(""); // or SPECTATOR
			message_end();
			
			// And send it now for already connected players
			// Use MSG_ONE with for-loop instead of MSG_ALL, because MSG_ALL messages sends after MSG_ONE (ChatPrint sends chat messages via MSG_ONE)
			static players[MAX_PLAYERS];
			new playersCount;
			get_players(players, playersCount, "c"); // Don't include bots
			
			for (new n = 0; n < playersCount; n++) {
				message_begin(MSG_ONE, msgidTeamInfo, _, players[n]);
				write_byte(CHATPRINT_RED_COLOR_PLINDEX);
				write_string("TERRORIST");
				message_end();
				message_begin(MSG_ONE, msgidTeamInfo, _, players[n]);
				write_byte(CHATPRINT_BLUE_COLOR_PLINDEX);
				write_string("CT");
				message_end();
				message_begin(MSG_ONE, msgidTeamInfo, _, players[n]);
				write_byte(CHATPRINT_GREY_COLOR_PLINDEX);
				write_string(""); // or SPECTATOR
				message_end();
			}
			
			register_library(CHATPRINT_LIBRARY_NAME);
		}
		
		g_msgidSayText = get_user_msgid("SayText");
		
		fInitialized = true;
	}
}

#undef CHATPRINT_NEWLINE_CODE
#undef CHATPRINT_COLOR_CTRLCHAR_CODE
#undef CHATPRINT_DEFAULT_COLOR_CODE
#undef CHATPRINT_TEAM_COLOR_CODE
#undef CHATPRINT_GREEN_COLOR_CODE
#undef CHATPRINT_RED_COLOR_CODE
#undef CHATPRINT_BLUE_COLOR_CODE
#undef CHATPRINT_GREY_COLOR_CODE
#undef CHATPRINT_DEFAULT_COLOR_LETTER
#undef CHATPRINT_DEFAULT_COLOR_LETTER2
#undef CHATPRINT_DEFAULT_COLOR_LETTER3
#undef CHATPRINT_DEFAULT_COLOR_NUMBER
#undef CHATPRINT_TEAM_COLOR_LETTER
#undef CHATPRINT_TEAM_COLOR_NUMBER
#undef CHATPRINT_GREEN_COLOR_LETTER
#undef CHATPRINT_GREEN_COLOR_NUMBER
#undef CHATPRINT_RED_COLOR_LETTER
#undef CHATPRINT_RED_COLOR_NUMBER
#undef CHATPRINT_BLUE_COLOR_LETTER
#undef CHATPRINT_BLUE_COLOR_NUMBER
#undef CHATPRINT_GREY_COLOR_LETTER
#undef CHATPRINT_GREY_COLOR_NUMBER

#undef CHATPRINT_USERMSG_MAXBYTES
#undef CHATPRINT_CHATMSG_MAXBYTES
#undef CHATPRINT_RAWCHATMSG_MAXBYTES

#undef CHATPRINT_PLAYERINFO_MAXINDEX
#undef CHATPRINT_RED_COLOR_PLINDEX
#undef CHATPRINT_BLUE_COLOR_PLINDEX
#undef CHATPRINT_GREY_COLOR_PLINDEX

#endif