/* ARISA - Admin Interface - Network 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_net_new(network_t *n) {
	int i;
	LOCK(global);
	for(i = 0; i < global->no_networks; ++i) {
		if(global->networks[i] == n) {
			UNLOCK(global);
			return 0;
		}
	}
	UNLOCK(global);
	return 1;
}

/** Network Menu Commands **/

MENU_HELPER(cmd_networks_helper) {
	int i,j;
	LOCK(global);
	for(j = 0; args[no_args-1][j] != '\0'; ++j) {
		if(args[no_args-1][j] == '?')
			break;
	}
	for(i = 0; i < global->no_networks; ++i) {
		LOCK(global->networks[i]);
		if(global->networks[i]->deleted == 0 &&
			(j == 0 || 
			 strncmp(global->networks[i]->name,args[no_args-1],j) == 0))
			admin_msg(ac,"%s",global->networks[i]->name);
		UNLOCK(global->networks[i]);
	}
	UNLOCK(global);
}

MENU_CMD(cmd_network_servers) {
	network_t *n = (network_t *)ins->data;
	int ret;
	LOCK(n);
	ret = cmd_strarr(ac,&n->servers,&n->no_servers,args,no_args);
	UNLOCK(n);
	return ret;
}

MENU_CMD(cmd_network_on_connects) {
	network_t *n = (network_t *)ins->data;
	int ret;
	LOCK(n);
	ret = cmd_strarr(ac,&n->on_connects,&n->no_on_connects,args,no_args);
	UNLOCK(n);
	return ret;
}

MENU_CMD(cmd_network_taglines) {
	network_t *n = (network_t *)ins->data;
	int ret;
	LOCK(n);
	ret = cmd_strarr(ac,&n->settings->taglines,&n->settings->no_taglines,
			args,no_args);
	UNLOCK(n);
	return ret;
}

MENU_CMD(cmd_network_info) {
	network_t *n = (network_t *)ins->data;
	char buffer[32];
	int i;
	LOCK(n);
	admin_msg(ac,"-- Network %s --",n->name);
	admin_msg(ac,"State: %s",networkstate_to_str(n->state));
	admin_msg(ac,"Number of Servers: %d",n->no_servers);
	admin_msg(ac,"Number of On-connects: %d",n->no_on_connects);
	admin_msg(ac,"Configured Nick: %s",n->settings->nick);
	if(n->info != NULL && n->state != NETWORK_OFFLINE) {
		LOCK(n->info);
		admin_msg(ac,"Present Nick: %s",
			n->info->nick != NULL ? n->info->nick : "Not Set");
		admin_msg(ac,"Present Server: %s:%u",
				n->info->server,
				n->info->port);
		if(n->state == NETWORK_CONNECTED) {
			lctime_r(&n->info->connected,buffer,sizeof(buffer));
			buffer[strlen(buffer)-1] = '\0';
			admin_msg(ac,"Connected at: %s",buffer);
		}
		admin_msg(ac,"Current Message Queue: %d Messages",
				pqueue_length(&n->info->p_squeue) +
				pqueue_length(&n->info->j_squeue) +
				pqueue_length(&n->info->d_squeue) +
				pqueue_length(&n->info->r_squeue));
		UNLOCK(n->info);
	}
	for(i = 0; i < n->no_channels; ++i) {
		LOCK(n->channels[i]);
		if(n->channels[i]->deleted == 0) {
			if(n->channels[i]->joined != 0) {
				lctime_r(&n->channels[i]->joined,buffer,
						sizeof(buffer));
				buffer[strlen(buffer)-1] = '\0';
				admin_msg(ac,"Channel %s, Joined At: %s",
						n->channels[i]->name,buffer);
			} else
				admin_msg(ac,"Channel %s, Not Joined",
						n->channels[i]->name);
		}
		UNLOCK(n->channels[i]);
	}
	UNLOCK(n);
	return 0;
}

