#include <exec/types.h>
#include <exec/io.h>
#include <exec/memory.h>
#include <exec/ports.h>s
#include <exec/nodes.h>
#include <graphics/text.h>
#include <graphics/rastport.h>
#include <graphics/GfxBase.h>
#include <intuition/intuitionbase.h>
#include <intuition/intuition.h>
#include <libraries/dos.h>
#include <libraries/diskfont.h>
#include <devices/console.h>
#include <devices/narrator.h>
#include <proto/all.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define deBUG 0

/*This preparation subroutine is from RAM Kernel module p417*/

/* Wokbench pen color registers */
#define GREEN 0
#define BLACK 1
#define WHITE 2
#define RED   3

#define CLS SetAPen(rastPort, 2); RectFill(rastPort,0,0,640,200); \
            SetAPen(rastPort, 1); Move(rastPort, indentLeft+x, indentTop+y)
#define HPRINT(q)  Move(rastPort, indentLeft+x, indentTop+y); \
                   Text(rastPort, q, strlen(q));

/* do or don't wait for the user to click the close gadget before exiting */
#define WAIT_FOR_CLOSE FALSE
#define DONT_WAIT      TRUE

/* set title bar of window w to specified string s */
#define TITLE(w, s) (SetWindowTitles((w), (UBYTE *) (s), (UBYTE *)~0))

/* our functions */
void cleanexit(UBYTE *, LONG);
BYTE OpenConsole(struct IOStdReq *, struct IOStdReq *, struct Window *);
void CloseConsole(struct IOStdReq *);
void QRead(struct IOStdReq *, UBYTE *);
UBYTE ConGetChar(struct MsgPort *, UBYTE *);
LONG ConMayGetChar(struct MsgPort *, UBYTE *);
void ConPuts(struct IOStdReq *, UBYTE *);
void ConWrite(struct IOStdReq *, UBYTE *, LONG);
void ConPutChar(struct IOStdReq *, UBYTE);

/*Library pointers*/
struct GfxBase *GfxBase = NULL;
struct IntuitionBase *IntuitionBase = NULL;
struct Library *DiskfontBase = NULL;
struct IOStdReq *writeReq = NULL;
struct IOStdReq *readReq = NULL;
struct MsgPort *writePort = NULL;
struct MsgPort *readPort = NULL;
struct MsgPort write_port;
struct narrator_rb voice_io;
BOOL OpenedConsole = FALSE;
BYTE NError = -1;

/* Open the various libraries and return success code */
BOOL openLibs(VOID)
 {GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 33L);
  if (GfxBase)
   {IntuitionBase = 
     (struct IntuitionBase *)OpenLibrary("intuition.library", 33L);
    if (IntuitionBase)
     {DiskfontBase = OpenLibrary("diskfont.library", 33L);
      if (DiskfontBase) 
       {NError = 
      !OpenDevice("narrator.device", 0, (struct IORequest *) &voice_io, 0);
        if (NError)
            return (TRUE);}}} return (FALSE);}

/* Open full height window */
struct Window *doWindow(VOID)
 {static struct NewWindow nw =
    {0, 0, 0, 0, -1, -1, CLOSEWINDOW,
     WINDOWCLOSE|WINDOWDEPTH|WINDOWDRAG|SMART_REFRESH|ACTIVATE|GIMMEZEROZERO,
     NULL, NULL, NULL, NULL, NULL, ~0, ~0, ~0, ~0, WBENCHSCREEN};
  struct Window *window;
  nw.Height = GfxBase->NormalDisplayRows;
  nw.Width = GfxBase->NormalDisplayColumns;
  window = OpenWindow(&nw);
  return(window);}

VOID undoWindow(struct Window *window, BOOL immediate)
 {struct IntuiMessage *intuiMessage;
  if (window)
    {if (! immediate)
       (VOID) Wait(1<<window->UserPort->mp_SigBit);
     while (intuiMessage = (struct IntuiMessage *)GetMsg(window->UserPort))
       ReplyMsg((struct Message *)intuiMessage);
     CloseWindow(window);}}

VOID closeLibs(VOID)
{if (DiskfontBase) CloseLibrary(DiskfontBase);
 if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
 if (GfxBase) CloseLibrary((struct Library *)GfxBase);
 if (OpenedConsole) CloseConsole(writeReq);
 if (write_port.mp_SigBit != -1) FreeSignal(write_port.mp_SigBit);
 if (NError == 0) CloseDevice((struct IORequest *) &voice_io);
 if (readReq) DeleteExtIO(readReq);
 if (readPort) DeletePort(readPort);
 if (writeReq) DeleteExtIO(writeReq);
 if (writePort) DeletePort(writePort);}

