#include "../include/traffic.h"

#define	lpp	(LINES - 6) /* Lines per page to display IP qtatistics */

void print_field(u_short y, u_short x, struct host *h, u_char col);
void help();
u_int column_width(u_char col);

void
show_stats(int sig)
{


	u_int           i;		/* Counter variable */
	struct host 	*host;	/* Pointer host structure */

	/* Initialize */
	total.last_in = total.last_out = 0;
	total.last_pkt_in = total.last_pkt_out = 0;
	total.last_tcp_in = total.last_udp_in = total.last_icmp_in = 0;
	total.last_tcp_out = total.last_udp_out = total.last_icmp_out = 0;

	/* Proccess all hosts statistics */
	for (i = 0; i < h_num; i++) {
		host = &hosts[i];	/* To make code more clear */

		/* Update total transfers */
		host->tot_in += host->last_in = host->in;
		host->tot_out += host->last_out = host->out;

		host->tot_tcp_in += host->last_tcp_in = host->tcp_in;
		host->tot_udp_in += host->last_udp_in = host->udp_in;
		host->tot_icmp_in += host->last_icmp_in = host->icmp_in;

		host->tot_tcp_out += host->last_tcp_out = host->tcp_out;
		host->tot_udp_out += host->last_udp_out = host->udp_out;
		host->tot_icmp_out += host->last_icmp_out = host->icmp_out;

		/* Summarize */
		total.last_in += host->last_in;	
		total.last_out += host->last_out;	

		total.last_tcp_in += host->last_tcp_in;
		total.last_udp_in += host->last_udp_in;
		total.last_icmp_in += host->last_icmp_in;

		total.last_tcp_out += host->last_tcp_out;
		total.last_udp_out += host->last_udp_out;
		total.last_icmp_out += host->last_icmp_out;

		/* Check maximum transfers */
		if (host->in > host->max_in)
			host->max_in = host->in;
		if (host->out > host->max_out)
			host->max_out = host->out;

		host->in = 0;
		host->out = 0;
		host->tcp_in = host->udp_in = host->icmp_in = 0;
		host->tcp_out = host->udp_out = host->icmp_out = 0;

		/* Update packets counters */
		host->tot_pkt_in += host->last_pkt_in = host->pkt_in;
		host->tot_pkt_out += host->last_pkt_out = host->pkt_out;

		/* Summarize */
		total.last_pkt_in += host->pkt_in;
		total.last_pkt_out += host->pkt_out;

		/* Check maximum packets */
		if (host->pkt_in > host->max_pkt_in)
			host->max_pkt_in = host->pkt_in;
		if (host->pkt_out > host->max_pkt_out)
			host->max_pkt_out = host->pkt_out;

		host->pkt_in = 0;
		host->pkt_out = 0;

	}
	/* Summarize */
		total.tot_in += total.last_in;
		total.tot_out += total.last_out;

	/* Summarize */
	total.tot_pkt_in += total.last_pkt_in; 
	total.tot_pkt_out += total.last_pkt_out; 

	/* Summarize - Check maximum transfers */
	if (total.last_in > total.max_in)
		total.max_in = total.last_in;
	if (total.last_out > total.max_out)
		total.max_out = total.last_out;

	/* Summarize - Check maximum packets */
	if (total.last_pkt_in > total.max_pkt_in)
		total.max_pkt_in = total.last_pkt_in;
	if (total.last_pkt_out > total.max_pkt_out)
		total.max_pkt_out = total.last_pkt_out;

	opt.times++;

	/* Lock */
	if (m_packet)
		m_display = 1;
	
	if ((opt.logfile != NULL) && m_packet)
		m_file = 1;

	if (m_packet)
		return;

	/* If logging enabled then log */
	if ((opt.logfile != NULL) && !m_file)
		log_file();

	/* Display on screen */
	if (!opt.daemon)
		display();
}

