/*
 *========================================================================
 * $Id: display_values.c 72 2006-07-20 18:04:33Z rgb $
 *
 * See copyright in copyright.h and the accompanying file COPYING
 *========================================================================
 */

#include "wulflogger.h"

/*
 * This routine switches between all the different kinds of displays
 * we recognize and walks the linked list of hosts, displaying its
 * (relevant) contents.
 */
void display_values()
{

 char displaytype[64];

 /* 
  * If verbose is on, we don't do a "real" display at all, regardless
  * of how it is set.
  */
 if((verbose == D_ALL) || (verbose == D_DISPLAY_VALUES)){
   printf("D_DISPLAY_VALUES: Starting display_values().  Use -v %d to focus.\n",D_DISPLAY_VALUES);
 }

 switch(display_type) {
   case DISPLAY_BASIC:
     display_basic();
     break;
   case DISPLAY_LOAD:
   default:
     display_load();
     break;
   case DISPLAY_MEMORY:
     display_memory();
     break;
   case DISPLAY_NET:
     display_net();
     break;
   case DISPLAY_TIMES:
     display_times();
     break;
   case DISPLAY_PIDS:
     display_pids();
     break;
   case DISPLAY_PIDS_CMDLINE:
     display_pids_cmdline();
     break;
 }

}

/*
 *========================================================================
 * display_basic()
 *
 * Displays name, status, timestamp, eth0 rx/tx, swapin, swapout,
 * pagein, pageout, ctxt, intr, and users.  Is currently default display
 * (type 0).
 * (Note that this is very much like vmstat on a whole cluster at once.)
 *========================================================================
 */
void display_basic()
{

 /* Loop indices */
 int i,j,k;
 unsigned int mem_used,mem_free;
 char scaleout[4][32];

 /* 
  * We need these to define EACH host as we walk the list of hosts for 
  * display.
  */
 Host *hostptr;
 ListElement *element;

 if((verbose == D_ALL) || (verbose == D_DISPLAY_VALUES)){
   printf("D_DISPLAY_VALUES: Starting display_basic.  Use -v %d to focus.\n",D_DISPLAY_VALUES);
 }

 printf("# %14s %6s  %11s   %6s %6s %6s %7s %7s %3s %3s %3s %3s %4s %4s %4s\n",
      "Name      ",
      "Status",
      "Timestamp",
      " load1",
      " load5",
      "load15",
      "rx byts",
      "tx byts",
      " si",
      " so",
      " pi"
      " po",
      "ctxt",
      "intr",
      "prun",
      "pblk"
   );

 /*
  * Loop over all hosts and pop them on the display pad
  */
 element = hostlist->head;
 for(i=0;i<numhosts;i++){
   if(element == NULL) break;	/* For whatever reason, out of hosts */
   hostptr = element->data;
   if(hostptr->connected == 2) {
     printf("%-16.16s %6s%11lu.%02d  %6.2f %6.2f %6.2f %6.0f %6.0f  %3.0f %3.0f %3.0f %3.0f %4.0f %4.0f %4d %4d\n",
       hostptr->hostname,
       "up  ",
       hostptr->val.stat_tv_sec,
       hostptr->val.stat_tv_usec / 10000,
       hostptr->val.load1,
       hostptr->val.load5,
       hostptr->val.load15,
       hostptr->val.interface[-1].rx_bytes_rate,
       hostptr->val.interface[-1].tx_bytes_rate,
       hostptr->val.swap_in_rate,
       hostptr->val.swap_out_rate,
       hostptr->val.page_in_rate,
       hostptr->val.page_out_rate,
       hostptr->val.ctxt_rate,
       hostptr->val.intr_rate,
       hostptr->val.procs_running,
       hostptr->val.procs_blocked
     );
   } else {
     printf("%-16.16s %6s\n",
       hostptr->hostname,
       "down ");
   }
   element = element->next;
 }


 fflush(STDOUT);
 
}


