#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <dos.h>
#include <exec/types.h>
#include <libraries/dosextens.h>

#include <dlg/dlg.h>
#include <dlg/user.h>
#include <dlg/input.h>
#include <dlg/resman.h>

#include <link/io.h>

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

#include <pragmas/dlg.h>

#include <private/Version.h>
#define  ObjRev "1"
const UBYTE version[]="\0$VER: DLG Line Editor " BUILDVER "." ObjRev " ©" COPYRIGHT " by Digerati Dreams "__AMIGADATE__;

void  main(int , char **);
long  select_menu(void);
BYTE  select_option(void);
long  list_mess(long, long, long);
BYTE  enter_line(long);
long  wrap(void);
BYTE  check_line(void);
BYTE  load_file(char *);
BYTE  save_file(char *);
BYTE  check_word(long, long);
long  find_string(char *, long *);
BYTE  search_replace(void);
BYTE  replace_string(long, long, char *, long, long *);
long  query_replace(long, long, char *, char *, long, long *);
void  sub_replace(long *, long, long, char *, long, long, long);
long  scan_back(void);
BYTE  write_file(char *);
void _CXBRK(void);


#define MAXLINELEN   132
#define HOT          UserDat.Hot_Keys

char *buff    = 0;
long  pointer = 0;
long  messagelen;

struct Ram_File  RStruct;
struct USER_DATA UserDat;
struct UserInfo  ui      = {&UserDat, &RStruct};
struct Query     q       = {NULL, NULL, NULL, NULL, NULL, 0, 0, 0};


char fakestack[255];
char Ext[5];

BPTR               sout;
struct Library    *DLGBase = NULL;
struct LangStruct *ls;
char             **SA;


void main(int argc,char **argv)

{char filename[80];
 long error;

 sout = Output();
 if (!(DLGBase = OpenLibrary(DLGNAME, DLGVERSION)))  exit(5);
 if (argc < 3)                                       exit(5);

 if (GetDevName(Ext) == -1)            _CXBRK();
 if (!ReadUser(&RStruct,&UserDat,Ext))  _CXBRK();
 if (!(ls = GetLang(Ext)))             _CXBRK();
 SA = ls->strings;

 if (!Strnicmp(Ext,"TL",2))   UserDat.User_Level = 255;
 UserDat.Screen_Width--;
 fakestack[0] = 0;

 strcpy(filename,  argv[1]);
 messagelen = atol(argv[2]);
 buff       = malloc(messagelen);
 if (!buff)
    {AFPrintf(&UserDat, sout, SA[944], messagelen);
    _CXBRK();
    }

 if (UserDat.Screen_Width > MAXLINELEN)
    {AFPrintf(&UserDat, sout, SA[945]);
     UserDat.Screen_Width = 127;
    }

 if ((error=load_file(filename)) != 1)
    {AFPrintf(&UserDat, sout, SA[946]);
     AFPrintf(&UserDat, sout, SA[947], pointer);
     list_mess(0,pointer,1);
    }
 if (error == 10)  _CXBRK();

 AFPrintf(&UserDat, sout, SA[948]);
 Draw_Line(UserDat.Screen_Width);
 AFPrintf(&UserDat, sout, SA[949]);
 pointer = 0;

 for(;;)
    {while(enter_line(list_mess(scan_back(),pointer,1))==3);

     error = select_menu();
     if (error == 2)
        {if (!save_file(filename))
            {AFPrintf(NULL, sout, "\n");
             break;
            }
        }

     if (error==10)  break;
    }

 _CXBRK();
}


long select_menu(void)

