/* ARISA - Admin Interface - Channel Menu
 * Copyright (C) 2003 Carl Ritson
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

static int is_chan_new(network_t *n, channel_t *c) {
	int i;
	LOCK(n);
	for(i = 0; i < n->no_channels; ++i) {
		if(n->channels[i] == c) {
			UNLOCK(n);
			return 0;
		}
	}
	UNLOCK(n);
	return 1;
}

/** Channel Menu Commands **/

MENU_HELPER(cmd_channels_helper) {
	network_t *n = (network_t *)ins->data;
	int i,j;
	
	LOCK(n);
	for(j = 0; args[no_args-1][j] != '\0'; ++j) {
		if(args[no_args-1][j] == '?')
			break;
	}
	for(i = 0; i < n->no_channels; ++i) {
		LOCK(n->channels[i]);
		if(n->channels[i]->deleted == 0 &&
			(j == 0 ||
			 strncmp(n->channels[i]->name,args[no_args-1],j) == 0))
			admin_msg(ac,"%s",n->channels[i]->name);
		UNLOCK(n->channels[i]);
	}
	UNLOCK(n);
}

MENU_HELPER(cmd_networks_helper); // pre-declaration
MENU_HELPER(cmd_net_channels_helper) {
	network_t *n;
	void *ptr;

	if(no_args == 2)
		cmd_networks_helper(ins,ac,args,no_args);
	else if(no_args > 2) {
		n = irc_network_find(args[1]);
		if(n != NULL) {
			ptr = ins->data;
			ins->data = n;
			cmd_channels_helper(ins,ac,args,no_args);
			ins->data = ptr;
		}
	}
}

static const cmd_t channel_menu[]; // pre-declaration
MENU_CMD(cmd_channel_save) {
	network_t *n = (network_t *)ins->prev->data;
	channel_t *c = (channel_t *)ins->data;
	int ret;
	if(is_chan_new(n,c)) {
		ret = irc_channel_add(n,c);
		if(ret == 0) {
			admin_msg(ac,"Successfully Saved.");
			ins->free = NULL;
		} else
			admin_msg(ac,"Save Failed.");
	} else
		admin_msg(ac,"Channel is already saved.");
	return 0;
}

MENU_CMD(cmd_channel_msg) {
	network_t *n = (network_t *)ins->prev->data;
	channel_t *c = (channel_t *)ins->data;
	char buffer[32];
	char cbuffer[512];
	
	if(ins->free != NULL) {
		admin_msg(ac,"This command cannot be used on unsaved channels.");
		return 0;
	}
	
	LOCK(c);
	xstrncpy(buffer,c->name,sizeof(buffer));
	UNLOCK(c);
	colourise(COLOUR_IRC,cbuffer,sizeof(cbuffer),args[1]);
	irc_send_msg(n,buffer,cbuffer);

	return 0;
}

MENU_CMD(cmd_channel_info) {
	channel_t *c = (channel_t *)ins->data;
	int i;
	
	LOCK(c);
	admin_msg(ac,"-- Channel %s --",c->name);
	if(c->key != NULL)
		admin_msg(ac,"Key: %s",c->key);
	if(c->joined != 0) {
		char ctime_buf[32];
		lctime_r(&c->joined,ctime_buf,sizeof(ctime_buf));
		ctime_buf[strlen(ctime_buf)-1] = '\0';
		admin_msg(ac,"Join at: %s",ctime_buf);
	} else
		admin_msg(ac,"Not Joined");
	if(c->nolist != 0 && c->nolist > xtime()) {
		char ctime_buf[32];
		lctime_r(&c->nolist,ctime_buf,sizeof(ctime_buf));
		ctime_buf[strlen(ctime_buf)-1] = '\0';
		if(c->nolist != TIME_MAX)
			admin_msg(ac,"nolist Enabled Till: %s",ctime_buf);
		else
			admin_msg(ac,"nolist Permenantly Enabled");
	}
	if(c->plist != 0) {
		admin_msg(ac,"Pack Listing Every %d Minutes, Format: %s",
			c->plist,pformat_to_str(c->pformat));
		if(c->last_plist != 0) {
			char ctime_buf[32];
			lctime_r(&c->last_plist,ctime_buf,sizeof(ctime_buf));
			ctime_buf[strlen(ctime_buf)-1] = '\0';
			admin_msg(ac,"Last Pack Listing: %s",ctime_buf);
		}
	}
	if(c->mode != NULL)
		admin_msg(ac,"Mode: %s",c->mode);
	if(c->topic != NULL) {
		char buffer[512];
		xstrncpy(buffer,c->topic,sizeof(buffer));
		irc_strip_colours(buffer);
		admin_msg(ac,"Topic: %s",buffer);
	}
	if(c->limit != 0)
		admin_msg(ac,"User Limit: %d",c->limit);
	if(no_args >= 2 && c->no_bans > 0) {
		admin_msg(ac,"-- Bans --");
		for(i = 0; i < c->no_bans; ++i)
			admin_msg(ac,"  %s",c->bans[i]);
	}

	UNLOCK(c);
	return 0;
}