/*
 *========================================================================
 * display_load()
 *
 * Displays: name, status, timestamp, load1, load5, load15.  Much like
 * the load part of uptime.  This is currently display type 1.
 *========================================================================
 */
void display_load()
{

 /* Loop indices */
 int i,j,k;

 /* 
  * We need these to define EACH host as we walk the list of hosts for 
  * display.
  */
 Host *hostptr;
 ListElement *element;

 if((verbose == D_ALL) || (verbose == D_DISPLAY_VALUES)){
   printf("D_DISPLAY_VALUES: Starting display_load.  Use -v %d to focus.\n",D_DISPLAY_VALUES);
   printf("D_DISPLAY_VALUES: hostlist = %0x\n",hostlist);
 }

 printf("# %14s %6s  %11s   %6s %6s %6s\n",
      "Name      ",
      "Status",
      "Timestamp",
      " load1",
      " load5",
      "load15"
 );

 /*
  * Loop over all hosts and pop them on the display pad
  */
 element = hostlist->head;

 for(i=0;i<numhosts;i++){
   if(element == NULL) break;	/* For whatever reason, out of hosts */
   hostptr = element->data;
   if(hostptr->connected == 2) {
     printf("%-16.16s %6s%11lu.%02d  %6.2f %6.2f %6.2f\n",
       hostptr->hostname,
       "up  ",
       hostptr->val.loadavg_tv_sec,
       hostptr->val.loadavg_tv_usec / 10000,
       hostptr->val.load1,
       hostptr->val.load5,
       hostptr->val.load15);
   } else {
     printf("%-16.16s %6s\n",
       hostptr->hostname,
       "down ");
   }
   element = element->next;
 }

 fflush(STDOUT);
 
}


/*
 *========================================================================
 * display_memory()
 *
 * This routine displays memory statistics (from meminfo) and related
 * values for each host, much like free or meminfo for a whole cluster at
 * once.  It is display type 2, currently.
 *========================================================================
 */
void display_memory()
{

 /* Loop indices */
 int i,j,k;

 /* 
  * A buffer to aid in truncating names.  One extra space for terminating
  * null.  The second one is to hold output from scale_k().
  */
 char namebuf[10];
 char row_out[10][10];
 /* scratch space for positioning and counters both */
 int row = 0,col = 0;
 /* controls the hosts loop so we can page */
 int imin_col,imax_col;

 /* 
  * We need these to define EACH host as we walk the list of hosts for 
  * display.
  */
 Host *hostptr;
 ListElement *element;

 if((verbose == D_ALL) || (verbose == D_DISPLAY_VALUES)){
   printf("D_DISPLAY_VALUES: Starting display_memory().  Use -v %d to focus.\n",D_DISPLAY_VALUES);
 }

 printf("# %14s %6s  %11s  %7s %7s %7s %7s %5s %7s %7s %5s %5s %5s\n",
      "Name      ",
      "Status",
      "Timestamp",
      "m-tot",
      "m-used",
      "m-free",
      "m-free*",
      "s-tot",
      "s-used",
      "s-free",
      "m-shr",
      "m-buf",
      "m-cch"
 );


 /*
  * Loop over all hosts and pop them on the display pad
  */
 element = hostlist->head;
 for(i=0;i<numhosts;i++){
   if(element == NULL) break;	/* For whatever reason, out of hosts */
   hostptr = element->data;
   if(hostptr->connected == 2) {
     sprintf(row_out[0],"%5.5s",scale_k(hostptr->val.mem_total,5,0));
     sprintf(row_out[1],"%7.7s",scale_k(hostptr->val.mem_used,7,0));
     sprintf(row_out[2],"%7.7s",scale_k(hostptr->val.mem_free,7,0));
     sprintf(row_out[3],"%7.7s",scale_k(hostptr->val.mem_free + hostptr->val.mem_buffers + hostptr->val.mem_cached,7,0));
     sprintf(row_out[4],"%5.5s",scale_k(hostptr->val.swap_total,5,0));
     sprintf(row_out[5],"%7.7s",scale_k(hostptr->val.swap_used,7,0));
     sprintf(row_out[6],"%7.7s",scale_k(hostptr->val.swap_free,7,0));
     sprintf(row_out[7],"%5.5s",scale_k(hostptr->val.mem_shared,5,0));
     sprintf(row_out[8],"%5.5s",scale_k(hostptr->val.mem_buffers,5,0));
     sprintf(row_out[9],"%5.5s",scale_k(hostptr->val.mem_cached,5,0));
     printf("%-16.16s %6s%11lu.%02d   %5.5s %7.7s %7.7s %7.7s %5.5s %7.7s %7.7s %5.5s %5.5s %5.5s\n",
       hostptr->hostname,
       "up  ",
       hostptr->val.meminfo_tv_sec,
       hostptr->val.meminfo_tv_usec / 10000,
       row_out[0],
       row_out[1],
       row_out[2],
       row_out[3],
       row_out[4],
       row_out[5],
       row_out[6],
       row_out[7],
       row_out[8],
       row_out[9]
     );

   } else {
     printf("%-16.16s %6s\n",
          hostptr->hostname,
	  "down ");
   }
   element = element->next;
 }

 fflush(STDOUT);
 
}


