PROGRAM VideoText;
FROM vt USES startup,info; {$opt q,s+,i+ }
{ Hauptprogramm/Ereignisverwaltung zum Projekt VideoText }

CONST version = '$VER: VideoText 4.2  (29.06.95)';

{          global  i2c_serial  sys }
{         /  |   \   /        /    }
{ pagelist decode cct        /     }
{       \    |    /         /      }
{        bildschirm _______/       }
{            |                     }
{          datei                   }
{            |                     }
{           jobs                   }
{          /   \                   }
{      info    startup             }
{                                  }
{  HAUPTPROGRAMM VIDEOTEXT         }

VAR l: Long;
    testing: Boolean;
    roundrobin: Byte;
    eingabe,inputname: Str80;
    taste,ch: Char;
    j,toprequest,top_pending: Integer;

PROCEDURE topscan1;
{ schaut, ob die TOP-Seiten 1F0/1F1 schon da sind }
VAR pg1,pg2: p_onepage;
    hilf: p_onepage;
    i: Integer;
    refresh,schluss,save_fifo: Boolean;
BEGIN
  pg1 := hunt_in_list($1F0,0,False);
  IF (pg1<>Nil) THEN IF pg1^.pg<>$1F0 THEN pg1 := Nil;
  pg2 := hunt_in_list($1F1,0,True);
  IF (pg1<>Nil) AND (pg2<>Nil) THEN BEGIN
    busy_pointer; topinfo(pg1,pg2); normal_pointer;
    IF toprequest=1 THEN BEGIN   { gwöhnliche TOP-Text-Auswahl }
      { Anzahl TOP-Seiten aus 1F0 ermitteln }
      top_pending := 0; i := 840; schluss := False;
      REPEAT
        CASE topcode[pg1^.chars[i]] OF { Magazinnummer }
          14: { Don't Care } ;
          15: schluss := True;
          16: { ungültige Ziffer } ;
          OTHERWISE IF topcode[pg1^.chars[i+7]]=2 THEN Inc(top_pending);
        END;
        i := i + 8;
      UNTIL (i=960) OR schluss;
      IF top_pending>2 THEN BEGIN  { ggf. 1 Seite nachfordern }
        save_fifo := fifo; fifo := False;
        add_job('1f4',False);
        fifo := save_fifo;
        redraw_queue(-1);
      END;
    END ELSE BEGIN
      { "blinde" Seitenanforderung }
      busy_pointer; topgrab(pg1,pg2); normal_pointer;
      mainline; Write('Blockseiten angefordert');
    END;
    refresh := (pg1=visblpage) OR (pg2=visblpage);
    del_from_list(pg1); hilf := pg2^.next; del_from_list(pg2);
    update_list(hilf,-2);
    IF refresh THEN writepage(thispage,True);
    toprequest := 0;
  END;
END;

PROCEDURE topscan2;
{ Sind die TOP-Seiten 1F2, 1F3, 1F4 schon da? }
VAR pg: ARRAY[1..3] OF p_onepage;
    i,n: Integer;
BEGIN
  FOR i := 1 TO 3 DO
    IF top_pending>=i THEN
      pg[i] := hunt_in_list($1F1+i,0,True) ELSE pg[i] := Nil;
  n := 0;
  FOR i := 1 TO 3 DO IF pg[i]<>Nil THEN Inc(n);
  IF n=top_pending THEN BEGIN  { alle in 1F0 angekündigten Seiten da? }
    sleep; topselect(pg[1],pg[2],pg[3]);
    top_pending := 0;
    FOR i := 1 TO 3 DO
      IF pg[i]<>Nil THEN  del_from_list(pg[i]);
    redraw_all; wakeup;
  END;
END;

PROCEDURE handle_escseq(VAR s: str80);
{ für die ESC-Sequenzen der Sondertasten }
VAR i: integer;
    len,code,ft: Integer;
    pg1,pg2: p_onepage;
    save_fifo: Boolean;
BEGIN
  mainline;
  len := Length(s);
  IF (s[len]='~') AND (s[1] IN ['0'..'9']) THEN BEGIN    { *** F-Tasten }
    code := Ord(s[1])-48;
    IF len>2 THEN code := 10*code + Ord(s[2])-48;
    Inc(code); { Sorry, ich verlier sonst den Überblick }
    CASE code OF
    1: TV_display(0); { F1: Fernsehdarstellung ganz aus }
    11: TV_display(2); { Shift-F1: Vollbild }
    2: BEGIN   { F2: Decoder-Reset }
        init_CCT; Write('Decoder-Reset ausgef}hrt'); redraw_queue(-1);
      END;
    4: BEGIN  { F4: Dateiformat }
        asciifile := NOT asciifile; fileinfo;
      END;
    5: BEGIN { F5: app/ovwr }
        overwrite := NOT overwrite; fileinfo;
      END;
    15: BEGIN { Shift-F5: mit/ohne Icon }
        withicon := NOT withicon; fileinfo;
      END;
    6,16: BEGIN  { F6/Shift-F6: TOP-Text Kram }
        Write('TOP-Seiten angefordert'); top_pending := 0;
        save_fifo := fifo; fifo := False;
        IF code=16 THEN BEGIN
          add_job('1f3',False); add_job('1f2',False); toprequest := 1;
        END ELSE
          toprequest := 2;
        add_job('1f1',False); add_job('1f0/*',False);
        fifo := save_fifo;
        redraw_queue(-1);
      END;
    7: BEGIN { F7: alle Jobs löschen }
        queued := 0;
        FOR i := 0 TO maxactive-1 DO BEGIN
          activejobs[i].pg := 0;
          sperren(i);
        END;
        thisjob := 0;
        redraw_queue(-1);
      END;
    17: BEGIN { Shift-F7: alle Seiten löschen }
        sleep; Write('Alle Seiten wegwerfen? ');
        IF ja_nein THEN BEGIN
          kill_list; thispage := Nil;
          writepage(Nil,True); redraw_list;
        END;
        wakeup;
      END;
    8: IF queued>0 THEN BEGIN { F8: LIFO/FIFO-Umschaltung }
        fifo := NOT fifo; redraw_queue(-1);
      END;
    9,19: BEGIN { (Shift-)F9: VT.config/VT2.config editieren }
        mainline; Write('Editor-Aufruf ... ');
        busy_pointer; edconfig(code DIV 10 + 1);
        normal_pointer;
      END;
    10,20: BEGIN { (Shift-)F10: VT.config/VT2.config lesen }
        busy_pointer; getconfig(code DIV 10);
        normal_pointer;
      END;
    OTHERWISE Write('f}r Anleitung '#155'2mHELP'#155'0m dr}cken!');
    END;
  END; { Ende F-Tasten }
  IF (s='?~') THEN create_help;  { Help }
  { *** Cursor: Listen durchblättern }
  IF s[1] IN ['A'..'D','S','T'] THEN
    IF jobcursor THEN BEGIN    { Warteschlange blättern }
      mark_queue(False);
      CASE s[1] OF
        'A': Inc(thisjob);
        'B': Dec(thisjob);
        'C': thisjob := -queued;
        'D': thisjob := maxactive-1;
        'S': thisjob := thisjob - 5;
        'T': thisjob := thisjob + 5;
        OTHERWISE;
      END;
      IF thisjob<-queued THEN thisjob := -queued;
      IF thisjob>=maxactive-1 THEN thisjob := maxactive-1;
      mark_queue(True);
      IF thisjob>=0 THEN BEGIN
        aktspeicher := thisjob; display_select(aktspeicher); END;
    END ELSE BEGIN      { Seitenliste blättern }
      mark_list(False);
      IF thispage<>Nil THEN CASE s[1] OF
        'A': IF (thispage^.prev<>Nil) THEN
            thispage := thispage^.prev;
        'B': IF (thispage^.next<>Nil) THEN
            thispage := thispage^.next;
        'C': FOR i := 1 TO colht DO
          IF (thispage^.next<>Nil) THEN
            thispage := thispage^.next;
        'D': FOR i := 1 TO colht DO
          IF (thispage^.prev<>Nil) THEN
            thispage := thispage^.prev;
        'S': thispage := next_magazine(thispage);
        'T': thispage := prev_magazine(thispage);
        OTHERWISE;
      END;
      mark_list(True);
      writepage(thispage,True);
    END;
END;

PROCEDURE handle_key(key: Char);
{ der Übersichtlichkeit halber aus dem Hauptprogramm herausgezogen }
VAR j,ft: Integer;
    s: Str80;
    l: Long;
    ok: Boolean;
BEGIN
  mainline;
  CASE key OF
    '0'..'9','/','*','.','!': IF Length(eingabe) < 8 THEN
        eingabe := eingabe + key;
    #8: IF Length(eingabe) > 0 THEN
        eingabe[Length(eingabe)] := #0;
    #13: BEGIN
        add_job(eingabe,True);
        redraw_queue(-1);
        eingabe := '';
      END;
    #9: BEGIN  { Tab: Cursor zwischen Jobliste und Seitenliste umschalten }
        jobcursor := NOT jobcursor;
        mark_queue(jobcursor); mark_list(NOT jobcursor);
      END;
    #127: IF jobcursor THEN BEGIN  { Del: Job löschen }
        IF thisjob>=0 THEN BEGIN
          activejobs[thisjob].pg := 0;
          sperren(thisjob);
          redraw_queue(thisjob);
        END;
        IF (thisjob<0) AND (-thisjob<=queued) THEN BEGIN
          FOR j := -thisjob TO queued-1 DO
            queue[(firstinq+j-2) MOD qlen + 1] :=
              queue[(firstinq+j-1) MOD qlen + 1];
          Dec(queued);
          IF thisjob<0 THEN Inc(thisjob);
          redraw_queue(-1);
        END;
      END ELSE IF thispage<>Nil THEN BEGIN  { bzw. eine Seite löschen }
          del_from_list(thispage);
          update_list(thispage,-1);
          writepage(thispage,True);
        END;
    'x': BEGIN
        sleep;
        Write('Wirklich aufh|ren? ');
        IF ja_nein THEN stop := True;
        wakeup;
      END;
    't': BEGIN
        testing := not testing;
        IF NOT testing THEN test(False);
      END;
    'T': IF testing THEN BEGIN
        sleep; { Uhrzeit umstellen kann 'Zeit kosten' }
        gettime(aktspeicher,s); force_time(s);
        wakeup; Write('Systemzeit von VT }bernommen');
      END;
    'l': BEGIN
        sleep; IF fileselect('VT-Seiten laden',False,inputname) THEN
          IF filetype(inputname)=1 THEN BEGIN
            busy_pointer; Write(getpages(inputname)); normal_pointer;
            Write(' Seiten gelesen'); redraw_list; writepage(thispage,True);
          END ELSE
            Write('keine VT-Seitendatei, sorry');
        wakeup;
      END;
    's','S',#19: BEGIN
        sleep; { save_action enthält meist Rückfragen }
        j := Pos(key,'sS'#19);
        IF save_action(thispage,j)<>0 THEN; { nicht gespeichert :-( }
        wakeup;
      END;
    'i': BEGIN   { IFF-Bild }
        sleep;
        IF fileselect('IFF-Bild speichern',True,iffpicname) THEN BEGIN
          IF filetype(iffpicname)<>-1 THEN BEGIN
            j := Length(iffpicname) - 17;
            Write('"'); IF j>1 THEN BEGIN
              Write('...',Copy(iffpicname,j,16));
            END ELSE
              Write(iffpicname);
            Write('" }berschreiben'); ok := ja_nein;
          END ELSE
            ok := True;
          IF ok THEN BEGIN
            l := colperm;  colperm := $01234567;
            s := colperms; colperms := '01234567';
            REPEAT writepage(visblpage,concealed); UNTIL stop OR NOT incomplete;
            mainline; Write('IFF-Bild ... '); busy_pointer;
            IF iffdump THEN Write('gespeichert')
              ELSE Write(#155'2mDateifehler!');
            normal_pointer;
            colperm := l; colperms := s; writepage(visblpage,concealed);
          END;
        END;
        wakeup;
      END;
    'P': IF thispage<>Nil THEN BEGIN
        sleep; busy_pointer;
        Write('Seite wird gedruckt ... ');
        IF printpage(thispage) THEN Write('OK.')
        ELSE Write(#155'2mFehler!');
        normal_pointer; wakeup;
      END;
    'n': BEGIN { Sendernamen anzeigen }
        IF activejobs[0].pg=0 THEN BEGIN
          anfordern(0,100,0,%000);
          j := 50; REPEAT Delay(1); Dec(j) UNTIL seite_da(0) or (j=0);
        END;
        gethead(0,s);
        IF activejobs[0].pg=0 THEN sperren(0);
        Write('Sender: '#155'2m',s);
      END;
    'N': BEGIN
        sleep;
        IF fileselect('Ausgabedatei festlegen',True,outputname) THEN;
        fileinfo;
        wakeup;
      END;
    ' ': writepage(thispage,True);
    '?': writepage(thispage,False);
    '#': IF root<>Nil THEN BEGIN
          busy_pointer; dump_numbers; normal_pointer;
          Write('Seitennummern als Clip gespeichert');
        END;
    #155: BEGIN { Sondertasten auswerten }
        s := '';
        REPEAT  ch := readkey; s := s + ch;  UNTIL ch >= '@';
        handle_escseq(s);
      END;
    OTHERWISE Write('f}r Anleitung '#155'2mHELP'#155'0m dr}cken!');
  END;
END;

PROCEDURE handle_click;
{ angeklickte Seitennummern aufsuchen/anfordern }
VAR nr: Integer;
    pg: p_onepage;
    code: Char;
BEGIN
  mouseclicked := False;
  nr := number_from_page(clickedx,clickedy);
  IF nr>=0 THEN BEGIN   { Nummer in einer Seite angeklickt }
    pg := hunt_in_list(nr,0,False);
    IF pg<>Nil THEN IF pg^.pg<>nr THEN pg := Nil;
    IF (pg<>Nil) AND (pg<>thispage) THEN BEGIN  { Seite nur anspringen }
      mark_queue(False); jobcursor := False;
      mark_list(False); thispage := pg; mark_list(True);
      writepage(thispage,True);
    END ELSE IF nr IN [$100..$899] THEN BEGIN    { Seite (neu) anfordern }
      add_job(IntStr(bcd(nr)),False); redraw_queue(-1);
    END;
    Exit;
  END;
  pg := page_from_list(clickedx,clickedy);
  IF pg<>Nil THEN BEGIN
    mark_queue(False); jobcursor := False;
    mark_list(False); thispage := pg; mark_list(True);
    writepage(thispage,True);
    Exit;
  END;
  nr := pos_from_queue(clickedx,clickedy);
  IF nr<maxactive THEN BEGIN
    mark_list(False); jobcursor := True;
    mark_queue(False); thisjob := nr; mark_queue(True);
    Exit;
  END;
  code := click_action(clickedx,clickedy);
  CASE code OF
    'T': BEGIN
        testing := NOT testing;
        IF NOT testing THEN test(False);
      END;
    'J': IF queued>0 THEN BEGIN
        fifo := NOT fifo; redraw_queue(-1);
      END;
    'S': IF (queued=0) AND (active=0) THEN BEGIN
        add_job('100/*',True); redraw_queue(-1);
      END;
    'D': BEGIN
        sleep; IF fileselect('Ausgabedatei festlegen',True,outputname) THEN;
        fileinfo; wakeup;
      END;
    'F': BEGIN  asciifile := NOT asciifile; fileinfo;  END;
    'M': BEGIN  overwrite := NOT overwrite; fileinfo;  END;
    'I': BEGIN  withicon  := NOT withicon;  fileinfo;  END;
    '+','-': IF thispage<>Nil THEN BEGIN
        mark_queue(False); jobcursor := False; mark_list(False);
        IF (code='-') AND (thispage^.prev<>Nil) THEN
          thispage := thispage^.prev;
        IF (code='+') AND (thispage^.next<>Nil) THEN
          thispage := thispage^.next;
        mark_list(True);
        writepage(thispage,True);
      END;
    OTHERWISE;
  END;
END;

BEGIN  { Hauptprogramm }
  { Eine Menge Variablen werden bereits in den Units, wo sie auch deklariert }
  { sind, initialisiert. }
  get_args; inputname := outputname;
  colperm := $13675402; colperms := '13675402';
  AddExitServer(sysclean); sysinit(version);
  paraminfo; say_hello(version); thispage := root; { zwei Info-Seiten erzeugen }
  init_CCT; { SAA 5246 initialisieren }
  active := 0; FOR j := 0 TO maxactive-1 DO activejobs[j].pg := 0;
  roundrobin := 0; testing := False; stop := False;
  toprequest := 0; top_pending := 0;
  lastkey := #0;  eingabe := '';
  cursoroff;
  redraw_all;
  REPEAT
    space_in_queue; IF queued<qlen THEN Write(eingabe,#155'7m '#155'0m ');
    IF lastkey=#0 THEN  taste := readkey
    ELSE BEGIN  taste := lastkey; lastkey := #0;  END;
    IF taste<>#0 THEN
      handle_key(taste)
    ELSE BEGIN
      Delay(5);  { Multitasking-freundlich! }
      IF incomplete THEN writepage(thispage,True);
      IF toprequest>0 THEN topscan1;
      IF top_pending>0 THEN topscan2;
      IF testing THEN test(True);
      IF queued>0 THEN handle_queue;
      IF active>0 THEN BEGIN
        handle_jobs;
        attempt_input(roundrobin);
        roundrobin := (roundrobin+1) MOD maxactive;
      END;
      IF NOT testing AND (toprequest+top_pending=0) AND (queued+active=0)
        AND (lastkey=#0) AND NOT stop THEN  { nichts mehr zu tun :-) }
        l := Wait(-1);
    END;
    intui_events;
    IF mouseclicked THEN handle_click;
  UNTIL stop;
  SetStdIO(Nil); CloseConsole(Con);
  kill_list; sysclean;
END.