void
display()
{
	extern WINDOW			*win;				/* Pointer to ncurses window */
	extern struct options	opt;				/* Options */
	extern struct host		*hosts;				/* Pointer to host info array */
	extern u_int	  		h_num;				/* Number of watched hosts */

	u_int			i;		/* Counter variable */
	char			*buf;	/* Pointer to buffor */
	u_char			next=1;	/* Position of next column */
	u_long			active=0; /* Active hosts counter */

	/* Erase window */
	werase(win);

	if ( opt.mode == MODE_STAT) {
		/* Print info */
		mvwprintw( win, 0, 0, "Traffic Analyzer (c) Krzysztof \"Msciciel\" Pawlowski 2002, 2004");
		/* sort */
		switch(opt.sort) {
			case COL_IP:
				qsort(hosts, h_num, sizeof(struct host), cmp_ip);
				break;
			case COL_DATA:
				qsort(hosts, h_num, sizeof(struct host), cmp_data_cur);
				break;
			case COL_DATA_MAX:
				qsort(hosts, h_num, sizeof(struct host), cmp_data_max);
				break;
			case COL_DATA_TOT:
			case COL_DATA_AVG:
				qsort(hosts, h_num, sizeof(struct host), cmp_data_tot);
				break;
			case COL_PKT:
				qsort(hosts, h_num, sizeof(struct host), cmp_pkt_cur);
				break;
			case COL_PKT_TOT:
			case COL_PKT_AVG:
				qsort(hosts, h_num, sizeof(struct host), cmp_pkt_tot);
				break;
			case COL_PKT_MAX:
				qsort(hosts, h_num, sizeof(struct host), cmp_pkt_max);
				break;
			case COL_MAC:
				qsort(hosts, h_num, sizeof(struct host), cmp_mac);
				break;
			case COL_HOSTNAME:
				qsort(hosts, h_num, sizeof(struct host), cmp_hostname);
				break;
			case COL_TCP:
				qsort(hosts, h_num, sizeof(struct host), cmp_tcp);
				break;
			case COL_UDP:
				qsort(hosts, h_num, sizeof(struct host), cmp_udp);
				break;
			case COL_ICMP:
				qsort(hosts, h_num, sizeof(struct host), cmp_icmp);
				break;
			case COL_TCP_TOT:
				qsort(hosts, h_num, sizeof(struct host), cmp_tcp_tot);
				break;
			case COL_UDP_TOT:
				qsort(hosts, h_num, sizeof(struct host), cmp_udp_tot);
				break;
			case COL_ICMP_TOT:
				qsort(hosts, h_num, sizeof(struct host), cmp_icmp_tot);
				break;
        }		

		/* Print columns */
		for(i=0; i < MAX_COL; i++)
			if (opt.columns[i] != 0) {
				next += print_col(opt.columns[i], next) + 2;
				if ( next >= COLS )
					opt.columns[i] = 0;
			}

		/* Calculate number of active hosts */
		for(i=0; i < h_num; i++)
			if ((hosts[i].last_in > 0) || (hosts[i].last_out > 0))
				active++;
				

		/* Print footer */
		mvwprintw( win, LINES - 1, 1, "Device: %s | Unit: %s / %s | Refresh: %ds | Time: %2dh %2dm %2ds | From / To | Active: %d"
									, opt.dev, opt.unit_name, opt.unit_t_name, opt.delay
									, opt.times * opt.delay / 3600
									, ((opt.times * opt.delay) % 3600) / 60
									, (opt.times * opt.delay) % 60
									, active );
	}
	/* Print help */
	else if ( opt.mode == MODE_HELP)
		help();

	wrefresh(win);

	/* Exit if timeout has been reached */
	if (((opt.times * opt.delay) >= opt.timeout) && (opt.timeout > 0)) {
		endwin();
		exit(0);
	}
	
}

