/* $Id: isdnrep.c,v 1.24 1995/11/12 11:09:19 akool Exp akool $
 *
 * ISDN accounting for isdn4linux. (Report-module)
 *
 * Copyright 1995 by Andreas Kool (akool@Kool.f.EUnet.de)
 *
 * 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Log: isdnrep.c,v $
 * Revision 1.24  1995/11/12  11:09:19  akool
 * Formatfelder vergroessert
 * Fremdverursachte Einheiten werden ge-()
 * Alle Floating-Point-Zahlen werden deutsch (mit Komma) ausgegeben
 *
 * Revision 1.23  1995/11/06  18:04:19  akool
 * Denkfehler in der "-6" Berechnung :-(
 *
 * Revision 1.22  1995/10/22  15:31:19  akool
 * Aufschluesselung bach Tarifzonen implementiert
 *
 * Revision 1.21  1995/10/17  19:53:19  akool
 * Auf echte Charging-Info umgestellt
 *
 * Revision 1.20  1995/10/15  17:58:19  akool
 * Vergleich errechnete zu uebermittelten Einheiten implementiert
 *
 * Revision 1.16  1995/10/12  13:50:19  akool
 * Neue Option "MYMSNS=x" in der "isdnlog.conf" zum definieren der Anzahl
 * eigener MSN's
 *
 * Revision 1.15  1995/10/09  18:42:18  akool
 * Offensichtlich sinnlose Daten i.d. "isdn.log" werden nun ignoriert
 *
 * Revision 1.14  1995/10/08  10:25:16  akool
 * Ueberschreitung verschiedener Zeittakte bei einer Verbindung implementiert.
 *
 * Revision 1.6  1995/09/30  19:55:17  akool
 * First public release
 *
 * Revision 1.1  1995/09/23  16:44:19  akool
 * Initial revision
 *
 */


#define  PUBLIC extern
#include "isdnlog.h"


typedef struct {
  char   num[NUMSIZE];
  int	 called;
  int	 connects;
  time_t connect[MAXCONNECTS];
} UNKNOWN;


static int      unknowns = 0;
static UNKNOWN  unknown[MAXUNKNOWN];
static int  	zones[MAXZONES];


static char msg1[]    = "%s: Can't open %s (errno=%d)\n";
static char usage[]   = "%s: usage: %s [ -%s ]\n";
static char options[] = "an6";