MENU_CMD(cmd_network_save) {
	network_t *n = (network_t *)ins->data;
	int ret;
	if(is_net_new(n)) {
		ret = irc_network_add(n);
		if(ret == 0) {
			admin_msg(ac,"Successfully Saved.");
			ins->free = NULL;
		} else
			admin_msg(ac,"Save Failed.");
	} else
		admin_msg(ac,"Network is already saved.");
	return 0;
}

MENU_CMD(cmd_network_msg) {
	network_t *n = (network_t *)ins->data;
	char buffer[512];
	colourise(COLOUR_IRC,buffer,sizeof(buffer),args[2]);
	irc_send_msg(n,args[1],buffer);
	return 0;
}

MENU_CMD(cmd_network_ctcp) {
	network_t *n = (network_t *)ins->data;
	char buffer[512];
	colourise(COLOUR_IRC,buffer,sizeof(buffer),args[2]);
	irc_send_ctcp_msg(n,args[1],buffer);
	return 0;
}

MENU_CMD(cmd_network_raw) {
	network_t *n = (network_t *)ins->data;
	char buffer[512];
	colourise(COLOUR_IRC,buffer,sizeof(buffer),args[1]);
	irc_send_raw(n,buffer);
	return 0;
}

MENU_CMD(cmd_network_clear_queue) {
	network_t *n = (network_t *)ins->data;
	LOCK(n);
	if(n->info != NULL) {
		LOCK(n->info);
		pqueue_clear(&n->info->p_squeue,xfree,0);
		pqueue_clear(&n->info->j_squeue,xfree,0);
		pqueue_clear(&n->info->d_squeue,xfree,0);
		pqueue_clear(&n->info->r_squeue,xfree,0);
		admin_msg(ac,"Done.");
		UNLOCK(n->info);
	}
	UNLOCK(n);
	return 0;
}

