/* ARISA - Admin Interface - Pool 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_pool_new(interface_t *intf, pool_t *p) {
	int i;
	LOCK(intf);
	for(i = 0; i < intf->send.no_pools; ++i) {
		if(intf->send.pools[i] == p) {
			UNLOCK(intf);
			return 0;
		}
	}
	UNLOCK(intf);
	return 1;
}

/** Pool Menu Commands **/

MENU_HELPER(cmd_pools_helper) {
	interface_t *intf = (interface_t *)ins->data;
	int i,j;
	
	LOCK(intf);
	if(intf->type != INTERFACE_SEND) {
		UNLOCK(intf);
		return;
	}
	for(j = 0; args[no_args-1][j] != '\0'; ++j) {
		if(args[no_args-1][j] == '?')
			break;
	}
	for(i = 0; i < intf->send.no_pools; ++i) {
		LOCK(intf->send.pools[i]);
		if(intf->send.pools[i]->deleted == 0 &&
			(j == 0 || strncmp(intf->send.pools[i]->name,args[no_args-1],j) == 0))
			admin_msg(ac,"%s",intf->send.pools[i]->name);
		UNLOCK(intf->send.pools[i]);
	}
	UNLOCK(intf);
}

MENU_HELPER(cmd_interfaces_helper); // pre-declaration
MENU_HELPER(cmd_int_pools_helper) {
	interface_t *intf;
	void *ptr;
	int i,j;
	
	if(no_args == 2) {
		for(j = 0; args[1][j] != '\0'; ++j) {
			if(args[1][j] == '?')
				break;
		}
		LOCK(global);
		for(i = 0; i < global->no_interfaces; ++i) {
			LOCK(global->interfaces[i]);
			if(global->interfaces[i]->deleted == 0 &&
				global->interfaces[i]->type == INTERFACE_SEND &&
				(j == 0 || strncmp(global->interfaces[i]->name,args[1],j) == 0))
				admin_msg(ac,"%s",global->interfaces[i]->name);
			UNLOCK(global->interfaces[i]);
		}
		UNLOCK(global);
	} else if(no_args > 2) {
		intf = interface_find(args[1]);
		if(intf != NULL) {
			ptr = ins->data;
			ins->data = intf;
			cmd_pools_helper(ins,ac,args,no_args);
			ins->data = ptr;
		}
	}
}

MENU_CMD(cmd_pool_delete) {
	interface_t *intf = (interface_t *)ins->prev->data;
	pool_t *p = (pool_t *)ins->data;
	int done = 1;
	if(!is_pool_new(intf,p)) {
		pool_del(intf,p);
		LOCK(p);
		if(p->deleted != 0)
			admin_msg(ac,"Pool %s Deleted",p->name);
		else {
			done = 0;
			admin_msg(ac,"Pool %s Deletion not possible",p->name);
		}
		UNLOCK(p);
	}
	if(done)
		return RET_UP;
	else
		return 0;
}

