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

#include <exec/types.h>

#include <libraries/dosextens.h>

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

#include <link/io.h>

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

#include <pragmas/dlg.h>

struct LangStruct * __saveds __asm LIBGetLang(register __a0 char *);
LONG   __saveds __asm LIBTCheckCarrier(register __a0 char *devname);
LONG   __saveds __asm LIBGetDevName(register __a0 char *);
LONG   __saveds __asm LIBStricmp(register __a0 char *,  register __a1 char *);
LONG   __saveds __asm LIBStrnicmp(register __a0 char *, register __a1 char *, register __d0 USHORT);
void   __saveds __asm LIBUpper(register __a0 char *);
void   __saveds __asm LIBCapitalize(register __a0 char *);
char * __saveds __asm LIBDLGBinSearch(register __a0 char  *, register __a1 char  *, register __d0 USHORT, register __d1 USHORT, register __d2 USHORT);

#undef index
char **libgetlang(void);
char  *index(char *r, char);


char __saveds __asm LIBGetChar(void)

{char a;

 Read(Input(), &a, 1);
 return(a);
}


char __saveds __asm LIBReadChar(register __d0 ULONG micros)

{char a;

 if (WaitForChar(Input(), micros))
    {Read(Input(), &a, 1);
     return(a);
    }

 return(FALSE);
}


void __saveds __asm LIBClearLine(void)

{for(;;)
    {Delay(20);

     if (!LIBReadChar(100))  break;
     while(LIBReadChar(100));
    }
}


void __saveds __asm LIBPutChar(register __d0 char a,
                               register __a0 BPTR fh)

{char let;

 let = a;
 Write(fh,&let,1);
}


char **libgetlang()

{struct LangStruct *ls = NULL;
 char               devname[4];

 if (!LIBGetDevName(devname))
      ls = LIBGetLang(devname);
 if (!ls)  ls = LIBGetLang("TL0");

 return(ls->strings);
}


LONG __saveds __asm LIBDLGQuery(register __a0 struct Query    *q,
                                register __a1 struct UserInfo *ui)

