#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include <exec/types.h>
#include <exec/memory.h>

#include <libraries/dosextens.h>

#include <devices/tpt.h>

#include <dlg/broadcast.h>
#include <dlg/resman.h>
#include <dlg/user.h>
#include <dlg/msg.h>

#include <link/io.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/dlg.h>

#include <pragmas/dlg.h>

char nline   = '\n';
char dash [] = "----------------------------------------";
char space[] = "                                        ";

#undef index

char **libgetlang(void);
char  *index(char *, char);
void   Quote(char *, BPTR, UBYTE *);
LONG   TempMore (BPTR, UBYTE, UBYTE, USHORT);

char  __saveds __asm LIBGetChar(void);
char  __saveds __asm LIBReadChar(register __d0 ULONG);
void  __saveds __asm LIBPutChar(register __d0 char, register __a0 BPTR);
BOOL  __saveds __asm LIBExists(register __a0 char *);
LONG  __saveds __asm LIBFileSize(register __a0 char  *, register __a1 ULONG *);
LONG  __saveds __asm LIBStricmp(register __a0 char *,  register __a1 char *);
LONG  __saveds __asm LIBStrnicmp(register __a0 char *, register __a1 char *, register __d0 USHORT);
LONG  __saveds __asm LIBTranslateBuffer(register __a0 char *, register __a1 char *, register __d0 ULONG, register __a2 struct USER_DATA *, register __a3 struct Ram_File *, register __d1 char *);

LONG  __saveds __asm LIBFreeArea(register __d0 long, register __a0 char *, register __d1 UBYTE);
LONG  __saveds __asm LIBBorrowArea(register __d0 long, register __a0 char *, register __a1 char *, register __d1 char, register __d2 UBYTE);
LONG  __saveds __asm LIBGetDevName(register __a0 char *);
LONG  __saveds __asm LIBTSetFlags(register __d0 ULONG, register __a0 char *);
LONG  __saveds __asm LIBTUnSetFlags(register __d0 ULONG, register __a0 char *);


/// index
char *index(char *str, char c)
{while(*str)
      {if (*str == c)  return(str);
       str++;
      }

 return(NULL);
}
//-

/// PrintSpace
BOOL __saveds __asm LIBPrintSpace(register __a0 BPTR   fh,
                                  register __d0 UBYTE  ansi,
                                  register __d1 USHORT spaces)

{if (spaces)
     if ((ansi & ANSI_POS)  &&  spaces > 5)
         AFPrintf(NULL, fh, "[%ldC", spaces);
       else
        {while(spaces > 40)
              {Write(fh, space, 40);
               spaces -= 40;
              }

         Write(fh, space, spaces);
        }

 return(TRUE);
}
//-

/// Draw_Line
void __saveds __asm LIBDraw_Line(register __d0 UBYTE width)

{BPTR sout;

 sout = Output();

 if (width)
    {width--;

     while(width > 40)
          {Write(sout, dash, 40);
           width -= 40;
          }

     Write(sout, dash, width);
    }

 Write(sout, &nline, 1);
 return;
}
//-

/// SDraw_LIne
void __saveds __asm LIBSDraw_Line(register __a0 UBYTE *buffer,
                                  register __d0 UBYTE  width)

{if (width)
    {width--;

     while(width > 40)
          {buffer = stpcpy(buffer, dash);
           width -= 40;
          }

     buffer = stpcpy(buffer, &dash[40-width]);
    }

 *buffer = '\n';
  buffer++;
 *buffer =  0;

 return;
}
//-

/// Pause
BOOL __saveds __asm LIBPause(void)

{char **SA;
 BPTR   sout;

 SA   = libgetlang();
 sout = Output();

 AFPrintf(NULL, sout, SA[3639]);

 while(LIBGetChar() != 13);

 AFPrintf(NULL, sout, SA[3640]);
 AFPrintf(NULL, sout, SA[3641]);
 AFPrintf(NULL, sout, SA[3640]);

 return(TRUE);
}
//-