/*
 *========================================================================
 * display_net()
 *
 * Displays hostname, status, timestamp and various key network interface
 * rates for all interfaces found on all hosts.  Note that variable
 * numbers and types of interfaces make this ugly -- can't be helped.
 * This is display type 3.
 *========================================================================
 */
void display_net()
{

 /* Loop indices */
 int i,j,k;

 /* scratch space for positioning and counters both */
 int row = 0,col = 0;
 /* controls the hosts loop so we can page */
 int imin_col,imax_col;
 /* 
  * We need these to define EACH host as we walk the list of hosts for 
  * display.
  */
 Host *hostptr;
 ListElement *element;

 if((verbose == D_ALL) || (verbose == D_DISPLAY_VALUES)){
   printf("D_DISPLAY_VALUES: Starting display_net().  Use -v %d to focus.\n",D_DISPLAY_VALUES);
 }

 sprintf(display_msg,"");

 printf("# %14s %-15s %6s  %11s    %4s %6s %6s %6s %6s %6s %6s %6s\n",
      "Name      ",
      "       IP",
      "Status",
      "Timestamp",
    "dev#",
    "rx_bts",
    "rx_pks",
    "rx_ers",
    "tx_bts",
    "tx_pks",
    "tx_ers",
    "tcp_sk"
 );

 k = 0;
 element = hostlist->head;
 for(i=0;i<numhosts;i++){
   if(element == NULL) break;	/* For whatever reason, out of hosts */
   hostptr = element->data;
   if(hostptr->connected == 2) {
     for(j = 0;j < hostptr->val.num_interfaces;j++){
      /* For the moment, only eth displays... */
      if( strncmp("eth",hostptr->val.interface[j].devtype,3) == 0 )
        /* printf("Device type = %s\n",hostptr->val.interface[j].devtype);*/
        printf("%-16.16s %15s  %6s%11lu.%02d  %3s%1s %6.0f %6.0f %6.0f %6.0f %6.0f %6.0f   %2ld\n",
         hostptr->hostname,
         hostptr->val.interface[j].ip,
	 "up  ",
         hostptr->val.netdev_tv_sec,
         hostptr->val.netdev_tv_usec / 10000,
         hostptr->val.interface[j].devtype,
         hostptr->val.interface[j].devid,
         hostptr->val.interface[j].rx_bytes_rate,
         hostptr->val.interface[j].rx_packets_rate,
         hostptr->val.interface[j].rx_errs_rate,
         hostptr->val.interface[j].tx_bytes_rate,
         hostptr->val.interface[j].tx_packets_rate,
         hostptr->val.interface[j].tx_errs_rate,
         hostptr->val.tcp_inuse);
     }
   } else {
     printf("%-16.16s                  %6s\n",
          hostptr->hostname,
	  "down ");
   }
   element = element->next;
 }

 fflush(STDOUT);
 
}