/* Print column */
int
print_col(u_char col, u_char pos)
{

	int				i,j;
	struct host 	*host;	/* Pointer host structure */
	u_short			len;	/* Column width */

	/* Get column width */
	len = column_width(col);

	/* Print header */
	switch (col) {
		case COL_IP:
			mvwprintw( win, 2, pos + (len - 4 ) / 2, "Host");
			break;
		case COL_DATA:
			mvwprintw( win, 2, pos + (len - 4 ) / 2, "Data");
			break;
		case COL_DATA_MAX:
			mvwprintw( win, 2, pos + (len - 8 ) / 2, "Data Max");
			break;
		case COL_DATA_AVG:
			mvwprintw( win, 2, pos + (len - 8 ) / 2, "Data Avg");  
			break;
		case COL_DATA_TOT:
			mvwprintw( win, 2, pos + (len - 8 ) / 2, "Data Total");  
			break;
		case COL_PKT:
			mvwprintw( win, 2, pos + (len - 7 ) / 2, "Packets");  
			break;
		case COL_PKT_TOT:
			mvwprintw( win, 2, pos + (len - 13 ) / 2, "Packets Total");  
			break;
		case COL_PKT_AVG:
			mvwprintw( win, 2, pos + (len - 11 ) / 2, "Packets Avg");  
			break;
		case COL_PKT_MAX:
			mvwprintw( win, 2, pos + (len - 11 ) / 2, "Packets Max");  
			break;
		case COL_MAC:
			mvwprintw( win, 2, pos + (len - 3 ) / 2, "MAC");  
			break;
		case COL_HOSTNAME:
			mvwprintw( win, 2, pos + (len - 8 ) / 2, "Hostname");  
			break;
		case COL_TCP:
			mvwprintw( win, 2, pos + (len - 3 ) / 2, "TCP");  
			break;
		case COL_UDP:
			mvwprintw( win, 2, pos + (len - 3 ) / 2, "UDP");  
			break;
		case COL_ICMP:
			mvwprintw( win, 2, pos + (len - 4 ) / 2, "ICMP");  
			break;
		case COL_TCP_TOT:
			mvwprintw( win, 2, pos + (len - 9 ) / 2, "TCP Total");  
			break;
		case COL_UDP_TOT:
			mvwprintw( win, 2, pos + (len - 9 ) / 2, "UDP Total");  
			break;
		case COL_ICMP_TOT:
			mvwprintw( win, 2, pos + (len - 10 ) / 2, "ICMP Total");  
			break;
	};
	
	/* Print fields */
	for (i = opt.page * lpp, j=0; i < h_num && i < opt.page * lpp + lpp - 2 * opt.total; i++, j++) {

		print_field(4 + j, pos, &hosts[i], col);

	}

	/* Print summarize line */
	if (opt.total) {
		if (col == COL_IP)
				mvwprintw( win, LINES - 3, 1, "%s", "TOTAL");	
		else
			print_field(LINES - 3, pos, &total, col);
	}

	return len;
}