{char filename[80];
 BYTE c;

 for(;;)
    {c = select_option();

     switch(c)
           {case 'L': AFPrintf(&UserDat, sout, SA[950]);
                      AFPrintf(&UserDat, sout, SA[951]);
                      AFPrintf(&UserDat, sout, SA[952], pointer);
                      list_mess(0,pointer,1);
                      break;

            case 'E': AFPrintf(&UserDat, sout, SA[953]);
                      search_replace();
                      break;

            case 'A': AFPrintf(&UserDat, sout, SA[954]);
                      if (BoolQuery(SA[955], 0, &ui))  return(10);
                      AFPrintf(NULL, sout, "\n\n");
                      break;

            case 'S': AFPrintf(&UserDat, sout, SA[956]);
                      return(2);
                      break;

            case 'C': AFPrintf(&UserDat, sout, SA[957]);
                      AFPrintf(&UserDat, sout, SA[958]);
                      break;

            case 'R': AFPrintf(&UserDat, sout, SA[959]);
                      q.prompt     = SA[960];
                      q.string     = filename;
                      q.length     = 79;
                      q.typelength = 255;
                      q.flags      = QUERY_UPCASE|QUERY_NOSTACK;
                      DLGQuery(&q, &ui);
                      AFPrintf(NULL, sout, "\n\n");

                      if (load_file(filename))
                          AFPrintf(&UserDat, sout, SA[961]);
                        else
                          AFPrintf(&UserDat, sout, SA[962]);
                      break;

            case 'W': AFPrintf(&UserDat, sout, SA[963]);
                      q.prompt     = SA[964];
                      q.string     = filename;
                      q.length     = 79;
                      q.typelength = 255;
                      q.flags      = QUERY_UPCASE|QUERY_NOSTACK;
                      DLGQuery(&q, &ui);
                      AFPrintf(&UserDat, sout, "\n\n");

                      if (write_file(filename))
                          AFPrintf(&UserDat, sout, SA[965]);
                        else
                          AFPrintf(&UserDat, sout, SA[966]);
                      break;

            default:  AFPrintf(NULL, sout, "\n");
           }

     if (c == 'C')  break;
    }

 return(0);
}


BYTE select_option(void)

{char a[2];

 if (UserDat.User_Level==255)  AFPrintf(&UserDat, sout, SA[967]);
 AFPrintf(&UserDat, sout, SA[968]);

 Chk_Abort();

 q.prompt     = NULL;
 q.string     = a;
 q.length     = 1;
 q.typelength = 1;
 q.flags      = QUERY_UPCASE|QUERY_NOSTACK;
 DLGQuery(&q, &ui);

 if (UserDat.User_Level != 255  &&  (a[0]=='R' || a[0]=='W'))  a[0] = 0;
 return(a[0]);
}


long list_mess(long counter, long end, long linepos)

{char *c = buff + counter;

 if (!end)  return(1);

 while(counter < end)
      {PutChar(*c, sout);

       if (*c == 32)
          {if (check_word(counter, linepos))
              {AFPrintf(NULL, sout, "\n");
               linepos = 0;
              }
          }
        else
          {if (*c == 10)  linepos = 0;

           if (linepos >= UserDat.Screen_Width)
              {AFPrintf(NULL, sout, "\n");
               linepos = 0;
              }
          }

       linepos++;
       counter++;
       c++;
      }

 return(linepos);
}


BYTE enter_line(long linepos)

{unsigned char a;

 for(;;)
    {Chk_Abort();
     a = GetChar();
     if (a == 26  ||  a == 24)
        {if (linepos>1)  AFPrintf(NULL, sout, "\n");
         break;
        }

     if (a == 8)
        {if (pointer==0)  continue;

         if (linepos<=1)
            {pointer = pointer - linepos;
             AFPrintf(&UserDat, sout, SA[969]);
             return(3);
            }

         AFPrintf(NULL, sout, "\010 \010");
         linepos--;
         pointer--;

         continue;
        }

     if (a > 126  &&  a < 160)  continue;
     if (a == 13)               a = 10;
     if (a < 32  &&  a != 10)   continue;

     PutChar(a, sout);

     buff[pointer] = a;

     pointer++;
     linepos++;

     if (pointer >= messagelen)
        {AFPrintf(&UserDat, sout, SA[970]);
         pointer--;
         return(0);
        }

     if (a == 10)                        linepos = 1;
     if (linepos > UserDat.Screen_Width)  linepos = wrap();
    }

 return(0);
}