MENU_CMD(cmd_channel_settings) {
	channel_t *c = (channel_t *)ins->data;
	
	if(no_args <= 1) {
		pqueue_t settings;
		pqueue_init(&settings,0);
		channel_read_settings(c,&settings);

		LOCK(c);
		output_settings(ac,"-- Channel Settings for %s --",
				c->name,&settings);
		UNLOCK(c);
	} else if(no_args >= 3) {
		if(channel_apply_setting(c,args[1],args[2]) == -1)
			admin_msg(ac,"Invalid setting: %s",args[1]);
	} else
		admin_msg(ac,"%s [<setting> <value>]",args[0]);
	
	return 0;
}

MENU_CMD(cmd_channel_nolist) {
	channel_t *c = (channel_t *)ins->data;
	unsigned long sec;
	LOCK(c);
	if(no_args >= 2) {
		sec = strtol(args[1],NULL,10);
		if(sec == -1)
			c->nolist = TIME_MAX;
		else if(sec > 0)
			c->nolist = xtime() + sec;
		else
			c->nolist = 0;
	}
	if(c->nolist == 0 || c->nolist < xtime())
		admin_msg(ac,"nolist not enabled");
	else if(c->nolist == TIME_MAX)
		admin_msg(ac,"nolist permenantly enabled");
	else {
		char buffer[32];
		lctime_r(&c->nolist,buffer,sizeof(buffer));
		buffer[strlen(buffer)-1] = '\0';
		admin_msg(ac,"nolist enabled till: %s",buffer);
	}
	UNLOCK(c);
	return 0;
}

MENU_CMD(cmd_channel_join) {
	network_t *n = (network_t *)ins->prev->data;
	channel_t *c = (channel_t *)ins->data;
	char buffer[64];
	
	if(ins->free != NULL) { // unsaved
		admin_msg(ac,"This command cannot be used on unsaved channels.");
		return 0;
	}
	
	buffer[0] = '\0';
	LOCK(n);
	if(n->state == NETWORK_CONNECTED) {
		LOCK(c);
		if(c->joined == 0) {
			if(c->key == NULL)
				snprintf(buffer,sizeof(buffer),
						"JOIN %s",c->name);
			else
				snprintf(buffer,sizeof(buffer),
						"JOIN %s %s",c->name,c->key);
			admin_msg(ac,"Sending JOIN Command for Channel %s",
					c->name);
		} else
			admin_msg(ac,"Already Joined to Channel %s",c->name);
		UNLOCK(c);
	} else
		admin_msg(ac,"Network %s is not connected.",n->name);
	UNLOCK(n);
	
	if(buffer[0] != '\0')
		irc_send_raw(n,buffer);
	
	return 0;
}

MENU_CMD(cmd_channel_part) {
	network_t *n = (network_t *)ins->prev->data;
	channel_t *c = (channel_t *)ins->data;
	char buffer[512];
	
	if(ins->free != NULL) {
		admin_msg(ac,"This command cannot be used on unsaved channels.");
		return 0;
	}
	
	buffer[0] = '\0';
	LOCK(n);
	if(n->state == NETWORK_CONNECTED) {
		LOCK(c);
		if(c->joined != 0) {
			if(no_args >= 2)
				snprintf(buffer,sizeof(buffer),"PART %s :%s",
						c->name,args[1]);
			else
				snprintf(buffer,sizeof(buffer),"PART %s",
						c->name);
			admin_msg(ac,"Sending PART Command for Channel %s",
					c->name);
		} else
			admin_msg(ac,"Not Joined to Channel %s",c->name);
		UNLOCK(c);
	} else
		admin_msg(ac,"Network %s is not connected.",n->name);
	UNLOCK(n);
	
	if(buffer[0] != '\0')
		irc_send_raw(n,buffer);
	
	return 0;
}		

MENU_CMD(cmd_channel_delete) {
	network_t *n = (network_t *)ins->prev->data;
	channel_t *c = (channel_t *)ins->data;
	
	LOCK(c);
	admin_msg(ac,"Deleted Channel %s.",c->name);
	UNLOCK(c);
	irc_channel_del(n,c);
	
	return RET_UP;
}

MENU_CMD(cmd_channel_taglines) {
	channel_t *c = (channel_t *)ins->data;
	int ret;
	LOCK(c);
	ret = cmd_strarr(ac,&c->taglines,&c->no_taglines,args,no_args);
	UNLOCK(c);
	return ret;
}

MENU_CMD(cmd_channel_rename) {
	network_t *n = (network_t *)ins->prev->data;
	channel_t *c = (channel_t *)ins->data;
	
	if(irc_channel_rename(n,c,args[1]) == 0) {
		if(ins->prompt != NULL && ins->free_prompt != 0)
			xfree(ins->prompt);
		ins->prompt = xstrdup(args[1]);
		ins->free_prompt = 1;
		admin_output_prompt(ac);
	} else
		admin_msg(ac,"Rename To %s Failed",args[1]);
	
	return 0;
}

