/*************************************************************************\
  output.c:
        Klartextausgaben aus der Hauptdatenbank zum JPC-Programm
\*************************************************************************/

#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 out1[80], out2[80];        /* Namen der Ergebnisdateien */
char win1[80], win2[80], win3[80];      /* drei RAW:-Fenster */


void write_line(char line[], char splitword[], FILE *f, int style)
/* <line> nach <f> ausgeben, dabei auftretende target[]'s markieren */
/* <splitword> hilft, diese auch über Zeilengrenzen hinweg zu finden */
{
  char word[80];
  int i, j, k, sow, sol, hyphen;
  int found;
    
  hyphen = 0; /* Position eines evtl. Trennungsstrichs am Zeilenende */
  i = strlen(line);  while (i>0 && isspace(line[--i])) ;
  if (line[i] == '-') hyphen = i;
  i = 0; sol = 0; j = 0; sow = 0;
  do {
    if (line[i] && (isalnum(line[i]) || strchr("äöüßÄÖÜ", line[i]))) {
      if (j==0) sow = i;
      word[j++] = line[i];
    } else if (j>0) {   /* ein Wort zu Ende */
      word[j] = '\0'; civilize(word, FALSE);
      if (*splitword) {
        strcat(splitword, word); strcpy(word, splitword); 
        strcpy(splitword, "");
      }
      if (i==hyphen)
        strcpy(splitword, word);
      found = FALSE;
      for (k=0; k<targets; k++)
        if (match(target[k], word, TRUE)==0) 
          found = TRUE;
      if (found) {
        fprintf(f, "%.*s\e[%dm", sow-sol, line+sol, style);
        fprintf(f, "%.*s\e[0m", i-sow, line+sow);
        sol = i;
      }
      j = 0;
    }
  } while (line[i++]);
  fprintf(f, "%s\n", line+sol);
}


void long_entry(long recnum, FILE *f, int tagstyle, int hitstyle)
/* Eintrag aus der Hauptdatenbank ausgeben, */
/* für hitstyle!=PLAIN Stichwörter suchen und markieren */
{
  FILE *datf, *posf;
  char line[80], splitword[80];
  int c, i, j, len;
  long l;

  sprintf(line, "JPC:%s/data/%s.pos", dbpath[thisdb], dbpath[thisdb]);
  posf = fopen(line, "rb");
  fseek(posf, 4*recnum, SEEK_SET);
  l = getlong(posf);
  fclose(posf);
  sprintf(line, "JPC:%s/data/%s.dat", dbpath[thisdb], dbpath[thisdb]);
  datf = fopen(line, "rb");
  fseek(datf, l, SEEK_SET);
  /* ein Word lesen, ausnahmsweise Motorola-Format: */
  len = fgetc(datf)<<8; len |= fgetc(datf);
  j = 0; i = 2;
  strcpy(splitword, "");
  while (i<len) {
    c = fgetc(datf); i++;
    if (c==19) {        /* Zeilenende %-) */
      line[j] = '\0'; j = 0;
      if (hitstyle!=PLAIN && targets>0)
        write_line(line, splitword, f, hitstyle);
      else
        fprintf(f, "%s\n", line);
      c = fgetc(datf); i++;
      if (*fieldname[c]) {
        if (tagstyle!=PLAIN)
          fprintf(f, "\e[%dm%s\e[0m ", tagstyle, fieldname[c]);
        else
          fprintf(f, "%s ", fieldname[c]);
      }
    } else
      line[j++] = ibm_decode[c];
  }
  line[j] = '\0';
  if (hitstyle!=PLAIN && targets>0)
    write_line(line, splitword, f, hitstyle);
  else
    fprintf(f, "%s\n", line);
  fclose(datf);
}


void short_entry(long recnum, FILE *f, int truncate)
/* Eintrag aus der Klartext-Liste (einzeilig) ausgeben */
{
  FILE *txtf;
  UBYTE *s, sbuf[80], line[80];

  sprintf(sbuf, "JPC:%s/data/%s.txt", dbpath[thisdb], dbpath[thisdb]);
  txtf = fopen(sbuf, "rb");
  fseek(txtf, linelen*recnum, SEEK_SET);
  fgets(line, 80, txtf);
  fclose(txtf);
  for (s = line; *s; s++)
    *s = ibm_decode[*s];
  while (isspace(*--s)) 
    *s = '\0';
  if (truncate>0) line[truncate] = '\0';
  fprintf(f, "%s\n", line);
}


