/*
 * stats.c
 * Statistics gathering and printing.
 *
 * Copyright (c) 2002 Christoph Pfisterer
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 */

#include "netstrain.h"

/* settings */
#define QUANTUM (2)

/* internal functions */
static void stats_hook(counter_t sendcount, counter_t recvcount);
static void stats_line(const char *prefix,
		       counter_t total_b, counter_t last_b,
		       counter_t total_us, counter_t last_us);
static void print_count(counter_t count);
static void print_rate(counter_t rate);
static counter_t timestamp(void);

/* internal data */
static time_t next_time;
static counter_t start_stamp;
static counter_t last_stamp;
static counter_t last_sendcount = 0;
static counter_t last_recvcount = 0;


void stats_init(void)
{
  next_time = time(NULL) + QUANTUM;
  last_stamp = start_stamp = timestamp();

  transfer_hook(stats_hook);

  printf("sent:   please wait...\nrecv'd:\n");
}

static void stats_hook(counter_t sendcount, counter_t recvcount)
{
  time_t now;
  counter_t now_stamp;
  counter_t total_b, last_b, total_us, last_us;

  now = time(NULL);
  if (now < next_time)
    return;
  next_time = now + QUANTUM;

  now_stamp = timestamp();
  total_us = now_stamp - start_stamp;
  last_us = now_stamp - last_stamp;
  last_stamp = now_stamp;

  printf("\033[A\033[K\033[A\033[K");

  total_b = sendcount;
  last_b = total_b - last_sendcount;
  last_sendcount = total_b;
  stats_line("sent:   ", total_b, last_b, total_us, last_us);

  total_b = recvcount;
  last_b = total_b - last_recvcount;
  last_recvcount = total_b;
  stats_line("recv'd: ", total_b, last_b, total_us, last_us);
}

static void stats_line(const char *prefix,
		       counter_t total_b, counter_t last_b,
		       counter_t total_us, counter_t last_us)
{
  counter_t total_bps, last_bps;

  total_bps = (total_b * 1000000 + (total_us >> 1)) / total_us;
  last_bps = (last_b * 1000000 + (last_us >> 1)) / last_us;

  printf("%s", prefix);
  print_count(total_b);
  printf(", ");
  print_rate(total_bps);
  printf(" total, ");
  print_rate(last_bps);
  printf(" current\n");
}

static void print_count(counter_t count)
{
  int card;

  if (count < 100000) {
    card = (int)count;
    printf("%7dB", card);
  } else {
    count >>= 10;
    if (count < 100000) {
      card = (int)count;
      printf("%7dK", card);
    } else {
      count >>= 10;
      card = (int)count;
      printf("%7dM", card);
    }
  }
}

static void print_rate(counter_t rate)
{
  counter_t card_c;
  int card;
  int frac;

  if (rate > 10240) {
    card_c = rate >> 10;
    if (card_c >= 10000000) {
      printf("      \"huge\"");
    } else {
      card = (int)card_c;
      frac = (int)(((rate * 10) >> 10) % 10);
      printf("%7d.%01dK/s", card, frac);
    }
  } else {
    card = (int)rate;
    printf("%9dB/s", card);
  }
}

static counter_t timestamp(void)
{
  struct timeval tv;

  gettimeofday(&tv, NULL);
  return (counter_t)tv.tv_sec * 1000000 + (counter_t)tv.tv_usec;
}


syntax highlighted by Code2HTML, v. 0.9.1