//
//  BFHist Version 0.4 of 05-06-02
//  Bug report: 2:5090/114.31@FidoNet,
//  mailto:lan31@narod.ru, lan31@mail.ru
//  New version: http://lan31.narod.ru
//
//  BFHist - Statistics generator for BinkleyForce FTN mailer.
//  Copyright (C) 2001-2002 Andrey Lykhin, Krasnoyarsk, Russia.
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

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

void printf_traffic (long int);
void printf_time (long int);
void printf_cps  (long int);

int main(int argc, char *argv[])
{
   char version[20] = "BFHist v0.4";
   #ifdef __linux__
      strcat(version, "/lnx");
   #elif defined(__FreeBSD__) || defined(__NetBSD__)
      strcat(version, "/bsd");
   #elif defined(__OS2__) || defined(OS2)
      strcat(version, "/os2");
   #elif defined(__NT__)
      strcat(version, "/w32");
   #elif defined(__sun__)
      strcat(version, "/sun");
   #elif defined(MSDOS)
      strcat(version, "/dos");
   #elif defined(__BEOS__)
      strcat(version, "/beos");
   #endif

   if (argc < 3)
   {
      printf ("%s 05-06-02 Copyright (C) 2001-2002 Andrey Lykhin 2:5090/114.31\n",
             version);
      printf ("Usage: bfhist [-a] name_line hist_file\n");
      printf ("Example: bfhist cuaa1 /var/spool/ftn/history\n");
      printf ("  name_line - name line, cuaa1 or ttyS1 or tcpip or other.\n");
      printf ("  -a        - statistics for all hist_file current name_line.\n");
      return 0;
   }

   FILE *hist_file;
   hist_file = fopen (argv[argc-1], "rt");
   if ( hist_file == NULL)
   {
      fprintf(stderr, "Cannot open input file '%s'.\n", argv[argc-1]);
      return 1;
   }

   struct session {
      char addr[20];
      long int time;
      long int online;
      char flag[5];
      int  code;
      long int out_netm;
      long int out_arcm;
      long int out_files;
      long int inc_netm;
      long int inc_arcm;
      long int inc_files;
   };
   session *ses = (session*)malloc (sizeof (session));
   if (ses == NULL)
   {
      printf("Not enough memory to allocate buffer\n");
      exit(1);
   }

   struct system {
      char     sys_addr[20];
      long int sys_online;
      int      sys_ses;
      long int sys_out;
      long int sys_inc;
      int      sys_o;
      int      sys_i;
      long int sys_online_o;
      long int sys_online_i;
   };
   system *link = (system*)malloc (sizeof (system));
   if (link == NULL)
   {
      printf("Not enough memory to allocate buffer\n");
      exit(1);
   }

   // time
   time_t time_ses, time_start, time_end;
   struct tm *tmp;
   //struct tm_start, tm_end;

   time_start = time(NULL) - 24L*60L*60L;
   time_end   = time(NULL);

   //tmp = localtime(&time_start);
   //tm_start = *tmp;

   //tmp = localtime(&time_end);
   //tm_end = *tmp;

   //char time_start_str[30], time_end_str[30];
   //strftime (time_start_str, 30, "with %H:%M %d %B %Y ", &tm_start);
   //strftime (time_end_str,   30, "at %H:%M %d %B %Y",    &tm_end);

   int all = 1;
   if (strcmp (argv[argc-3], "-a"))
   {
      all = 0;
      //printf ("Statistics %s", time_start_str);
      //printf ("%s:\n", time_end_str);
   }

   char hist_str[100];
   fgets (hist_str, 100, hist_file);
   char *tty;
   int tot_ses=0;
   int tot_sys=0;
   int res_cmp=1;
   while (!feof (hist_file))
   {
      tty = strtok (hist_str, ",");
      if (strcmp (tty, argv[argc-2]))
      {
         fgets (hist_str, 100, hist_file);
         continue;
      }
      strcpy (ses[tot_ses].addr, strtok (NULL, ","));
      ses[tot_ses].time = atol  (strtok (NULL, ","));
      if (all == 0)
      {
         if (ses[tot_ses].time < time_start || ses[tot_ses].time > time_end)
         {
            fgets (hist_str, 100, hist_file);
            continue;
         }
      }
      ses[tot_ses].online = atol (strtok (NULL, ","));
      if (ses[tot_ses].online == 0)
      {
         fgets (hist_str, 100, hist_file);
         continue;
      }
      strcpy (ses[tot_ses].flag, strtok (NULL, ","));
      ses[tot_ses].code      = atol (strtok (NULL, ","));
      ses[tot_ses].out_netm  = atol (strtok (NULL, ","));
      ses[tot_ses].out_arcm  = atol (strtok (NULL, ","));
      ses[tot_ses].out_files = atol (strtok (NULL, ","));
      ses[tot_ses].inc_netm  = atol (strtok (NULL, ","));
      ses[tot_ses].inc_arcm  = atol (strtok (NULL, ","));
      ses[tot_ses].inc_files = atol (strtok (NULL, ","));
      for (int x=0; x<tot_ses; x++)
      {
         res_cmp = res_cmp && strcmp (ses[x].addr, ses[tot_ses].addr);
      }
      if (res_cmp==1)
      {
         strcpy (link[tot_sys].sys_addr, ses[tot_ses].addr);
         link[tot_sys].sys_online = 0;
         link[tot_sys].sys_ses = 0;
         link[tot_sys].sys_out = 0;
         link[tot_sys].sys_inc = 0;
         link[tot_sys].sys_o = 0;
         link[tot_sys].sys_i = 0;
         link[tot_sys].sys_online_o = 0;
         link[tot_sys].sys_online_i = 0;
         tot_sys++;
         link = (system*) realloc (link, (sizeof (system) * (tot_sys+1)));
         if (link == NULL)
         {
            printf("Not enough memory to allocate buffer\n");
            exit(1);
         }
      }
      res_cmp=1;
      tot_ses++;
      ses = (session*) realloc (ses, (sizeof (session) * (tot_ses+1)));
      if (ses == NULL)
      {
         printf("Not enough memory to allocate buffer\n");
         exit(1);
      }
      fgets (hist_str, 100, hist_file);
   }

   for (int n=0; n<tot_sys; n++)
   {
      for (int z=0; z<tot_ses; z++)
      {
         if (strcmp (ses[z].addr, link[n].sys_addr)==0)
         {
            link[n].sys_online += ses[z].online;
            link[n].sys_out += ses[z].out_netm + ses[z].out_arcm + ses[z].out_files;
            link[n].sys_inc += ses[z].inc_netm + ses[z].inc_arcm + ses[z].inc_files;
            link[n].sys_ses++;
            if (strchr (ses[z].flag, 'I'))
            {
               link[n].sys_i++;
               link[n].sys_online_i += ses[z].online;
            }
            if (strchr (ses[z].flag, 'O'))
            {
               link[n].sys_o++;
               link[n].sys_online_o += ses[z].online;
            }
         }
      }
   }

   // sort addr
   int y = 1;
   int i = 2;
   for (int x=0; x<tot_sys-1; x++)
   {
      while (y<=tot_sys-1)
      {
         if (strcmp (link[x].sys_addr, link[y].sys_addr) > 0)
         {
            char tmp[20];
            strcpy (tmp, link[x].sys_addr);
            strcpy (link[x].sys_addr, link[y].sys_addr);
            strcpy (link[y].sys_addr, tmp);

            long int tmp2;
            tmp2 = link[x].sys_online;
            link[x].sys_online = link[y].sys_online;
            link[y].sys_online = tmp2;

            int tmp3;
            tmp3 = link[x].sys_ses;
            link[x].sys_ses = link[y].sys_ses;
            link[y].sys_ses = tmp3;

            tmp2 = link[x].sys_out;
            link[x].sys_out = link[y].sys_out;
            link[y].sys_out = tmp2;

            tmp2 = link[x].sys_inc;
            link[x].sys_inc = link[y].sys_inc;
            link[y].sys_inc = tmp2;

            tmp3 = link[x].sys_o;
            link[x].sys_o = link[y].sys_o;
            link[y].sys_o = tmp3;

            tmp3 = link[x].sys_i;
            link[x].sys_i = link[y].sys_i;
            link[y].sys_i = tmp3;

            tmp2 = link[x].sys_online_o;
            link[x].sys_online_o = link[y].sys_online_o;
            link[y].sys_online_o = tmp2;

            tmp2 = link[x].sys_online_i;
            link[x].sys_online_i = link[y].sys_online_i;
            link[y].sys_online_i = tmp2;
         }
         y++;
      }
      y=i;
      i++;
   }

   // print res
   int tot_o = 0, tot_i = 0;
   long int tot_online = 0, tot_online_o = 0, tot_online_i = 0, tot_traff = 0,
            tot_out = 0, tot_inc = 0, tot_sys_oi_traff;
   //printf ("\n");
   printf ("Address         Ses  Online    O  Out.onl   I  Inc.onl Traff   Out   Inc   CPS\n");
   printf ("------------------------------------------------------------------------------\n");

   for (int l=0; l<tot_sys; l++)
   {
      printf ("%-16s", link[l].sys_addr);
      printf ("%3u ",  link[l].sys_ses);

      tot_o += link[l].sys_o;
      tot_i += link[l].sys_i;

      printf_time (link[l].sys_online);
      tot_online += link[l].sys_online;

      if (link[l].sys_o) printf ("%3u ",  link[l].sys_o);
      else printf ("  - ");

      printf_time (link[l].sys_online_o);
      tot_online_o += link[l].sys_online_o;

      if (link[l].sys_i) printf ("%3u ",  link[l].sys_i);
      else printf ("  - ");

      printf_time (link[l].sys_online_i);
      tot_online_i += link[l].sys_online_i;

      tot_sys_oi_traff = link[l].sys_out + link[l].sys_inc;
      printf_traffic (tot_sys_oi_traff);
    
      tot_traff += link[l].sys_out + link[l].sys_inc;

      printf_traffic (link[l].sys_out);
      tot_out += link[l].sys_out;

      printf_traffic (link[l].sys_inc);
      tot_inc += link[l].sys_inc;

      printf_cps (tot_sys_oi_traff/link[l].sys_online);
      printf ("\n");
   }

   printf ("------------------------------------------------------------------------------\n");
   printf ("Total: %3u sys. ", tot_sys);
   printf ("%3u ", tot_ses);
   printf_time (tot_online);

   if (tot_o) printf ("%3u ", tot_o);
   else printf ("  - ");

   printf_time (tot_online_o);

   if (tot_i) printf ("%3u ", tot_i);
   else printf ("  - ");

   printf_time    (tot_online_i);
   printf_traffic (tot_traff);
   printf_traffic (tot_out);
   printf_traffic (tot_inc);

   if (tot_traff) printf_cps (tot_traff/tot_online);
   else printf ("    0");

   printf ("\n\n");
   printf ("Time     Address          Online  LPxE Traff   Out   Inc   CPS\n");
   printf ("--------------------------------------------------------------\n");

   for (int b=0; b<tot_ses; b++)
   {
      time_ses = ses[b].time;
      tmp = localtime(&time_ses);
      char time_str[10];
      strftime (time_str, 10, "%H:%M:%S ", tmp);
      printf ("%s", time_str);
      printf ("%-16s", ses[b].addr);
      printf_time (ses[b].online);

      printf ("%3s", ses[b].flag);
      if (ses[b].code) printf ("E ");
      else printf ("  ");

      long int ses_tot_oi = ses[b].out_netm + ses[b].out_arcm + ses[b].out_files
               + ses[b].inc_netm + ses[b].inc_arcm + ses[b].inc_files;
      printf_traffic (ses_tot_oi);

      long int ses_tot_out = ses[b].out_netm + ses[b].out_arcm + ses[b].out_files;
      printf_traffic (ses_tot_out);

      long int ses_tot_inc = ses[b].inc_netm + ses[b].inc_arcm + ses[b].inc_files;
      printf_traffic (ses_tot_inc);

      printf_cps (ses_tot_oi/ses[b].online);
      printf ("\n");
   }

   printf ("--------------------------------------------------------------\n");
   printf ("Total: %3u session                        %20s", tot_ses, version);
   printf ("\n");

   free (ses);
   free (link);
   fclose (hist_file);
   return 0;
}


void printf_cps (long int cps)
{
   if (cps >= 1048576) printf ("%4lum", cps/1048576);
   if (cps >= 100000 && cps < 1048576) printf ("%4luk", cps/1024);
   if (cps < 100000) printf ("%5lu", cps);
}

void printf_traffic (long int tr)
{
   if (tr >= 1048576) printf ("%4lum ", tr/1048576);
   if (tr >= 1024 && tr < 1048576) printf ("%4luk ", tr/1024);
   if (tr < 1024) printf ("%5lu ", tr);
}

void printf_time (long int time)
{
   if (time)
   {
      long int h, m;
      printf ("%2lu:",  h=time/3600);
      printf ("%.2lu:", m=(time-h*3600)/60);
      printf ("%.2lu ", time-h*3600-m*60);
   }
   else printf (" -:--:-- ");
}

