/*
 * $Id: logfile.c,v 1.4 2006/12/20 15:15:45 c4chris Exp $
 */

#include "os.h"

/*
 * logfile.c - routines for updating log and snapshot files
 *
 * David A. Curry				Jeffrey C. Mogul
 * Purdue University				Digital Equipment Corporation
 * Engineering Computer Network			Western Research Laboratory
 * 1285 Electrical Engineering Building		250 University Avenue
 * West Lafayette, IN 47907-1285		Palo Alto, CA 94301
 * davy@ecn.purdue.edu				mogul@decwrl.dec.com
 * 
 */
#include <sys/param.h>
#include <sys/time.h>
#include <curses.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include "nfswatch.h"
#include "externs.h"
#include "screen.h"

#ifdef SUNOS5
static char *scrncpy(char *, chtype *, int);
#endif

/*
 * snapshot - take a snapshot of the screen.
 */
void
snapshot(void)
{
	FILE *fp;
	register int x, y;
	char buffer[BUFSIZ];

	/*
	 * We want to append to the snapshot file.
	 */
	if ((fp = fopen(snapshotfile, "a")) == NULL) {
		(void) mvprintw(SCR_PROMPT_Y, SCR_PROMPT_X,
			"could not open \"%s\"", snapshotfile);
		(void) refresh();
		return;
	}

#ifdef NCURSES_VERSION
	for (y = 0; y < LINES - 1; y++) {
	  int lastnb = 0;
	  for(x = 0; x < COLS; x++) {
	    chtype ch = mvinch(y, x);
	    buffer[x] = ch & A_CHARTEXT;
	    if (buffer[x] != ' ')
	      lastnb = x;
	  }
	  lastnb += 1;
	  buffer[lastnb++] = '\n';
	  buffer[lastnb] = '\0';
	  fputs(buffer, fp);
	}
#else
	/*
	 * For all lines but the last one ...
	 */
	for (y = 0; y < LINES - 1; y++) {
		(void) mvprintw(SCR_PROMPT_Y, SCR_PROMPT_X,
			"dumping line %d", y + 1);
		(void) clrtoeol();
		(void) refresh();

		/*
		 * Search backwards on each line for a non-space.
		 * x is the count of significant characters.
		 */
		for (x = COLS - 1; x > 0; x--) {
			/*
			 *  Non-space found, increment Z and exit loop
			 */
			if (curscr->_y[y][x] != ' ') {
				x++;
				break;
			}
		}

		/*
		 * Copy x characters and append a \n and \0 to the
		 * string, then output it.
		 */
#ifdef SUNOS5
		(void) scrncpy(buffer, curscr->_y[y], x);
#else
		(void) strncpy(buffer, curscr->_y[y], x);
#endif
		buffer[x++] = '\n';
		buffer[x] = '\0';

		(void) fputs(buffer, fp);
	}


	(void) fputc('\014', fp);
#endif
	(void) fclose(fp);

	/*
	 * Tell them we're done.
	 */
	(void) mvprintw(SCR_PROMPT_Y, SCR_PROMPT_X,
		"screen dumped to \"%s\"", snapshotfile );
	(void) refresh();
}

/*
 * update_logfile - put out the information to the log file.
 */