main(int argc, char *argv[], char *envp[])
{
  register char      *p, *p1, *p2;
  register int	      i, k, n;
  auto     FILE      *fi, *fc;
  auto     char       s[BUFSIZ], s1[BUFSIZ], num[2][20], msn[20], name[20];
  auto	   char	      start[20], stop[20];
  auto	   int	      hit, takt, zone, lday = -1, payer, eh, realeh, diffeh;
  auto	   int	      lmonth = -1;
  auto	   double     duration, rest[2], restdm[2];
  extern   int        errno;
  auto	   time_t     t, t1, t2, now, from;
  auto 	   struct tm *tm;
  auto	   double     dm, dms = 0.0, dmss = 0.0, einheit = 0.23;
  auto	   int	      nx[2], call[2], calls[2], ncall = 0;
  auto	   int 	      Tarif96 = 0, Tarif962 = 0, c, notforus, resteh = 0;
  auto	   double     restdur = 0.0, d = 0.0;
  auto	   int	      all = 0, numbers = 0, new = 0, e = 0, restcalls = 0;


  while ((c = getopt(argc, argv, options)) != EOF)
    switch (c) {
      case 'a' : all++;
      	       	 break;

      case 'n' : numbers++;
      	       	 break;

      case '6' : new++;
      	       	 break;

      case '?' : fprintf(stderr, usage, argv[0], argv[0], options);
	         return(1);
    } /* switch */


  if (!all) {
    time(&now);
    tm = localtime(&now);
    tm->tm_sec = tm->tm_min = tm->tm_hour = 0;
    from = mktime(tm);
  } /* if */

  if ((fi = fopen(LOGFILE, "r")) != (FILE *)NULL) {

    readconfig(argv[0]);

    calls[0] = calls[1] = 0;
    rest[1] = restdm[1] = 0.0;

    memset(zones, 0, sizeof(zones));

    *start = 0;

    while (fgets(s, BUFSIZ, fi)) {
      if ((*s != '#') && (p = strchr(s, '|'))) {

      	realeh = notforus = 0;

     	if (p1 = p2 = strchr(p + 1, '|')) {
          do {
            *p1-- = 0;
          } while (isspace(*p1));

       	  strcpy(num[0], p + 1);

       	  p = p2 + 1;

          if (p1 = p2 = strchr(p, '|')) {

            do {
              *p1-- = 0;
            } while (isspace(*p1));

            strcpy(num[1], p);

            p = p2 + 1;

            duration = (double)atoi(p);

            if (p1 = p2 = strchr(p, '|')) {
              p = p2 + 1;
              duration = atoi(p) / 100.0;

              if (p1 = p2 = strchr(p, '|')) {
                p = p2 + 1;
                t = atol(p);
              	if (p1 = p2 = strchr(p, '|')) { /* Gebuehrenimpuls */
                  p = p2 + 1;
                  realeh = atoi(p);
                } /* if */
              }
              else
                t = atom(s);
            }
            else
              t = atom(s);

            if (t < from)
              continue;

            tm = localtime(&t);
            day = tm->tm_mday;
            month = tm->tm_mon;

            Tarif96 = tm->tm_year > 95;

            /* Ab Juli '96 gibt's noch mal eine Senkung in den Zonen 3 und 4
               genaue Preise sind jedoch noch nicht bekannt. FIX-ME */

            Tarif962 = Tarif96 && (tm->tm_mon > 5);

            if (new)
              Tarif96 = 1;

            einheit = Tarif96 ? 0.12 : 0.23;

            if (duration > 172800.0) /* laenger als 2 Tage? Das KANN nicht sein! */
              duration = 0;

            for (n = CALLING; n <= CALLED; n++) {
              nx[n] = -1;
              hit = 0;

              if (!*num[n]) {
                if (!numbers)
                  strcpy(num[n], "UNKNOWN");
                hit++;
              }
              else {
                for (i = 0; i < knowns; i++) {
                  if (match(num[n], known[i]->num)) {

                    if (!numbers)
                      strcpy(num[n], known[i]->who);

                    nx[n] = i;
                    known[i]->dur[n] += duration;
                    known[i]->usage++;
                    hit++;
                    break;
                  } /* if */

                } /* for */
              } /* else */

              if (!hit) {
                for (i = 0; i < unknowns; i++)
                  if (!strcmp(unknown[i].num, num[n])) {
                    hit++;
                    break;
                  } /* if */

                strcpy(unknown[i].num, num[n]);
                unknown[i].called = !n;
                unknown[i].connect[unknown[i].connects] = t;

                if (unknown[i].connects + 1 < MAXCONNECTS)
                  unknown[i].connects++;
                else
                  fprintf(stderr, "%s: WARNING: Too many unknown connection's from %s\n", argv[0], unknown[i].num);

                if (!hit) {
                  if (unknowns < MAXUNKNOWN)
                    unknowns++;
                  else
                    fprintf(stderr, "%s: WARNING: Too many unknown number's\n", argv[0]);
                } /* if */

              } /* if */
            } /* for 'n' */

            if ((nx[0] == -1) && (nx[1] == -1)) { /* Selbst telefoniert ? */
              notforus++;
              nx[0] = 0;
            } /* if */

            if ((nx[0] >= 0) && (nx[0] < mymsns)) /* habe ich rausgewaehlt ... */
              payer = IPAY;   /* gilt Tarifzone der Gegenstelle, und ich muss zahlen */
            else
              payer = YOUPAY; /* gilt Tarifzone des Anrufers, und der zahlt */

            /* unbekannte werden stets der Fernzone zugeschlagen */

            t1 = t;
            t2 = t + duration;
	    rest[0] = duration;

            eh = 0;

            while (t1 < t2) {
              if (Tarif96)
                takt = cheap96(t1, (nx[payer] == -1) ? 4 : known[nx[payer]]->zone);
              else
                takt = cheap(t1, (nx[payer] == -1) ? 4 : known[nx[payer]]->zone);

              if (!takt) {
                fprintf(stderr, "%s: OOPS! Abbruch: Zeittakt==0 ???\n", argv[0]);
                break;
              } /* if */

              eh++;
              t1 += takt;

              rest[0] -= takt;
            } /* while */

            if (payer == IPAY) {
              if (takt) {
                rest[0] *= -1.0;
                restdm[0] = (einheit / takt) * rest[0];
              } /* if */

              if (nx[payer] == -1) {
                resteh += realeh;
                restdur += duration;
                restcalls++;
              }
              else {
                rest[0] = 0;

                zones[known[nx[payer]]->zone] += realeh;
                known[nx[payer]]->eh[payer] += realeh;
              } /* else */
            } /* if */

            strcpy(s1, ctime(&t));

            if (p = strchr(s1, '\n'))
              *p = 0;

            if (day != lday) {
              if (lday == -1) {
                time(&now);
                printf("I S D N  Connection Report  -  %s", ctime(&now));
              }
              else {
#if V2
                printf("%d call's, %d called", call[1], call[0]);
#endif
                printf("%48sSUBTOTAL %s DM", "", double2str(dms, 8, 2, 0));
                dmss += dms;
                dms = 0;

                calls[0] += call[0];
                calls[1] += call[1];
                call[0] = call[1] = 0;
              } /* if */

              *(s1 + 10) = 0;
              printf("\n%s %s\n", s1, s1 + 20);
              lday = day;

              if (!*start)
                sprintf(start, "%s %s", s1, s1 + 20);
	      else
                sprintf(stop, "%s %s", s1, s1 + 20);

            } /* if */

            *(s1 + 19) = 0;
            printf("  %s ", s1 + 11);

            if (payer == IPAY) {
              dm = realeh * einheit;
              dms += dm;
	      diffeh = eh - realeh;

              printf("  calling %-14s %s s %c%4d EH  %s DM",
                num[1],
                double2str(duration, 8, 2, 0),
                (realeh ? ' ' : '*'),
                (realeh ? realeh : eh),
                double2str(dm, 8, 2, 0));

              if (diffeh && !notforus)
                printf(" (%d)", diffeh);

              printf("\n");

              rest[1] += rest[0];
              restdm[1] += restdm[0];

            }
            else
              printf("called by %-14s %s s (%4d EH )\n",
                num[0],
                double2str(duration, 8, 2, 0),
                eh);

            call[payer]++;
          } /* if */
        } /* if */
      } /* if */
    } /* while */

    fclose(fi);

    if (lday != -1) {
      printf("%48sSUBTOTAL %s DM\n", "", double2str(dms, 8, 2, 0));
      dmss += dms;
      printf("%51sTOTAL %s DM\n", "", double2str(dmss, 8, 2, 0));

      if (all)
        printf("\nSummary for %s .. %s\n", start, stop);
      else
        printf("\nSummary for %s\n", start);
      printf("-----------------------------------------------------------\n");

      ncall = 0;

      for (i = 0; i < knowns; i++) {
        if (known[i]->eh[CALLED]) {
          printf("%-14s %3d call(s) %s min %4d EH %s DM\n",
            known[i]->who,
            known[i]->usage,
            double2str(known[i]->dur[CALLED] / 60.0, 9, 2, 0),
            known[i]->eh[IPAY],
            double2str(known[i]->eh[IPAY] * einheit, 7, 2, 0));
          d += known[i]->dur[CALLED];
          e += known[i]->eh[IPAY];
          ncall += known[i]->usage;
        } /* if */
      } /* for */

      if (resteh) {
        printf("%-14s %3d call(s) %s min %4d EH %s DM\n",
            "UNKNOWN",
            restcalls,
            double2str(restdur / 60.0, 9, 2, 0),
            resteh,
            double2str(resteh * einheit, 7, 2, 0));
        d += restdur;
        e += resteh;
        ncall += restcalls;
      } /* if */

      printf("===========================================================\n");
      printf("%-14s %3d call(s) %s min %4d EH %s DM\n",
         "",
         ncall,
         double2str(d / 60.0, 9, 2, 0),
         e,
         double2str(e * einheit, 7, 2, 0));


      printf("\n\n");

      if (!Tarif96) {
        zones[3] += zones[4];
        zones[4] = 0;
      } /* if */

      for (i = 1; i < MAXZONES; i++)
        if (zones[i]) {

          p = "";

          if (Tarif96)
            switch (i) {
              case 1 : p = "City";       break;
              case 2 : p = "Region 50";  break;
              case 3 : p = "Region 200"; break;
              case 4 : p = "Fernzone";   break;
            } /* switch */
          else {
            switch (i) {
              case 1 : p = "Ortszone";     break;
              case 2 : p = "Regionalzone"; break;
              case 3 : p = "Weitzone"; 	   break;
            } /* switch */
          } /* else */

          printf("%15sZone %d : %-15s %5d EH %s DM\n", "", i, p,
            zones[i],
            double2str(zones[i] * einheit, 7, 2, 0));
        } /* if */

      if (resteh)
        printf("%15sZone x : %-15s %5d EH %s DM\n", "", "UNKNOWN",
          resteh,
          double2str(resteh * einheit, 7, 2, 0));

#if V2
      if (rest[1])
        printf("\n\n (%6.2f min / %6.2f DM verschenkt!)\n", rest[1] / 60.0, restdm[1]);
#endif

      if (unknowns) {
        printf("\nUnknown caller(s)\n");
      	printf("-----------------------------------------------------------\n");

        for (i = 0; i < unknowns; i++) {

          printf("%s %-14s ", unknown[i].called ? "called by" : "  calling", unknown[i].num);

          for (k = 0; k < unknown[i].connects; k++) {
            strcpy(s1, ctime(&unknown[i].connect[k]));

            if (p = strchr(s1, '\n'))
              *p = 0;

            *(s1 + 19) = 0;

            if (k && (k + 1) % 2) {
              printf("\n\t\t\t ");
            } /* if */

            printf("%s%s", k & 1 ? ", " : "", s1 + 4);
          } /* for */

          printf("\n");
        } /* for */
      } /* if */
    } /* if */
  }
  else {
    fprintf(stderr, msg1, argv[0], LOGFILE, errno);
    return(1);
  } /* else */
} /* main */