/// Clr
void __saveds __asm LIBClr(register __d0 UBYTE flag)

{if (flag & ANSI_CLR)
     Write(Output(), "\014", 1);
   else
     Write(Output(), "\n\n", 2);
}
//-

/// More
LONG __saveds __asm LIBMore(register __a0 BPTR  fh,
                            register __d0 UBYTE ansi,
                            register __d1 UBYTE header)

{char   a;
 char **SA;

 SA = libgetlang();
 AFPrintf(NULL, fh, SA[3642]);

 a = LIBGetChar();
 a = toupper(a);

 if (a==3)  a = 'N';

 if (header  &&  a!='N'  &&  (ansi&ANSI_POS)  && !(ansi&ANSI_SCROLL))
     AFPrintf(NULL, fh, "[%ldH[J", header);
  else
    {AFPrintf(NULL, fh, SA[3643]);
     AFPrintf(NULL, fh, SA[3644]);
     AFPrintf(NULL, fh, SA[3643]);
    }

 if (a == 'N')  return(1);
 if (a == '=')  return(2);
 return(0);
}
//-

/// TempMore
LONG TempMore(BPTR fh,UBYTE ansi,UBYTE header,USHORT screenlen)

{char   a;
 char **SA;

 SA = libgetlang();
 AFPrintf(NULL, fh, SA[3642]);

 a = LIBGetChar();
 a = toupper(a);

 if (a==3)  a = 'N';

 if (header  &&  a!='N'  &&  (ansi&ANSI_POS)  &&  !(ansi&ANSI_SCROLL))
     AFPrintf(NULL, fh, "[%ldA\015[J", screenlen-header);
  else
    {AFPrintf(NULL, fh, SA[3643]);
     AFPrintf(NULL, fh, SA[3644]);
     AFPrintf(NULL, fh, SA[3643]);
    }

 if (a == 'N')  return(1);
 if (a == '=')  return(2);
 return(0);
}
//-

/// DispBuffer
LONG __saveds __asm LIBDispBuffer(register __d0 BPTR              fh,
                                  register __a0 char             *buffer,
                                  register __a1 USHORT           *screenpos,
                                  register __d1 USHORT            indent,
                                  register __a2 char             *ibuf,
                                  register __d2 USHORT            header,
                                  register __a3 char             *breakbuf,
                                  register __d3 struct USER_DATA *AUser)