/* Print field */
void print_field(u_short y, u_short x, struct host *h, u_char col)
{
	extern struct options	opt;
	extern WINDOW			*win;

		switch(col) {
			/* Print data column */
			case COL_DATA: 
				if (cmp(opt.unit_name,"B") || cmp(opt.unit_name,"Bit"))
					mvwprintw( win, y, x, "%7d / %7d ", (int)(h->last_in * opt.unit / opt.delay)
															, (int)(h->last_out * opt.unit / opt.delay));	
				else if (cmp(opt.unit_name,"KB") || cmp(opt.unit_name,"kBit"))
					mvwprintw( win, y, x, "%6.1f / %6.1f ", h->last_in * opt.unit / opt.delay
																, h->last_out * opt.unit / opt.delay );
				else if (cmp(opt.unit_name,"MB") || cmp(opt.unit_name,"mBit"))
					mvwprintw( win, y, x, "%5.3f / %5.3f ", h->last_in * opt.unit / opt.delay
														, h->last_out * opt.unit / opt.delay );
				else
					mvwprintw( win, y, x, "%8.5f / %8.5f ", h->last_in * opt.unit / opt.delay
														, h->last_out * opt.unit / opt.delay );
				break;

			/* Print IP column */
			case COL_IP:
				mvwprintw( win, y, 1, "%s", inet_ntoa(h->ip));	
				break;

			/* Print data maximum column */
			case COL_DATA_MAX:
				if (cmp(opt.unit_name,"B") || cmp(opt.unit_name,"Bit")) 
					mvwprintw( win, y, x, "%7d / %7d ", (int)(h->max_in * opt.unit / opt.delay)
														, (int)(h->max_out * opt.unit / opt.delay));	
				else if (cmp(opt.unit_name,"KB") || cmp(opt.unit_name,"kBit"))
					mvwprintw( win, y, x, "%6.1f / %6.1f ", h->max_in * opt.unit / opt.delay
															, h->max_out * opt.unit / opt.delay );
				else if (cmp(opt.unit_name,"MB") || cmp(opt.unit_name,"mBit"))
					mvwprintw( win, y, x, "%5.3f / %5.3f", h->max_in * opt.unit / opt.delay
														, h->max_out * opt.unit / opt.delay); 
				else
					mvwprintw( win, y, x, "%8.5f / %8.5f", h->max_in * opt.unit / opt.delay
														, h->max_out * opt.unit / opt.delay); 
				break;
		
			/* Print data average column */
			case COL_DATA_AVG:
				if (opt.times > 0) {
					if (cmp(opt.unit_name,"B") || cmp(opt.unit_name,"Bit"))
						mvwprintw( win, y, x, "%7d / %7d", (int)(h->tot_in * opt.unit / (opt.times * opt.delay))
														, (int)(h->tot_out * opt.unit / (opt.times * opt.delay))); 
					else if (cmp(opt.unit_name,"KB") || cmp(opt.unit_name,"kBit"))
						mvwprintw( win, y, x, "%6.1f / %6.1f", h->tot_in * opt.unit / (opt.times * opt.delay)
														, h->tot_out * opt.unit / (opt.times * opt.delay)); 
					else if (cmp(opt.unit_name,"MB") || cmp(opt.unit_name,"mBit"))
						mvwprintw( win, y, x, "%5.3f / %5.3f", h->tot_in * opt.unit / (opt.times * opt.delay)
														, h->tot_out * opt.unit / (opt.times * opt.delay));
					else
						mvwprintw( win, y, x, "%8.5f / %8.5f", h->tot_in * opt.unit / (opt.times * opt.delay)
														, h->tot_out * opt.unit / (opt.times * opt.delay));
				}
				break;

			/* Print data total column */
			case COL_DATA_TOT:
				if (cmp(opt.unit_t_name,"B") || cmp(opt.unit_t_name,"Bit")) 
					mvwprintw( win, y, x, "%9d / %9d ", (int)(h->tot_in * opt.unit_t)
														, (int)(h->tot_out * opt.unit_t));	
				else if (cmp(opt.unit_t_name,"KB") || cmp(opt.unit_t_name,"kBit"))
					mvwprintw( win, y, x, "%9.1f / %9.1f ", h->tot_in * opt.unit_t
															, h->tot_out * opt.unit_t);
				else if (cmp(opt.unit_t_name,"MB") || cmp(opt.unit_t_name,"mBit"))
					mvwprintw( win, y, x, "%8.1f / %8.1f ", h->tot_in * opt.unit_t
														, h->tot_out * opt.unit_t); 
				else
					mvwprintw( win, y, x, "%8.3f / %8.3f ", h->tot_in * opt.unit_t
														, h->tot_out * opt.unit_t); 
				break;

			/* Print packet current column */
			case COL_PKT: 
				mvwprintw( win, y, x, "%5d / %5d ", (int)(h->last_pkt_in / opt.delay)
													, (int)(h->last_pkt_out / opt.delay));	
				break;

			/* Print packet average column */
			case COL_PKT_AVG: 
				if (opt.times > 0)
					mvwprintw( win, y, x, "%5d / %5d ", (int)(h->tot_pkt_in / (opt.delay * opt.times))
														, (int)(h->tot_pkt_out / (opt.delay * opt.times)));	
				break;

			/* Print packet maximum column */
			case COL_PKT_MAX: 
				mvwprintw( win, y, x, "%5d / %5d ", (int)(h->max_pkt_in / opt.delay)
													, (int)(h->max_pkt_out / opt.delay));	
				break;

			/* Print packet current column */
			case COL_PKT_TOT: 
				mvwprintw( win, y, x, "%8d / %8d ", (int)h->tot_pkt_in
													, (int)h->tot_pkt_out);	
				break;

			/* Print MAC address column */
			case COL_MAC: 
				mvwprintw( win, y, x, "%18s ", h->mac);
				break;

			/* Print hostname column */
			case COL_HOSTNAME:
				mvwprintw( win, y, x, "%32s ", h->hostname);
				break;

			/* Print TCP column */
			case COL_TCP: 
				if (cmp(opt.unit_name,"B") || cmp(opt.unit_name,"Bit"))
					mvwprintw( win, y, x, "%7d / %7d ", (int)(h->last_tcp_in * opt.unit / opt.delay)
															, (int)(h->last_tcp_out * opt.unit / opt.delay));	
				else if (cmp(opt.unit_name,"KB") || cmp(opt.unit_name,"kBit"))
					mvwprintw( win, y, x, "%6.1f / %6.1f ", h->last_tcp_in * opt.unit / opt.delay
																, h->last_tcp_out * opt.unit / opt.delay );
				else
					mvwprintw( win, y, x, "%5.3f / %5.3f ", h->last_tcp_in * opt.unit / opt.delay
														, h->last_tcp_out * opt.unit / opt.delay );
				break;

			/* Print UDP column */
			case COL_UDP: 
				if (cmp(opt.unit_name,"B") || cmp(opt.unit_name,"Bit"))
					mvwprintw( win, y, x, "%7d / %7d ", (int)(h->last_udp_in * opt.unit / opt.delay)
															, (int)(h->last_udp_out * opt.unit / opt.delay));	
				else if (cmp(opt.unit_name,"KB") || cmp(opt.unit_name,"kBit"))
					mvwprintw( win, y, x, "%6.1f / %6.1f ", h->last_udp_in * opt.unit / opt.delay
																, h->last_udp_out * opt.unit / opt.delay );
				else
					mvwprintw( win, y, x, "%5.3f / %5.3f ", h->last_udp_in * opt.unit / opt.delay
														, h->last_udp_out * opt.unit / opt.delay );
				break;

			/* Print ICMP column */
			case COL_ICMP: 
				if (cmp(opt.unit_name,"B") || cmp(opt.unit_name,"Bit"))
					mvwprintw( win, y, x, "%7d / %7d ", (int)(h->last_icmp_in * opt.unit / opt.delay)
															, (int)(h->last_icmp_out * opt.unit / opt.delay));	
				else if (cmp(opt.unit_name,"KB") || cmp(opt.unit_name,"kBit"))
					mvwprintw( win, y, x, "%6.1f / %6.1f ", h->last_icmp_in * opt.unit / opt.delay
																, h->last_icmp_out * opt.unit / opt.delay );
				else
					mvwprintw( win, y, x, "%5.3f / %5.3f ", h->last_icmp_in * opt.unit / opt.delay
														, h->last_icmp_out * opt.unit / opt.delay );
				break;

			/* Print TCP total column */
			case COL_TCP_TOT:
				if (cmp(opt.unit_t_name,"B") || cmp(opt.unit_t_name,"Bit")) 
					mvwprintw( win, y, x, "%9d / %9d ", (int)(h->tot_tcp_in * opt.unit_t)
														, (int)(h->tot_tcp_out * opt.unit_t));	
				else if (cmp(opt.unit_t_name,"KB") || cmp(opt.unit_t_name,"kBit"))
					mvwprintw( win, y, x, "%9.1f / %9.1f ", h->tot_tcp_in * opt.unit_t
															, h->tot_tcp_out * opt.unit_t);
				else
					mvwprintw( win, y, x, "%8.1f / %8.1f ", h->tot_tcp_in * opt.unit_t
														, h->tot_tcp_out * opt.unit_t); 
				break;

			/* Print UDP total column */
			case COL_UDP_TOT:
				if (cmp(opt.unit_t_name,"B") || cmp(opt.unit_t_name,"Bit")) 
					mvwprintw( win, y, x, "%9d / %9d ", (int)(h->tot_udp_in * opt.unit_t)
														, (int)(h->tot_udp_out * opt.unit_t));	
				else if (cmp(opt.unit_t_name,"KB") || cmp(opt.unit_t_name,"kBit"))
					mvwprintw( win, y, x, "%9.1f / %9.1f ", h->tot_udp_in * opt.unit_t
															, h->tot_udp_out * opt.unit_t);
				else
					mvwprintw( win, y, x, "%8.1f / %8.1f ", h->tot_udp_in * opt.unit_t
														, h->tot_udp_out * opt.unit_t); 
				break;

			/* Print ICMP total column */
			case COL_ICMP_TOT:
				if (cmp(opt.unit_t_name,"B") || cmp(opt.unit_t_name,"Bit")) 
					mvwprintw( win, y, x, "%9d / %9d ", (int)(h->tot_icmp_in * opt.unit_t)
														, (int)(h->tot_icmp_out * opt.unit_t));	
				else if (cmp(opt.unit_t_name,"KB") || cmp(opt.unit_t_name,"kBit"))
					mvwprintw( win, y, x, "%9.1f / %9.1f ", h->tot_icmp_in * opt.unit_t
															, h->tot_icmp_out * opt.unit_t);
				else
					mvwprintw( win, y, x, "%8.1f / %8.1f ", h->tot_icmp_in * opt.unit_t
														, h->tot_icmp_out * opt.unit_t); 
				break;

		};
}

