/* laststalk.c - Stalk users on a Unix system
 *
 * Copyright (C) 2001 Alan Shutko
 *
 * 
 * Description:
 * 
 *  This program snarfs the output of last and will generate a
 *  histogram showing when a user has logged in by time and day of
 *  week.  The longer the bar, the more likely (historically) it is
 *  that the user is logged in at the time.
 * 
 * History:
 * ats     2/26/01    Created
 *
 * Tokens: ::Header:: laststalk.h
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
 * BUGS: We don't handle people who've been logged in more than a day
 */

#define MAX_LINE_LEN 512
#define DAY_ABBR_LEN 3          /* How long can day abbreviations (Sun, Mon, Tue) be? */
#define HOUR_LEN     2          /* How many characters are hours? */
#define MIN_LEN      2          /* How many characters are minutes? */
#define NUM_MIN      6

static int count[7][24][NUM_MIN];


char *day_str[] = 
{
    "Sun",
    "Mon",
    "Tue",
    "Wed",
    "Thu",
    "Fri",
    "Sat"
};

#undef PILOT
#undef LINUX
/*
 * FIXME Hardcoding offsets for various formats bothers me.  This
 * should be done some other way
 */
#ifdef LINUX
#define DAY_COL        39
#define START_HOUR_COL 50
#define START_MIN_COL  53
#define END_HOUR_COL   58
#define END_MIN_COL    61
#else
#define DAY_COL        40
#define START_HOUR_COL 51
#define START_MIN_COL  54
#define END_HOUR_COL   59
#define END_MIN_COL    62
#endif /* LINUX */

#ifdef PILOT
#define SCREEN_LENGTH (26.-8.)  /* FIXME what do these numbers mean? */
#else
#define SCREEN_LENGTH (80.-14.)
#endif

#define LOGIN_LEN 8

int day_min(int min_int)
{
    return (60*min_int/NUM_MIN);
}

int read_day(char *buf)
{
    int i;
    
    for (i = 0; i < sizeof(day_str)/sizeof(char *); i++)
        if (memcmp(buf, day_str[i], DAY_ABBR_LEN) == 0)
            return i;

    return -1;
}

int read_hour(char *buf)
{
    return strtol(buf, NULL, 10);
}

int read_min(char *buf)
{
    return strtol(buf, NULL, 10)/(60/NUM_MIN);
}

void histogram(void)
{
    int day, hour, min, i, max = 0;
    float scale;
    
    /* Find scaling value
     * FIXME assumes 80 column screen
     */

    for (day = 0; day < 7; day++)
        for (hour = 0; hour < 24; hour++)
            for (min = 0; min < NUM_MIN; min++)
                max = (max > count[day][hour][min]) ? max
                    : count[day][hour][min];

    scale = (float)max/SCREEN_LENGTH;
    

/*      if (SCREEN_LENGTH / max > 2) */
/*          scale =  */
        
#ifdef PILOT
    printf(".PRE\n");
#endif
    
    for (day = 0; day < 7; day++)
        for (hour = 0; hour < 24; hour++)
        {
#ifdef PILOT
            if ((hour % 4) == 0)
                printf(".BM %s %d:00\n", day_str[day], hour);
#endif /* PILOT */
            
            for (min = 0; min < NUM_MIN; min++)
            {
                if (1 || count[day][hour][min])
                {
                    printf("%s %.2d:%.2d :: ", day_str[day], hour,
                           day_min(min));
                    
                    if (count[day][hour][min] != 0 &&
                        count[day][hour][min]/scale == 0)
                        printf("*");
                    
                    for (i = 0; i < count[day][hour][min]/scale ; i++)
                        printf("*");
                    
                    printf("\n");
                }
            }
        }
#ifdef PILOT
    printf("./PRE\n");
#endif
    
}


int main(int argc, char **argv)
{
    char buf[MAX_LINE_LEN],
        login[8];
    int day, start_hour, start_min, end_hour, end_min, hour, min;
    
    if (argc < 2)
    {
        printf("%s username, please\n", argv[0]);
        exit(1);
    }

    memset(login, ' ', LOGIN_LEN);
    memcpy(login, argv[1], strlen(argv[1]));
    

    do
    {
        fgets(buf, MAX_LINE_LEN, stdin);
        if (memcmp(buf, login, LOGIN_LEN) != 0)
            continue;

        buf[DAY_COL+DAY_ABBR_LEN] = 0;
        day = read_day(&(buf[DAY_COL]));

        buf[START_HOUR_COL + HOUR_LEN] = 0;
        start_hour = read_hour(&(buf[START_HOUR_COL]));
        
        buf[START_MIN_COL + MIN_LEN] = 0;
        start_min = read_min(&(buf[START_MIN_COL]));

        buf[END_HOUR_COL + HOUR_LEN] = 0;
        end_hour = read_hour(&(buf[END_HOUR_COL]));

        buf[END_MIN_COL + MIN_LEN] = 0;
        end_min = read_min(&(buf[END_MIN_COL]));
        
        for (hour = start_hour; hour <= end_hour; hour++)
            for (min = (hour == start_hour) ? start_min : 0;
                 min < ((hour == end_hour) ? end_min : NUM_MIN);
                 min++)
                count[day][hour][min]++;
    } while (!feof(stdin));

    histogram();
    exit(0);
}

