// Licensed under the terms of the GNU GPL v3, or any later version.
//
// Copyright 2019 Nolan Leake <nolan@sigbus.net>
//
// Loosely based on bandwidth2 (originally by Guillaume Coré <fridim@onfi.re>)

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>

#define RED "#FF7373"
#define ORANGE "#FFA500"

typedef unsigned long long int ulli;

void usage(char *argv[])
{
  printf("Usage: %s "
         "[-t seconds] [-w %%age] [-c %%age] [-d decimals] [-l label] [-h]\n",
         argv[0]);
  printf("\n");
  printf("-t seconds\trefresh time (default is 1)\n");
  printf("-w %%\tSet warning (color orange) for cpu usage. (default: none)\n");
  printf("-c %%\tSet critical (color red) for cpu usage. (default: none)\n");
  printf("-d number\tNumber of decimal places for percentage (default: 2)\n");
  printf("-l label\tLabel to print before the cpu usage (default: CPU)\n");
  printf("-h \t\tthis help\n");
  printf("\n");
}

void display(const char *label, double used,
             int const warning, int const critical, int const decimals)
{
  if (critical != 0 && used > critical) {
    printf("%s<span color='%s'>", label, RED);
  } else if (warning != 0 && used > warning) {
    printf("%s<span color='%s'>", label, ORANGE);
  } else {
    printf("%s<span>", label);
  }

  printf("%*.*lf%%</span>\n", decimals + 3 + 1, decimals, used);
}

ulli get_usage(ulli *used_jiffies)
{
  FILE *fd = fopen("/proc/stat", "r");
  ulli user, nice, sys, idle, iowait, irq, sirq, steal, guest, nguest;

  if (!fd) {
    perror("Couldn't open /proc/stat\n");
    exit(EXIT_FAILURE);
  }
  if (fscanf(fd, "cpu  %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
             &user, &nice, &sys, &idle, &iowait, &irq, &sirq,
             &steal, &guest, &nguest) != 10) {
    perror("Couldn't read jiffies from /proc/stat\n");
    exit(EXIT_FAILURE);
  }
  fclose(fd);

  *used_jiffies = user + nice + sys + irq + sirq + steal + guest + nguest;
  return *used_jiffies + idle + iowait;
}

int main(int argc, char *argv[])
{
  int warning = 50, critical = 80, t = 1, decimals = 2;
  char *label = "CPU ";
  int c;
  char *envvar = NULL;

  envvar = getenv("REFRESH_TIME");
  if (envvar)
    t = atoi(envvar);
  envvar = getenv("WARN_PERCENT");
  if (envvar)
    warning = atoi(envvar);
  envvar = getenv("CRIT_PERCENT");
  if (envvar)
    critical = atoi(envvar);
  envvar = getenv("DECIMALS");
  if (envvar)
    decimals = atoi(envvar);
  envvar = getenv("LABEL");
  if (envvar)
    label = envvar;

  while (c = getopt(argc, argv, "ht:w:c:d:l:"), c != -1) {
    switch (c) {
    case 't':
      t = atoi(optarg);
      break;
    case 'w':
      warning = atoi(optarg);
      break;
    case 'c':
      critical = atoi(optarg);
      break;
    case 'd':
      decimals = atoi(optarg);
      break;
    case 'l':
      label = optarg;
      break;
    case 'h':
      usage(argv);
      return EXIT_SUCCESS;
    }
  }

  ulli old_total;
  ulli old_used;

  old_total = get_usage(&old_used);

  while (1) {
    ulli used;
    ulli total;

    sleep(t);
    total = get_usage(&used);

    display(label, 100.0D * (used - old_used) / (total - old_total),
            warning, critical, decimals);
    fflush(stdout);
    old_total = total;
    old_used = used;
  }

  return EXIT_SUCCESS;
}