/* Display help */
void help() 
{
	extern WINDOW	*win;

	wprintw(win, "Keys:\n\
	a + <column>    - add column\n\
	d + <column>    - remove column\n\
	u + <unit>      - change data unit size\n\
	U + <unit>      - change total data unit size\n\
	s + <column>    - sort\n\
	t               - total line\n\
	r               - reset statistics\n\
	?   - help\n\
	q   - quit\n\
\n\
Columns:\n\
	h   - host ip\n\
	c   - current data transfer\n\
	a   - average data transfer\n\
	m   - maximum data transfer\n\
	s   - total data transfer\n\
	p   - current packets flow\n\
	o   - average packets flow\n\
	m   - maximum packets flow\n\
	P   - total packets flow\n\
	M   - MAC address\n\
	H   - hostname\n\
	t   - TCP data flow\n\
	u   - UDP data flow\n\
	i   - ICMP date flow\n\
	T   - Total TCP data flow\n\
	U   - Total UDP data flow\n\
	I   - Total ICMP date flow\n\
\n\
Units:\n\
	b - Bits\n\
	B - Bytes\n\
	k - Kilobits\n\
	K - Kilobytes\n\
	m - Megabits\n\
	M - Megabytes\n\
	g - Gigabits\n\
	G - Gigabytes\n");
}