MENU_CMD(cmd_channel_listen) {
	channel_t *c = (channel_t *)ins->data;

	if(ins->free == NULL) {
		if(strcasecmp(args[1],"on") == 0)
			irc_listen(NULL,c,ac->msgqueue);
		else
			irc_unlisten(NULL,c,ac->msgqueue);
	} else
		admin_msg(ac,"This command cannot be used on unsaved channels.");
	return 0;
}

static const char *mode_str(int mode) {
	if(mode & MODE_OWNER)
		return "~";
	else if(mode & MODE_ANTIKICK)
		return "&";
	else if(mode & MODE_OP)
		return "@";
	else if(mode & MODE_HOP)
		return "%";
	else if(mode & MODE_VOICE)
		return "+";
	else
		return "";
}

MENU_CMD(cmd_channel_names) {
	channel_t 	*c = (channel_t *)ins->data;
	network_t 	*n = (network_t *)ins->prev->data;
	nickmode_t	*nms = NULL;
	char 		buffer[128];
	int 		i,tmp,pos = 0;
	
	if(ins->free != NULL) {
		admin_msg(ac,
			"This command cannot be used on unsaved channels.");
		return 0;
	}
	
	LOCK(n);
	
	LOCK(n->info);
	tmp = nickhash_query_channel(n->info->nick_tracker,c,&nms);
	UNLOCK(n->info);
	
	for(i = 0; i < tmp; ++i) {
		pos += snprintf(buffer+pos,sizeof(buffer)-pos-1,"%s%s ",
				mode_str(nms[i].mode),nms[i].nick);
		if(pos > 60) {
			admin_msg(ac,"%s",buffer);
			pos = 0;
		}
	}
	if(nms != NULL)
		xfree(nms);

	UNLOCK(n);

	if(pos != 0)
		admin_msg(ac,"%s",buffer);
	
	return 0;
}

/** Channel Menu Structure **/

static const cmd_t channel_menu[] = {
	{"delete",cmd_channel_delete,0,0,1,0,PRIVS_EMPTY,NULL},
	{"info",  cmd_channel_info,  0,1,0,0,PRIVS_EMPTY,NULL},
	{"join",  cmd_channel_join,  0,0,1,0,PRIVS_EMPTY,NULL},
	{"listen",cmd_channel_listen,1,1,0,0,PRIVS_EMPTY,NULL},
	{"msg",	  cmd_channel_msg,   1,-2,0,0,PRIVS_EMPTY,NULL},
	{"names", cmd_channel_names, 0,0,0,0,PRIVS_EMPTY,NULL},
	{"nolist",cmd_channel_nolist,0,1,1,0,PRIVS_EMPTY,NULL},
	{"part",  cmd_channel_part,  0,-2,1,0,PRIVS_EMPTY,NULL},
	{"rename",cmd_channel_rename,1,1,1,0,PRIVS_EMPTY,NULL},
	{"save",cmd_channel_save,0,0,1,0,PRIVS_EMPTY,NULL},
	{"settings", cmd_channel_settings, 0,3,1,0,PRIVS_EMPTY,NULL},
	{"taglines",cmd_channel_taglines,0,3,1,0,PRIVS_EMPTY,NULL},
	{NULL}
};

/** Channel Menu Entry **/
MENU_CHECK(cmd_channel_check) {
	channel_t *c = (channel_t *)ins->data;
	int ret = 0;
	LOCK(c);
	if(c->deleted != 0) {
		admin_msg(ac,"Channel %s, Deleted.",c->name);
		ret = -1;
	}
	UNLOCK(c);
	return ret;
}

MENU_CMD(cmd_channel_entry) {
	network_t *n = (network_t *)ins->prev->data;
	channel_t *c;
	
	if(ins->prompt != NULL && ins->free_prompt)
		xfree(ins->prompt);
	ins->prompt	= xstrdup(args[1]);
	ins->free_prompt= 1;
	ins->check 	= cmd_channel_check;
	
	c = irc_channel_find(n,args[1]);
	if(c == NULL) {
		c = alloc_channel();
		c->name = xstrdup(args[1]);
		ins->free = (void (*)(void *)) free_channel;
		admin_msg(ac,"New Channel: %s",args[1]);
	}
	ins->data = c;
	return 0;
}

static void register_channel_menu(menu_t *n_menu) {
	menu_t *c_menu = menu_from_cmds(
			"channel",			// name
			1,				// min_args
			1,				// max_args
			1,				// log
			0,				// hide
			PRIVS_EMPTY,			// privs
			cmd_channel_entry,		// func
			cmd_channels_helper,		// helper
			(cmd_t *)channel_menu);

	menu_add(n_menu,c_menu);
	menu_deref(c_menu);
}