long wrap()

{long a   = pointer - 1;
 long pos = 0;
 char wrapline[MAXLINELEN];

 if (check_line())
    {AFPrintf(NULL, sout, "\n");
     return(1);
    }

 while(buff[a] != 32)
      {pos++;
       a--;
       AFPrintf(NULL, sout, "\010 \010");
      }

 strncpy(wrapline, buff+(a+1), pos);
 wrapline[pos] = 0;

 AFPrintf(NULL, sout, "\n%s", wrapline);
 return(pos);
}


/* Returns a 1 if there are no spaces in the line.  Otherwise a ZERO is returned... */
BYTE check_line()

{long a;

 for(a=pointer-1; a != (pointer-UserDat.Screen_Width); a--)
    {if (buff[a] == 10)
         return(1);

     if (buff[a]==32)
         return(0);
    }

 return(1);
}


BYTE load_file(char *filename)

{FILE *fp;
 long  flag = 0;

 if ((fp=fopen(filename,"r"))==NULL)
      return(1);

 while((buff[pointer]=getc(fp)) != EOF)
      {if (buff[pointer]>126 || (buff[pointer]<32 && buff[pointer]!=13 && buff[pointer]!=10))
          {if (!flag)
               AFPrintf(&UserDat, sout, SA[971]);
           flag++;
           continue;
          }
        else
          {if (buff[pointer]==13)  buff[pointer]=10;
          }

       pointer++;
       if (pointer>=messagelen)
          {AFPrintf(&UserDat, sout, SA[972]);
           fclose(fp);
           return(10);
          }
      }

  if (flag)
      AFPrintf(&UserDat, sout, SA[973], flag);

 fclose(fp);
 return(0);
}


BYTE save_file(char *filename)

{FILE *fp;
 long  counter;

 if (!(fp = fopen(filename,"w")))
    {AFPrintf(&UserDat, sout, SA[974]);
     return(1);
    }

 for(counter=0; counter < pointer; counter++)
    {if (buff[counter]==10)
         buff[counter]=13;
     putc(buff[counter],fp);
    }

 if (buff[counter-1]!=13)
     putc(13,fp);

 fclose(fp);
 return(0);
}


BYTE check_word(long counter, long linepos)

{long a;

 for(a=1; counter+a < pointer; a++)
    {if (*(buff+counter+a) == 32)  break;
     if (*(buff+counter+a) == 10)  break;
    }

 if ((linepos+a) > UserDat.Screen_Width)
      return(1);

 return(0);
}


long find_string(char *string, long *position)

{long length;
 long flag;
 long counter = 0;
 long c       = 0;
 long d       = 0;

 length = strlen(string);

 while(c < pointer)
      {if (buff[c] == string[0])
          {flag = 0;

           for(d=0; d<length; d++)
              {if (buff[c+d] != string[d])
                  {flag = 1;
                   break;
                  }
              }

           if (!flag)
              {if (counter < 100)
                  {counter++;
                   position[counter] = c;
                  }
              }
          }

       c++;
      }

 return(counter);
}


BYTE search_replace(void)

{char sstring [127];
 char rstring [127];
 long position[102];
 long counter;
 long searchlen;
 long rplclen;
 long multiflag;

 AFPrintf(&UserDat, sout, SA[975]);

 q.prompt     = SA[976];
 q.string     = sstring;
 q.length     = 127;
 q.typelength = 127;
 q.flags      =  0;
 if (!(searchlen=  DLGQuery(&q, &ui)))
    {AFPrintf(&UserDat, sout, SA[949]);
     return(0);
    }

 counter = find_string(sstring,position);
 if (!counter)
    {AFPrintf(&UserDat, sout, SA[977], sstring);
     return(0);
    }

 if (counter > 1)
    {if (counter >= 100)
         AFPrintf(&UserDat, sout, SA[978]);
       else
         AFPrintf(&UserDat, sout, SA[979], sstring, counter);

     multiflag = BoolQuery(SA[980], 1, &ui);
    }
  else
     AFPrintf(&UserDat, sout, SA[981], sstring);

 AFPrintf(&UserDat, sout, SA[982], sstring);

 q.prompt     = SA[983];
 q.string     = rstring;
 q.length     = 127;
 q.typelength = 127;
 q.flags      =  0;
 if (!(rplclen=  DLGQuery(&q, &ui)))
    {AFPrintf(&UserDat, sout, SA[984]);
     return(0);
    }

 if(multiflag==1)
    query_replace(searchlen,rplclen,sstring,rstring,counter,position);
  else
   {replace_string(searchlen,rplclen,rstring,counter,position);
    AFPrintf(&UserDat, sout, SA[985]);
    AFPrintf(&UserDat, sout, SA[986], counter);
   }
}