/*
 *========================================================================
 * display_times()
 *
 * Displays name, status, timestamp, cpu information, time, uptime, and
 * duty cycle (fraction of clocks the CPU(s) has been in use).
 * Most of this is slowly varying and will only be useful for a glance,
 * but duty cycle is actually a composite measure of some interest.
 * This is display type 4.
 *========================================================================
 */
void display_times()
{

 /* Loop indices */
 int i,j,k;
 /* 
  * Display controls, both local and semi-global.
  * minimum number of lines needed to run an xterm display with ONE host
  */
 int minlines;
 /* scratch space for positioning and counters both */
 int row = 0,col = 0;
 /* controls the hosts loop so we can page */
 int imin_col,imax_col;
 /* 
  * We need these to define EACH host as we walk the list of hosts for 
  * display.
  */
 Host *hostptr;
 ListElement *element;

 if((verbose == D_ALL) || (verbose == D_DISPLAY_VALUES)){
   printf("D_DISPLAY_VALUES: Starting D_DISPLAY_VALUES.  Use -v %d to focus.\n",D_DISPLAY_VALUES);
 }

 printf("# %14s %6s  %11s    %17.17s          %4s %4s %4s %7s         %7s      %4s\n",
      "Name      ",
      "Status",
      "Timestamp",
      "CPU Model Name",
      "Cores",
      "ClkM",
      "CchK",
      "Time",
      "Uptime",
      "Dty%"
   );

 element = hostlist->head;
 for(i=0;i<numhosts;i++){
   if(element == NULL) break;	/* For whatever reason, out of hosts */
   hostptr = element->data;
   if(hostptr->connected == 2) {
     printf("%-16.16s  %6s%11lu.%02d   %-26.26s %2d   %4.f %4d %11s %16s %3.f\n",
       hostptr->hostname,
       "up  ",
       hostptr->val.cpuinfo_tv_sec,
       hostptr->val.cpuinfo_tv_usec / 10000,
       hostptr->val.cpuinfo_model_name,
       hostptr->val.cpuinfo_cores,
       hostptr->val.cpuinfo_clock,
       hostptr->val.cpuinfo_cachesize,
       hostptr->val.time,
       hostptr->val.uptime,
       hostptr->val.duty_cycle
       );
   } else {
     printf("%-16.16s %6s\n",
          hostptr->hostname,
	  "down ");
   }
   element = element->next;
 }

 fflush(STDOUT);
 
}

/*
 *========================================================================
 * display_pids()
 *
 * Displays the name, status, timestamp and then all RUNNING tasks.
 * This is display type 5 and the "riskiest" of the displays, since
 * a runaway system may be able to produce evil results if
 * 
 *========================================================================
 */