MENU_CMD(cmd_network_settings) {
	network_t *n = (network_t *)ins->data;
	
	if(no_args == 1) {
		pqueue_t settings;
		pqueue_init(&settings,0);
		network_read_settings(n,&settings);
		
		LOCK(n);
		output_settings(ac,"-- Network Settings for %s --",
				n->name,&settings);
		UNLOCK(n);
	} else if(no_args >= 3) {
		if(network_apply_setting(n,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_network_start) {
	network_t *n = (network_t *)ins->data;
	int ret = 0;
	if(is_net_new(n)) {
		CHAIN_CMD(cmd_network_save);
		if(is_net_new(n)) {
			admin_msg(ac,"Unable to start network.");
			return 0;
		} else
			ret = 1;
	}
	LOCK(n);
	if(ret == 0 || (ret == 1 && n->settings->no_autoconnect == 1)) {
		if(n->state == NETWORK_OFFLINE) {
			ret = irc_network_run(n);
			if(ret != -1)
				admin_msg(ac,"Network %s, Started.",n->name);
			else
				admin_msg(ac,"Network %s, Failed to start.",n->name);
		} else
			admin_msg(ac,"Network %s is already running.",n->name);
	}
	UNLOCK(n);
	return 0;
}

MENU_CMD(cmd_network_stop) {
	network_t *n = (network_t *)ins->data;
	thread_t *t;
	LOCK(n);
	if(n->state != NETWORK_OFFLINE && n->info != NULL) {
		t = irc_network_stop(n);
		UNLOCK(n);
		if(t != NULL) {
			thread_join(t,NULL);
			LOCK(n);
			admin_msg(ac,"Network %s, Stopped.",n->name);
		} else {
			LOCK(n);
			admin_msg(ac,"Network %s, is not running.",n->name);
		}
	} else
		admin_msg(ac,"Network %s, is not running.",n->name);
	UNLOCK(n);
	return 0;
}		

MENU_CMD(cmd_network_delete) {
	network_t *n = (network_t *)ins->data;
	if(!is_net_new(n)) {
		LOCK(n);
		admin_msg(ac,"Deleted Network %s.",n->name);
		UNLOCK(n);
		irc_network_del(n);
	}
	return RET_UP;
}

MENU_CMD(cmd_network_rename) {
	network_t *n = (network_t *)ins->data;
	char buffer[96];
	
	if(irc_network_rename(n,args[1]) == 0) {
		snprintf(buffer,sizeof(buffer),"network: %s",args[1]);
		if(ins->prompt != NULL && ins->free_prompt != 0)
			xfree(ins->prompt);
		ins->prompt = xstrdup(buffer);
		ins->free_prompt = 1;
	
		admin_msg(ac,"Renamed Network to %s",args[1]);
		admin_output_prompt(ac);
	} else
		admin_msg(ac,"Failed Renamed to %s",args[1]);
	
	return 0;
}


MENU_CMD(cmd_network_listen) {
	network_t *n = (network_t *)ins->data;
	if(strcasecmp(args[1],"on") == 0)
		irc_listen(n,NULL,ac->msgqueue);
	else
		irc_unlisten(n,NULL,ac->msgqueue);
	return 0;
}

/** Network Menu Structure **/

static const cmd_t network_menu[] = {
	{"clear-queue",	cmd_network_clear_queue,0,0,1,0,PRIVS_EMPTY,NULL},
	{"ctcp",	cmd_network_ctcp,	2,-2,0,0,PRIVS_EMPTY,NULL},
	{"delete",	cmd_network_delete,	0,0,1,0,PRIVS_EMPTY,NULL},
	{"info",	cmd_network_info,	0,0,0,0,PRIVS_EMPTY,NULL},
	{"listen",	cmd_network_listen,	1,1,0,0,PRIVS_EMPTY,NULL},
	{"msg",		cmd_network_msg,	2,-2,0,0,PRIVS_EMPTY,NULL},
	{"on-connects",	cmd_network_on_connects,0,3,1,0,PRIVS_EMPTY,NULL},
	{"raw",		cmd_network_raw,	1,-2,0,0,PRIVS_EMPTY,NULL},
	{"rename",	cmd_network_rename,	1,1,1,0,PRIVS_EMPTY,NULL},
	{"save",	cmd_network_save,	0,0,1,0,PRIVS_EMPTY,NULL},
	{"servers",	cmd_network_servers,	0,3,1,0,PRIVS_EMPTY,NULL},
	{"settings",	cmd_network_settings,	0,5,1,0,PRIVS_EMPTY,NULL},
	{"start",	cmd_network_start,	0,0,1,0,PRIVS_EMPTY,NULL},
	{"stop",	cmd_network_stop,	0,0,1,0,PRIVS_EMPTY,NULL},
	{"taglines",	cmd_network_taglines,	0,3,1,0,PRIVS_EMPTY,NULL},
	{NULL}
};

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

MENU_CMD(cmd_network_entry) {
	char buffer[96];
	network_t *n;
	
	snprintf(buffer,sizeof(buffer),"network: %s",args[1]);
	if(ins->prompt != NULL && ins->free_prompt)
		xfree(ins->prompt);
	ins->prompt	= xstrdup(buffer);
	ins->free_prompt= 1;
	ins->check 	= cmd_network_check;
	
	n = irc_network_find(args[1]);
	if(n == NULL) {
		LOCK(global);
		n = alloc_network(global->network_settings);
		UNLOCK(global);
		n->name = xstrdup(args[1]);
		ins->free = (void (*)(void *)) free_network;
		admin_msg(ac,"New Network: %s",args[1]);
	}
	ins->data = n;
	return 0;
}

static void register_network_menu(void) {
	menu_t *n_menu = menu_from_cmds(
			"network",			// name
			1,				// min_args
			1,				// max_args
			1,				// log	
			0,				// hide
			PRIV_TO_MASK(PRIV_NETWORKS),	// privs
			cmd_network_entry,		// func
			cmd_networks_helper,		// helper
			(cmd_t *)network_menu);

	register_channel_menu(n_menu);

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