//===== Hercules Plugin ======================================
//= ReadOnly Channel
//===== By: ==================================================
//= Dastgir/Hercules
//===== Current Version: =====================================
//= 1.1
//===== Compatible With: ===================================== 
//= Hercules 2016-12-21
//===== Description: =========================================
//= Adds ReadOnly channel
//===== Additional Comments: =================================  
//= v1.1 - Added Colors
//============================================================
/*
Channels.conf:
readonly: {
	chan1: "Color"
	chan2: "Color"
	// As Many Channels as you want
}

Script command:
chanmsg("#Channel", "Message");
*/

#include "common/hercules.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "libconfig/libconfig.h"

#include "common/conf.h"
#include "common/memmgr.h"
#include "common/showmsg.h"
#include "common/utils.h"

#include "map/channel.h"
#include "map/npc.h"
#include "map/pc.h"

#include "plugins/HPMHooking.h"
#include "common/HPMDataCheck.h"

HPExport struct hplugin_info pinfo = {
	"readonly_channel",
	SERVER_TYPE_MAP,
	"1.1",
	HPM_VERSION,
};

/**
 * Max ReadOnly Channels that can be defined.
 */
#define MAX_RO_CHANNEL 10

/**
 * Channel Structure.
 * Saves the Channel ReadOnly Status
 * @author Dastgir
 */
struct readonly_channel_data {
	char *name;
} ro_channel[MAX_RO_CHANNEL];

/**
 * Reads the Channel ReadOnly Status from conf/channels.conf
 * @author Dastgir
 */
void read_readonly_channel_config(void)
{
	struct config_t channels_conf;
	struct config_setting_t *chsys = NULL;
	const char *config_filename = "conf/channels.conf";
	unsigned int count = 0;

	if (!libconfig->load_file(&channels_conf, config_filename)) {
		ShowError("read_readonly_channel_config: Cannot read %s.\n", config_filename);
		return;
	}

	chsys = libconfig->lookup(&channels_conf, "chsys");

	if (chsys == NULL) {
		ShowError("read_readonly_channel_config: cannot find 'chsys'.\n");
		libconfig->destroy(&channels_conf);
		return;
	} else {
		struct config_setting_t *settings = libconfig->setting_get_elem(chsys, 0);
		struct config_setting_t *channels;
		int i, k;

		if ((channels = libconfig->setting_get_member(settings, "readonly")) != NULL) {
			int channel_count = libconfig->setting_length(channels);

			if (channel_count > MAX_RO_CHANNEL) {
				ShowError("read_readonly_channel_config: Please Increase MAX_RO_CHANNEL limit to accomadate more channels.\n");
				libconfig->destroy(&channels_conf);
				return;
			}

			for(i = 0; i < channel_count; i++) {
				struct config_setting_t *chan = libconfig->setting_get_elem(channels, i);
				const char *name = config_setting_name(chan);
				const char *color = libconfig->setting_get_string_elem(channels, i);
				int cidx;

				ARR_FIND(0, MAX_RO_CHANNEL, k, ro_channel[k].name == NULL);

				for (k = 0; k < MAX_RO_CHANNEL; k++) {
					if (ro_channel[k].name == NULL) {
						break;
					}
					if (strcmpi(ro_channel[k].name, name) == 0) {
						k = -1;
						break;
					}
				}

				if (k == -1) {
					ShowError("channels.conf: duplicate (read-only) channel '%s', skipping channel...\n", name);
					continue;
				}
				if (k == MAX_RO_CHANNEL) {
					ShowError("read_readonly_channel_config: Please Increase MAX_RO_CHANNEL limit to accomadate more channels.\n");
					continue;
				}

				// Add Color
				ARR_FIND(0, channel->config->colors_count, cidx, strcmpi(channel->config->colors_name[cidx], color) == 0);
				if (cidx == channel->config->colors_count) {
					ShowError("channels.conf: unknown color '%s' for channel '%s', skipping channel...\n", color, name);
					continue;
				}

				ro_channel[k].name = (char *)malloc(strlen(name)*sizeof(char));
				safestrncpy(ro_channel[k].name, name, strlen(name)+1);
				count++;				

				channel->create(HCS_TYPE_PUBLIC, name, cidx);
			}
		}

		ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' readOnly-channels in '"CL_WHITE"%s"CL_RESET"'.\n", count, config_filename);
	}
	libconfig->destroy(&channels_conf);
}

/**
 * channel_send hook, to avoid sending messages into readOnly Channels
 * @author Dastgir
 */
void channel_send_pre(struct channel_data **chan_, struct map_session_data **sd_, const char **msg)
{
	struct map_session_data *sd = *sd_;
	struct channel_data *chan = *chan_;
	if (sd != NULL && chan != NULL) {
		int i;
		for (i = 0; i < MAX_RO_CHANNEL; i++) {
			if (ro_channel[i].name == NULL)	// Save Iterations
				break;
			if (strcmpi(ro_channel[i].name, chan->name) == 0) {
				char message[150];
				safesnprintf(message, 150, "You cannot send message to read-only channel [ #%s ].", chan->name);
				clif->message(sd->fd, message);
				hookStop();
				return;
			}
		}
	}
	return;
}

/**
 * Syntax:
 * chanmsg("#ChannelName", "Message");
 * @author Dastgir
 */
BUILDIN(chanmsg)
{
	const char *channel_name = script_getstr(st, 2);
	const char *message = script_getstr(st, 3);

	struct channel_data *chan = channel->search(channel_name, NULL);

	if (chan == NULL) {
		ShowError("chanmsg: No Such Channel '%s' Exists.\n", channel_name);
		script_pushint(st, 0);
		return false;
	}

	channel->send(chan, NULL, message);
	script_pushint(st, 1);
	return true;
}

HPExport void plugin_init(void)
{
	int i;
	addHookPre(channel, send, channel_send_pre);
	addScriptCommand("chanmsg", "ss", chanmsg);

	for (i = 0; i < MAX_RO_CHANNEL; i++) {
		if (ro_channel[i].name != NULL) {
			ro_channel[i].name = NULL;
		}
	}
}

HPExport void server_online(void)
{
	ShowInfo("'%s' Plugin by Dastgir/Hercules. Version '%s'\n", pinfo.name, pinfo.version);
	read_readonly_channel_config();
}

HPExport void plugin_final(void)
{
	// Free the Memory
	int i;
	for (i = 0; i < MAX_RO_CHANNEL; i++) {
		if (ro_channel[i].name != NULL) {
			free(ro_channel[i].name);
			ro_channel[i].name = NULL;
		} else {
			break;	// No More Channels Left.
		}
	}
}