void display_pids()
{

 /* Loop indices */
 int i,j,k;
 /* 
  * A buffer to aid in truncating names.  One extra space for terminating
  * null.  The second one is to hold output from scale_k().
  */
 char namebuf[10];
 char row_out[10][10];
 /* scratch space for positioning and counters both */
 int row = 0,col = 0;
 /* controls the hosts loop so we can page */
 int imin_col,imax_col;
 /* 
  * We need these to define EACH host as we walk the list of hosts for 
  * display.
  */
 Host *hostptr;
 Pid *pidptr;
 ListElement *element,*pidelement;
 
 

 if((verbose == D_ALL) || (verbose == D_DISPLAY_VALUES)){
   printf("D_DISPLAY_VALUES: Starting display_user().  Use -v %d to focus.\n",D_DISPLAY_VALUES);
 }

 printf("# %14s %6s  %11s    %5s %4s %8s %7s %7s %8s %-s\n",
      "Name      ",
      "Status",
      "Timestamp",
      "PID ",
      "Nice",
      "User  ",
      "Vsize",
      "RSS  ",
      "Time",
      "  Command"
   );

 /*
  * Loop over all hosts and pop them on the pad
  */
 element = hostlist->head;
 j = 0;
 for(i=0;i<numhosts;i++){
   if(element == NULL) break;	/* For whatever reason, out of hosts */
   hostptr = element->data;
   if(hostptr->connected == 2) {
     /*
      * This display is going to be fundamentally different from
      * the others in that one cannot predict how many (if any)
      * tasks that match the specified criteria will be running
      * on any host in the list.  These numbers can also jump
      * up or down without warning as tasks are started or die or
      * or stopped.  To manage this sort of free form data presentation
      * we will collect the pid data in a linked list of structs
      * indexed per host.  That is, hostptr->var.runlist will be
      * a linked list of tasks that match the specified task criteria
      * Filling it will be tricky, but is handled elsewhere.  Here
      * we simply walk the list for each host and displace a line
      * for each entry found.
      sprintf(row_out[0],"%5.5s",scale_k(hostptr->val.mem_total,5,0));
      */

     if(hostptr->pidlist->size == 0){
       printf("%-16.16s %6s%11lu.%02d   %5s  %2s  %8s %7s %7s %8s %-s\n",
       hostptr->hostname,
       "up  ",
       hostptr->val.pids_tv_sec,
       hostptr->val.pids_tv_usec / 10000,
           "  -",
           "-",
           "  -",
           "  -",
           "  -",
           "  -",
           "Idle/No Matching Task"
       );
       j++;
     } else {
       pidelement = hostptr->pidlist->head;
       while(pidelement != NULL){
         pidptr = pidelement->data;
         /*
          * Never display xmlsysd itself.  I know, one "should", but
	  * we won't.
          */
         if(strncmp(pidptr->taskname,"xmlsysd",7) == 0) {
	   if(hostptr->pidlist->size == 1) {
             printf("%-16.16s %6s%11lu.%02d   %5s  %2s  %8s %7s %7s %8s %-s\n",
               hostptr->hostname,
               "up  ",
               hostptr->val.pids_tv_sec,
               hostptr->val.pids_tv_usec / 10000,
               "  -",
               "-",
               "  -",
               "  -",
               "  -",
               "  -",
               "Idle/No Matching Task"
             );
             j++;
	   }
	 } else {
           printf("%-16.16s %6s%11lu.%02d   %5d  %2d  %8s %7s %7s %8s %-s\n",
               hostptr->hostname,
               "up  ",
               hostptr->val.pids_tv_sec,
               hostptr->val.pids_tv_usec / 10000,
               pidptr->pid,
               pidptr->nice,
               pidptr->user,
               pidptr->vsize,
               pidptr->rss,
               pidptr->time,
               pidptr->taskname
           );
           j++;
         }
         pidelement = pidelement->next;
       }
     }
   } else {
     printf("%-16.16s %6s\n",
         hostptr->hostname,
         "down ");
     j++;
   }
   element = element->next;
 }

 fflush(STDOUT);
 
}

/*
 *========================================================================
 * display_pids_cmdline()
 *
 * Displays the name, status, timestamp and then all RUNNING tasks,
 * including the entire commandline (otherwise much like display_pids()).
 * This is display type 6.
 *========================================================================
 */
