// Oxxy (C) 2015, HPM plugin.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../common/HPMi.h"
#include "../common/malloc.h"
#include "../common/mmo.h"
#include "../common/socket.h"
#include "../common/strlib.h"
#include "../common/timer.h"
#include "../common/mapindex.h"
#include "../map/clif.h"
#include "../map/script.h"
#include "../map/pc.h"
#include "../map/atcommand.h"
#include "../map/battle.h"
#include "../map/map.h"
#include "../map/log.h"
#include "../map/channel.h"
#include "../map/chat.h"
#include "../map/skill.h"

static char atcmd_output[CHAT_SIZE_MAX];

#include "../common/HPMDataCheck.h" /* should always be the last file included! (if you don't make it last, it'll intentionally break compile time) */

HPExport struct hplugin_info pinfo = {
	"Chat Color",    // Plugin name
	SERVER_TYPE_MAP,// Which server types this plugin works with?
	"1.0",       // Plugin version
	HPM_VERSION, // HPM Version (don't change, macro is automatically updated)
};

BUILDIN(setcolor) {
	int color = script_getnum(st, 2);
	TBL_PC* sd;

	sd = script->rid2sd(st);

	pc_setglobalreg(sd, script->add_str("CHAT_COLOR"), color);
	return true;
}

ACMD(color) {
	int color;

	if(!message || !*message || (!sscanf(message, "%x", &color))) {
		clif->message(fd, "Usage: @color <HEX_COLOR>");
		return false;
	}
	
	if (color > 0xFFFFFF || color < 0) color = 0;

	pc_setglobalreg(sd, script->add_str("CHAT_COLOR"), color);
	sprintf(atcmd_output,"Color has been set to %06X", color);
	clif->message(fd, atcmd_output);
	return true;
}

BUILDIN(color2hex) {
	int color = script_getnum(st, 2);
	char colorstring[7];

	snprintf(colorstring, 7, "%06X", color);

	script_pushstrcopy(st, colorstring);
	return true;
}