main(unsigned int num_arg, char * arg[])
 {UBYTE reply[20], file_text[50], file_sound[50];
  int ht=0;
  FILE *fin = NULL, *fins = NULL;
  BOOL Read_file(int, FILE *, FILE *, char *, struct Window *);
  BOOL immediate = TRUE;
  struct Window *window = NULL;

  printf("Please make certain that the window is at least 620 pixels wide\n");
  printf("and 200 pixels high.  Hit enter when ready.");
  getchar();

  printf("\n\n\n%s v2.0       by Simcha Kuritzky\n\n",arg[0]);
  printf("This program  reads  in  an  ASCII file  of  the Masoretic  (Hebrew)  Bible,\n");
  printf("and displays it verse by verse on the screen.  It can also read in a file of\n");
  printf("phonemes created by the program Substitute and pronounce it along  with  the\n");
  printf("displayed verse.   You can also conduct text searches and print extracts  of\n");
  printf("the current file.\n\n");
  
  if ((num_arg > 1) && (arg[1][0] == '?'))
    printf("Expert mode is READ input_text_file input_phoneme_file font_choice.\n\n");
  if (num_arg < 4)
   {printf("Do you wish to continue (y/n)? ");
    scanf(" %s",reply);
    reply[0] = toupper(reply[0]); if (reply[0] == 'N') goto end_section;}

  if (num_arg > 1)
   {strcpy(file_text,arg[1]); fin = fopen(file_text,"r");
    printf("\nInput file: %s\n",file_text);}
  while (fin == NULL)
   {printf("\nWhat is the full path and name of the input text file?\n");
    scanf(" %s",file_text);
    if ((fin = fopen(file_text,"r")) == NULL) printf("File not found.\n");}

  strcpy(file_sound,file_text);
  strncat(file_sound,".sound",7);
  if (num_arg > 2) {strcpy(file_sound,arg[2]); strcpy(reply,"Y");
     if ((strlen(arg[2]) == 1) && (toupper(arg[2][0]) == 'N')) strcpy(reply,"N");}
  else 
   {printf("Do you wish to hear a phoneme file along with it?\n");
    scanf(" %s",reply); reply[0] = toupper(reply[0]);}
  if (reply[0] == 'Y')
   {fins = fopen(file_sound,"r");
    printf("\nPhoneme file: %s\n",file_sound);
    while (fins == NULL)
     {printf("\nWhat is the full path and name of the input phoneme file?\n");
      scanf(" %s",file_sound);
      if ((fins = fopen(file_sound,"r")) == NULL) printf("File not found.\n");}}

  ht = 0;  if (num_arg > 3) sscanf(arg[3],"%d",&ht);
  while ((ht < 1) || (ht > 5))
   {printf("\n\n");
    printf("[1]  Ancient Hebrew \n");
    printf("[2]  Torah scroll Hebrew \n");
    printf("[3]  Textbook Hebrew (includes vowel points)\n");
    printf("[4]  Masoretic Hebrew (includes vowel & cantillation marks)\n");
    printf("[5]  End this program now\n");
    printf("\nWhich font do you wish to use? "); scanf("%d",&ht);}

if (openLibs())
  if (window = doWindow())
  {switch (ht)
   {case 4:  ht = 32; break; 
    case 3:  ht = 24; break;
    case 2:  ht = 15; break;
    case 1:  ht = 16; break;
    case 5:  break;}

   if (ht == 5)
    closeLibs();
   else
    Read_file(ht, fin, fins, file_text, window); 
   undoWindow(window, immediate);}

  end_section:
  fclose(fin);
  fclose(fins);
  printf("\nFinished.\n");
  exit(20);}

/*	txt = input line
	st = start up string (either 1 char tab or string of #226)
	num = numeric text string built by program (initialized to st)
	c = current char of txt
	tlen = width of text string (incremented word by word)
	word_val = numeric value of current word
	verse = numeric value of current verse
	n = string equivalent of word_val
	l = current digit of n
	num_lken = width of num
	sp = difference between lengths of text & numeric strings in char_lens
	word = text version of current word which only includes letters
	v = number of verses printed */