MENU_CMD(cmd_pool_rename) {
	interface_t *intf = (interface_t *)ins->prev->data;
	pool_t *p = (pool_t *)ins->data;
	
	if(pool_rename(intf,p,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,"Failed Renamed to %s",args[1]);

	return 0;
}

MENU_CMD(cmd_pool_save) {
	interface_t *intf = (interface_t *)ins->prev->data;
	pool_t *p = (pool_t *)ins->data;
	int ret;
	if(is_pool_new(intf,p)) {
		ret = pool_add(intf,p);
		if(ret == 0) {
			admin_msg(ac,"Successfully Saved");
			ins->free = NULL;
		} else
			admin_msg(ac,"Save Failed.");
	} else
		admin_msg(ac,"Pool is already saved.");
	return 0;
}

static void cmd_pool_show_info(acontext_t *ac, pool_t *p) {
	char btmp[16];
	float f;
	int i;
	
	LOCK(p);
	admin_msg(ac,"-- Pool %s --",p->name);
	admin_msg(ac,"Sends: %d/%d",p->no_csends,p->sends);
	for(i = 0,f = 0.0; i < AVGSPEED; ++i)
		f += (float)p->avgspeed[i];
	f /= ((float)AVGSPEED) * 1024.0;
	if(p->bandwidth != 0)
		admin_msg(ac,"Current Rate: %.2f KiB/sec (Limit %ld, Samples: %d)",
				f,p->bandwidth,AVGSPEED);
	else
		admin_msg(ac,"Current Rate: %.2f KiB/sec (Samples: %d)",
				f,AVGSPEED);
	admin_msg(ac,"Record Rate: %.2f KiB/sec",
			((float)p->record_rate)/1024.0);
	admin_msg(ac,"Record Send: %.2f KiB/sec",
			((float)p->record_send)/1024.0);
	admin_msg(ac,"Total Transfered: %s",
			format_bytes(btmp,sizeof(btmp),
				((unsigned long long)p->stat_mib)*1024*1024 +
				(unsigned long long)p->stat_carry,1));
	UNLOCK(p);
}	

MENU_CMD(cmd_pool_info) {
	pool_t *p = (pool_t *)ins->data;
	cmd_pool_show_info(ac,p);
	return 0;
}

static int cmd_pool_settings_p(pool_t *p, acontext_t *ac, 
		char **args, int no_args) {
	if(no_args == 1) {
		pqueue_t settings;
		pqueue_init(&settings,0);
		pool_read_settings(p,&settings);
		
		LOCK(p);
		output_settings(ac,"-- Pool Settings for %s --",
				p->name,&settings);
		UNLOCK(p);
	} else if(no_args >= 3) {
		if(pool_apply_setting(p,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_pool_settings) {
	pool_t *p = (pool_t *)ins->data;
	return cmd_pool_settings_p(p,ac,args,no_args);
}

static const char *send_state_text(state_t s); // pre-declaration
static void cmd_pool_display_send(acontext_t *ac, send_t *s, time_t now) {
	char buffer1[256],buffer2[16],buffer3[16];
	float f;
	int i;

	LOCK(s);
	RLOCK(s->pack);
	for(i = 0, f = 0.0; i < AVGSPEED; ++i)
		f += (float)s->avgspeed[i];
	f /= ((float)AVGSPEED) * 1024.0;

	if(s->network != NULL)
		LOCK(s->network);
	admin_cmsg(ac,"%%r-%%n To:  [%%9%s:%s%%n] (%s)",
			s->network != NULL ? s->network->name : "Unknown",
			s->nick != NULL ? s->nick : "Unknown",s->host);
	if(s->network != NULL)
		UNLOCK(s->network);
	admin_cmsg(ac,"  Rate: %%9%.1f KiB/sec%%n, State: %s, Elp:%s Rem:%s (%ds), Retries: %d",
			f,send_state_text(s->state),
			s->connected == 0 ? "-" :
			 etimestr(now - s->connected,buffer2,sizeof(buffer2)),
			f > 0.0 && s->pos != s->pack->size ?
			 etimestr(
				 (s->pack->size - s->pos) /
				 (off_t)((f*1024.0) >= 1.0 ? (f*1024.0) : 1.0),
				 buffer3,sizeof(buffer3)) 
			 : "-",
			s->last_contact != 0 ? now - s->last_contact : 0,
			s->retries);
	pathtofn(s->pack->file,buffer1,sizeof(buffer1));
	admin_cmsg(ac,"  File: %%9%s%%n (%lldKiB/%lldKiB)",
			buffer1,
			s->pos/1024ULL,s->pack->size/1024ULL);
	
	RUNLOCK(s->pack);
	UNLOCK(s);
}

static int cmd_pool_sends_p(pool_t *p, acontext_t *ac, 
		char **args, int no_args) {
	int i;
	if(no_args == 1) {
		time_t now = xtime();
		LOCK(p);
		admin_msg(ac,"-- Sends on Pool %s --",p->name);
		for(i = 0; i < p->no_csends; ++i)
			cmd_pool_display_send(ac,p->csends[i],now);
		if(i == 0)
			admin_msg(ac,"None");
		UNLOCK(p);
	} else if((tolower(args[1][0]) == 'c' || tolower(args[1][0]) == 'd') && 
			no_args >= 3) {
		if(no_args >= 4) {
			i = pool_send_close(p,args[2],NULL,args[3],NULL,NULL,no_args >= 5 ? args[4] : NULL);
			i += pool_send_close(p,args[2],NULL,NULL,args[3],NULL,no_args >= 5 ? args[4] : NULL);
		} else
			i = pool_send_close(p,args[2],NULL,NULL,NULL,NULL,NULL);
		admin_msg(ac,"Closed %d Matching Sends",i);
	} else
		admin_msg(ac,"%s [close <hostmask> [<nick|file> <reason>]]",args[0]);
	return 0;
}

MENU_CMD(cmd_pool_sends) {
	pool_t *p = (pool_t *)ins->data;
	return cmd_pool_sends_p(p,ac,args,no_args);
}

/** Pool Menu Structure **/

static const cmd_t pool_menu[] = {
	{"delete",	cmd_pool_delete,	0,0,1,0,PRIVS_EMPTY,NULL},
	{"info",	cmd_pool_info,		0,0,0,0,PRIVS_EMPTY,NULL},
	{"rename",	cmd_pool_rename,	1,1,1,0,PRIVS_EMPTY,NULL},
	{"save",	cmd_pool_save,		0,0,1,0,PRIVS_EMPTY,NULL},
	{"sends",	cmd_pool_sends,		0,4,1,0,PRIVS_EMPTY,NULL},
	{"settings",	cmd_pool_settings,	0,2,1,0,PRIVS_EMPTY,NULL},
	{NULL}
};

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

MENU_CMD(cmd_pool_entry) {
	interface_t *intf = (interface_t *)ins->prev->data;
	pool_t *p;
	
	LOCK(intf);
	if(intf->type != INTERFACE_SEND) {
		UNLOCK(intf);
		admin_msg(ac,"Only available on %s type interfaces.",
				interfacetype_to_str(INTERFACE_SEND));
		return -1;
	} else
		UNLOCK(intf);

	if(ins->prompt != NULL && ins->free_prompt)
		xfree(ins->prompt);
	ins->prompt	= xstrdup(args[1]);
	ins->free_prompt= 1;
	ins->check 	= cmd_pool_check;

	p = pool_find(intf,args[1]);
	if(p == NULL) {
		p = alloc_pool();
		p->name = xstrdup(args[1]);
		ins->free = (void (*)(void *)) free_pool;
		admin_msg(ac,"New Pool: %s",args[1]);
	}
	ins->data = p;
	return 0;
}

static void register_pool_menu(menu_t *intf_menu) {
	menu_t *p_menu = menu_from_cmds(
			"pool",				// name
			1,				// min_args
			1,				// max_args
			1,				// log
			0,				// hide
			PRIV_TO_MASK(PRIV_POOLS),	// privs
			cmd_pool_entry,			// func
			cmd_pools_helper,		// helper
			(cmd_t *)pool_menu);

	menu_add(intf_menu,p_menu);
	menu_deref(p_menu);
}