void
update_logfile(void)
{
	char *tstr;
	char *ctime();
	float percent;
	char buf[BUFSIZ];
	struct timeval tv;
	register int i, j, nfstotal;

	long count, tot_count;
	double dcount, sumsqr, sum;
        static char nfsprocs_header[80] = 
            " Procedure          int   pct    total  completed  ave.resp  var.resp  max.resp"; 

	(void) gettimeofday(&tv, (struct timezone *) 0);

	/*
	 * Start a log entry.
	 */
	(void) fprintf(logfp, "#\n# begin\n#\n");
	(void) fprintf(logfp, "Date: %.24s\n", ctime(&tv.tv_sec));

	tv.tv_sec -= starttime.tv_sec;
	tstr = prtime(tv.tv_sec);

	(void) fprintf(logfp, "Cycle Time: %d\n", cycletime);
	(void) fprintf(logfp, "Elapsed Time: %.8s\n", tstr+11);

	/*
	 * Print total packet counters.
	 */
	(void) fprintf(logfp, "#\n# total packets     %8s %8s %8s\n#\n",
		"network", "to host", "dropped");
	(void) fprintf(logfp, "Interval Packets:   %8ld %8ld %8ld\n",
		int_pkt_total, int_dst_pkt_total, int_pkt_drops);
	(void) fprintf(logfp, "Total Packets:      %8ld %8ld %8ld\n",
		pkt_total, dst_pkt_total, pkt_drops);

	/*
	 * Put out a header for the packet counters.
	 */
	(void) fprintf(logfp, "#\n# packet counters         %8s %8s %8s\n#\n",
		"int", "pct", "total");

	/*
	 * Print the packet counters.  Percentage is calculated as
	 * this interval counter over total packets this interval.
	 */
	for (i = 0; i < PKT_NCOUNTERS; i++) {
		if (int_dst_pkt_total) {
			percent = ((float) pkt_counters[i].pc_interval /
				  (float) int_dst_pkt_total) * 100.0;
		}
		else {
			percent = 0.0;
		}

		(void) sprintf(buf, "%s:", pkt_counters[i].pc_name);
		(void) fprintf(logfp, "%-25s %8ld %7.0f%% %8ld\n",
			buf, pkt_counters[i].pc_interval, percent,
			pkt_counters[i].pc_total);
	}

	/*
	 * Calculate the total number of NFS packets this
	 * interval.
	 */
	nfstotal = pkt_counters[PKT_NFSWRITE].pc_interval +
		   pkt_counters[PKT_NFSREAD].pc_interval;

	/*
	 * Put out a header for the NFS counters.
	 */
	(void) fprintf(logfp, "#\n# nfs counters            %8s %8s %8s\n#\n",
		"int", "pct", "total");

	/*
	 * Print the NFS counters.  Percentage is calculated as
	 * packets this interval over total NFS packets this
	 * interval.
	 */

	for (i = 0; i < nnfscounters; i++) {
		if (nfstotal) {
			percent = ((float) nfs_counters[i].nc_interval /
				  (float) nfstotal) * 100.0;
		}
		else {
			percent = 0.0;
		}

		(void) sprintf(buf, "%s:", nfs_counters[i].nc_name);
		(void) fprintf(logfp, "%-25s %8ld %7.0f%% %8ld\t",
			buf, nfs_counters[i].nc_interval, percent,
			nfs_counters[i].nc_total);

		/*
		 * Print individual proc counters.
		 */
		(void) fputc('(', logfp);

		for (j = 0; j < MAXNFSPROC; j++) {
			if (j)
				(void) fputc('/', logfp);

			(void) fprintf(logfp, "%ld", nfs_counters[i].nc_proc[j]);
		}

		(void) fprintf(logfp, ")\n");
	}

	/*
	 * Put out a header for the individual file counters.
	 */
	(void) fprintf(logfp, "#\n# file counters           %8s %8s %8s\n#\n",
		"int", "pct", "total");

	/*
	 * Print the individual file counters.  Percentage is
	 * calculated as packets this interval over total NFS
	 * packets this interval.
	 */
	for (i = 0; i < nfilecounters; i++) {
		if (nfstotal) {
			percent = ((float) fil_counters[i].fc_interval /
				  (float) nfstotal) * 100.0;
		}
		else {
			percent = 0.0;
		}

		(void) sprintf(buf, "%s:", fil_counters[i].fc_name);
		(void) fprintf(logfp, "%-25s %8ld %7.0f%% %8ld\t",
			buf, fil_counters[i].fc_interval, percent,
			fil_counters[i].fc_total);

		/*
		 * Print individual proc counters.
		 */
		(void) fputc('(', logfp);

		for (j = 0; j < MAXNFSPROC; j++) {
			if (j)
				(void) fputc('/', logfp);

			(void) fprintf(logfp, "%ld", fil_counters[i].fc_proc[j]);
		}

		(void) fprintf(logfp, ")\n");
	}

	/*
	 * Put out a header for the NFS procs counters.
	 */
        if (showwhich == SHOWNFSPROCS || showwhich == SHOWNFS3PROCS) {
	    int proto = NFSv2;
	    int lim = MAXNFSPROC;
	    if (showwhich == SHOWNFS3PROCS) {
		proto = NFSv3;
		lim = MAXNFS3PROC;
	    }
	    (void) fprintf(logfp, "#\n# nfs procs \n#\n");

	    (void) fprintf(logfp, "%s\n", nfsprocs_header);
	    tot_count = 0;

	    for (i = 0; i < lim; i++) {
	        tot_count += prc_counters[proto][i].pr_interval;
            }

	    for (i = 0; i < lim; i++) { 
	        if (tot_count)
	           percent = (((float) prc_counters[proto][i].pr_interval)
		     / ((float)tot_count)) * 100.0;
		else
		    percent = 0.0;

		(void) fprintf(logfp, "%-17s %5ld  %3.0f%% %8ld", nfs_procnams[proto][i],
		     prc_counters[proto][i].pr_interval, percent, prc_counters[proto][i].pr_total);
			    
	        count = prc_counters[proto][i].pr_complete;

		if (count != 0) {
		    dcount = (double) count;
		    sum = prc_counters[proto][i].pr_response;
		    sumsqr = prc_counters[proto][i].pr_respsqr;

		    (void) fprintf(logfp, "   %8ld  %8.2f", count, sum /dcount);

		    if (count > 1) {
		        (void) fprintf(logfp, "  %8.2f",
			    sqrt((dcount * sumsqr - sum * sum) /   (dcount * (dcount - 1.0)))); 
		    }
		    else {
		        (void) fprintf(logfp, "          ");
                    }
		    (void) fprintf(logfp, "  %8.2f", prc_counters[proto][i].pr_maxresp);
	        }
	        (void) fprintf(logfp, "\n");
	    } 
        }
	/*
	 * End the log entry.
	 */
	(void) fprintf(logfp, "#\n# end\n#\n");
	(void) fflush(logfp);
}

#ifdef SUNOS5
/*
 * scrncpy - copy a curses array of chtype's (s2) to a character array (s1),
 *	     truncating or null padding to always copy n bytes.
 */
static char *
scrncpy(char *s1, chtype *s2, int n)
{
	register char *os1;

	os1 = s1;

	n++;
	while ((--n != 0) && ((*s1++ = *s2++) != '\0'))
		;

	if (n != 0) {
		while (--n != 0)
			*s1++ = '\0';
	}

	return(os1);
}
#endif /* SUNOS5 */