BOOL Read_file(int ht, FILE *fin, FILE *fins, char *file_text, struct Window *window)
 {int bgn=0, bgnchp=0, chap=0, SChap=0, SVerse=0, verse=0, NChap=0, NVerse=0, x=0, y=0, i=0;
  UBYTE txt[512], t1, init_string[30], a='a', reply[30], book[30], NBook[30], 
    SBook[30], isL2R(UBYTE), num[4], phon[512], prevphon[512];
  BYTE error;
  ULONG signals, conreadsig, windowsig;
  LONG lch;
  BOOL Done = FALSE, NextVerse = FALSE, found = TRUE, sound;
  UBYTE ibuf, audio_chan[] = {3, 5, 10, 12};
  int ChapNum(int, UBYTE *, UBYTE *);
  UWORD sex, mode, sampfreq, pitch, rate, volume;
 
  struct TextFont *textFont, *oldTextFont;
  struct TextAttr textAttr;
  struct RastPort *rastPort = window->RPort;
  SHORT indentLeft = window->BorderLeft, indentTop = window->BorderTop;
  strcpy(SBook,"");
  write_port.mp_SigBit = -1;
  if (!(writePort = CreatePort("RKM.console.write",0)))
    cleanexit("Can't create write port\n",RETURN_FAIL);
  if (!(writeReq = CreateExtIO(writePort, (LONG)sizeof(struct IOStdReq))))
    cleanexit("Can't create write request\n",RETURN_FAIL);
  if (!(readPort = CreatePort("RKM.console.read",0)))
    cleanexit("Can't create read port\n",RETURN_FAIL);
  if (!(readReq = CreateExtIO(readPort, (LONG)sizeof(struct IOStdReq))))
    cleanexit("Can't create read request\n",RETURN_FAIL);
  if (error = OpenConsole(writeReq, readReq, window))
    cleanexit("Can't open console device\n",RETURN_FAIL);
  else OpenedConsole = TRUE;
  sex = DEFSEX; sampfreq = DEFFREQ; pitch = DEFPITCH;
  volume = DEFVOL; rate = DEFRATE; mode = DEFMODE;

  TITLE(window, "Bible Reader v2.0");
  AskFont(rastPort,&textAttr);
  oldTextFont = rastPort->Font;
  textAttr.ta_Name = "Torah.font";
  textAttr.ta_YSize = ht;
  textAttr.ta_Style = FS_NORMAL;
  textAttr.ta_Flags = FPF_DISKFONT | FPF_PROPORTIONAL | FPF_DESIGNED;
  textFont = OpenDiskFont(&textAttr);
  if (textFont)
  {SetFont(rastPort,textFont);
   indentTop = textFont->tf_YSize+1; SetBPen(rastPort, WHITE);
   CLS;

   /*preliminary read through file to set variables */
   bgn = 0; bgnchp = -1; x = 30;
   while ((fgets(txt,511,fin) != NULL) && ((!bgn) || (bgnchp == -1)))
   {if ((txt[0] == 9) || (txt[0] == 226))
     {if (!bgn) 
       {for (bgn = 1; txt[bgn] == 226; bgn++);
        if (txt[0] == 9) x = 595;}}
    else
      {if (bgnchp == -1)
        {NChap = ChapNum(strlen(txt), txt, NBook);
         bgnchp = NChap - 1;  strcpy(book,NBook);}}}
   fclose(fin);

   NChap = bgnchp; NVerse = 0;
   if (fins != NULL) sound = TRUE; else sound = FALSE;
   fin = fopen(file_text,"r"); strcpy(txt,"\0");
   strcpy(init_string,"HIT THE SPACE BAR TO CONTINUE");
   for (i=0; init_string[i] != '\0'; ++i) init_string[i] += 64;

   HPRINT(init_string); strcpy(init_string,"\0"); strcpy(phon,"\0");
    strcpy(prevphon,"\0");

   while (((fgets(txt,511,fin) != NULL))&& !Done)
   {if (isdigit(txt[bgn]) || isL2R(txt[1]))
    {if (!strcmp(SBook,book) && (SChap == chap) && (SVerse == verse))
       {found = TRUE; printf("\nText found.\n");}
     if (sound && found && isdigit(txt[bgn]))
     {write_port.mp_SigBit = AllocSignal(-1);
      write_port.mp_Node.ln_Name = "speech_write";
      write_port.mp_Node.ln_Type = NT_MSGPORT;
      write_port.mp_Flags = PA_SIGNAL;
      write_port.mp_SigTask = (struct Task *)FindTask(NULL);
      NewList(&write_port.mp_MsgList);
      voice_io.message.io_Length = strlen(phon);
      voice_io.message.io_Data = (APTR) phon;
      voice_io.message.io_Command = CMD_WRITE;
      voice_io.message.io_Offset = 0;
      voice_io.message.io_Message.mn_Node.ln_Type = NT_MSGPORT;
      voice_io.message.io_Message.mn_Length = sizeof(voice_io);
      voice_io.message.io_Message.mn_ReplyPort = &write_port;
      voice_io.message.io_Unit = 0;
      voice_io.ch_masks = (UBYTE *) audio_chan;
      voice_io.nm_masks = sizeof(audio_chan);
      voice_io.sampfreq = sampfreq;
      voice_io.pitch = pitch;
      voice_io.rate = rate;
      voice_io.mode = mode;
      voice_io.volume = volume;
      SendIO((struct IORequest *) &voice_io);
      signals = 
        Wait((1L << voice_io.message.io_Message.mn_ReplyPort -> mp_SigBit));}
     if (isdigit(txt[bgn]))
      {for (i=0;i<3;i++) num[i] = txt[bgn+2-i]; num[3] = '\0';
       sscanf(num,"%d",&NVerse);
       if (fins != NULL) {strcpy(prevphon,phon); fgets(phon,511,fins);}}
     if (isL2R(txt[1]))
      {NChap = ChapNum(strlen(txt), txt, NBook);
       bgnchp = NChap - 1;  strcpy(book,NBook); NVerse = 0;}
     while (!NextVerse && found)
     {QRead(readReq, &ibuf);
      conreadsig = 1 << readPort->mp_SigBit;
      windowsig = 1 << window->UserPort->mp_SigBit;
      signals = Wait(conreadsig | windowsig);
      if (signals & conreadsig)
      if ((lch=ConMayGetChar(readPort,&ibuf)) != -1)  a = lch;
      NextVerse = FALSE;
      switch (a)
      {case ' ':  NextVerse = TRUE; break;
       case 't':
         rewind(fin); NextVerse = TRUE; 
         if (fins != NULL) rewind(fins); strcpy(phon,"\0");
         break;
       case 's':  sound = FALSE; break;
       case 'S':  if (fins != NULL)
        {sound = TRUE;
         write_port.mp_SigBit = AllocSignal(-1);
         write_port.mp_Node.ln_Name = "speech_write";
         write_port.mp_Node.ln_Type = NT_MSGPORT;
         write_port.mp_Flags = PA_SIGNAL;
         write_port.mp_SigTask = (struct Task *)FindTask(NULL);
         NewList(&write_port.mp_MsgList);
         voice_io.message.io_Length = strlen(prevphon);
         voice_io.message.io_Data = (APTR) prevphon;
         voice_io.message.io_Command = CMD_WRITE;
         voice_io.message.io_Offset = 0;
         voice_io.message.io_Message.mn_Node.ln_Type = NT_MSGPORT;
         voice_io.message.io_Message.mn_Length = sizeof(voice_io);
         voice_io.message.io_Message.mn_ReplyPort = &write_port;
         voice_io.message.io_Unit = 0;
         voice_io.ch_masks = (UBYTE *) audio_chan;
         voice_io.nm_masks = sizeof(audio_chan);
         voice_io.sampfreq = sampfreq;
         voice_io.pitch = pitch;
         voice_io.rate = rate;
         voice_io.mode = mode;
         voice_io.volume = volume;
         SendIO((struct IORequest *) &voice_io);
         signals = 
           Wait((1L << voice_io.message.io_Message.mn_ReplyPort -> mp_SigBit));}
         break;
       case 'g':  
         WindowToBack(window);
         printf("\nIs the book %s? ",book); scanf("%s",reply);
         reply[0] = toupper(reply[0]);
         if (reply[0] == 'N')
          {printf("\nName of book? "); scanf("%s",SBook);
           for (i=0; i<strlen(SBook); i++) SBook[i] = toupper(SBook[i]);}
         else strcpy(SBook,book);
         printf("\nChapter and verse desired: "); scanf("%d %d",&SChap,&SVerse);
         if ((SChap < chap) || ((SChap == chap) && (SVerse < verse)))
          {printf("\nDo you wish to start your search from the top? ");
           scanf("%s",reply); reply[0] = toupper(reply[0]);
           if (reply[0] == 'Y') rewind(fin);}
         if (!strcmp(SBook,book) && (SChap == chap) && (SVerse == verse))
           printf("\nYou are already there!\n");
         else
          {found = FALSE; printf("\nNow searching...\n");
           NextVerse = TRUE; WindowToFront(window);}
         break;
       case 'q':  NextVerse = TRUE; Done = TRUE; break;
       case '?':  WindowToBack(window);
           printf("\nThe following commands can be entered from the");
           printf("other window:\n");
           printf("[space] will advance to the next line.\n");
           printf("g  will go to a particular verse.\n");
           printf("q  will terminate the program.\n");
           if (fins != NULL)
            {printf("s  will silence the program.\n");
             printf("S  will restart sound (and pronounce current verse).\n");}
           printf("w  where am I? (Book chapter:verse).\n");
           printf("\n"); break;
       case 'w':  WindowToBack(window);
                  printf("\nCurrently on %s %d:%d\n",book,chap,verse); break;
      }}
     y = 1; CLS;}
    if (!Done) HPRINT(txt); 
    y += ht; NextVerse = FALSE;
    verse = NVerse;  chap = NChap;}

   strcpy(init_string,"END OF FILE");
   for (i=0; init_string[i] != '\0'; ++i) init_string[i] += 64;

   HPRINT(init_string); strcpy(init_string,"\0");
   QRead(readReq, &ibuf);
   conreadsig = 1 << readPort->mp_SigBit;
   windowsig = 1 << window->UserPort->mp_SigBit;
   signals = Wait(conreadsig | windowsig);
   if (signals & conreadsig)
    if ((lch=ConMayGetChar(readPort,&ibuf)) != -1)
     a = lch;
 
   if(!(CheckIO(readReq))) AbortIO(readReq);
   WaitIO(readReq);
   closeLibs();
   SetFont(rastPort,oldTextFont);
   CloseFont(textFont);} 
  return(WAIT_FOR_CLOSE);}

