/*========================================================================*\
 |  Datei: jpc.c                                      Datum: 25 Okt 1997  |
 *------------------------------------------------------------------------*
 |                  Auswertung des Katalog-CDROMs von JPC                 |
 |                                                                        |
\*========================================================================*/

char version[] = "$VER:JPC_kat 1.6 (11.01.98)";

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <signal.h>
#include <exec/types.h>         /* typedef's für UBYTE etc. */
#include "jpc.h"


char win0[80];                  /* das Debug-Fenster */
FILE *dbugf = NULL;
char *dbpath[DBMAX];            /* Verzeichnisnamen, "JPCPOP" etc. */
char dbcode[DBMAX][20];         /* Namen der Init-Dateien, "DB_1" etc. */
char indpath[MAXINDEX + 1][20]; /* Verzeichnisname, z. B. "KOMPO" */
char indname[MAXINDEX + 1][20]; /* z. B. "Komponist" */
int indcode[MAXINDEX + 1];      /* interne Kennummern, z. B. 46 */
char indshort[MAXINDEX + 1];    /* Kennbuchstaben, z. B. 'K' */
int indexes;
char fnamebuf[MAXFNAMES][20];   /* z. B. "Interpret" */
char *fieldname[256];           /* verweist auf Einträge in fnamebuf[] */
UBYTE ibm_decode[256], sort[256];       /* Zeichentabellen */
UWORD thisdb;                   /* welche der drei Datenbanken? */
long int reccnt;                /* Größe der Datenbank */
char *selected = NULL;          /* ein Flag pro Datensatz */
long int selcnt;                /* Summe über selected[] */
int targets;
char target[MAXTARGET][80];     /* Suchwörter */
int blksize;                    /* i. a. 2048 */
int recnumsize;                 /* 2 oder 3 Bytes */
int linelen;                    /* Format der Kurztext-Dateien */
char separator;                 /* normalerweise '|' */
int envconfig = 0;              /* über s: oder env: konfiguriert? */


void cli_help( char *myname )
/* Erklärung der CLI-Parameter */
{
  printf ("Benutzung: \e[2m%s [-d]\e[0m\n", myname);
  printf (" -d: Debug-Ausgaben einschalten\n");
}


long getvalue( FILE *datei, char *keywd )
/* aus der Datei Zeilen lesen, bis eine <keywd> enthält, numerischen */
/* Wert vom Zeilenende zurückgeben, -1, wenn keine Zahl zu finden ist. */
{
  int i, l;
  char s[80];

  l = strlen (keywd);
  do
    fgets (s, 80, datei);
  while( strstr( s, keywd ) == NULL );
  i = strlen( s );
  while( !isdigit( s[--i] ) )
    if( i < l )
      return -1;
  while( isdigit ( s[--i] ) )
    ;
  if( dbugf )
    fprintf( dbugf, "%s=%ld\n", keywd, atol (s + i + 1) );
  return atol( s + i + 1 );
}