void display_pids_cmdline()
{

 /* Loop indices */
 int i,j,k;
 /* 
  * A buffer to aid in truncating names.  One extra space for terminating
  * null.  The second one is to hold output from scale_k().
  */
 char namebuf[10];
 char row_out[10][10];
 /* scratch space for positioning and counters both */
 int row = 0,col = 0;
 /* controls the hosts loop so we can page */
 int imin_col,imax_col;
 /* 
  * We need these to define EACH host as we walk the list of hosts for 
  * display.
  */
 Host *hostptr;
 Pid *pidptr;
 ListElement *element,*pidelement;
 
 

 if((verbose == D_ALL) || (verbose == D_DISPLAY_VALUES)){
   printf("D_DISPLAY_VALUES: Starting display_user().  Use -v %d to focus.\n",D_DISPLAY_VALUES);
 }

 printf("# %14s %6s  %11s    %5s %4s %8s %7s %7s %8s %-s\n",
      "Name      ",
      "Status",
      "Timestamp",
      "PID ",
      "Nice",
      "User  ",
      "Vsize",
      "RSS  ",
      "Time",
      "  Command"
   );

 /*
  * Loop over all hosts and pop them on the pad
  */
 element = hostlist->head;
 j = 0;
 for(i=0;i<numhosts;i++){
   if(element == NULL) break;	/* For whatever reason, out of hosts */
   hostptr = element->data;
   if(hostptr->connected == 2) {
     /*
      * This display is going to be fundamentally different from
      * the others in that one cannot predict how many (if any)
      * tasks that match the specified criteria will be running
      * on any host in the list.  These numbers can also jump
      * up or down without warning as tasks are started or die or
      * or stopped.  To manage this sort of free form data presentation
      * we will collect the pid data in a linked list of structs
      * indexed per host.  That is, hostptr->var.runlist will be
      * a linked list of tasks that match the specified task criteria
      * Filling it will be tricky, but is handled elsewhere.  Here
      * we simply walk the list for each host and displace a line
      * for each entry found.
      sprintf(row_out[0],"%5.5s",scale_k(hostptr->val.mem_total,5,0));
      */

     if(hostptr->pidlist->size == 0){
       printf("%-16.16s %6s%11lu.%02d   %5s  %2s  %8s %7s %7s %8s %-s\n",
       hostptr->hostname,
       "up  ",
       hostptr->val.pids_tv_sec,
       hostptr->val.pids_tv_usec / 10000,
           "  -",
           "-",
           "  -",
           "  -",
           "  -",
           "  -",
           "Idle/No Matching Task"
       );
       j++;
     } else {
       pidelement = hostptr->pidlist->head;
       while(pidelement != NULL){
         pidptr = pidelement->data;
         /*
          * Never display xmlsysd itself.  I know, one "should", but
	  * we won't.
         printf("host %s, taskname %s, size %d\n",hostptr->hostname,pidptr->taskname,hostptr->pidlist->size);
          */
         if(strncmp(pidptr->taskname,"xmlsysd",7) == 0) {
	   if(hostptr->pidlist->size == 1) {
             printf("%-16.16s %6s%11lu.%02d   %5s  %2s  %8s %7s %7s %8s %-s\n",
               hostptr->hostname,
               "up  ",
               hostptr->val.pids_tv_sec,
               hostptr->val.pids_tv_usec / 10000,
               "  -",
               "-",
               "  -",
               "  -",
               "  -",
               "  -",
               "Idle/No Matching Task"
             );
             j++;
	   }
	 } else {
           printf("%-16.16s %6s%11lu.%02d   %5d  %2d  %8s %7s %7s %8s %-s\n",
             hostptr->hostname,
             "up  ",
             hostptr->val.pids_tv_sec,
             hostptr->val.pids_tv_usec / 10000,
             pidptr->pid,
             pidptr->nice,
             pidptr->user,
             pidptr->vsize,
             pidptr->rss,
             pidptr->time,
             pidptr->cmdline
           );
           j++;
	 }
         pidelement = pidelement->next;
       }
     }
   } else {
     printf("%-16.16s %6s\n",
         hostptr->hostname,
         "down ");
     j++;
   }
   element = element->next;
 }

 fflush(STDOUT);
 
}