{struct  USER_DATA *User = AUser;

 long    screenwidth;
 long    screenhalf;
 long    screenlen;
 long    linelen;
 long    counter;
 long    pos;

 char    moreflag;
 char    ansi;
 UBYTE   wrap;
 UBYTE   b;
 UBYTE   scroll;
 UBYTE   moreret  =   0;
 UBYTE   donemore = FALSE;
 UBYTE   inquote  = FALSE;

 screenwidth = (User->Screen_Width) ? User->Screen_Width : 9999;
 screenhalf  =  screenwidth / 2;
 screenlen   = (User->Screen_Len)   ? User->Screen_Len   : 9999;

 moreflag    =  User->More_Flag;
 ansi        =  User->Ansi_Flag;
 scroll      = (ansi & ANSI_POS) && (ansi & ANSI_SCROLL) && (header > 1);

 pos     = 0;
 wrap    = 1;

 do {if (breakbuf)
        {char  **SA;

         b = LIBReadChar(0);

         if (b)
            {/* Check for Control-C */
             if (b == 3  &&  index(breakbuf, 3))
                {SA = libgetlang();
            AFPrintf(User, fh, SA[3645]);
                 return(-1);
                }

             /* Check for break chars */
             b = toupper(b);
             if (index(breakbuf, b))
                {Write(fh, &nline, 1);
                 return((LONG)b);
                }
            }
        }


     /* If we didn't have a hard return, strip leading spaces */
     if (wrap != 1  &&  screenwidth < 9999)
         while(buffer[pos] == 32)  pos++;


     /* Do Quoting */
     if (header>=6 && (ansi & ANSI_COLOR))
         if (wrap==1)  Quote(buffer+pos, fh, &inquote);


     /* Find next line to print */
    {long   count  = indent;
     UBYTE  inansi = FALSE;

     wrap = 0;

     for(counter = 0; count <= screenwidth; counter++) /* Scan the line */
        {b = buffer[pos+counter];

         if (inansi)
            {if (isalpha(b))
                 inansi = FALSE;  /* End of sequence */
             continue;
            }

         if (b == 27  ||  b == 155)
            {inansi = TRUE;     /* Esc/CSI */
             continue;
            }

         if (b == 13)             /* Cr */
             continue;

         if (b == 10)             /* Lf */
            {wrap = 1;
             break;
            }

         if (b == 0)             /* End of buffer */
            {wrap = 3;
             break;
            }

         count++;
        }

     linelen = counter;
    }


     /* If no hard return, do word wrap */
     if (!wrap)
         if (screenwidth < 9999)
            {wrap = 2;

             for(counter--; counter; counter--)
                {if (buffer[pos+counter] == 32)
                    {if (counter > screenhalf) linelen=counter;
                     break;
                    }
                }
            }


     /* Do partial screen scroll */
     if (scroll)
         if (donemore)
             AFPrintf(User, fh, "[%ldA[M[%ldB", screenlen-header, screenlen-header-1);


     /* Do indent */
     if (indent)
         if (pos && wrap != 3)
             if (ibuf)
                 Write(fh, ibuf, indent);
               else
                 LIBPrintSpace(fh, ansi, indent);


     /* Output the Line */
     if ((ansi & ANSI_POS) && screenwidth<9999)
        {long  spacecount;
         long  count;
         char  linebuf[512];

         spacecount = 0;
         count      = 0;

         for(counter=0; counter<linelen; counter++)
            {if (buffer[pos+counter]==' '  &&  spacecount < 99)
                {spacecount++;
                 continue;
                }

             if (spacecount > 5)
                {linebuf[count++] =  27;
                 linebuf[count++] = '[';
                 linebuf[count++] = (spacecount/10) + '0';
                 linebuf[count++] = (spacecount%10) + '0';
                 linebuf[count++] = 'C';
                 spacecount       =  0;
                }
              else
                for(;spacecount; spacecount--)
                     linebuf[count++] = ' ';

             linebuf[count++] = buffer[pos+counter];
            }

         if (count)
             Write(fh, linebuf, count);
        }
      else
        if (linelen)  Write(fh, buffer+pos, linelen);

     if (wrap != 3  &&  wrap != 0)  Write(fh, &nline, 1);
     if (wrap != 3  ||  !pos)     (*screenpos)++;

     pos     += linelen;
     if (wrap==1) pos++;


     /* Do More Prompt */
     if ((*screenpos) >= screenlen)
        {(*screenpos) = (header)?header:1;
          if (scroll)  donemore = TRUE;

          if (moreflag) 
             {moreret = TempMore(fh,ansi,header,screenlen);
              if (moreret==2)
                  moreflag=0;
                else
                  if (moreret)  return(-1);
             }
        }
    } while(wrap!=3);


 if (moreret==2)  return(-2);
 return(0);
}
//-

/// DispMsg
LONG __saveds __asm LIBDispMsg(register __a0 struct MsgDisplay *md,
                               register __a1 struct USER_DATA  *User)