void setup()
/* globale Variablen initialisieren */
{
  int c, i, j, m, n;
  UBYTE *s, sbuf[80];
  FILE *datei;
  char tab[] = "ÇüéâäàáçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø×fáíóúñÑªº¿®¬½¼¡«»";
  static char leer = '\0';

  /* Decodierung des IBM-Zeichensatzes: */
  for (c = 0; c < 128; c++)
    ibm_decode[c] = c;
  for (c = 128; c < 176; c++)
    ibm_decode[c] = tab[c - 128];
  for (c = 176; c < 256; c++)
    ibm_decode[c] = ' ';        /* %-) */
  ibm_decode[13] = ' ';
  ibm_decode[225] = 'ß';
  /* Einen Katalog auswählen: */
  if (!(datei = fopen ("JPC:jpc/eps.ini", "r")))
    exit (20);
  getvalue (datei, "[DATABASE]");
  m = getvalue (datei, "DB_COUNT");
  printf ("\n");
  for (i = 0; i < m; i++)
    {
      fscanf (datei, "%s", dbcode[i]);
      s = strchr (dbcode[i], '=');
      *s = '\0';
      dbpath[i] = s + 1;
      printf ("Kat. %d: %s\n", i, dbpath[i]);
    }
  fclose( datei );              /* "eps.ini" */
  printf( "Katalog? " );
  gets( sbuf );
  thisdb = atoi( sbuf );
  thisdb %= m;
  /* Datenfeldnamen ermitteln: */
  for (i = 0; i < 256; i++)
    fieldname[i] = &leer;
  sprintf (sbuf, "JPC:jpc/%s.ini", dbcode[thisdb]);
  datei = fopen (sbuf, "r");
  getvalue (datei, "[SLIST]");
  do
    fgets( sbuf, 80, datei );
  while( strncmp (sbuf, "SEPARATOR", 9) != 0);
  separator = ibm_decode[ sbuf[10] ];
  linelen = getvalue (datei, "LINELEN");
  getvalue (datei, "[KATEGORIES]");
  m = getvalue (datei, "MAXKAT");
  n = 0;
  do
    {
      fgets (sbuf, 80, datei);
      if (strncmp (sbuf, "KAT", 3) == 0)
        {
          i = atoi (sbuf + 3);
          if ((s = strchr (sbuf, '@')))
            {
              strcpy (fnamebuf[n], s + 1);
              if ((s = strchr (fnamebuf[n], ',')))
                *s = '\0';
              fieldname[i] = fnamebuf[n];
              n++;
              if (dbugf)
                fprintf (dbugf, "%3d %s\n", i, fieldname[i]);
            }
        }
    }
  while (i < m);
  fieldname[39] = "Neuheit:";
  fieldname[41] = "Trägermedium:";
  if (!*fieldname[43])
    fieldname[43] = "Kategorie:";
  if (!*fieldname[82])
    fieldname[82] = "Bewertung:";
  fclose (datei);               /* "db_x.ini" */
  /* Indexnamen (entsprechen überwiegend den Datenfeldnamen): */
  sprintf (sbuf, "JPC:%s/%s.glb", dbpath[thisdb], dbpath[thisdb]);
  datei = fopen (sbuf, "r");
  reccnt = getvalue (datei, "RECCOUNT");
  recnumsize = getvalue (datei, "ART_NO_LEN");
  blksize = getvalue (datei, "HIT_BLOCK_LEN");
  indexes = getvalue (datei, "KEY_COUNT");
  n = 0;
  for (j = 0; j < indexes; j++)
    {
      do
        fscanf (datei, "%s", sbuf);
      while (strcmp (sbuf, "KEY:") != 0);
      fscanf (datei, "%s", indpath[MAXINDEX]);
      if (dbugf)
        fprintf (dbugf, "%s\r\e[10C", indpath[MAXINDEX]);
      indcode[MAXINDEX] = getvalue (datei, "KAT");
      switch( indcode[MAXINDEX] )
        {
        case 70:
          strcpy (indname[MAXINDEX], "Volltext");
          break;
        default:
          strcpy (indname[MAXINDEX], fieldname[indcode[MAXINDEX]]);
        }
      if( (s = strchr( indname[MAXINDEX], ':' )) )
        *s = '\0';              /* ggf. Doppelpunkt killen */
      if (dbugf)
        fprintf (dbugf, "\e[A\e[20C%s\n", indname[MAXINDEX]);
      /* Falls mehrere Indexe sich auf dasselbe Datenfeld beziehen, soll */
      /* sich nur der durchsetzen, der keine Wortfolgen enthält: */
      for (i = 0; i < n; i++)
        if (indcode[i] == indcode[MAXINDEX])
          break;
      if (i < n)
        {                       /* Nummer bereits vergeben. Wer hat recht? */
          do
            {
              fgets (sbuf, 80, datei);
            }
          while (strstr (sbuf, "PHRASE") == NULL);
          if (strchr (sbuf, 'Y'))
            i = n;              /* der alte darf bleiben */
        }
      else
        i = n++;                /* neues Feld anlegen */
      if (i < n)
        {
          strcpy (indpath[i], indpath[MAXINDEX]);
          strcpy (indname[i], indname[MAXINDEX]);
          indcode[i] = indcode[MAXINDEX];
        }
    }
  indexes = n;
  fclose (datei);
  fieldname[60] = &leer;
  fieldname[70] = &leer;        /* Tracks und Presse */
  strcpy( indshort, "KWTBLPMAVUR" );
  /* Sortiertabelle: */
  sprintf (sbuf, "JPC:%s/norm.stb", dbpath[thisdb]);
  datei = fopen (sbuf, "r");
  fread (sort, sizeof (char), 256, datei);
  fclose (datei);               /* jpcpop.glb */
  /* Speicher für die Bitmap reservieren: */
  if (selected != NULL)
    free (selected);
  selected = (char *) calloc (reccnt, sizeof (char));
  selcnt = 0;
  if (selected == NULL)
    {
      printf ("Fehler: kein Speicher für Bitmap (%ld Byte)\n", reccnt);
      exit (20);
    }
}