void clif_parseGlobalMsg(int fd, struct map_session_data* sd)
{
	const char* text = (char*)RFIFOP(fd,4);
	size_t textlen = RFIFOW(fd,2) - 4;

	char *name, *message, *fakename = NULL;
	size_t namelen, messagelen;

	bool is_fake;

	int color = pc->readregistry(sd,script->add_str("CHAT_COLOR"));

	// validate packet and retrieve name and message
	if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) )
		return;

	if( atcommand->exec(fd, sd, message, true)  )
		return;

	if( !pc->can_talk(sd) )
		return;

	if( battle->bc->min_chat_delay ) { //[Skotlex]
		if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0)
			return;
		sd->cantalk_tick = timer->gettick() + battle->bc->min_chat_delay;
	}

	if( (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE ) {
		unsigned int next = pc->nextbaseexp(sd);
		if( next == 0 ) next = pc->thisbaseexp(sd);
		if( next ) { // 0%, 10%, 20%, ...
			int percent = (int)( ( (float)sd->status.base_exp/(float)next )*1000. );
			if( (battle->bc->snovice_call_type || percent) && ( percent%100 ) == 0 ) {// 10.0%, 20.0%, ..., 90.0%
				switch (sd->state.snovice_call_flag) {
					case 0:
						if( strstr(message, msg_txt(1479)) ) // "Dear angel, can you hear my voice?"
							sd->state.snovice_call_flag = 1;
						break;
					case 1: {
						char buf[256];
						snprintf(buf, 256, msg_txt(1480), sd->status.name);
						if( strstr(message, buf) ) // "I am %s Super Novice~"
							sd->state.snovice_call_flag = 2;
					}
						break;
					case 2:
						if( strstr(message, msg_txt(1481)) ) // "Help me out~ Please~ T_T"
							sd->state.snovice_call_flag = 3;
						break;
					case 3:
						sc_start(NULL,&sd->bl, status->skill2sc(MO_EXPLOSIONSPIRITS), 100, 17, skill->get_time(MO_EXPLOSIONSPIRITS, 5)); //Lv17-> +50 critical (noted by Poki) [Skotlex]
						clif->skill_nodamage(&sd->bl, &sd->bl, MO_EXPLOSIONSPIRITS, 5, 1);  // prayer always shows successful Lv5 cast and disregards noskill restrictions
						sd->state.snovice_call_flag = 0;
						break;
				}
			}
		}
	}

	if( battle->bc->idletime_criteria & BCIDLE_CHAT )
		sd->idletime = sockt->last_tick;

	if( sd->gcbind ) {
		channel->send(sd->gcbind,sd,message);
		return;
	}

	if(color && !sd->chatID) {
		char mout[200];
		unsigned char mylen = 1;

		mylen += snprintf(mout, 200, "%s : %s",sd->fakename[0]?sd->fakename:sd->status.name,message);

		WFIFOHEAD(fd,mylen + 12);
		WFIFOW(fd,0) = 0x2C1;
		WFIFOW(fd,2) = mylen + 12;
		WFIFOL(fd,4) = sd->bl.id;
		WFIFOL(fd,8) = (color&0x0000FF) << 16 | (color&0x00FF00) | (color&0xFF0000) >> 16; // RGB -> BGR
		safestrncpy((char*)WFIFOP(fd,12), mout, mylen);
		clif->send(WFIFOP(fd,0), WFIFOW(fd,2), &sd->bl, AREA_WOS);
		return;
	}

	/**
	 * Fake Name Design by FatalEror (bug report #9)
	 **/
	if( ( is_fake = ( sd->fakename[0] ) ) ) {
		fakename = (char*) aMalloc(strlen(sd->fakename)+messagelen+3);
		strcpy(fakename, sd->fakename);
		strcat(fakename, " : ");
		strcat(fakename, message);
		textlen = strlen(fakename) + 1;
	}

	// send message to others (using the send buffer for temp. storage)
	WFIFOHEAD(fd, 8 + textlen);
	WFIFOW(fd,0) = 0x8d;
	WFIFOW(fd,2) = 8 + textlen;
	WFIFOL(fd,4) = sd->bl.id;
	safestrncpy((char*)WFIFOP(fd,8), is_fake ? fakename : text, textlen);
	//FIXME: chat has range of 9 only
	clif->send(WFIFOP(fd,0), WFIFOW(fd,2), &sd->bl, sd->chatID ? CHAT_WOS : AREA_CHAT_WOC);

	// send back message to the speaker
	if( is_fake ) {
		WFIFOW(fd,0) = 0x8e;
		WFIFOW(fd,2) = textlen + 4;
		safestrncpy((char*)WFIFOP(fd,4), fakename, textlen);
		aFree(fakename);
	} else {
		memcpy(WFIFOP(fd,0), RFIFOP(fd,0), RFIFOW(fd,2));
		WFIFOW(fd,0) = 0x8e;
	}
	WFIFOSET(fd, WFIFOW(fd,2));
	
	// Chat logging type 'O' / Global Chat
	logs->chat(LOG_CHAT_GLOBAL, 0, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, NULL, message);
	
#ifdef PCRE_SUPPORT
	// trigger listening npcs
	map->foreachinrange(npc_chat->sub, &sd->bl, AREA_SIZE, BL_NPC, text, textlen, &sd->bl);
#endif
}

HPExport void plugin_init (void) {

	iMalloc = GET_SYMBOL("iMalloc");

	script = GET_SYMBOL("script");
	clif = GET_SYMBOL("clif");
	pc = GET_SYMBOL("pc");
	battle = GET_SYMBOL("battle");
	timer = GET_SYMBOL("timer");
	map = GET_SYMBOL("map");
	logs = GET_SYMBOL("logs");
	channel = GET_SYMBOL("channel");
	atcommand = GET_SYMBOL("atcommand");
	sockt = GET_SYMBOL("sockt");
	chat = GET_SYMBOL("chat");
	strlib = GET_SYMBOL("strlib");
	session = GET_SYMBOL("session");
	skill = GET_SYMBOL("skill");
	mapindex = GET_SYMBOL("mapindex");
	unit = GET_SYMBOL("unit");

	addAtcommand("color", color);
	addScriptCommand("color2hex","i",color2hex);
	addScriptCommand("setcolor","i",setcolor);
	clif->pGlobalMessage = clif_parseGlobalMsg;
}

HPExport void server_online (void) {
	ShowInfo ("'%s' Plugin by Ancyker and Oxxy. Version '%s'\n",pinfo.name,pinfo.version);
}