(*********************************************************************
  :Program.    SpellChecker.mod
  :Contents.   Program for checking Textfile for correct writing
  :Author.     Stefan Salewski
  :Copyright.  PD
  :Language.   Modula-2
  :Translator. M2Amiga AMSoft V3.3d
  :History.    V1.0 1.Mar.1990
  :Address.    Stolper Weg 3, D-2160 Stade
  :Imports.    TurboFilesV1.1, Assembler2V1.1 (my own)
  :Imports.    MemSystem (Nicolas Benezan)
  :Imports.    Sound, ARPFileReq, IntuiPointer (Bernd Preussing)
*********************************************************************)

MODULE SpellChecker;
  FROM Arts IMPORT Assert,Requester,TermProcedure;
  FROM Assembler2 IMPORT MinInt,MaxInt;
  FROM ARPFileReq IMPORT FileReq;
  FROM Conversions IMPORT ValToStr;
  FROM Exec IMPORT UByte,WaitPort,GetMsg,ReplyMsg;
  FROM Graphics IMPORT jam2,jam1,RectFill,SetDrMd,SetAPen,Text,Move;
  FROM Intuition IMPORT OpenWindow,CloseWindow,NewWindow,WindowPtr,
       IDCMPFlags,IDCMPFlagSet,WindowFlags,WindowFlagSet,Border,StringInfo,
       ScreenFlags,ScreenFlagSet,Gadget,GadgetFlags,GadgetFlagSet,
       ActivationFlags,ActivationFlagSet,IntuiText,boolGadget,strGadget,
       RefreshGadgets,OnGadget,OffGadget,IntuiMessagePtr,GadgetPtr,
       ActivateGadget,AddGList,RemoveGList;
  FROM IntuiPointer IMPORT Busy,Normal;
  FROM Lexi IMPORT SearchString,ExpandLex,SaveLex,LoadLex,ReadWord,InfoSet,
       WordsInLex,InitLex,CleanLex,MinCount,MaxCount,InsertWord,Word,
       MinWordLength,MaxWordLength,ExportLex,IsCap,DeleteWord,Infos;
  FROM Sound IMPORT Sound;
  IMPORT Str;
  FROM Strings IMPORT Insert,Delete;
  FROM SYSTEM IMPORT ADR,BYTE,BITSET,LONGSET,CAST;
  FROM TurboFiles IMPORT FilePtr,Lookup,CloseFile,ReadOnly,TurboResult,
       TurboSetPos,TurboGetPos,SetPosMode,TurboRead,TurboWrite,NewFile,
       ReadWrite,DeleteFile;

  CONST
    StartMessage='Attention: Program needs ARP-Library & Device T:';
    LexName='Lexikon';
    TmpName='T:Lex.tmp';
    SaveText='Save File';
    LoadText='Load File';
    CheckText='Check Text';
    ExpandText='Add Words To Lex';
    CleanLexName='T:CleanLex.txt';
    TextName='';
    SaveLexText='Save Lexikon';
    LoadLexText='Load Lexikon';
    ExportText='Export Lexikon';
    WindowTitle='Spellchecker (c) 1990 by Stefan Salewski   ';
    TextLines=3;
    LeftEdge=20;
    TopEdge=20;
    StringLength=80;
    MaxCheckLength=80;
    CopyBufferSize=1024;
    MaxGadgets=10;
    Frame=16;
    YDis=4;
    GadgetHeight=20;
    GadgetWidth=12*8;
    TextHeight=8;
    StrGadgetHeight=9;
    InfoHeight=12;
    TitelHeight=11;
    BL=2;
    WindowWidth=4*GadgetWidth+5*Frame;
    WindowHeight=TextLines*TextHeight+3*GadgetHeight+
                 6*YDis+TitelHeight+Frame DIV 2;
    CharWidth=8;
    LineLength=(WindowWidth-2*Frame) DIV CharWidth;
    BufferSize=(TextLines+1)*LineLength;
    GT0='AddToLex';
    GT0a='Delete It';
    GT1='Ignore';
    GT2='LoadLex';
    GT3='SaveLex';
    GT4='CheckText';
    GT5='Del.Words';
    GT6='Quit';
    GT7='CleanLex';
    GT8='ExpandLex';
    GT9='Export';
    ADD=0;DIT=0;IGN=1;LOA=2;
    SAV=3;CHE=4;DEL=5;QUI=6;
    CLE=7;EPA=8;EPO=9;STR=10;
    Load=FALSE;
    Save=TRUE;
    TFRB=1024;
    TFWB=10240;

  TYPE
    InfoText=ARRAY[0..LineLength] OF CHAR;
    String=ARRAY[0..StringLength] OF CHAR;
    FileName=String;
    Line=[1..TextLines];
    Vertex=RECORD
            x,y:INTEGER
          END;
  VAR
    border1,border2,strBorder:Border;
    p:ARRAY[0..45] OF Vertex;
    pStr:ARRAY[0..4] OF Vertex;
    newWindow:NewWindow;
    wPtr:WindowPtr;
    gadget:ARRAY[0..MaxGadgets-1] OF Gadget;
    gText: ARRAY[0..MaxGadgets-1] OF IntuiText;
    stringGadget:Gadget;
    lexName:FileName;
    textName:FileName;
    exName:FileName;
    stringInfo:StringInfo;
    strBuf,undoStrBuf:String;
    minCount,maxCount:UByte;
    lexIsChanged:BOOLEAN;
    integer:INTEGER;

  PROCEDURE BeepOK;
  BEGIN
    Sound(6,3,50);
  END BeepOK;

  PROCEDURE BeepError;
  BEGIN
    Sound(10,0,500);
  END BeepError;

  PROCEDURE Exit;
  BEGIN
    IF wPtr#NIL THEN
      CloseWindow(wPtr);
      wPtr:=NIL;
    END
  END Exit;

  PROCEDURE Point(VAR c:CHAR;ok:CHAR);
  BEGIN
    IF (c#ok) AND ((c<=CHAR(31)) OR ((c>=CHAR(128)) AND (c<=CHAR(159)))) THEN
      c:='_'
    END
  END Point;

  PROCEDURE ClearTextArea;
  BEGIN
    SetAPen(wPtr^.rPort,1);
    RectFill(wPtr^.rPort,Frame,TitelHeight,
             WindowWidth-1-Frame,TitelHeight+TextLines*(TextHeight+YDis));
  END ClearTextArea;

  PROCEDURE DisplayText(VAR text:ARRAY OF CHAR;line:Line;pen:CARDINAL);
  BEGIN
    SetDrMd(wPtr^.rPort,jam1);
    SetAPen(wPtr^.rPort,pen);
    Move(wPtr^.rPort,Frame,TitelHeight-BL+line*(TextHeight+YDis));
    Text(wPtr^.rPort,ADR(text),Str.Length(text));
  END DisplayText;

  PROCEDURE Info(errorText:ARRAY OF CHAR);
    VAR
      text:ARRAY[0..WindowWidth DIV CharWidth] OF CHAR;
      num:ARRAY[0..6] OF CHAR;
      l:LONGCARD;
      error:BOOLEAN;
      line:Line;
  BEGIN
    ClearTextArea;
    line:=1;
    IF errorText[0]#0C THEN
      DisplayText(errorText,1,3);
      INC(line)
    END;
    text:='Words in Lexikon: ';
    l:=WordsInLex();
    ValToStr(CAST(LONGINT,l),FALSE,num,10,6,' ',error);
    Str.Concat(text,num);
    DisplayText(text,line,2);
    INC(line);
    text:='MinCount: ';
    l:=minCount;
    ValToStr(CAST(LONGINT,l),FALSE,num,10,3,' ',error);
    Str.Concat(text,num);
    Str.Concat(text,'    MaxCount: ');
    l:=maxCount;
    ValToStr(CAST(LONGINT,l),FALSE,num,10,3,' ',error);
    Str.Concat(text,num);
    DisplayText(text,line,2);
  END Info;

  PROCEDURE GadgetsOn(on:BITSET);
  BEGIN
    integer:=RemoveGList(wPtr,ADR(gadget[0]),-1);
    FOR integer:=0 TO MaxGadgets-1 DO
      IF integer IN on THEN
        EXCL(gadget[integer].flags,gadgDisabled);
      ELSE
        INCL(gadget[integer].flags,gadgDisabled);
      END;
    END;
    IF MaxGadgets IN on THEN
      EXCL(stringGadget.flags,gadgDisabled);
    ELSE
      INCL(stringGadget.flags,gadgDisabled);
    END;
    integer:=AddGList(wPtr,ADR(gadget[0]),-1,-1,NIL);
    RefreshGadgets(ADR(gadget[0]),wPtr,NIL);
  END GadgetsOn;

  PROCEDURE OpenMainWindow():WindowPtr;
    VAR
      nw:NewWindow;
       w:WindowPtr;
  BEGIN
    WITH nw DO
      leftEdge:=LeftEdge;
      topEdge:=TopEdge;
      width:=WindowWidth;
      height:=WindowHeight;
      detailPen:=-1;
      blockPen:=-1;
      idcmpFlags:=IDCMPFlagSet{gadgetUp,closeWindow};
      flags:=WindowFlagSet{windowDrag,windowDepth,windowClose,activate};
      firstGadget:=NIL;
      checkMark:=NIL;
      title:=ADR(WindowTitle);
      screen:=NIL;
      bitMap:=NIL;
      minWidth:=width;
      minHeight:=height;
      maxWidth:=width;
      maxHeight:=height;
      type:=ScreenFlagSet{wbenchScreen};
    END;
    w:=OpenWindow(nw);
    Assert(w#NIL,ADR("Can't open Window"));
    SetDrMd(w^.rPort,jam2);
    SetAPen(w^.rPort,1);
    RectFill(w^.rPort,4,TitelHeight,WindowWidth-1-4,WindowHeight-1-2);
    integer:=AddGList(w,ADR(gadget[0]),-1,-1,NIL);
    RefreshGadgets(ADR(gadget[0]),w,NIL);
    RETURN w
  END OpenMainWindow;

  PROCEDURE InitGadgets;
    VAR
      i,pos:INTEGER;
      x0,x1,y0,y1,dx,dy:INTEGER;
  BEGIN
    x0:=0;
    x1:=GadgetWidth-1-1;
    y0:=0;
    y1:=GadgetHeight-1;
    FOR i:=0 TO 7 DO
      p[0+i*5].x:=x0;
      p[0+i*5].y:=y0;
      p[1+i*5].x:=x1;
      p[1+i*5].y:=y0;
      p[2+i*5].x:=x1;
      p[2+i*5].y:=y1;
      p[3+i*5].x:=x0;
      p[3+i*5].y:=y1;
      p[4+i*5].x:=x0;
      p[4+i*5].y:=y0;
      IF i<2 THEN
        dx:=4;
        dy:=2;
      ELSE
        dx:=1;
        dy:=1;
      END;
      x0:=x0+dx;
      x1:=x1-dx;
      y0:=y0+dy;
      y1:=y1-dy;
    END;
    p[40]:=p[11];
    p[41]:=p[1];
    p[42]:=p[2];
    p[43]:=p[12];
    p[44]:=p[13];
    p[45]:=p[3];
    pStr[0].x:=0;
    pStr[0].y:=0;
    pStr[1].x:=2*GadgetWidth+Frame+1;
    pStr[1].y:=0;
    pStr[2].x:=2*GadgetWidth+Frame+1;
    pStr[2].y:=StrGadgetHeight;
    pStr[3].x:=0;
    pStr[3].y:=StrGadgetHeight;
    pStr[4].x:=0;
    pStr[4].y:=0;
    WITH border1 DO
      leftEdge:=0;
      topEdge:=0;
      frontPen:=2;
      backPen:=0;
      drawMode:=jam2;
      count:=46;
      xy:=ADR(p);
      nextBorder:=ADR(border2);
    END;
    border2:=border1;
    border2.leftEdge:=1;
    border2.nextBorder:=NIL;
    WITH strBorder DO
      leftEdge:=-1;
      topEdge:=-1;
      frontPen:=0;
      backPen:=0;
      drawMode:=jam2;
      count:=5;
      xy:=ADR(pStr);
      nextBorder:=NIL;
    END;
    FOR i:=0 TO MaxGadgets-1 DO
      WITH gadget[i] DO
        IF i<MaxGadgets-1 THEN
          nextGadget:=ADR(gadget[i+1])
        ELSE
          nextGadget:=ADR(stringGadget)
        END;
        IF i>0 THEN
          pos:=i+2
        ELSE
          pos:=i
        END;
        leftEdge:=Frame+(pos MOD 4)*(GadgetWidth+Frame);
        topEdge:=TextLines*TextHeight+TitelHeight+4*YDis+
                 (pos DIV 4)*(GadgetHeight+YDis);
        width:=GadgetWidth;
        height:=GadgetHeight;
        flags:=GadgetFlagSet{};
        activation:=ActivationFlagSet{relVerify};
        gadgetType:=boolGadget;
        gadgetRender:=ADR(border1);
        selectRender:=NIL;
        gadgetText:=ADR(gText[i]);;
        mutualExclude:=LONGSET{};
        specialInfo:=NIL;
        gadgetID:=i;
        userData:=NIL;
      END;
      WITH gText[i] DO
        frontPen:=1;
        backPen:=0;
        drawMode:=jam1;
        leftEdge:=12;
        topEdge:=6;
        iTextFont:=NIL;
        iText:=NIL;
        nextText:=NIL;
      END;
    END;
    gText[0].iText:=ADR(GT0);
    gText[1].iText:=ADR(GT1);
    gText[2].iText:=ADR(GT2);
    gText[3].iText:=ADR(GT3);
    gText[4].iText:=ADR(GT4);
    gText[5].iText:=ADR(GT5);
    gText[6].iText:=ADR(GT6);
    gText[7].iText:=ADR(GT7);
    gText[8].iText:=ADR(GT8);
    gText[9].iText:=ADR(GT9);
    WITH stringInfo DO
      buffer:=ADR(strBuf);
      undoBuffer:=ADR(undoStrBuf);
      bufferPos:=0;
      maxChars:=SIZE(strBuf);
      dispPos:=0;
    END;
    WITH stringGadget DO
      nextGadget:=NIL;
      leftEdge:=Frame+GadgetWidth+Frame;
      topEdge:=TitelHeight+TextLines*TextHeight+5*YDis;
      width:=2*GadgetWidth+Frame;
      height:=StrGadgetHeight;
      flags:=GadgetFlagSet{gadgDisabled};
      activation:=ActivationFlagSet{relVerify};
      gadgetType:=strGadget;
      gadgetRender:=ADR(strBorder);
      selectRender:=NIL;
      gadgetText:=NIL;
      mutualExclude:=LONGSET{};
      specialInfo:=ADR(stringInfo);
      gadgetID:=MaxGadgets;
      userData:=NIL;
    END;
    INCL(gadget[0].flags,gadgDisabled);
    INCL(gadget[1].flags,gadgDisabled);
  END InitGadgets;

  PROCEDURE LoadLexikon;
  BEGIN
    IF FileReq(lexName,NIL,LoadLexText,Load) THEN
      Busy(wPtr);
      IF LoadLex(lexName) THEN
        lexIsChanged:=FALSE;
        minCount:=MinCount();
        maxCount:=MaxCount();
        Info('Lexikon Loaded!');
        BeepOK
      ELSE
        Info('Error while loading Lexikon!');
        BeepError;
      END;
      Normal(wPtr);
    END;
  END LoadLexikon;

  PROCEDURE SaveLexikon;
  BEGIN
    IF FileReq(lexName,NIL,SaveLexText,Save) THEN
      Busy(wPtr);
      IF SaveLex(lexName) THEN
        lexIsChanged:=FALSE;
        Info('Lexikon saved!');
        BeepOK;
      ELSE
        Info('Error while saving Lexikon!');
        BeepError;
      END;
      Normal(wPtr);
    END;
  END SaveLexikon;

  PROCEDURE Export;
  BEGIN
    IF FileReq(exName,NIL,ExportText,Save) THEN
      Busy(wPtr);
      IF ExportLex(exName) THEN
        Info('Lexikon exported!');
        BeepOK;
      ELSE
        Info('Error while exporting Lexikon!');
        BeepError;
      END;
      Normal(wPtr);
    END;
  END Export;

  PROCEDURE ExamineText;
    VAR
      tmpName:FileName;
      infoText:InfoText;
      buffer:ARRAY[0..BufferSize] OF CHAR;
      sourcePtr,destPtr:FilePtr;
      pos:CARDINAL;
      len:LONGINT;
      word,copy:ARRAY[0..MaxCheckLength] OF CHAR;
      exit:BOOLEAN;
      info:InfoSet;
      isCap,error:BOOLEAN;
      sourceOpen,tmpOpen:BOOLEAN;

    PROCEDURE DisplayError;
      VAR
        line:Line;
        cp,newPos,oldPos,errorPos:LONGINT;
        actual,hhh,skip:LONGINT;
    BEGIN
      ClearTextArea;
      cp:=TurboGetPos(sourcePtr);
      skip:=MinInt(len+LineLength,cp);
      IF TurboSetPos(sourcePtr,-skip,current) THEN END;
      TurboRead(sourcePtr,ADR(buffer),BufferSize-1,actual);
      buffer[actual]:=0C;
      errorPos:=skip-len;
      hhh:=Str.FirstPos(buffer,0,'.');
      IF (hhh<0) OR (hhh>errorPos) THEN
        hhh:=Str.FirstPos(buffer,0,' ');
        IF (hhh<0) OR (hhh>errorPos) THEN
          hhh:=0
        END;
      END;
      FOR newPos:=0 TO actual-1 DO
        Point(buffer[newPos],' ')
      END;
      SetAPen(wPtr^.rPort,2);
      SetDrMd(wPtr^.rPort,jam1);
      FOR line:=1 TO TextLines DO
        Move(wPtr^.rPort,Frame,TitelHeight-BL+line*(TextHeight+YDis));
        newPos:=hhh;
        REPEAT
          oldPos:=newPos;
          newPos:=Str.FirstPos(buffer,oldPos+1,' ');
        UNTIL (newPos>hhh+LineLength) OR (newPos=-1);
        IF oldPos=hhh THEN oldPos:=hhh+LineLength END;
        IF oldPos>actual THEN
          oldPos:=actual
        END;
        WHILE hhh<oldPos DO
          IF hhh=errorPos THEN
            SetAPen(wPtr^.rPort,3)
          ELSIF
            hhh=errorPos+len THEN
            SetAPen(wPtr^.rPort,2)
          END;
          Text(wPtr^.rPort,ADR(buffer[hhh]),1);
          INC(hhh);
        END;
      END;
      IF sourcePtr^.res=endOfFile THEN
        sourcePtr^.res:=done
      END;
      IF TurboSetPos(sourcePtr,cp,beginning) THEN END;
    END DisplayError;

    PROCEDURE Ignore;
    BEGIN
    END Ignore;

    PROCEDURE Add;
      VAR
        w:Word;
        pos:CARDINAL;
        l:INTEGER;
    BEGIN
      (*
      LOOP
        l:=Str.FirstPos(strBuf,0,'-');
        IF l=-1 THEN
          EXIT
        ELSE
          Delete(strBuf,l,0)
        END;
      END;
      *)
      IF NOT SearchString(strBuf,pos,1) THEN
        IF (pos#0) AND (Str.Length(strBuf)<=MaxWordLength) THEN
          Str.Copy(w,strBuf);
          InsertWord(w,pos,2);
          lexIsChanged:=TRUE;
        END;
      END;
    END Add;

  PROCEDURE AddOrIgnore;
  VAR
    i:INTEGER;
    intuiMessagePtr:IntuiMessagePtr;
    class:IDCMPFlagSet;
    code:CARDINAL;
    gadgetPtr:GadgetPtr;
  BEGIN
    Str.Copy(strBuf,word);
    RefreshGadgets(ADR(stringGadget),wPtr,NIL);
    IF ActivateGadget(ADR(stringGadget),wPtr,NIL) THEN END;
    WaitPort(wPtr^.userPort);
    intuiMessagePtr:=GetMsg(wPtr^.userPort);
    class:=intuiMessagePtr^.class;
    code:= intuiMessagePtr^.code;
    IF TurboSetPos(destPtr,-LONGINT(len),current) THEN END;
    TurboWrite(destPtr,ADR(strBuf),Str.Length(strBuf));
    IF gadgetUp IN class THEN
      gadgetPtr:=intuiMessagePtr^.iAddress;
      i:=gadgetPtr^.gadgetID;
      ReplyMsg(intuiMessagePtr);
      CASE i OF
        |ADD:Add;
        |IGN:(*Ignore;*)
        |QUI:exit:=TRUE;
        |STR:(*Ignore;*)
      ELSE
        HALT;
      END;
    ELSE
      exit:=TRUE;
      ReplyMsg(intuiMessagePtr);
    END;
  END AddOrIgnore;

  PROCEDURE CopyFiles(VAR sourceName,destName:ARRAY OF CHAR):BOOLEAN;
    VAR
      buf:ARRAY[0..CopyBufferSize-1] OF BYTE;
      act:LONGINT;
      source,dest:FilePtr;
      ok:BOOLEAN;
  BEGIN
    ok:=FALSE;
    IF Lookup(source,sourceName,TFRB,ReadOnly)=done THEN
      IF Lookup(dest,destName,TFWB,NewFile)=done THEN
        WHILE (source^.res=done) DO
          TurboRead(source,ADR(buf),SIZE(buf),act);
          TurboWrite(dest, ADR(buf),act)
        END;
        ok:=(source^.res=endOfFile) AND (dest^.res=done);
        CloseFile(dest);
      END;
      CloseFile(source);
    END;
    RETURN ok;
  END CopyFiles;

  BEGIN
    tmpName:=TmpName;
    exit:=FALSE;
    IF FileReq(textName,NIL,CheckText,Save) THEN
      IF Lookup(sourcePtr,textName,TFRB,ReadOnly)#done THEN
        Info("Can't open Textfile!");
        BeepError;
        RETURN
      END;
      IF Lookup(destPtr,tmpName,TFWB,NewFile)#done THEN
        CloseFile(sourcePtr);
        Info("Can't open Tmp-File!");
        BeepError;
        RETURN
      END;
      GadgetsOn({ADD,IGN,QUI,STR});
      ClearTextArea;
      infoText:='Checking Text for WriteErrors';
      DisplayText(infoText,1,3);
      infoText:='If You select Quit or Close-Gadget,';
      DisplayText(infoText,2,3);
      infoText:='then the file will be NOT changed!';
      DisplayText(infoText,3,3);
      REPEAT
        ReadWord(sourcePtr,destPtr,word,info,MinWordLength,MaxCheckLength);
        IF word[0]#0C THEN
          isCap:=IsCap(word[0]);
          copy:=word;
          error:=(cap IN info) AND NOT isCap;
          IF NOT error THEN
            error:=NOT SearchString(copy,pos,1);
            IF error AND (cap IN info) (*AND isCap*) THEN
              copy:=word;
              INC(CAST(UByte,copy[0]),32);
              error:=NOT SearchString(copy,pos,1);
            END
          END;
          IF error THEN
            len:=Str.Length(word);
            DisplayError;
            BeepOK;
            AddOrIgnore;
          END;
        END;
      UNTIL (sourcePtr^.res#done) OR exit;
      CloseFile(sourcePtr);
      CloseFile(destPtr);
      minCount:=MinCount();
      maxCount:=MaxCount();
      IF NOT exit THEN
        IF CopyFiles(tmpName,textName) THEN
          Info('All errors corrected!');
          BeepOK;
        ELSE
          Info('Read-Write-Error');
          BeepError;
        END;
      ELSE
        Info('Abort: File is unchanged!');
        BeepOK;
      END;
      GadgetsOn({LOA..EPO});
      IF DeleteFile(tmpName) THEN END;
    END;
  END ExamineText;

  PROCEDURE DelWords;
  VAR
    w:Word;
    i:INTEGER;
    intuiMessagePtr:IntuiMessagePtr;
    class:IDCMPFlagSet;
    code:CARDINAL;
    gadgetPtr:GadgetPtr;
    infoText:InfoText;
  BEGIN
    infoText:='Type word to delete into StringGadget';
    ClearTextArea;
    DisplayText(infoText,1,3);
    infoText:='Click DeleteIt or press RETURN to delete';
    DisplayText(infoText,2,3);
    infoText:='Click Close- or Quit-Gadget to exit';
    DisplayText(infoText,3,3);
    gText[0].iText:=ADR(GT0a);
    GadgetsOn({DIT,IGN,QUI,STR});
    LOOP
      IF ActivateGadget(ADR(stringGadget),wPtr,NIL) THEN END;
      WaitPort(wPtr^.userPort);
      intuiMessagePtr:=GetMsg(wPtr^.userPort);
      class:=intuiMessagePtr^.class;
      code:= intuiMessagePtr^.code;
      IF gadgetUp IN class THEN
        gadgetPtr:=intuiMessagePtr^.iAddress;
        i:=gadgetPtr^.gadgetID;
        ReplyMsg(intuiMessagePtr);
        CASE i OF
          |ADD,STR:
            IF Str.Length(strBuf)<=MaxWordLength THEN
              Str.Copy(w,strBuf);
              IF DeleteWord(w) THEN
                lexIsChanged:=TRUE;
                Info('Wort deleted!');
                BeepOK;
              ELSE
                Info('Word NOT found!');
                BeepError;
              END;
            ELSE
              Info('Word NOT found!');
              BeepError;
            END;
          |IGN:
            Info('Word not Deleted!');
            BeepOK;
          |QUI:EXIT;
        ELSE
          HALT;
        END;
      ELSE
        ReplyMsg(intuiMessagePtr);
        EXIT
      END;
    END;
    minCount:=MinCount();
    maxCount:=MaxCount();
    Info('');
    BeepOK;
    gText[0].iText:=ADR(GT0);
    GadgetsOn({LOA..EPO});
  END DelWords;

  PROCEDURE Clean;
    VAR
      oldMinCount:CARDINAL;
      fileName:FileName;
  BEGIN
    Busy(wPtr);
    lexIsChanged:=TRUE;
    fileName:=CleanLexName;
    oldMinCount:=CleanLex(fileName);
    minCount:=MinCount();
    maxCount:=MaxCount();
    fileName:='Lexikon cleaned! (to ';
    Str.Concat(fileName,CleanLexName);
    Str.Concat(fileName,')');
    Info(fileName);
    Normal(wPtr);
    BeepOK;
  END Clean;

  (*
  PROCEDURE Words0;
  BEGIN
    InitLex;
    Info('Lexikon initialized!');
  END Words0;
  *)

  PROCEDURE Expand;
    VAR
      infoText:InfoText;
  BEGIN
    (*textName:=TextName;*)
    IF FileReq(textName,NIL,ExpandText,Load) THEN
      ClearTextArea;
      infoText:='Expanding Lexikon';
      DisplayText(infoText,1,2);
      infoText:='Please have some patience';
      DisplayText(infoText,2,2);
      GadgetsOn({});
      Busy(wPtr);
      IF ExpandLex(textName) THEN
        lexIsChanged:=TRUE;
        minCount:=MinCount();
        maxCount:=MaxCount();
        Info('Lexikon expanded!');
        BeepOK;
      ELSE
        Info("Can't expand Lexikon!");
        BeepError;
      END;
      Normal(wPtr);
      GadgetsOn({LOA..EPO});
    END
  END Expand;

  PROCEDURE ReallyExit():BOOLEAN;
  BEGIN
    RETURN NOT lexIsChanged OR
               Requester(ADR('Lexikon has been changed !'),
                         ADR('Will You go back to save it ?'),
                         ADR('Exit'),
                         ADR('Go Back'))
  END ReallyExit;

  PROCEDURE GetMessage;
    VAR
      i:INTEGER;
      intuiMessagePtr:IntuiMessagePtr;
      class:IDCMPFlagSet;
      code:CARDINAL;
      gadgetPtr:GadgetPtr;
  BEGIN
    LOOP
      WaitPort(wPtr^.userPort);
      intuiMessagePtr:=GetMsg(wPtr^.userPort);
      class:=intuiMessagePtr^.class;
      code:= intuiMessagePtr^.code;
      IF gadgetUp IN class THEN
        gadgetPtr:=intuiMessagePtr^.iAddress;
        i:=gadgetPtr^.gadgetID;
        ReplyMsg(intuiMessagePtr);
        CASE i OF
          (*|ADD:AddToLex;
          |IGN:Ignore;*)
          |LOA:LoadLexikon;
          |SAV:SaveLexikon;
          |CHE:ExamineText;
          |DEL:DelWords;
          |QUI:IF ReallyExit() THEN EXIT END;
          |CLE:Clean;
          |EPA:Expand;
          |EPO:Export;
          (*|STR:AddToLex;*)
        ELSE
          HALT
        END;
      ELSE
        ReplyMsg(intuiMessagePtr);
        IF ReallyExit() THEN EXIT END;
      END;
      REPEAT
        intuiMessagePtr:=GetMsg(wPtr^.userPort);
      UNTIL intuiMessagePtr=NIL;
    END;
  END GetMessage;

BEGIN
  lexIsChanged:=FALSE;
  minCount:=0;
  maxCount:=0;
  lexName:=LexName;
  textName:=TextName;
  exName:="";
  wPtr:=NIL;
  TermProcedure(Exit);
  InitGadgets;
  wPtr:=OpenMainWindow();
  Info(StartMessage);
  GadgetsOn({LOA..EPO});
  GetMessage;
END SpellChecker.