void info()
{
  printf ("\f \n\e[7m%35s%-35s\e[0m\n", "Recherche-Programm zum JPC Mu",
          "sik-/Video-Katalog auf CD-ROM");
  printf ("%32s%-38s\n", "Version ", version + 13);
  printf ("%35s%-35s\n\n", "© 1994-1997 Wilhelm Nöker <wn",
          "oeker@t-online.de>   FREEWARE");
  printf ("%35s%-35s\n", "CD-ROM: DM 39.95 bei JPC, Lübecke",
          "r Str. 9, 49124 Georgsmarienhütte");
  printf ("%35s%-35s\n", "Tel. 0180/525 1717, T-Online: *J",
          "PC#, Internet: http://www.jpc.de");
}


void help()
{
  int i;

  printf ("\nDatenbank: %s (%ld Datensätze). Indexnamen:",
          dbpath[thisdb], reccnt);
  for (i = 0; i < indexes; i++)
    {
      if ((i % 5) == 0)
        printf ("\n");
      printf ("\r\e[%dC", 15 * (i % 5) + 1);
      printf ("\e[2m%c\e[0m=%s", indshort[i], indname[i]);
    }
  printf ("\n%s%s\n", "Kommandos: Zeigen, s/Speichern, q/Quit, Neustart, ",
          "oder Suchanfrage, z. B.:");
  switch (thisdb)
    {
    case 0:
      printf (" t=berg?aga* |t=schneewa* &~v=heino &p<20 &l=88-99\n");
      break;
    case 1:
      printf (" l=?dd |l=9? &w=zauberfl* &~p<30\n");
      break;
    case 2:
      printf (" t=j |t=james &t=stewar? &l=1940-1950 &p<30\n");
      break;
    }
  printf ("weitere Einschränkung möglich durch: f/Finde <Wortfolge>\n");
  printf ("\e[2m%s\e[0m",
          "\e[3A\e[11CZ\e[7Cs\e[CS\e[10Cq\e[CQ\e[5CN\n\n\e[37Cf\e[CF\n");
}


void by_key()
{
  int ende = FALSE, saveme = FALSE;
  int i, j, k, m, ind, mode, op;
  char eing[200];
  char key0[80], key1[80];

  targets = 0;
  help ();
  while( !ende )
    {
      printf ("\n%ld.Kommando: ", selcnt);
      if( fgets( eing, 200, stdin ) == NULL )
        {
          printf("Hey!\n");
          break;
        }
      m = strlen (eing);
      i = 0;
      while (isspace (eing[i]))
        i++;
      if (i == m)
        help ();
      while (i < m && !ende)
        {
          /* Recherchekommando? */
          mode = 5;             /* Maske: 4=neue Auswahl? 2=negieren? 1=erw./_einschr.? */
          while (strchr ("&|~", eing[i]))
            {                   /* log. Operatoren? */
              switch (eing[i])
                {
                case '&':
                  mode &= 2;
                  break;
                case '|':
                  mode &= 2;
                  mode |= 1;
                  break;
                case '~':
                  mode |= 2;
                  break;
                }
              i++;
            }
          ind = -1;
          op = ' ';
          for (k = 0; k < indexes; k++)         /* Indexbezeichner */
            if (toupper (eing[i]) == indshort[k])
              ind = k;
          if (ind >= 0)
            {                   /* Vergleichsoperator folgt */
              i++;
              op = eing[i++];
            }
          if (strchr ("<=>", op))
            {
              j = k = i;
              while (isgraph (eing[j]))
                {
                  if (eing[j] == '-')
                    k = j + 1;
                  j++;
                }
              eing[j] = '\0';
              strcpy (key1, eing + k);
              if (k > i)
                {               /* Bereichsangabe mit '-'? */
                  eing[k - 1] = '\0';
                  strcpy (key0, eing + i);
                }
              else
                strcpy (key0, key1);
              i = j + 1;
              civilize (key0, indshort[ind] == 'P');
              civilize (key1, indshort[ind] == 'P');
              if (op == '>')
                strcpy (key1, "*");
              if (op == '<')
                strcpy (key0, "*");
              if (mode > 3)
                printf ("neue");
              else if (mode & 1)
                printf ("erweiternde");
              else
                printf ("einschränkende");
              printf (" Auswahl: %s%s%s",
                      indname[ind], (mode & 2) ? "<>" : "=", key0);
              if (strcmp (key0, key1) != 0)
                printf ("-%s", key1);
              printf ("\n");
              if (mode & 4)
                clr_select ();
              hunt (ind, key0, key1);
              printf ("Auswertung ... ");
              fflush (stdout);
              eval_select (mode & 3);
              printf ("%ld Datensätze\n", selcnt);
              if (mode & 4)     /* neue Auswahl, gemerkte Stichwörter löschen */
                targets = 0;
              /* Stichwörter, die sich auf die großen Textblöcke beziehen, merken: */
              if (strchr ("TV", indshort[ind]) && strcmp (key0, key1) == 0
                  && (mode & 2) == 0 && targets < MAXTARGET)
                strcpy (target[targets++], key0);
            }
          else
            {                   /* kein Recherchekommando gefunden */
              switch (eing[i])
                {
                case 'z': case 'Z':
                  if (selcnt > 0)
                    browse();
                  break;
                case 'q': case 'x':
                  saveme = TRUE;
                case 'Q': case 'X':
                  ende = TRUE;
                  break;
                case 's':
                  saveall (FALSE);
                  break;
                case 'S':
                  saveall (TRUE);
                  break;
                case 'n': case 'N':
                  info();
                  setup();
                  help();
                  selcnt = 0;
                  targets = 0;
                  break;
                case 'f': case 'F':
                  targets = 0;
                  k = i + 1;
                  do
                    {
                      j = k;
                      while (eing[j] && isspace (eing[j]))
                        j++;
                      k = j;
                      while (eing[k] && isgraph (eing[k]))
                        k++;
                      if (k > j)
                        {
                          strncpy (target[targets], eing + j, k - j);
                          target[targets][k - j] = '\0';
                          civilize (target[targets], FALSE);
                          targets++;
                        }
                    }
                  while (k > j && targets < MAXTARGET);
                  hand_auslese (eing[i] == 'F');
                  break;
                default:
                  help ();
                }
              i = m;            /* "sonstiger Befehl" beendet die Eingabezeile */
            }
          while (isspace (eing[i]))
            i++;                /* zum nächsten Wort */
        }                       /* Ende einer Befehlszeile */
    }
  if( saveme )
    printf( "Fensterabmessungen in '%s' gesichert\n", writeconfig() );
}