{register UBYTE  *buffer;
 register LONG    readlen;
 register UBYTE  *currchar;
 UBYTE            ansi;


 {ULONG           size;
  BPTR            fh;
  register UBYTE  lflags;

  if (LIBFileSize(md->filename, &size)==-1)  return(-1);

  readlen = size - md->findex;
  buffer  = AllocMem(readlen+1, MEMF_PUBLIC);
  if (!buffer)   return(-1);

  if (md->flags & MSG_FILEAREA)
      lflags = FILELOCK | WRITELOCK;
    else
      lflags = MSGLOCK  | WRITELOCK;

  if (md->area != PVTAREA)  LIBBorrowArea(md->area, md->passwd, "", 64, lflags);

  if (!(fh = Open(md->filename,MODE_OLDFILE)))
     {LIBFreeArea(md->area, md->passwd, lflags);
      FreeMem(buffer, readlen+1);
      return(-1);
     }

  Seek(fh,md->findex,OFFSET_BEGINNING);
  Read(fh, buffer, readlen);
  Close(fh);

  LIBFreeArea(md->area, md->passwd, lflags);

  currchar  = buffer + readlen;
 *currchar  = 0;
 }

 ansi = User->Ansi_Flag;

 {register UBYTE *oindex  = buffer;
  register UBYTE *tchar;
  UBYTE           inansi  = FALSE;
  UBYTE           transchar;

  for(currchar = buffer; *currchar; currchar++)
     {transchar = *currchar;
      if (md->transarray)
         {transchar = md->transarray[transchar];
          if (!transchar)  continue;
         }

      if (transchar == 1)
         {currchar++;
          while(*currchar)
               {if (*currchar == 13)  break;
                currchar++;
               }

          if (!*currchar)  break;
          if (*(currchar+1) == 10)  currchar++;
          continue;
         }

      if (transchar == 13  ||  transchar == 10)
         {*oindex++ = 10;
          if (transchar == 13)
              if (*(currchar+1) == 10)  currchar++;

          if (md->flags & MSG_STRIPSB)
             {tchar = currchar + 1;
              if (!strncmp(tchar, "SEEN-BY: ", 9))  *tchar = 0;
             }

          continue;
         }

      if (transchar <  27)  continue;

      if (!(ansi & ANSI_COLOR))
         {if (inansi)
             {if (isalpha(transchar)) inansi=FALSE;   /* End of sequence */
              continue;
             }

          if (transchar == 27  ||  transchar == 155)  /* Esc */
             {inansi = TRUE;
              continue;
             }
         }

      if (transchar >  27  &&  transchar <  32)                        continue;
      if (transchar > 126  &&  transchar < 160  &&  transchar != 155)  continue;

     *oindex++ = transchar;
     }

  *oindex = 0;
 }

 {register LONG  retval;

  retval = LIBDispBuffer(Output(),buffer,md->screenpos,0,NULL,(ansi&ANSI_NOFREEZE)?0:6,md->breakbuf,User);
  AFPrintf(User, Output(), "%ao%a6");

  FreeMem(buffer, readlen+1);
  return(retval);
 }
}
//-

/// Quote
void Quote(char *buf, BPTR out, UBYTE *inquote)

{char *ebuf = buf + 8;

 while(buf < ebuf)
      {if (!(*buf))      break;
       if (*buf ==10)    break;

       if (*buf == '>')
          {if (!(*inquote))
              {Write(out, "\033[37m", 5);
               *inquote = TRUE;
              }

           return;
          }

       buf++;
      }

 if (*inquote)
    {Write(out, "\033[36m", 5);
    *inquote = FALSE;
    }

 return;
}
//-

/// DispForm
BOOL __saveds __asm LIBDispForm(register __a0 char             *filename,
                                register __a1 struct USER_DATA *DispUser,
                                register __a2 struct USER_DATA *TransUser,
                                register __a3 struct Ram_File  *Ram,
                                register __d0 char             *aport)