BYTE replace_string(long searchlen,long rplclen, char *string, long counter, long *position)

{long diff;
 long a;

  diff=rplclen-searchlen;
  for(a=1;a<=counter;a++) {
    if((pointer+diff)>=messagelen) {
      AFPrintf(&UserDat, sout, SA[987]);
      return(1);
    }
    sub_replace(position,searchlen,rplclen,string,diff,a,counter);
  }
}


long query_replace(long searchlen, long rplclen, char *sstring, char *rstring, long counter, long *position)

{long  next;
 long  nnext;
 long  diff;
 long  a;
 long  d;

 UBYTE e;

 position[0] = 0;
 diff        = rplclen-searchlen;
 nnext       = 1;
 AFPrintf(NULL, sout, "\n\n");

 for(a=1; a<=counter; a++)
    {next  = list_mess(position[a-1],position[a],nnext);
     nnext = next;

     AFPrintf(&UserDat, sout, SA[988], sstring);
     AFPrintf(&UserDat, sout, SA[989]);

     while(e = GetChar())
          {Chk_Abort();
           e = toupper(e);
           if (e == 'Y')  break;
           if (e == 'N')  break;
          }

     for(d=0;d<searchlen+18;d++)
         AFPrintf(NULL, sout, "\010 \010");

     AFPrintf(&UserDat, sout, SA[949]);
     if ((pointer+diff) >= messagelen)
        {AFPrintf(&UserDat, sout, SA[990]);
         return(0);
        }

     if (e != 'N')  sub_replace(position,searchlen,rplclen,rstring,diff,a,counter);
    }

 list_mess(position[a-1],pointer,nnext);
}


void sub_replace(long *position, long searchlen, long rplclen, char *string, long diff, long a, long counter)

{long b;
 long c;
 long tempcount;

  if(diff>-1) {
    for(tempcount=pointer;tempcount >= position[a]+searchlen;tempcount--)
      buff[tempcount+diff]=buff[tempcount];
  }
  else {
     for(tempcount=position[a]+rplclen ; tempcount<pointer ;
    tempcount=tempcount+1)
       buff[tempcount]=buff[tempcount-diff];
   }
   for(b=0 ; b<rplclen ; b++)
     buff[position[a]+b] = string[b];
   pointer = pointer + diff;
   for(c=a+1;c<=counter;c++)
     position[c] = position[c]+diff;
}


long scan_back(void)

{long a;

 if (pointer < 4)  return(0);

 a = pointer - 4;
 while(buff[a] != 10  &&  a > 0)
       a--;

 return(a);
}


BYTE write_file(char *filename)

{FILE *fp;

 if (Exists(filename))
    {if (!(BoolQuery(SA[991], 0, &ui)))
        {AFPrintf(NULL, sout, "\n\n");
         return(-1);
        }
      else
        {AFPrintf(NULL, sout, "\n\n");
         DeleteFile(filename);
        }
    }

 if (!(fp = fopen(filename, "w")))  return(-1);

 fwrite(buff, pointer, 1, fp);
 fclose(fp);
 return(0);
}


void _CXBRK(void)

{if (buff)     free(buff);
 CloseLibrary(DLGBase);
 exit(0);
}