{UBYTE *stack;
 UBYTE *currptr;
 char **SA;
 BPTR   sout;

 static char bspace = '\010';
 static char hidden = '#';

 long  numitems;
 long  curritem;

 SHORT b        = 0;
 SHORT maxb     = 0;
 SHORT numsemis = 0;
 SHORT totsemis = 0;
 SHORT numtyped = 0;

 UBYTE a;
 UBYTE stackflag;
 UBYTE shifted;
 UBYTE hot;

 UBYTE tempflag = FALSE;
 UBYTE posedt   =   0;

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

 hot   = ui->User->Hot_Keys;
 stack = (UBYTE *)ui->Ram->Command_Stack;

 if (q->flags & QUERY_GUESS)
    {posedt        = 2;
     numitems      = q->typelength;
     q->typelength = q->length;
     curritem      = (SHORT)((LONG)(q->defstring));
    }
  else
    if ((q->template) && *(q->template))
       {tempflag = TRUE;
       *stack    = 0;
       }

 stackflag = *stack;
 if (!stackflag)
    {if (q->prompt)
         AFPrintf(ui->User, sout, SA[3651], q->prompt);

     if (posedt==2)
        {if (curritem != -1)
            {currptr = (char *)((LONG)(q->template)+(LONG)(curritem*q->length));
             strcpy(stack, currptr);
             numtyped = strlen(stack);
             Write(sout, stack, numtyped);
             AFPrintf(NULL, sout, "[%ldD", numtyped);
            }
        }
      else
        if ((q->typelength>1) && (ui->User->Ansi_Flag & ANSI_POS)  &&  !tempflag)
           {posedt = 1;

            if (q->defstring && !(q->flags&QUERY_NODEFEDT))
               {strcpy(stack, q->defstring);
                b = strlen(stack);
                Write(sout, stack, b);
               }

            numtyped = b;
           }

     while((tempflag && ((a=*(q->template))!='_') && a) || ((a=LIBGetChar()) != 13))
          {if (posedt && ((a==27) || (a==155)))
              {if (a==27  &&  LIBGetChar()!='[')  continue;

               a       = LIBGetChar();
               shifted = FALSE;
               if (a == 32)
                  {shifted = TRUE;
                   a       = LIBGetChar()+3;
                  }

               switch(a)
                     {case 'A':        /* Cursor Up */
                      case 'B':        /* Cursor Down */
                       case 84:
                       case 83: if (posedt != 2)  continue;

                                if (((a=='A') && curritem<1) || (a==83))
                                   {currptr  = (char *)((LONG)(q->template)+((LONG)q->length*(LONG)(numitems-1)));
                                    curritem =  numitems - 1;
                                   }
                                 else
                                   if (((a=='B') && ((curritem==-1)||(curritem==(numitems-1)))) || (a==84))
                                      {currptr  = (char *)(q->template);
                                       curritem =  0;
                                      }
                                    else
                                      {if (a=='A')
                                          {curritem--;
                                           currptr -= q->length;
                                          }
                                        else
                                          {curritem++;
                                           currptr += q->length;
                                          }
                                 }

                                strcpy(stack, currptr);
                                numtyped = strlen(stack);

                                if (b)  AFPrintf(NULL, sout, "[%ldD", b);
                                Write(sout,  stack, numtyped);
                                Write(sout, "[K",      3);

                                b = maxb;
                                if (b >= numtyped)
                                    b = numtyped;
                                  else
                                    AFPrintf(NULL, sout, "[%ldD", numtyped-b);

                                continue;

                      case 'C':        /* Cursor Right */
                                if (shifted)
                                   {if (b != numtyped)
                                       {AFPrintf(NULL, sout, "[%ldC", numtyped-b);
                                        maxb     = numtyped;
                                        b        = numtyped;
                                        numsemis = totsemis;
                                       }
                                    continue;
                                   }

                                if (b < numtyped)
                                   {if ((stack[b]==';') && !(q->flags&QUERY_NOSTACK))
                                         numsemis++;
                                    b++;
                                    maxb = b;
                                    Write(sout, "[C", 3);
                                   }

                                continue;

                      case 'D':        /* Cursor Left */
                                if (!b)  continue;

                                if (shifted)
                                   {AFPrintf(NULL, sout, "[%ldD", b);
                                    maxb     = 0;
                                    b        = 0;
                                    numsemis = 0;
                                    continue;
                                   }

                                b--;
                                maxb = b;

                                if ((stack[b]==';') && !(q->flags&QUERY_NOSTACK))
                                     numsemis--;

                                if (!b && (posedt==2))
                                   {Write(sout, "\010[K", 4);
                                    numtyped = 0;
                                    continue;
                                   }

                                Write(sout, &bspace, 1);
                                continue;

                       default: continue;
                }
              }

           if (a == 24)
              {if (b)
                  {AFPrintf(NULL, sout, "[%ldD", b);
                   Write(sout, "[K", 3);

                   b        = 0;
                   maxb     = 0;
                   numtyped = 0;
                   totsemis = 0;
                   numsemis = 0;
                  }
               continue;
              }

           if (a==8)
              {if (!b)  continue;

               if (posedt == 2)
                  {char *cmpres;

                   b--;
                   maxb = b;

                   if (!b)
                      {Write(sout, "\010[K", 4);
                       numtyped = 0;
                       continue;
                      }

                   cmpres = LIBDLGBinSearch((q->template),stack,q->length,b+1,numitems);
                   do{currptr = cmpres;
                      if (currptr==(UBYTE *)(q->template)) break;
                      cmpres -= q->length;
                     } while(!LIBStrnicmp(stack, cmpres, b+1));

                   curritem = ((long)currptr-(long)(q->template))/q->length;
                   strcpy(stack+b, currptr+b);
                   numtyped = strlen(stack);
                   Write(sout, stack+b+1, (long)(numtyped-b-1));
                   Write(sout, "[K", 3);
                   AFPrintf(NULL, sout, "[%ldD", numtyped-b);
                  }
                else
                  {do{b--;
                      maxb = b;
                      numtyped--;

                      if ((stack[b]==';') && !(q->flags&QUERY_NOSTACK))
                         {numsemis--;
                          totsemis--;
                         }

                      if (posedt)
                         {Write(sout, "\010[P", 4);
                          movmem(stack+b+1,stack+b,numtyped-b);
                         }
                       else
                         Write(sout, "\010 \010", 3);

                      if (tempflag) (q->template)--;
                     } while(tempflag && (*(q->template)!='_') && b);
                  }

               continue;
              }

           if ((a==127) && (posedt==1))
              {if (numtyped > b)
                  {numtyped--;
                   if ((stack[b+1]==';')&&!(q->flags&QUERY_NOSTACK))
                        totsemis--;
                   Write(sout, "[P", 3);
                   movmem(stack+b+1,stack+b,numtyped-b);
                  }
               continue;
              }

          if (tempflag)
             {if (!*(q->template)) continue;
              (q->template)++;
             }

          if (numtyped == q->typelength) continue;

          if ((a==';') && !(q->flags&QUERY_NOSTACK) && (posedt!=2))
             {if (!tempflag)
                 {numsemis++;
                  totsemis++;
                 }
               else
                  continue;

              if (hot&&(q->length==1))
                 {Write(sout, &a, 1);
                  numsemis--;
                  totsemis--;
                  hot = FALSE;
                  continue;
                 }
             }

          if (a<32 || (a>127 && a<160))  continue;

          if (posedt == 2)
             {char *cmpres;

              stack[b] = a;
              cmpres   = LIBDLGBinSearch((q->template),stack,q->length,b+1,numitems);

              if (cmpres)
                 {do{currptr = cmpres;
                     if (currptr==(UBYTE *)(q->template)) break;
                     cmpres -= q->length;
                    } while(!LIBStrnicmp(stack, cmpres, b+1));
                 }

              if (currptr)
                 {curritem = ((long)currptr-(long)(q->template))/q->length;
                  strcpy(stack+b, currptr+b);
                  numtyped = strlen(stack);

                  Write(sout, stack+b, (long)(numtyped-b));
                  Write(sout, "[K", 3);

                  if (cmpres)
                     {b++;
                      maxb = b;
                     }

                  if (b < numtyped)  AFPrintf(NULL, sout, "[%ldD", numtyped-b);
                 }

              continue;
             }

          if (posedt == 1)
             {if (b != numtyped) 
                  {Write(sout, "[@", 3);
                   movmem(stack+b, stack+b+1, numtyped-b);
                  }
             }

          if (numsemis)
              Write(sout, &a ,1);
            else
              {if (q->valid&&!index(q->valid,a)) continue;

               if (q->flags&QUERY_UPCASE)
                   a = toupper(a);
                 else
                   if (q->flags&QUERY_CAPITAL)
                      {if (b == 0 || stack[b-1] == 32 || stack[b-1] == '-' || stack[b-1] == 39)
                           a = toupper(a);
                          else
                           a = tolower(a);
                      }

               if (q->flags&QUERY_HIDDEN)
                   Write(sout, &hidden, 1);
                 else
                   Write(sout, &a,      1);
              }

          stack[b] = a;
          b++;
          maxb = b;
          numtyped++;
          if ((q->length==1) && hot && !numsemis && (a<'0' || a>'9'))  break;
         }

     if (posedt && (b!=numtyped)) AFPrintf(NULL, sout, "[%ldC", numtyped-b);
     if (posedt && (numtyped>b))  b = numtyped;
     stack[b] = 0;
    }

 {long numchars;

  for(b = 0; stack[b]; b++)
     {if (stack[b] == ';'  &&  !(q->flags & QUERY_NOSTACK))  break;
      if (!q->valid)                                         continue;
      if (!index(q->valid, stack[b]))                        break;
     }

  numchars = (b < q->length) ? b : q->length;
  if (numchars)  movmem(stack, q->string, numchars);
  q->string[numchars] = 0;

  if (stackflag)
     {if (q->flags & QUERY_UPCASE)  LIBUpper(q->string);
      if (q->flags & QUERY_CAPITAL) LIBCapitalize(q->string);
     }

  if ((stack[numchars] == ';')  &&  !(q->flags & QUERY_NOSTACK))
       movmem((stack+numchars+1), stack, strlen(stack)-numchars);
     else
       movmem((stack+numchars),   stack, strlen(stack)-numchars+1);

  if (!numchars && q->defstring && (!posedt || (q->flags&QUERY_NODEFEDT)))
     {strcpy(q->string,q->defstring);
      numchars = strlen(q->string);
      Write(sout, q->string, numchars);
     }

  return((posedt==2)?((strlen(q->string))?(LONG)curritem:-1):numchars);
 }
}