char* write_config( char* s )
{
  FILE* config;

  config = fopen( s, "w" );
  fprintf( config, "%s\n%s\n%s\n%s\n%s\n%s\n", out1, out2, win0, win1, win2, win3 );
  fclose( config );
  return s;
}

char* writeconfig()
/* Fensterpositionen sichern, Rückgabewert: Name der Konfigdatei */
{
  if( envconfig )
    {
      write_config( "ENV:jpc.cfg" );
      return write_config( "ENVARC:jpc.cfg" );
    }
  else
    return write_config( "S:jpc.cfg" );
}


int main( int argc, char *argv[] )
{
  char sbuf[80], *s;
  int i, j, debugme = 0;
  FILE *config;

  /* Befehlszeile abarbeiten: */
  for (i = 1; i < argc; i++)
    {
      s = argv[i];
      if (*s == '-')
        switch (*++s)
          {
          case 'd':
            debugme = 1;
            break;
          default:
            cli_help (argv[0]);
            exit (5);
          }
      else
        {
          cli_help (argv[0]);
          exit (5);
        }
    }
  /* voreingestellte Dateinamen für Fenster und Ergebnisdateien: */
  strcpy (out1, "RAM:JPC-Kurzinfo");
  strcpy (out2, "RAM:JPC-Volltext");
  strcpy (win0, "CON:200/20/440/70/JPC-Debug-Info/INACTIVE");
  strcpy (win1, "RAW:0/11/580/245/aktuelle Auswahl");
  strcpy (win2, "RAW:200/0/430/256/Volltext");
  strcpy (win3, "RAW:50/100/540/80/JPC-Statusmeldung");
  config = fopen( "ENV:jpc.cfg", "r" );
  if( config != NULL )
    envconfig = 1;
  else
    config = fopen( "S:jpc.cfg", "r" );
  if (config)
    {
      for (i = 0; i < 6; i++)
        {
          fgets (sbuf, 80, config);
          for (j = strlen (sbuf) - 1; isspace (sbuf[j]); j--)
            sbuf[j] = '\0';
          switch (i)
            {
            case 0:
              strcpy (out1, sbuf);
              break;
            case 1:
              strcpy (out2, sbuf);
              break;
            case 2:
              strcpy (win0, sbuf);
              break;
            case 3:
              strcpy (win1, sbuf);
              break;
            case 4:
              strcpy (win2, sbuf);
              break;
            case 5:
              strcpy (win3, sbuf);
              break;
            }
        }
      fclose (config);
    }
  if (debugme)
    dbugf = fopen (win0, "r+");
  info ();
  setup ();
  by_key ();
  printf ("Und tschüß ...\n");
  if (dbugf)
    fclose (dbugf);
  return 0;
}