/* Get column width */
u_int column_width(u_char col)
{
	extern struct options	opt;

	switch(col) {
		case COL_DATA:
		case COL_DATA_MAX:
		case COL_DATA_AVG:
		case COL_TCP:
		case COL_UDP:
		case COL_ICMP:
			if (cmp(opt.unit_name,"G") || cmp(opt.unit_name,"gBit"))
				return 19;
			else if (cmp(opt.unit_name,"B") || cmp(opt.unit_name,"Bit"))
				return 17;
			else if (cmp(opt.unit_name,"KB") || cmp(opt.unit_name,"kBit"))
				return 15;
			else
				return 13;

		case COL_DATA_TOT:
		case COL_TCP_TOT:
		case COL_UDP_TOT:
		case COL_ICMP_TOT:
			if (cmp(opt.unit_t_name,"B") || cmp(opt.unit_t_name,"Bit"))
				return 21;
			else if (cmp(opt.unit_t_name,"KB") || cmp(opt.unit_t_name,"kBit"))
				return 21;
			else
				return 17;

		case COL_IP:
			return 15;

		case COL_PKT:
		case COL_PKT_AVG:
		case COL_PKT_MAX:
			return 13;

		case COL_PKT_TOT:
			return 19;

		case COL_MAC:
			return 19;
		
		case COL_HOSTNAME:
			return 32;

		default:
			return 0;
	}
}


syntax highlighted by Code2HTML, v. 0.9.1