{BPTR   sout;
 BPTR   fp;
 char  *port = aport;

 long   speed  = 0;
 long   indent = 0;
 USHORT pos    = 1;

 char   inbuffer [1024];
 char   outbuffer[1024];

 UBYTE  ansi;
 char   breakflag = TRUE;

 struct USER_DATA TempUser;

 sout = Output();

 {char   slowstr[81];

  strcpy(slowstr, filename);

  if (DispUser->menuset)
     {ASPrintf(NULL, slowstr, "%s.%ld", filename, DispUser->menuset);
      if (!LIBExists(slowstr))  strcpy(slowstr, filename);
     }
  if (!(fp = Open(slowstr,  MODE_OLDFILE)))  return(FALSE);
 }

 movmem(DispUser, &TempUser, sizeof(struct USER_DATA));
 ansi = TempUser.Ansi_Flag;

 while(FGets(fp, inbuffer, 1000))
      {if (inbuffer[0] == '%')
          {long  seconds;
           long  counter;               
           long  checkmore;

           if (!LIBStrnicmp(&inbuffer[1], "RETURN", 6))
              {LIBPause();
               indent = 0;
               pos    = 1;
               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "MOREOFF", 7))
              {TempUser.More_Flag = 0;
               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "CLS", 3))
              {LIBClr(ansi);
               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "MOREON", 6))
              {TempUser.More_Flag = DispUser->More_Flag & 1;
               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "WRAPOFF", 7))
              {TempUser.Screen_Width = 0;
               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "BREAKOFF", 8))
              {breakflag = FALSE;
               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "BREAKON", 7))
              {breakflag = TRUE;
               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "WRAPON", 6))
              {TempUser.Screen_Width = DispUser->Screen_Width;
               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "POSOFF", 6))
              {ansi &= ~ANSI_POS;
               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "POSON", 5))
              {ansi |= ANSI_POS;
               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "CLROFF", 6))
              {ansi &= ~ANSI_CLR;
               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "CLRON", 5))
              {ansi |= ANSI_CLR;
               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "COLOROFF", 8))
              {ansi &= ~ANSI_COLOR;
               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "COLORON", 7))
              {ansi |= ANSI_COLOR;
               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "DOMORE", 6))
              {checkmore = LIBMore(sout, ansi, 0);
               if (checkmore)
                  {if (checkmore==1)
                      {Write(sout, &nline, 1);
                       break;
                      }

                   TempUser.More_Flag=0;
                  }

               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "INDENT", 6)    &&  sscanf(&inbuffer[7],".%d",&indent))
                continue;

           if (!LIBStrnicmp(&inbuffer[1], "SETWIDTH", 8)  &&  sscanf(&inbuffer[9],".%d",&counter))
              {TempUser.Screen_Width=counter;
               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "PAUSE", 5)     &&  sscanf(&inbuffer[6],".%d",&seconds))
              {Delay((long)(seconds*50));
               continue;
              }

           if (!LIBStrnicmp(&inbuffer[1], "SLOW", 4))
               sscanf(&inbuffer[5], ".%d", &speed);
          }

    {char  *index;
     char  *newindex;
     char   inansi;

     if (speed)
         for(index = &inbuffer[6]; (*index >= '0'  &&  *index <= '9'); index++);
       else
         index = inbuffer;

     for(newindex=inbuffer, inansi=FALSE; *index; index++)
        {if (!(ansi & ANSI_COLOR))
            {if (inansi)
                {if (isalpha(*index)) inansi=FALSE;    /* End of sequence */
                 continue;
                }

             if (*index == 27  ||  *index == 155)
                {inansi = TRUE;        /* Esc */
                 continue;
                }
            }

         if (*index == 12  && (!(ansi & ANSI_CLR)))  continue;
        *newindex++ = *index;
        }
    *newindex = 0;

     TempUser.Ansi_Flag = ansi;
     LIBTranslateBuffer(inbuffer, outbuffer, 1024, TransUser, Ram, port);
    }

     if (indent)
        {LIBPrintSpace(sout, ansi, indent);
         indent = 0;
        }


     if (speed)
        {char *index;

         for(index=outbuffer; *index; index++)
            {Delay(speed);
             Write(sout, index, 1);
            }

         speed = 0;
         continue;
        }
      else
        {long  retval;

         retval = LIBDispBuffer(sout, outbuffer, &pos, indent, NULL, 1, (breakflag)?"\x03":NULL, &TempUser);
         if (retval==-2)
             TempUser.More_Flag = 0;
           else
             if (retval)
                {Write(sout, &nline, 1);
                 break;
                }
        }
    }


 Close(fp);
 return(TRUE);
}
//-