void saveall(int full)
/* Speichert die in selected[] markierten Datensätze. */
/* Bei <full>=True werden long_entrys ausgegeben, sonst short_entrys. */
{
  char *name;
  FILE *datei;
  long l;

  name = (full) ? out2 : out1;
  printf("Speichern de%s, Ausgabedatei:\n%s\n", 
        (full) ? "s vollen Katalogtextes" : "r Bestellinformationen", name);
  datei = fopen(name, "a");
  if (!datei) {
    printf("Fehler - Datei konnte nicht geöffnet werden!\n"); 
    return;
  }
  ctrl_c = 0; signal(SIGINT, intercept);
  printf("Datensatz Nr. ");
  for (l=0; l<reccnt; l++)
    if (selected[l]) {
      printf("%5ld\b\b\b\b\b", l);
      if (full) 
        long_entry(l, datei, PLAIN, PLAIN);
      else  
        short_entry(l, datei, 0);
      if (ctrl_c) {
        printf("\n*** Abbruch");
        break;
      }
    }
  fclose(datei);
  printf("\n");
  signal(SIGINT, SIG_DFL);  /* wieder automatische Ctrl-C-Abfrage */
}


void saveone(long rec, int full)
/* Bei <full>=TRUE wird ein long_entry ausgegeben, sonst ein short_entry. */
{
  char *name;
  FILE *datei, *fenster;

  fenster = fopen(win3, "r+");
  name = (full) ? out2 : out1;
  fprintf(fenster, "\fSpeichern de%s, Ausgabedatei:\n%s\n",
        (full) ? "s vollen Katalogtextes" : "r Bestellinformationen", name);
  datei = fopen(name, "a");
  if (!datei)
    fprintf(fenster, "Fehler - Datei konnte nicht geöffnet werden!\n");
  else {
    if (full) 
      long_entry(rec, datei, PLAIN, PLAIN);
    else  
      short_entry(rec, datei, 0);
    fclose(datei);
    fprintf(fenster, "fertig, ");
  }                           
  fprintf(fenster, "bitte eine Taste drücken -> ");
  fgetc(fenster);
  fclose(fenster);
}   


void print(long rec, int full, FILE **pprt)
/* ähnlich saveone(), gibt aber immer nach "PRT:" aus */
/* öffnet <printer>, falls nötig, schließt ihn aber *nicht* wieder */
{
  FILE *fenster;

  fenster = fopen(win3, "r+");
  fprintf(fenster, "\fDrucken de%s nach PRT:\n",
        (full) ? "s vollen Katalogtextes" : "r Bestellinformationen");
  if (!*pprt)
    *pprt = fopen("PRT:", "a");
  if (!*pprt)
    fprintf(fenster, "Fehler - Drucker nicht ansprechbar!\n");
  else {
    if (full) 
      long_entry(rec, *pprt, UNDERLINE, PLAIN);
    else  
      short_entry(rec, *pprt, 0);
  }
  fclose(fenster);
}   


void keyhelp(void)
/* Fenster mit Informationen zur Tastaturbelegung öffnen */
{
  FILE *fenster;

  fenster = fopen(win3, "r+");
  fprintf(fenster, "\n\e[7mTastaturbelegung:\e[0m\n");
  fprintf(fenster, "\e[2mCrsr, F1 - F10:\e[0m Datensätze durchblättern\n");
  fprintf(fenster, "\e[2mReturn:\e[0m Volltext-Fenster öffnen/schließen\n");
  fprintf(fenster, "\e[2ms/S:\e[0m Datensatz als Kurzinfo/Volltext speichern\n");
  fprintf(fenster, "\e[2mp/P:\e[0m Datensatz als Kurzinfo/Volltext drucken\n");
  fprintf(fenster, "\e[2mEsc:\e[0m Betrachten der Datensätze beenden\n");
  fgetc(fenster);
  fclose(fenster);
}