UBYTE isL2R(UBYTE inchar)
 {if ((inchar > 127) && (inchar < 160)) return(TRUE);
  return(FALSE);}

int ChapNum(int start, UBYTE *txt, UBYTE *NBook)
 {int i, j=0, ch=0, s;
  char a[9], chap[9];
  strcpy(chap," CHAPTER"); for (i=0; i<8; i++) chap[i] += 64; 
  i=start+1;
  while ((i > 0) && (txt[i] != 96)) i--;
  i++; start = i; s = (int)(strstr(txt,chap)-txt);
   while (i < strlen(txt))
    {a[j++] = txt[i++]-128;}
   a[j] = '\0';
   sscanf(a,"%d",&ch);
   for (i=0, j=0; i <= s; i++)
     if (isL2R(txt[i])) *(NBook+j++) = txt[i]-64;
   *(NBook+j) = '\0';
   return(ch);}

BYTE OpenConsole(writereq, readreq, window)
  struct IOStdReq *readreq;
  struct IOStdReq *writereq;
  struct Window *window;
   {BYTE error;
    writereq->io_Data = (APTR) window;
    writereq->io_Length = sizeof(struct Window);
    error = OpenDevice("console.device",0,writereq,0);
    readreq->io_Device = writereq->io_Device;
    readreq->io_Unit   = writereq->io_Unit;
    return(error);}

void CloseConsole(struct IOStdReq *writereq) {CloseDevice(writereq);}

void cleanexit(UBYTE *s,LONG n)
 {if (*s /*& (!FromWB)*/) printf(s);
  closeLibs();
  exit(n);}

void QRead(struct IOStdReq *readreq, UBYTE *whereto)
 {readreq->io_Command = CMD_READ;
  readreq->io_Data = (APTR)whereto;
  readreq->io_Length = 1;
  SendIO(readreq);}

LONG ConMayGetChar(struct MsgPort *msgport, UBYTE *whereto)
  {register temp;
   struct IOStdReq *readreq;

   if (!(readreq = (struct IOStdReq *)GetMsg(msgport))) return (-1);
   temp = *whereto;
   QRead(readreq,whereto);
   return(temp);}

UBYTE ConGetChar(struct MsgPort *msgport, UBYTE *whereto)
  {register temp;
   struct IOStdReq *readreq;

   WaitPort(msgport);
   readreq = (struct IOStdReq *)GetMsg(msgport);
   temp = *whereto;
   QRead(readreq,whereto);
   return((UBYTE)temp);}