LONG __saveds __asm LIBIntQuery(register __a0 char            *query,
                                register __d0 long             lower,
                                register __d1 long             upper,
                                register __d2 long             def,
                                register __a1 struct UserInfo *ui)

{long          value; 
 char          string[16];
 struct Query  q;

 q.prompt     =  query;
 q.template   =  NULL;
 q.string     =  string;
 q.defstring  =  NULL;
 q.valid      = "01234567890-";
 q.length     =  15;
 q.typelength =  15;
 q.flags      =  0;

 for(;;)
    {if (!LIBDLGQuery(&q, ui))
        {AFPrintf(ui->User, Output(), "%d", def);
         return((long)def);
        }

     if (!sscanf(string, "%ld", &value)  ||  value > upper  ||  value < lower)
        {char **SA;

         SA       = libgetlang();
         AFPrintf(ui->User, Output(), SA[3652], lower, upper);
         ui->Ram->Command_Stack[0] = 0;
         continue;
        }

     return(value);
    }
}


BOOL __saveds __asm LIBBoolQuery(register __a0 char *query,
                                 register __d0 UBYTE opt,
                                 register __a1 struct UserInfo *ui)

{BPTR   sout;
 char **SA;

 BOOL   retval;
 BOOL   stackflag;
 char   string[2];
 struct Query q;

 static char y[] = "Y";
 static char n[] = "N";

 sout      = Output();
 SA        = libgetlang();
 stackflag = ui->Ram->Command_Stack[0];

 q.prompt     = "";
 q.template   =  NULL;
 q.string     =  string;
 if (opt)
     q.defstring = y;
   else
     q.defstring = n;
 q.valid      = "YyNn";
 q.length     =  1;
 q.typelength =  1;
 q.flags      =  QUERY_UPCASE;

 if (!stackflag)
    {AFPrintf(ui->User, sout, SA[3651], query);

     if (opt)
         AFPrintf(ui->User, sout, " [Y/n] => ");
       else
         AFPrintf(ui->User, sout, " [y/N] => ");
    }

 LIBDLGQuery(&q, ui);

 if (string[0] == 'Y')
     retval = 1;
   else
     retval = 0;

 if (!stackflag)
    {if (retval > 0)
         Write(sout, "es", 2);
       else
         Write(sout, "o",  1);
    }

 return(retval);
}