void browse(void)
/* Ausgewählte Liste anzeigen */
{
  FILE *raw, *raw2=NULL, *printer=NULL;
  long *records;
  char s[80];
  long k, l, delta, move, dest, akt=0, offset=0;
  int i, j, lines, cols;
  int c;

  records = (long *) calloc(selcnt, sizeof(long));
  if (records == NULL) {
    printf("Auswahl zu groß, kein Speicher für Datensatzliste (%ld Byte)\n", 
        selcnt*sizeof(long));
    return;
  }
  for (l=0, k=0; l<reccnt && k<selcnt; l++)
    if (selected[l])
      records[k++] = l;
  raw = fopen(win1, "r+");
  fprintf(raw, "\e[0 p"); /* Cursor unsichtbar */
  fprintf(raw, "\e[12{"); /* über neue Fenstergröße benachrichtigen */
  fprintf(raw, "\e[ q");  /* und Fensterausmaße anfordern */
  do {
    dest = akt;
    *s = '\0'; c = (raw2) ? fgetc(raw2) : fgetc(raw);
    switch (c) {  
      case 13: if (raw2) {      /* Return: Volltext anzeigen/schließen */
          fclose(raw2); raw2 = NULL;
        } else {
          raw2 = fopen(win2, "r+"); 
          long_entry(records[akt], raw2, INVERSE, HILITE);
        } break;
      case 's': saveone(records[akt], FALSE); break;
      case 'S': saveone(records[akt], TRUE); break;
      case 'p': print(records[akt], FALSE, &printer); break;
      case 'P': print(records[akt], TRUE, &printer); break;
      case 155:         /* ESC-Sequenz */
        i = 0; do {
          s[i++] = c = (raw2) ? fgetc(raw2) : fgetc(raw);
        } while (c<'@'); s[i] = '\0';
        if (c=='|') {           /* Fenstergröße wurde verändert */
          fprintf(raw, "\e[ q");
        } else if (c=='r') {    /* Fensterabmessungen lesen */
          for (i=0; s[i]; i++)
            if (!isdigit(s[i])) s[i] = ' ';
          sscanf(s, "%d%d%d%d", &i, &j, &lines, &cols);
          lines -= i; cols -= j;
          akt = -1;     /* Neuaufbau erzwingen */
        } else if (c=='~') {   
          if (s[0] == '?')      /* Help-Taste */
            keyhelp();
          else          /* F-Taste: prozentualer Sprung */
            dest = ((s[0]-'0')*(selcnt-1)) / 9;
        } else {
          switch (s[0]) {
            case 'A': dest = akt-1; break;          /* Cursor hoch */
            case 'B': dest = akt+1; break;          /* Cursor runter */
            case 'C': dest = akt+lines-1; break;    /* Cursor rechts */
            case 'D': dest = akt-lines+1; break;    /* Cursor links */
            case 'S': dest = akt+5; break;          /* Shift-Cursor hoch */
            case 'T': dest = akt-5; break;          /* Shift-Cursor runter */
          }
        }
        break;
      default:          /* irgendeine Taste */
        if (raw2) {
          fclose(raw2); raw2 = NULL;
          /* ESC soll nicht beide Fenster auf einmal schließen können: */
          if (c=='\e')  c = ' ';
        } break;
    }
    if (dest<0) dest = 0;
    if (dest>=selcnt) dest = selcnt-1;
    delta = dest - akt;
    /* Wie weit muß der Bildschirmausschnitt verschoben werden? */
    move = 0;
    if (dest<offset)  move = dest-offset;
    if (dest>=offset+lines)  move = dest-(offset+lines-1);
    /* Markierungen aufheben: */
    if (akt>=offset)
      fprintf(raw, "\e[%ld;1H ", akt-offset+1);
    if (move>0) 
      fprintf(raw, "\e[%d;1H\e[K", lines+1);
    offset += move;
    if (akt<0)  move = lines;   /* naja, tut halt was es soll */
    akt = dest; 
    if (move>=lines || -move>=lines) {       /* kompletter Neuaufbau */
      fprintf(raw, "\f"); i = 1; j = lines;
    } else if (move<0) {        /* abwärts scrollen */
      fprintf(raw, "\e[%ldT", -move); i = 1; j = -move;
    } else if (move>0) {        /* aufwärts scrollen */
      fprintf(raw, "\e[%ldS", move); i = lines-move+1; j = lines;
    } else {                    /* nur neu markieren */
      fprintf(raw, "\e[%ld;1H>", akt-offset+1); i = 1; j = 0;
    }
    fprintf(raw, "\e[%d;1HNr. %ld/%ld\e[K", lines+1, akt+1, selcnt);
    fflush(raw);
    /* Zeilen neu aufbauen: */
    while (i<=j) {
      k = i + offset - 1;
      fprintf(raw, "\e[%d;1H%c", i, (k==akt) ? '>' : ' ');
      if (k<selcnt)
        short_entry(records[k], raw, cols);
      i++;
    }
    if (raw2 && delta != 0) {
      /* beim Blättern Volltext aktualisieren */
      fprintf(raw2, "\f"); long_entry(records[akt], raw2, INVERSE, HILITE);
    }
  } while (c != '\e');
  fclose(raw);
  if (printer)
    fclose(printer);
  free(records);
}

